[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, ð_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 = ¤t->saved_sigmask;
- else if (!oldset)
- oldset = ¤t->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, ®s->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, ®s->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, ®s->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, ®s->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,
++ ®s->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, ®s->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, ®s->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 = ð_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = ð_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 = ð_dmamask,
+- .coherent_dma_mask = 0xffffffff,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = ð_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 = ð_dmamask,
+- .coherent_dma_mask = 0xffffffff,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = ð_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 = ð_dmamask,
+- .coherent_dma_mask = 0xffffffff,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = ð_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, ð_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 = ¤t->saved_sigmask;
+ else if (!oldset)
+ oldset = ¤t->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(¤t->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(®s, 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,
+- ®s, 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(®s, 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,
++ ®s, 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(®s, 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,
++ ®s, 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)®s->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)®s->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(¤t->sighand->siglock);
+- current->saved_sigmask = current->blocked;
+- siginitset(¤t->blocked, mask);
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- current->blocked = set;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- current->blocked = set;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+- if (!(ka->sa.sa_flags & SA_NODEFER))
+- sigaddset(¤t->blocked,sig);
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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 = ¤t->saved_sigmask;
+- else
+- oldset = ¤t->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, ¤t->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(¤t->sighand->siglock);
++ current->saved_sigmask = current->blocked;
++ siginitset(¤t->blocked, mask);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ current->blocked = set;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ current->blocked = set;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
++ if (!(ka->sa.sa_flags & SA_NODEFER))
++ sigaddset(¤t->blocked,sig);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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 = ¤t->saved_sigmask;
++ else
++ oldset = ¤t->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, ¤t->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(¤t->sighand->siglock);
++ saveset = current->blocked;
++ siginitset(¤t->blocked, mask);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ saveset = current->blocked;
++ current->blocked = newset;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->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], ¤t->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(¤t->sighand->siglock);
++ current->blocked = set;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ current->blocked = set;
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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(¤t->sighand->siglock);
++ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
++ if (!(ka->sa.sa_flags & SA_NODEFER))
++ sigaddset(¤t->blocked,sig);
++ recalc_sigpending();
++ spin_unlock_irq(¤t->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 = ¤t->saved_sigmask;
++ else if (!oldset)
++ oldset = ¤t->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, ¤t->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 = ®s->regs[index];
+-
+- index = (instruction>>4)&15; /* 0x00F0 */
+- rm = ®s->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*) ®s->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*) ®s->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 = ®s->regs[index];
++
++ index = (instruction>>4)&15; /* 0x00F0 */
++ rm = ®s->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*) ®s->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*) ®s->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, ®s->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)©_user_memcpy) &&
++ (addr <= (unsigned long)©_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(¤t->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(®s, 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,
+- ®s, 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(¤t->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(¤t->sighand->siglock);
+- saveset = current->blocked;
+- siginitset(¤t->blocked, mask);
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- saveset = current->blocked;
+- current->blocked = newset;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->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(¤t->thread.fpu.hard);
+- release_fpu();
+- last_task_used_math = NULL;
+- regs->sr |= SR_FD;
+- }
+-
+- err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->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(¤t->sighand->siglock);
+- current->blocked = set;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- current->blocked = set;
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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(¤t->sighand->siglock);
+- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+- if (!(ka->sa.sa_flags & SA_NODEFER))
+- sigaddset(¤t->blocked,sig);
+- recalc_sigpending();
+- spin_unlock_irq(¤t->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 = ¤t->saved_sigmask;
+- else if (!oldset)
+- oldset = ¤t->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, ¤t->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(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->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, ®s->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(¤t->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(¤t->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)©_user_memcpy) &&
+- (addr <= (unsigned long)©_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], >f->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], >f->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, ®50);
+- (void) pci_read_config_byte(dev, CNTRL, ®51);
+- (void) pci_read_config_byte(dev, ARTTIM23, ®57);
+- (void) pci_read_config_byte(dev, MRDMODE, ®71);
+- (void) pci_read_config_byte(dev, BMIDESR0, ®72);
+- (void) pci_read_config_byte(dev, UDIDETCR0, ®73);
+- (void) pci_read_config_byte(dev, BMIDESR1, ®7a);
+- (void) pci_read_config_byte(dev, UDIDETCR1, ®7b);
+-
+- /* 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, ®54);
+ pci_read_config_byte(dev, 0x55, ®55);
- 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, ®54);
+ pci_read_config_byte(dev, 0x55, ®55);
+
+- 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, ®);
+@@ -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, ®dw);
+- 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, ®);
+- /* 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, ®dw);
+
-+ 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, ®);
+
-+ 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, ®48);
+ pci_read_config_word(dev, 0x4a, ®4a);
+
+- 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, ¶m, __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, ¶m, __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,
+ ®_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, ®50);
-- (void) pci_read_config_byte(dev, CNTRL, ®51);
-- (void) pci_read_config_byte(dev, ARTTIM23, ®57);
-- (void) pci_read_config_byte(dev, MRDMODE, ®71);
-- (void) pci_read_config_byte(dev, BMIDESR0, ®72);
-- (void) pci_read_config_byte(dev, UDIDETCR0, ®73);
-- (void) pci_read_config_byte(dev, BMIDESR1, ®7a);
-- (void) pci_read_config_byte(dev, UDIDETCR1, ®7b);
--
-- /* 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, ®54);
- pci_read_config_byte(dev, 0x55, ®55);
-- 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, ®54);
- pci_read_config_byte(dev, 0x55, ®55);
+@@ -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, ®);
-@@ -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, ®dw);
-- 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, ®);
-- /* 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, ®dw);
-+
-+ 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, ®);
-+
-+ /* 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, ®48);
- pci_read_config_word(dev, 0x4a, ®4a);
+ 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, ®);
+- 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, ¶m, __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, ¶m, __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,
- ®_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, ®);
-- 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, ®Data);
++ 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, ®Data);
++ 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 = ¶m->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 = ¶m->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, ®Data);
-+ 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, ®Data);
-+ 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 = ¶m->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 = ¶m->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, ¶ms);
++ 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, ¶ms);
+ }
-- 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, ¶ms);
+ }
-- 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, ¶ms);
-+ 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, ¶ms);
- }
- 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(¤t->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, ¶ms);
- }
+ 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(¤t->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, ¶ms, 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, ¶ms, 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(®->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(®->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(®->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(®->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_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_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