Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
diff --git a/CREDITS b/CREDITS
index 7fb4c73..192f749 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1097,7 +1097,7 @@
 S: Brazil
 
 N: Kumar Gala
-E: kumar.gala@freescale.com
+E: galak@kernel.crashing.org
 D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support
 S: Austin, Texas 78729
 S: USA
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 7018f5c..1c95588 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -20,6 +20,12 @@
 #                        +--> DIR=file  (htmldocs)
 #                        +--> man/      (mandocs)
 
+
+# for PDF and PS output you can choose between xmlto and docbook-utils tools
+PDF_METHOD	= $(prefer-db2x)
+PS_METHOD	= $(prefer-db2x)
+
+
 ###
 # The targets that may be used.
 .PHONY:	xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs
@@ -93,27 +99,39 @@
 C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example))
 $(obj)/procfs-guide.xml: $(C-procfs-example2)
 
-###
-# Rules to generate postscript, PDF and HTML
-# db2html creates a directory. Generate a html file used for timestamp
+notfoundtemplate = echo "*** You have to install docbook-utils or xmlto ***"; \
+		   exit 1
+db2xtemplate = db2TYPE -o $(dir $@) $<
+xmltotemplate = xmlto TYPE $(XMLTOFLAGS) -o $(dir $@) $<
 
-quiet_cmd_db2ps = XMLTO    $@
-      cmd_db2ps = xmlto ps $(XMLTOFLAGS) -o $(dir $@) $<
+# determine which methods are available
+ifeq ($(shell which db2ps >/dev/null 2>&1 && echo found),found)
+	use-db2x = db2x
+	prefer-db2x = db2x
+else
+	use-db2x = notfound
+	prefer-db2x = $(use-xmlto)
+endif
+ifeq ($(shell which xmlto >/dev/null 2>&1 && echo found),found)
+	use-xmlto = xmlto
+	prefer-xmlto = xmlto
+else
+	use-xmlto = notfound
+	prefer-xmlto = $(use-db2x)
+endif
+
+# the commands, generated from the chosen template
+quiet_cmd_db2ps = PS      $@
+      cmd_db2ps = $(subst TYPE,ps, $($(PS_METHOD)template))
 %.ps : %.xml
-	@(which xmlto > /dev/null 2>&1) || \
-	 (echo "*** You need to install xmlto ***"; \
-	  exit 1)
 	$(call cmd,db2ps)
 
-quiet_cmd_db2pdf = XMLTO   $@
-      cmd_db2pdf = xmlto pdf $(XMLTOFLAGS) -o $(dir $@) $<
+quiet_cmd_db2pdf = PDF      $@
+      cmd_db2pdf = $(subst TYPE,pdf, $($(PDF_METHOD)template))
 %.pdf : %.xml
-	@(which xmlto > /dev/null 2>&1) || \
-	 (echo "*** You need to install xmlto ***"; \
-	  exit 1)
 	$(call cmd,db2pdf)
 
-quiet_cmd_db2html = XMLTO  $@
+quiet_cmd_db2html = HTML   $@
       cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
 		echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
          Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
@@ -127,7 +145,7 @@
 	@if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \
             cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi
 
-quiet_cmd_db2man = XMLTO   $@
+quiet_cmd_db2man = MAN     $@
       cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi
 %.9 : %.xml
 	@(which xmlto > /dev/null 2>&1) || \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index a8316b1..0519c9d 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -68,9 +68,7 @@
 
      <sect1><title>Kernel utility functions</title>
 !Iinclude/linux/kernel.h
-<!-- This needs to clean up to make kernel-doc happy
-X!Ekernel/printk.c
- -->
+!Ekernel/printk.c
 !Ekernel/panic.c
 !Ekernel/sys.c
 !Ekernel/rcupdate.c
diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl
index 64be9f7..3ccce88 100644
--- a/Documentation/DocBook/stylesheet.xsl
+++ b/Documentation/DocBook/stylesheet.xsl
@@ -3,4 +3,5 @@
 <param name="chunk.quietly">1</param>
 <param name="funcsynopsis.style">ansi</param>
 <param name="funcsynopsis.tabular.threshold">80</param>
+<!-- <param name="paper.type">A4</param> -->
 </stylesheet>
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 8eedaa2..23a1c24 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -115,6 +115,33 @@
 is negative.  It requires explicit memory barrier semantics around the
 operation.
 
+Then:
+
+	int atomic_cmpxchg(atomic_t *v, int old, int new);
+
+This performs an atomic compare exchange operation on the atomic value v,
+with the given old and new values. Like all atomic_xxx operations,
+atomic_cmpxchg will only satisfy its atomicity semantics as long as all
+other accesses of *v are performed through atomic_xxx operations.
+
+atomic_cmpxchg requires explicit memory barriers around the operation.
+
+The semantics for atomic_cmpxchg are the same as those defined for 'cas'
+below.
+
+Finally:
+
+	int atomic_add_unless(atomic_t *v, int a, int u);
+
+If the atomic value v is not equal to u, this function adds a to v, and
+returns non zero. If v is equal to u then it returns zero. This is done as
+an atomic operation.
+
+atomic_add_unless requires explicit memory barriers around the operation.
+
+atomic_inc_not_zero, equivalent to atomic_add_unless(v, 1, 0)
+
+
 If a caller requires memory barrier semantics around an atomic_t
 operation which does not return a value, a set of interfaces are
 defined which accomplish this:
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index c563842..9f30ac6 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -30,7 +30,9 @@
 
 (1) Hand copy the text from the screen and type it in after the machine
     has restarted.  Messy but it is the only option if you have not
-    planned for a crash.
+    planned for a crash. Alternatively, you can take a picture of
+    the screen with a digital camera - not nice, but better than
+    nothing.
 
 (2) Boot with a serial console (see Documentation/serial-console.txt),
     run a null modem to a second machine and capture the output there
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index 2404099..330246a 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -140,3 +140,4 @@
 139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
 140 -> Osprey 440                                          [0070:ff07]
 141 -> Asound Skyeye PCTV
+142 -> Sabrent TV-FM (bttv version)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 57c9d63..efb708e 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -80,3 +80,5 @@
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
+ 82 -> MSI TV@Anywhere plus                     [1462:6231]
+
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index ec840ca..9d6544e 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -67,3 +67,4 @@
 tuner=66 - LG NTSC (TALN mini series)
 tuner=67 - Philips TD1316 Hybrid Tuner
 tuner=68 - Philips TUV1236D ATSC/NTSC dual in
+tuner=69 - Tena TNF 5335 MF
diff --git a/MAINTAINERS b/MAINTAINERS
index 2313de2..509927e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1565,7 +1565,7 @@
 
 LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
 P:     Kumar Gala
-M:     kumar.gala@freescale.com
+M:     galak@kernel.crashing.org
 W:     http://www.penguinppc.org/
 L:     linuxppc-embedded@ozlabs.org
 S:     Maintained
@@ -1873,6 +1873,16 @@
 W:	http://www.linuxtr.net
 S:	Maintained
 
+OMNIKEY CARDMAN 4000 DRIVER
+P:	Harald Welte
+M:	laforge@gnumonks.org
+S:	Maintained
+
+OMNIKEY CARDMAN 4040 DRIVER
+P:	Harald Welte
+M:	laforge@gnumonks.org
+S:	Maintained
+
 ONSTREAM SCSI TAPE DRIVER
 P:	Willem Riede
 M:	osst@riede.org
diff --git a/Makefile b/Makefile
index 8560b79..c319144 100644
--- a/Makefile
+++ b/Makefile
@@ -1193,6 +1193,17 @@
 __srctree = $(srctree)/
 endif
 
+ifeq ($(ALLSOURCE_ARCHS),)
+ifeq ($(ARCH),um)
+ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
+else
+ALLINCLUDE_ARCHS := $(ARCH)
+endif
+else
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
+endif
+
 ALLSOURCE_ARCHS := $(ARCH)
 
 define all-sources
@@ -1208,7 +1219,7 @@
 	  find $(__srctree)include $(RCS_FIND_IGNORE) \
 	       \( -name config -o -name 'asm-*' \) -prune \
 	       -o -name '*.[chS]' -print; \
-	  for ARCH in $(ALLSOURCE_ARCHS) ; do \
+	  for ARCH in $(ALLINCLUDE_ARCHS) ; do \
 	       find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
 	            -name '*.[chS]' -print; \
 	  done ; \
diff --git a/README b/README
index 4ee7dda..61c4f74 100644
--- a/README
+++ b/README
@@ -81,6 +81,11 @@
    failed patches (xxx# or xxx.rej). If there are, either you or me has
    made a mistake.
 
+   Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
+   (also known as the -stable kernels) are not incremental but instead apply
+   directly to the base 2.6.x kernel.  Please read
+   Documentation/applying-patches.txt for more information.
+
    Alternatively, the script patch-kernel can be used to automate this
    process.  It determines the current kernel version and applies any
    patches found.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3df7cbd..70b007e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -702,6 +702,8 @@
 
 source "drivers/base/Kconfig"
 
+source "drivers/connector/Kconfig"
+
 if ALIGNMENT_TRAP
 source "drivers/mtd/Kconfig"
 endif
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 557e52c..1b7eaab 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -623,8 +623,6 @@
 	locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
 
 	spin_unlock_irqrestore(&lchip->lock, flags);
-
-	dev->power.saved_state = NULL;
 	kfree(save);
 
 	return 0;
@@ -775,7 +773,7 @@
 
 static int locomo_remove(struct platform_device *dev)
 {
-	struct locomo *lchip = platform__get_drvdata(dev);
+	struct locomo *lchip = platform_get_drvdata(dev);
 
 	if (lchip) {
 		__locomo_remove(lchip);
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 32924c6..0c3cbd9 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -153,7 +153,7 @@
 	printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
 
 	SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
-	reset_scoop(dev);
+	reset_scoop(&pdev->dev);
 	SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
 	SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
 
diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c
index b0bbd1e..a2843be 100644
--- a/arch/arm/kernel/apm.c
+++ b/arch/arm/kernel/apm.c
@@ -20,6 +20,7 @@
 #include <linux/apm_bios.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index e55ea95..373c095 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -256,9 +256,7 @@
 asmlinkage void __cpuinit secondary_start_kernel(void)
 {
 	struct mm_struct *mm = &init_mm;
-	unsigned int cpu;
-
-	cpu = smp_processor_id();
+	unsigned int cpu = smp_processor_id();
 
 	printk("CPU%u: Booted secondary processor\n", cpu);
 
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index dc09fd2..bbe6e4a 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -132,14 +132,14 @@
 static struct map_desc fb_common_io_desc[] __initdata = {
 	{
 		.virtual	= ARMCSR_BASE,
-		.pfn		= DC21285_ARMCSR_BASE,
+		.pfn		= __phys_to_pfn(DC21285_ARMCSR_BASE),
 		.length		= ARMCSR_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= XBUS_BASE,
 		.pfn		= __phys_to_pfn(0x40000000),
 		.length		= XBUS_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}
 };
 
@@ -153,28 +153,28 @@
 		.virtual	= PCIMEM_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_MEM),
 		.length		= PCIMEM_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= PCICFG0_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG),
 		.length		= PCICFG0_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= PCICFG1_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG),
 		.length		= PCICFG1_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= PCIIACK_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_IACK),
 		.length		= PCIIACK_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= PCIO_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_IO),
 		.length		= PCIO_SIZE,
-		.type		= MT_DEVICE
-	}
+		.type		= MT_DEVICE,
+	},
 #endif
 };
 
@@ -187,13 +187,13 @@
 		.virtual	= PCIO_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_IO),
 		.length		= PCIO_SIZE,
-		.type		= MT_DEVICE
+		.type		= MT_DEVICE,
 	}, {
 		.virtual	= PCIMEM_BASE,
 		.pfn		= __phys_to_pfn(DC21285_PCI_MEM),
 		.length		= PCIMEM_SIZE,
-		.type		= MT_DEVICE
-	}
+		.type		= MT_DEVICE,
+	},
 #endif
 };
 
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index e201aa9..cd50664 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -72,6 +72,12 @@
 	depends PXA_SHARPSL_25x
 	select PXA_SHARP_C7xx
 
+config MACH_AKITA
+	bool "Enable Sharp SL-1000 (Akita) Support"
+	depends PXA_SHARPSL_27x
+	select PXA_SHARP_Cxx00
+	select MACH_SPITZ
+
 config MACH_SPITZ
 	bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
 	depends PXA_SHARPSL_27x
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index d210bd5..32526a0 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -11,8 +11,9 @@
 obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx)	+= corgi.o corgi_ssp.o corgi_lcd.o
-obj-$(CONFIG_PXA_SHARP_Cxx00)	+= spitz.o corgi_ssp.o corgi_lcd.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
 obj-$(CONFIG_MACH_TOSA)         += tosa.o
 
diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
new file mode 100644
index 0000000..f6d73cc
--- /dev/null
+++ b/arch/arm/mach-pxa/akita-ioexp.c
@@ -0,0 +1,223 @@
+/*
+ * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
+ * (uses a Maxim MAX7310 8 Port IO Expander)
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <asm/arch/akita.h>
+
+/* MAX7310 Regiser Map */
+#define MAX7310_INPUT    0x00
+#define MAX7310_OUTPUT   0x01
+#define MAX7310_POLINV   0x02
+#define MAX7310_IODIR    0x03 /* 1 = Input, 0 = Output */
+#define MAX7310_TIMEOUT  0x04
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
+
+/* I2C Magic */
+I2C_CLIENT_INSMOD;
+
+static int max7310_write(struct i2c_client *client, int address, int data);
+static struct i2c_client max7310_template;
+static void akita_ioexp_work(void *private_);
+
+static struct device *akita_ioexp_device;
+static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
+DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL);
+
+
+/*
+ * MAX7310 Access
+ */
+static int max7310_config(struct device *dev, int iomode, int polarity)
+{
+	int ret;
+	struct i2c_client *client = to_i2c_client(dev);
+
+	ret = max7310_write(client, MAX7310_POLINV, polarity);
+	if (ret < 0)
+		return ret;
+	ret = max7310_write(client, MAX7310_IODIR, iomode);
+	return ret;
+}
+
+static int max7310_set_ouputs(struct device *dev, int outputs)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return max7310_write(client, MAX7310_OUTPUT, outputs);
+}
+
+/*
+ * I2C Functions
+ */
+static int max7310_write(struct i2c_client *client, int address, int value)
+{
+	u8 data[2];
+
+	data[0] = address & 0xff;
+	data[1] = value & 0xff;
+
+	if (i2c_master_send(client, data, 2) == 2)
+		return 0;
+	return -1;
+}
+
+static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	int err;
+
+	if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+		return -ENOMEM;
+
+	max7310_template.adapter = adapter;
+	max7310_template.addr = address;
+
+	memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
+
+	if ((err = i2c_attach_client(new_client))) {
+		kfree(new_client);
+		return err;
+	}
+
+	max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
+	akita_ioexp_device = &new_client->dev;
+	schedule_work(&akita_ioexp);
+
+	return 0;
+}
+
+static int max7310_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, max7310_detect);
+}
+
+static int max7310_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	akita_ioexp_device = NULL;
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+	return 0;
+}
+
+static struct i2c_driver max7310_i2c_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "akita-max7310",
+	.id		= I2C_DRIVERID_AKITAIOEXP,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= max7310_attach_adapter,
+	.detach_client	= max7310_detach_client,
+};
+
+static struct i2c_client max7310_template = {
+	name:   "akita-max7310",
+	flags:  I2C_CLIENT_ALLOW_USE,
+	driver: &max7310_i2c_driver,
+};
+
+void akita_set_ioexp(struct device *dev, unsigned char bit)
+{
+	ioexp_output_value |= bit;
+
+	if (akita_ioexp_device)
+		schedule_work(&akita_ioexp);
+	return;
+}
+
+void akita_reset_ioexp(struct device *dev, unsigned char bit)
+{
+	ioexp_output_value &= ~bit;
+
+	if (akita_ioexp_device)
+		schedule_work(&akita_ioexp);
+	return;
+}
+
+EXPORT_SYMBOL(akita_set_ioexp);
+EXPORT_SYMBOL(akita_reset_ioexp);
+
+static void akita_ioexp_work(void *private_)
+{
+	if (akita_ioexp_device)
+		max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
+}
+
+
+#ifdef CONFIG_PM
+static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	flush_scheduled_work();
+	return 0;
+}
+
+static int akita_ioexp_resume(struct platform_device *pdev)
+{
+	schedule_work(&akita_ioexp);
+	return 0;
+}
+#else
+#define akita_ioexp_suspend NULL
+#define akita_ioexp_resume NULL
+#endif
+
+static int __init akita_ioexp_probe(struct platform_device *pdev)
+{
+	return i2c_add_driver(&max7310_i2c_driver);
+}
+
+static int akita_ioexp_remove(struct platform_device *pdev)
+{
+	i2c_del_driver(&max7310_i2c_driver);
+	return 0;
+}
+
+static struct platform_driver akita_ioexp_driver = {
+	.probe		= akita_ioexp_probe,
+	.remove		= akita_ioexp_remove,
+	.suspend	= akita_ioexp_suspend,
+	.resume		= akita_ioexp_resume,
+	.driver		= {
+		.name	= "akita-ioexp",
+	},
+};
+
+static int __init akita_ioexp_init(void)
+{
+	return platform_driver_register(&akita_ioexp_driver);
+}
+
+static void __exit akita_ioexp_exit(void)
+{
+	platform_driver_unregister(&akita_ioexp_driver);
+}
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Akita IO-Expander driver");
+MODULE_LICENSE("GPL");
+
+fs_initcall(akita_ioexp_init);
+module_exit(akita_ioexp_exit);
+
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
new file mode 100644
index 0000000..599be14
--- /dev/null
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -0,0 +1,228 @@
+/*
+ * Battery and Power Management code for the Sharp SL-C7xx
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/apm.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/hardware/scoop.h>
+
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
+
+static void corgi_charger_init(void)
+{
+	pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT);
+	pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
+	pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
+	pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
+}
+
+static void corgi_charge_led(int val)
+{
+	if (val == SHARPSL_LED_ERROR) {
+		dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+	} else if (val == SHARPSL_LED_ON) {
+		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+		GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+	} else {
+		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+		GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+	}
+}
+
+static void corgi_measure_temp(int on)
+{
+	if (on)
+		GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+	else
+		GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+}
+
+static void corgi_charge(int on)
+{
+	if (on) {
+		if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) {
+			GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+			GPSR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+		} else {
+			GPSR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+			GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+		}
+	} else {
+		GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+		GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+	}
+}
+
+static void corgi_discharge(int on)
+{
+	if (on)
+		GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+	else
+		GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+}
+
+static void corgi_presuspend(void)
+{
+	int i;
+	unsigned long wakeup_mask;
+
+	/* charging , so CHARGE_ON bit is HIGH during OFF. */
+	if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON))
+		PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON);
+	else
+		PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON);
+
+	if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE))
+		PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE);
+	else
+		PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE);
+
+	if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN))
+		PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN);
+	else
+		PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN);
+
+	/* Resume on keyboard power key */
+	PGSR2 = (PGSR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(0);
+
+	wakeup_mask = GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) | GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_CHRG_FULL);
+
+	if (!machine_is_corgi())
+		wakeup_mask |= GPIO_bit(CORGI_GPIO_MAIN_BAT_LOW);
+
+	PWER = wakeup_mask | PWER_RTC;
+	PRER = wakeup_mask;
+	PFER = wakeup_mask;
+
+	for (i = 0; i <=15; i++) {
+		if (PRER & PFER & GPIO_bit(i)) {
+			if (GPLR0 & GPIO_bit(i) )
+				PRER &= ~GPIO_bit(i);
+			else
+				PFER &= ~GPIO_bit(i);
+		}
+	}
+}
+
+static void corgi_postsuspend(void)
+{
+}
+
+/*
+ * Check what brought us out of the suspend.
+ * Return: 0 to sleep, otherwise wake
+ */
+static int corgi_should_wakeup(unsigned int resume_on_alarm)
+{
+	int is_resume = 0;
+
+	dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR);
+
+	if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) {
+		if (STATUS_AC_IN()) {
+			/* charge on */
+			dev_dbg(sharpsl_pm.dev, "ac insert\n");
+			sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+		} else {
+			/* charge off */
+			dev_dbg(sharpsl_pm.dev, "ac remove\n");
+			CHARGE_LED_OFF();
+			CHARGE_OFF();
+			sharpsl_pm.charge_mode = CHRG_OFF;
+		}
+	}
+
+	if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL)))
+		dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n");
+
+	if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT))
+		is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT);
+
+	if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP))
+		is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP);
+
+	if (resume_on_alarm && (PEDR & PWER_RTC))
+		is_resume |= PWER_RTC;
+
+	dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+	return is_resume;
+}
+
+static unsigned long corgi_charger_wakeup(void)
+{
+	return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) );
+}
+
+static int corgi_acin_status(void)
+{
+	return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0);
+}
+
+static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
+	.init            = corgi_charger_init,
+	.gpio_batlock    = CORGI_GPIO_BAT_COVER,
+	.gpio_acin       = CORGI_GPIO_AC_IN,
+	.gpio_batfull    = CORGI_GPIO_CHRG_FULL,
+	.status_acin     = corgi_acin_status,
+	.discharge       = corgi_discharge,
+	.charge          = corgi_charge,
+	.chargeled       = corgi_charge_led,
+	.measure_temp    = corgi_measure_temp,
+	.presuspend      = corgi_presuspend,
+	.postsuspend     = corgi_postsuspend,
+	.charger_wakeup  = corgi_charger_wakeup,
+	.should_wakeup   = corgi_should_wakeup,
+	.bat_levels      = 40,
+	.bat_levels_noac = spitz_battery_levels_noac,
+	.bat_levels_acin = spitz_battery_levels_acin,
+	.status_high_acin = 188,
+	.status_low_acin  = 178,
+	.status_high_noac = 185,
+	.status_low_noac  = 175,
+};
+
+static struct platform_device *corgipm_device;
+
+static int __devinit corgipm_init(void)
+{
+	int ret;
+
+	corgipm_device = platform_device_alloc("sharpsl-pm", -1);
+	if (!corgipm_device)
+		return -ENOMEM;
+
+	corgipm_device->dev.platform_data = &corgi_pm_machinfo;
+	ret = platform_device_add(corgipm_device);
+
+	if (ret)
+		platform_device_put(corgipm_device);
+
+	return ret;
+}
+
+static void corgipm_exit(void)
+{
+	platform_device_unregister(corgipm_device);
+}
+
+module_init(corgipm_init);
+module_exit(corgipm_exit);
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
index 4879c0f..b0c40a1 100644
--- a/arch/arm/mach-pxa/sharpsl.h
+++ b/arch/arm/mach-pxa/sharpsl.h
@@ -115,7 +115,7 @@
 #define CHARGE_LED_ERR()    sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR)
 #define DISCHARGE_ON()      sharpsl_pm.machinfo->discharge(1)
 #define DISCHARGE_OFF()     sharpsl_pm.machinfo->discharge(0)
-#define STATUS_AC_IN        sharpsl_pm.machinfo->status_acin()
-#define STATUS_BATT_LOCKED  READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
-#define STATUS_CHRG_FULL    READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
-#define STATUS_FATAL        READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
+#define STATUS_AC_IN()      sharpsl_pm.machinfo->status_acin()
+#define STATUS_BATT_LOCKED()  READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
+#define STATUS_CHRG_FULL()  READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
+#define STATUS_FATAL()      READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index 6c9e871..c10be00 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -21,7 +21,7 @@
 #include <linux/apm_bios.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 
 #include <asm/hardware.h>
 #include <asm/hardware/scoop.h>
@@ -45,15 +45,15 @@
 #define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
 #define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
 #define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD  10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
 #define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
 #define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
 #define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
 
 #define SHARPSL_CHARGE_ON_VOLT         0x99  /* 2.9V */
 #define SHARPSL_CHARGE_ON_TEMP         0xe0  /* 2.9V */
-#define SHARPSL_CHARGE_ON_JKVAD_HIGH   0x9b  /* 6V */
-#define SHARPSL_CHARGE_ON_JKVAD_LOW    0x34  /* 2V */
+#define SHARPSL_CHARGE_ON_ACIN_HIGH    0x9b  /* 6V */
+#define SHARPSL_CHARGE_ON_ACIN_LOW     0x34  /* 2V */
 #define SHARPSL_FATAL_ACIN_VOLT        182   /* 3.45V */
 #define SHARPSL_FATAL_NOACIN_VOLT      170   /* 3.40V */
 
@@ -160,9 +160,10 @@
 /*
  * Prototypes
  */
-static int sharpsl_read_MainBattery(void);
+static int sharpsl_read_main_battery(void);
 static int sharpsl_off_charge_battery(void);
-static int sharpsl_check_battery(int mode);
+static int sharpsl_check_battery_temp(void);
+static int sharpsl_check_battery_voltage(void);
 static int sharpsl_ac_check(void);
 static int sharpsl_fatal_check(void);
 static int sharpsl_average_value(int ad);
@@ -228,7 +229,7 @@
 	if (!sharpsl_pm.machinfo)
 		return;
 
-	sharpsl_pm.battstat.ac_status = (!(STATUS_AC_IN) ? APM_AC_OFFLINE : APM_AC_ONLINE);
+	sharpsl_pm.battstat.ac_status = (STATUS_AC_IN() ? APM_AC_ONLINE : APM_AC_OFFLINE);
 
 	/* Corgi cannot confirm when battery fully charged so periodically kick! */
 	if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON)
@@ -236,7 +237,7 @@
 		schedule_work(&toggle_charger);
 
 	while(1) {
-		voltage = sharpsl_read_MainBattery();
+		voltage = sharpsl_read_main_battery();
 		if (voltage > 0) break;
 		if (i++ > 5) {
 			voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
@@ -317,10 +318,10 @@
 {
 	dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
 
-	if (STATUS_AC_IN == 0) {
+	if (STATUS_AC_IN() == 0) {
 		sharpsl_charge_off();
 		return;
-	} else if ((sharpsl_check_battery(1) < 0) || (sharpsl_ac_check() < 0)) {
+	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
 		sharpsl_charge_error();
 		return;
 	}
@@ -335,7 +336,7 @@
 
 static void sharpsl_ac_timer(unsigned long data)
 {
-	int acin = STATUS_AC_IN;
+	int acin = STATUS_AC_IN();
 
 	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
 
@@ -364,7 +365,7 @@
 
 	sharpsl_pm.full_count++;
 
-	if (STATUS_AC_IN == 0) {
+	if (STATUS_AC_IN() == 0) {
 		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
 		if (sharpsl_pm.charge_mode == CHRG_ON)
 			sharpsl_charge_off();
@@ -399,12 +400,12 @@
 {
 	int is_fatal = 0;
 
-	if (STATUS_BATT_LOCKED == 0) {
+	if (STATUS_BATT_LOCKED() == 0) {
 		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
 		is_fatal = 1;
 	}
 
-	if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL == 0)) {
+	if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL() == 0)) {
 		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
 		is_fatal = 1;
 	}
@@ -461,12 +462,12 @@
 			| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
 }
 
-static int sharpsl_read_MainBattery(void)
+static int sharpsl_read_main_battery(void)
 {
 	return read_max1111(BATT_AD);
 }
 
-static int sharpsl_read_Temp(void)
+static int sharpsl_read_temp(void)
 {
 	int temp;
 
@@ -480,7 +481,7 @@
 	return temp;
 }
 
-static int sharpsl_read_jkvad(void)
+static int sharpsl_read_acin(void)
 {
 	return read_max1111(JK_VAD);
 }
@@ -522,16 +523,14 @@
 	return (sum/3);
 }
 
-/*  mode 0 - Check temperature and voltage
- *       1 - Check temperature only */
-static int sharpsl_check_battery(int mode)
+static int sharpsl_check_battery_temp(void)
 {
 	int val, i, buff[5];
 
 	/* Check battery temperature */
 	for (i=0; i<5; i++) {
 		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
-		buff[i] = sharpsl_read_Temp();
+		buff[i] = sharpsl_read_temp();
 	}
 
 	val = get_select_val(buff);
@@ -539,8 +538,13 @@
 	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
 	if (val > SHARPSL_CHARGE_ON_TEMP)
 		return -1;
-	if (mode == 1)
-		return 0;
+
+	return 0;
+}
+
+static int sharpsl_check_battery_voltage(void)
+{
+	int val, i, buff[5];
 
 	/* disable charge, enable discharge */
 	CHARGE_OFF();
@@ -552,7 +556,7 @@
 
 	/* Check battery voltage */
 	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_read_MainBattery();
+		buff[i] = sharpsl_read_main_battery();
 		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
 	}
 
@@ -575,14 +579,14 @@
 	int temp, i, buff[5];
 
 	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_read_jkvad();
-		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD);
+		buff[i] = sharpsl_read_acin();
+		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
 	}
 
 	temp = get_select_val(buff);
 	dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
 
-	if ((temp > SHARPSL_CHARGE_ON_JKVAD_HIGH) || (temp < SHARPSL_CHARGE_ON_JKVAD_LOW)) {
+	if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) {
 		dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
 		return -1;
 	}
@@ -591,7 +595,7 @@
 }
 
 #ifdef CONFIG_PM
-static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
+static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	sharpsl_pm.flags |= SHARPSL_SUSPENDED;
 	flush_scheduled_work();
@@ -604,7 +608,7 @@
 	return 0;
 }
 
-static int sharpsl_pm_resume(struct device *dev)
+static int sharpsl_pm_resume(struct platform_device *pdev)
 {
 	/* Clear the reset source indicators as they break the bootloader upon reboot */
 	RCSR = 0x0f;
@@ -622,7 +626,7 @@
 	dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
 	/* not charging and AC-IN! */
 
-	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN != 0)) {
+	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN() != 0)) {
 		dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
 		sharpsl_pm.charge_mode = CHRG_OFF;
 		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
@@ -671,7 +675,7 @@
 		dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
 	}
 
-	if ((STATUS_BATT_LOCKED == 0) || (sharpsl_fatal_check() < 0) )
+	if ((STATUS_BATT_LOCKED() == 0) || (sharpsl_fatal_check() < 0) )
 	{
 		dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
 		corgi_goto_sleep(alarm_time, alarm_enable, state);
@@ -711,7 +715,7 @@
 	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
 
 	/* Check AC-Adapter */
-	acin = STATUS_AC_IN;
+	acin = STATUS_AC_IN();
 
 	if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
 		CHARGE_OFF();
@@ -725,7 +729,7 @@
 
 	/* Check battery : check inserting battery ? */
 	for (i=0; i<5; i++) {
-		buff[i] = sharpsl_read_MainBattery();
+		buff[i] = sharpsl_read_main_battery();
 		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
 	}
 
@@ -739,7 +743,7 @@
 	}
 
 	temp = get_select_val(buff);
-	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_MainBattery());
+	dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_main_battery());
 
 	if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) ||
 			(!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT)))
@@ -771,7 +775,7 @@
 		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
 
 		/* AC Check */
-		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery(1) < 0))
+		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
 			return sharpsl_off_charge_error();
 
 		/* Start Charging */
@@ -793,7 +797,7 @@
 
 		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
 
-		if (sharpsl_check_battery(0) < 0)
+		if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
 			return sharpsl_off_charge_error();
 
 		CHARGE_OFF();
@@ -811,7 +815,7 @@
 			/* Check for timeout */
 			if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
 				return 1;
-			if (STATUS_CHRG_FULL) {
+			if (STATUS_CHRG_FULL()) {
 				dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n");
 	   			sharpsl_pm.full_count++;
 				CHARGE_OFF();
@@ -840,7 +844,7 @@
 			sharpsl_pm.full_count++;
 			return 1;
 		}
-		if (STATUS_CHRG_FULL) {
+		if (STATUS_CHRG_FULL()) {
 			dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
 			CHARGE_LED_OFF();
 			CHARGE_OFF();
@@ -886,13 +890,13 @@
 	.finish		= pxa_pm_finish,
 };
 
-static int __init sharpsl_pm_probe(struct device *dev)
+static int __init sharpsl_pm_probe(struct platform_device *pdev)
 {
-	if (!dev->platform_data)
+	if (!pdev->dev.platform_data)
 		return -EINVAL;
 
-	sharpsl_pm.dev = dev;
-	sharpsl_pm.machinfo = dev->platform_data;
+	sharpsl_pm.dev = &pdev->dev;
+	sharpsl_pm.machinfo = pdev->dev.platform_data;
 	sharpsl_pm.charge_mode = CHRG_OFF;
 	sharpsl_pm.flags = 0;
 
@@ -935,8 +939,8 @@
 		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING);
 	}
 
-	device_create_file(dev, &dev_attr_battery_percentage);
-	device_create_file(dev, &dev_attr_battery_voltage);
+	device_create_file(&pdev->dev, &dev_attr_battery_percentage);
+	device_create_file(&pdev->dev, &dev_attr_battery_voltage);
 
 	apm_get_power_status = sharpsl_apm_get_power_status;
 
@@ -947,12 +951,12 @@
 	return 0;
 }
 
-static int sharpsl_pm_remove(struct device *dev)
+static int sharpsl_pm_remove(struct platform_device *pdev)
 {
 	pm_set_ops(NULL);
 
-	device_remove_file(dev, &dev_attr_battery_percentage);
-	device_remove_file(dev, &dev_attr_battery_voltage);
+	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
+	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
 
 	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
 	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
@@ -969,23 +973,24 @@
 	return 0;
 }
 
-static struct device_driver sharpsl_pm_driver = {
-	.name		= "sharpsl-pm",
-	.bus		= &platform_bus_type,
+static struct platform_driver sharpsl_pm_driver = {
 	.probe		= sharpsl_pm_probe,
 	.remove		= sharpsl_pm_remove,
 	.suspend	= sharpsl_pm_suspend,
 	.resume		= sharpsl_pm_resume,
+	.driver		= {
+		.name		= "sharpsl-pm",
+	},
 };
 
 static int __devinit sharpsl_pm_init(void)
 {
-	return driver_register(&sharpsl_pm_driver);
+	return platform_driver_register(&sharpsl_pm_driver);
 }
 
 static void sharpsl_pm_exit(void)
 {
- 	driver_unregister(&sharpsl_pm_driver);
+ 	platform_driver_unregister(&sharpsl_pm_driver);
 }
 
 late_initcall(sharpsl_pm_init);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 4e9a699..2df1b56 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -345,6 +345,16 @@
 		reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
 }
 
+#ifdef CONFIG_MACH_AKITA
+static void akita_irda_transceiver_mode(struct device *dev, int mode)
+{
+	if (mode & IR_OFF)
+		akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+	else
+		akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+}
+#endif
+
 static struct pxaficp_platform_data spitz_ficp_platform_data = {
 	.transceiver_cap  = IR_SIRMODE | IR_OFF,
 	.transceiver_mode = spitz_irda_transceiver_mode,
@@ -417,6 +427,32 @@
 	platform_device_register(&spitzscoop2_device);
 }
 
+#ifdef CONFIG_MACH_AKITA
+/*
+ * Akita IO Expander
+ */
+struct platform_device akitaioexp_device = {
+	.name		= "akita-ioexp",
+	.id		= -1,
+};
+
+static void __init akita_init(void)
+{
+	spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode;
+
+	/* We just pretend the second element of the array doesn't exist */
+	spitz_pcmcia_config.num_devs = 1;
+	platform_scoop_config = &spitz_pcmcia_config;
+	spitz_bl_machinfo.set_bl_intensity = akita_bl_set_intensity;
+
+	platform_device_register(&akitaioexp_device);
+
+	spitzscoop_device.dev.parent = &akitaioexp_device.dev;
+	common_init();
+}
+#endif
+
+
 static void __init fixup_spitz(struct machine_desc *desc,
 		struct tag *tags, char **cmdline, struct meminfo *mi)
 {
@@ -452,3 +488,16 @@
 	.timer		= &pxa_timer,
 MACHINE_END
 #endif
+
+#ifdef CONFIG_MACH_AKITA
+MACHINE_START(AKITA, "SHARP Akita")
+	.phys_ram	= 0xa0000000,
+	.phys_io	= 0x40000000,
+	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
+	.fixup		= fixup_spitz,
+	.map_io		= pxa_map_io,
+	.init_irq	= pxa_init_irq,
+	.init_machine	= akita_init,
+	.timer		= &pxa_timer,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
new file mode 100644
index 0000000..3ce7486
--- /dev/null
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -0,0 +1,233 @@
+/*
+ * Battery and Power Management code for the Sharp SL-Cxx00
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/apm.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/hardware/scoop.h>
+
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/spitz.h>
+#include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
+
+static int spitz_last_ac_status;
+
+static void spitz_charger_init(void)
+{
+	pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN);
+	pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
+}
+
+static void spitz_charge_led(int val)
+{
+	if (val == SHARPSL_LED_ERROR) {
+		dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+	} else if (val == SHARPSL_LED_ON) {
+		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+	} else {
+		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+	}
+}
+
+static void spitz_measure_temp(int on)
+{
+	if (on)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+}
+
+static void spitz_charge(int on)
+{
+	if (on) {
+		if (sharpsl_pm.flags & SHARPSL_SUSPENDED) {
+			set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+		} else {
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+			reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+		}
+	} else {
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+	}
+}
+
+static void spitz_discharge(int on)
+{
+	if (on)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+}
+
+/* HACK - For unknown reasons, accurate voltage readings are only made with a load
+   on the power bus which the green led on spitz provides */
+static void spitz_discharge1(int on)
+{
+	if (on)
+		set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+	else
+		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+}
+
+static void spitz_presuspend(void)
+{
+	spitz_last_ac_status = STATUS_AC_IN();
+
+	/* GPIO Sleep Register */
+	PGSR0 = 0x00144018;
+	PGSR1 = 0x00EF0000;
+	if (machine_is_akita()) {
+		PGSR2 = 0x2121C000;
+		PGSR3 = 0x00600400;
+	} else {
+		PGSR2 = 0x0121C000;
+		PGSR3 = 0x00600000;
+	}
+
+	PGSR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+	PGSR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+	PGSR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+	PGSR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+	PGSR2 |= GPIO_bit(SPITZ_GPIO_KEY_STROBE0);
+
+	pxa_gpio_mode(GPIO18_RDY|GPIO_OUT | GPIO_DFLT_HIGH);
+
+	PRER = GPIO_bit(SPITZ_GPIO_KEY_INT);
+	PFER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+	PWER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET) | PWER_RTC;
+	PKWR = GPIO_bit(SPITZ_GPIO_SYNC) | GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+	PKSR = 0xffffffff; // clear
+
+	/* nRESET_OUT Disable */
+	PSLR |= PSLR_SL_ROD;
+
+	/* Clear reset status */
+	RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+
+	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+	PCFR = PCFR_GPR_EN | PCFR_OPDE;
+}
+
+static void spitz_postsuspend(void)
+{
+	pxa_gpio_mode(GPIO18_RDY_MD);
+	pxa_gpio_mode(10 | GPIO_IN);
+}
+
+static int spitz_should_wakeup(unsigned int resume_on_alarm)
+{
+	int is_resume = 0;
+	int acin = STATUS_AC_IN();
+
+	if (spitz_last_ac_status != acin) {
+		if (acin) {
+			/* charge on */
+			sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+			dev_dbg(sharpsl_pm.dev, "AC Inserted\n");
+		} else {
+			/* charge off */
+			dev_dbg(sharpsl_pm.dev, "AC Removed\n");
+			CHARGE_LED_OFF();
+			CHARGE_OFF();
+			sharpsl_pm.charge_mode = CHRG_OFF;
+		}
+		spitz_last_ac_status = acin;
+		/* Return to suspend as this must be what we were woken for */
+		return 0;
+	}
+
+	if (PEDR & GPIO_bit(SPITZ_GPIO_KEY_INT))
+		is_resume |= GPIO_bit(SPITZ_GPIO_KEY_INT);
+
+	if (PKSR & GPIO_bit(SPITZ_GPIO_SYNC))
+		is_resume |= GPIO_bit(SPITZ_GPIO_SYNC);
+
+	if (resume_on_alarm && (PEDR & PWER_RTC))
+		is_resume |= PWER_RTC;
+
+	dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+	return is_resume;
+}
+
+static unsigned long spitz_charger_wakeup(void)
+{
+	return (~GPLR0 & GPIO_bit(SPITZ_GPIO_KEY_INT)) | (GPLR0 & GPIO_bit(SPITZ_GPIO_SYNC));
+}
+
+static int spitz_acin_status(void)
+{
+	return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
+}
+
+struct sharpsl_charger_machinfo spitz_pm_machinfo = {
+	.init             = spitz_charger_init,
+	.gpio_batlock     = SPITZ_GPIO_BAT_COVER,
+	.gpio_acin        = SPITZ_GPIO_AC_IN,
+	.gpio_batfull     = SPITZ_GPIO_CHRG_FULL,
+	.gpio_fatal       = SPITZ_GPIO_FATAL_BAT,
+	.status_acin      = spitz_acin_status,
+	.discharge        = spitz_discharge,
+	.discharge1       = spitz_discharge1,
+	.charge           = spitz_charge,
+	.chargeled        = spitz_charge_led,
+	.measure_temp     = spitz_measure_temp,
+	.presuspend       = spitz_presuspend,
+	.postsuspend      = spitz_postsuspend,
+	.charger_wakeup   = spitz_charger_wakeup,
+	.should_wakeup    = spitz_should_wakeup,
+	.bat_levels       = 40,
+	.bat_levels_noac  = spitz_battery_levels_noac,
+	.bat_levels_acin  = spitz_battery_levels_acin,
+	.status_high_acin = 188,
+	.status_low_acin  = 178,
+	.status_high_noac = 185,
+	.status_low_noac  = 175,
+};
+
+static struct platform_device *spitzpm_device;
+
+static int __devinit spitzpm_init(void)
+{
+	int ret;
+
+	spitzpm_device = platform_device_alloc("sharpsl-pm", -1);
+	if (!spitzpm_device)
+		return -ENOMEM;
+
+	spitzpm_device->dev.platform_data = &spitz_pm_machinfo;
+	ret = platform_device_add(spitzpm_device);
+
+	if (ret)
+		platform_device_put(spitzpm_device);
+
+	return ret;
+}
+
+static void spitzpm_exit(void)
+{
+ 	platform_device_unregister(spitzpm_device);
+}
+
+module_init(spitzpm_init);
+module_exit(spitzpm_exit);
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index 1a1e8a1..712c3c2 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index dbf90ad..6004bb0 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -699,7 +699,7 @@
 
 config APM
 	tristate "APM (Advanced Power Management) BIOS support"
-	depends on PM
+	depends on PM && PM_LEGACY
 	---help---
 	  APM is a BIOS specification for saving power using several different
 	  techniques. This is mostly useful for battery powered laptops with
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 003548b..1e60acb 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -218,6 +218,7 @@
 #include <linux/time.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 43601de..c28d26f 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -6,6 +6,7 @@
 #include <linux/bitops.h>
 #include <linux/smp.h>
 #include <linux/thread_info.h>
+#include <linux/module.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
@@ -264,5 +265,52 @@
 	return 0;
 }
 
+#ifndef CONFIG_X86_CMPXCHG
+unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
+{
+	u8 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u8 *)ptr;
+	if (prev == old)
+		*(u8 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u8);
+
+unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
+{
+	u16 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u16 *)ptr;
+	if (prev == old)
+		*(u16 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u16);
+
+unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
+{
+	u32 prev;
+	unsigned long flags;
+
+	/* Poor man's cmpxchg for 386. Unsuitable for SMP */
+	local_irq_save(flags);
+	prev = *(u32 *)ptr;
+	if (prev == old)
+		*(u32 *)ptr = new;
+	local_irq_restore(flags);
+	return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u32);
+#endif
+
 // arch_initcall(intel_cpu_init);
 
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 9e24f7b2..e50b9315 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -560,11 +560,10 @@
 nmi_debug_stack_check:
 	cmpw $__KERNEL_CS,16(%esp)
 	jne nmi_stack_correct
-	cmpl $debug - 1,(%esp)
-	jle nmi_stack_correct
+	cmpl $debug,(%esp)
+	jb nmi_stack_correct
 	cmpl $debug_esp_fix_insn,(%esp)
-	jle nmi_debug_stack_fixup
-nmi_debug_stack_fixup:
+	ja nmi_stack_correct
 	FIX_STACK(24,nmi_stack_correct, 1)
 	jmp nmi_stack_correct
 
diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
index e42e46d3..b9b6bd5 100644
--- a/arch/i386/kernel/timers/timer_pit.c
+++ b/arch/i386/kernel/timers/timer_pit.c
@@ -25,8 +25,9 @@
 {
  	/* check clock override */
  	if (override[0] && strncmp(override,"pit",3))
- 		printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
- 
+ 		printk(KERN_ERR "Warning: clock= override failed. Defaulting "
+				"to PIT\n");
+ 	init_cpu_khz();
 	count_p = LATCH;
 	return 0;
 }
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 542d929..06e26f0 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -28,6 +28,7 @@
 #include <linux/proc_fs.h>
 #include <linux/efi.h>
 #include <linux/memory_hotplug.h>
+#include <linux/initrd.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -267,7 +268,7 @@
 	pkmap_page_table = pte;	
 }
 
-void __devinit free_new_highpage(struct page *page)
+static void __devinit free_new_highpage(struct page *page)
 {
 	set_page_count(page, 1);
 	__free_page(page);
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 9571a21..a162919 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -381,10 +381,8 @@
 .Lnotkern:
 	SAVE_ALL_INT
 	GET_CURRENT(%d0)
-	tstb	%curptr@(TASK_NEEDRESCHED)
-	jne	ret_from_exception	| deliver signals,
-					| reschedule etc..
-	RESTORE_ALL
+	| deliver signals, reschedule etc..
+	jra	ret_from_exception
 
 |
 |	mem_write --- write to user or supervisor address space
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index 4ba2c74..b2dbdf5 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -75,10 +75,8 @@
 .Lnotkern:
 	SAVE_ALL_INT
 	GET_CURRENT(%d0)
-	tstb	%curptr@(TASK_NEEDRESCHED)
-	jne	ret_from_exception	| deliver signals,
-					| reschedule etc..
-	RESTORE_ALL
+	| deliver signals, reschedule etc..
+	jra	ret_from_exception
 
 |
 | _060_real_chk():
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index cee3317..c787c5b 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -25,12 +25,8 @@
 	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-	DEFINE(TASK_WORK, offsetof(struct task_struct, thread.work));
-	DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, thread.work.need_resched));
-	DEFINE(TASK_SYSCALL_TRACE, offsetof(struct task_struct, thread.work.syscall_trace));
-	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, thread.work.sigpending));
-	DEFINE(TASK_NOTIFY_RESUME, offsetof(struct task_struct, thread.work.notify_resume));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+	DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
@@ -45,6 +41,10 @@
 	DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
 	DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
 
+	/* offsets into the thread_info struct */
+	DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+	DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
 	/* offsets into the pt_regs */
 	DEFINE(PT_D0, offsetof(struct pt_regs, d0));
 	DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 23ca60a..320fde0 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -44,9 +44,7 @@
 
 #include <asm/asm-offsets.h>
 
-.globl system_call, buserr, trap
-.globl resume, ret_from_exception
-.globl ret_from_signal
+.globl system_call, buserr, trap, resume
 .globl inthandler, sys_call_table
 .globl sys_fork, sys_clone, sys_vfork
 .globl ret_from_interrupt, bad_interrupt
@@ -58,7 +56,7 @@
 	movel	%sp,%sp@-		| stack frame pointer argument
 	bsrl	buserr_c
 	addql	#4,%sp
-	jra	ret_from_exception
+	jra	.Lret_from_exception
 
 ENTRY(trap)
 	SAVE_ALL_INT
@@ -66,7 +64,7 @@
 	movel	%sp,%sp@-		| stack frame pointer argument
 	bsrl	trap_c
 	addql	#4,%sp
-	jra	ret_from_exception
+	jra	.Lret_from_exception
 
 	| After a fork we jump here directly from resume,
 	| so that %d1 contains the previous task
@@ -75,30 +73,31 @@
 	movel	%d1,%sp@-
 	jsr	schedule_tail
 	addql	#4,%sp
-	jra	ret_from_exception
+	jra	.Lret_from_exception
 
-badsys:
-	movel	#-ENOSYS,%sp@(PT_D0)
-	jra	ret_from_exception
-
-do_trace:
+do_trace_entry:
 	movel	#-ENOSYS,%sp@(PT_D0)	| needed for strace
 	subql	#4,%sp
 	SAVE_SWITCH_STACK
 	jbsr	syscall_trace
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
-	movel	%sp@(PT_ORIG_D0),%d1
-	movel	#-ENOSYS,%d0
-	cmpl	#NR_syscalls,%d1
-	jcc	1f
-	jbsr	@(sys_call_table,%d1:l:4)@(0)
-1:	movel	%d0,%sp@(PT_D0)		| save the return value
-	subql	#4,%sp			| dummy return address
+	movel	%sp@(PT_ORIG_D0),%d0
+	cmpl	#NR_syscalls,%d0
+	jcs	syscall
+badsys:
+	movel	#-ENOSYS,%sp@(PT_D0)
+	jra	ret_from_syscall
+
+do_trace_exit:
+	subql	#4,%sp
 	SAVE_SWITCH_STACK
 	jbsr	syscall_trace
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	jra	.Lret_from_exception
 
-ret_from_signal:
+ENTRY(ret_from_signal)
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
 /* on 68040 complete pending writebacks if any */
@@ -111,7 +110,7 @@
 	addql	#4,%sp
 1:
 #endif
-	jra	ret_from_exception
+	jra	.Lret_from_exception
 
 ENTRY(system_call)
 	SAVE_ALL_SYS
@@ -120,30 +119,34 @@
 	| save top of frame
 	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 
-	tstb	%curptr@(TASK_SYSCALL_TRACE)
-	jne	do_trace
+	| syscall trace?
+	tstb	%curptr@(TASK_INFO+TINFO_FLAGS+2)
+	jmi	do_trace_entry
 	cmpl	#NR_syscalls,%d0
 	jcc	badsys
+syscall:
 	jbsr	@(sys_call_table,%d0:l:4)@(0)
 	movel	%d0,%sp@(PT_D0)		| save the return value
-
+ret_from_syscall:
 	|oriw	#0x0700,%sr
-	movel	%curptr@(TASK_WORK),%d0
+	movew	%curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
 	jne	syscall_exit_work
 1:	RESTORE_ALL
 
 syscall_exit_work:
 	btst	#5,%sp@(PT_SR)		| check if returning to kernel
 	bnes	1b			| if so, skip resched, signals
-	tstw	%d0
-	jeq	do_signal_return
-	tstb	%d0
-	jne	do_delayed_trace
-
+	lslw	#1,%d0
+	jcs	do_trace_exit
+	jmi	do_delayed_trace
+	lslw	#8,%d0
+	jmi	do_signal_return
 	pea	resume_userspace
-	jmp	schedule
+	jra	schedule
 
-ret_from_exception:
+
+ENTRY(ret_from_exception)
+.Lret_from_exception:
 	btst	#5,%sp@(PT_SR)		| check if returning to kernel
 	bnes	1f			| if so, skip resched, signals
 	| only allow interrupts when we are really the last one on the
@@ -152,19 +155,18 @@
 	andw	#ALLOWINT,%sr
 
 resume_userspace:
-	movel	%curptr@(TASK_WORK),%d0
-	lsrl	#8,%d0
+	moveb	%curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
 	jne	exit_work
 1:	RESTORE_ALL
 
 exit_work:
 	| save top of frame
 	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
-	tstb	%d0
-	jeq	do_signal_return
-
+	lslb	#1,%d0
+	jmi	do_signal_return
 	pea	resume_userspace
-	jmp	schedule
+	jra	schedule
+
 
 do_signal_return:
 	|andw	#ALLOWINT,%sr
@@ -254,7 +256,7 @@
 
 	/* check if we need to do software interrupts */
 	tstl	irq_stat+CPUSTAT_SOFTIRQ_PENDING
-	jeq	ret_from_exception
+	jeq	.Lret_from_exception
 	pea	ret_from_exception
 	jra	do_softirq
 
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 7e54422..540638c 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -109,7 +109,7 @@
 {
 	unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
 	put_reg(child, PT_SR, tmp);
-	child->thread.work.delayed_trace = 0;
+	clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
 }
 
 /*
@@ -118,7 +118,7 @@
 void ptrace_disable(struct task_struct *child)
 {
 	singlestep_disable(child);
-	child->thread.work.syscall_trace = 0;
+	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -198,9 +198,9 @@
 			goto out_eio;
 
 		if (request == PTRACE_SYSCALL)
-			child->thread.work.syscall_trace = ~0;
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		else
-			child->thread.work.syscall_trace = 0;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		singlestep_disable(child);
 		wake_up_process(child);
@@ -223,10 +223,10 @@
 		if (!valid_signal(data))
 			goto out_eio;
 
-		child->thread.work.syscall_trace = 0;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
 		put_reg(child, PT_SR, tmp);
-		child->thread.work.delayed_trace = 1;
+		set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
 
 		child->exit_code = data;
 		/* give it a chance to run. */
@@ -288,9 +288,6 @@
 
 asmlinkage void syscall_trace(void)
 {
-	if (!current->thread.work.delayed_trace &&
-	    !current->thread.work.syscall_trace)
-		return;
 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 				 ? 0x80 : 0));
 	/*
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index f85093b..f492631 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -32,6 +32,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 #include <linux/jiffies.h>
diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c
index 0b21bed..2cab762 100644
--- a/arch/mips/au1000/common/usbdev.c
+++ b/arch/mips/au1000/common/usbdev.c
@@ -348,7 +348,7 @@
 {
 	u32 cs;
 
-	warn(__FUNCTION__);
+	warn("%s", __FUNCTION__);
 
 	cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
 	au_writel(cs, ep->reg->ctrl_stat);
@@ -360,7 +360,7 @@
 {
 	u32 cs;
 
-	warn(__FUNCTION__);
+	warn("%s", __FUNCTION__);
 
 	cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
 	au_writel(cs, ep->reg->ctrl_stat);
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 5063c60..8d60fa9 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
  *    Copyright 2002-2004 MontaVista Software, Inc.
  *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
  *    Copyright 2004 Freescale Semiconductor, Inc
- *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.com>
+ *      PowerPC e500 modifications, Kumar Gala <galak@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
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index af9ca0e..5d581bb 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
 /*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
  * E500 Book E processors.
  *
  * Copyright 2004 Freescale Semiconductor, Inc
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 86124a9..26539cd 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -7,7 +7,7 @@
  * Copyright (c) 2004 Freescale Semiconductor, Inc
  *
  * Author: Andy Fleming
- * Maintainer: Kumar Gala <Kumar.Gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@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
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index ef4356b2..c45a6ad 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -19,6 +19,7 @@
 #include <linux/cpumask.h>
 #include <linux/module.h>
 #include <linux/sysrq.h>
+#include <linux/interrupt.h>
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index 5063c60..8d60fa9 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
  *    Copyright 2002-2004 MontaVista Software, Inc.
  *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
  *    Copyright 2004 Freescale Semiconductor, Inc
- *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.com>
+ *      PowerPC e500 modifications, Kumar Gala <galak@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
diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c
index af9ca0e..5d581bb 100644
--- a/arch/ppc/mm/fsl_booke_mmu.c
+++ b/arch/ppc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
 /*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
  * E500 Book E processors.
  *
  * Copyright 2004 Freescale Semiconductor, Inc
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 98edc75..04bdc39 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -3,7 +3,7 @@
  *
  * MPC834x SYS board specific routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
@@ -73,12 +73,19 @@
 	     *       A      B      C      D
 	     */
 	{
-		{PIRQA, PIRQB,  PIRQC,  PIRQD}, /* idsel 0x11 */
-		{PIRQC, PIRQD,  PIRQA,  PIRQB}, /* idsel 0x12 */
-		{PIRQD, PIRQA,  PIRQB,  PIRQC}  /* idsel 0x13 */
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* idsel 0x11 */
+		{PIRQC, PIRQD, PIRQA, PIRQB},	/* idsel 0x12 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},	/* idsel 0x13 */
+		{0, 0, 0, 0},
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* idsel 0x15 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},	/* idsel 0x16 */
+		{PIRQC, PIRQD, PIRQA, PIRQB},	/* idsel 0x17 */
+		{PIRQB, PIRQC, PIRQD, PIRQA},	/* idsel 0x18 */
+		{0, 0, 0, 0},			/* idsel 0x19 */
+		{0, 0, 0, 0},			/* idsel 0x20 */
 	};
 
-	const long min_idsel = 0x11, max_idsel = 0x13, irqs_per_slot = 4;
+	const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
 	return PCI_IRQ_TABLE_LOOKUP;
 }
 
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h
index 58e44c0..2e514d3 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.h
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -3,7 +3,7 @@
  *
  * MPC834X SYS common board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor, Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
index 7e952c1..c5cde97 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -3,7 +3,7 @@
  *
  * MPC8540ADS board specific routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h
index 3d05d7c..e48ca3a 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.h
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.h
@@ -3,7 +3,7 @@
  *
  * MPC8540ADS board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc8555_cds.h b/arch/ppc/platforms/85xx/mpc8555_cds.h
index e0e7556..1a8e6c6 100644
--- a/arch/ppc/platforms/85xx/mpc8555_cds.h
+++ b/arch/ppc/platforms/85xx/mpc8555_cds.h
@@ -3,7 +3,7 @@
  *
  * MPC8555CDS board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index 208433f..8e39a55 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -3,7 +3,7 @@
  *
  * MPC8560ADS board specific routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.h b/arch/ppc/platforms/85xx/mpc8560_ads.h
index 7df885d..143ae7e 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.h
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.h
@@ -3,7 +3,7 @@
  *
  * MPC8540ADS board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
index 16ad092..17ce48f 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -3,7 +3,7 @@
  *
  * MPC85xx ADS board common routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
index 84acf6e..7b26bcc 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
@@ -3,7 +3,7 @@
  *
  * MPC85XX ADS common board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index a211569..d8991b8 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -3,7 +3,7 @@
  *
  * MPC85xx CDS board specific routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor, Inc
  *
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
index 12b292c..5b588cf 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -3,7 +3,7 @@
  *
  * MPC85xx CDS board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor, Inc
  *
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index b4ee170..45a5b81 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -3,7 +3,7 @@
  * 
  * Wind River SBC8560 board specific routines
  * 
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  * 
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
index 58884a6..1e69b05 100644
--- a/arch/ppc/platforms/pmac_feature.c
+++ b/arch/ppc/platforms/pmac_feature.c
@@ -2317,6 +2317,14 @@
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
 	},
+	{	"PowerBook5,8",			"PowerBook G4 15\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
+	{	"PowerBook5,9",			"PowerBook G4 17\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
 	{	"PowerBook6,1",			"PowerBook G4 12\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
index 6a1475c..71c9fca 100644
--- a/arch/ppc/platforms/pq2ads.c
+++ b/arch/ppc/platforms/pq2ads.c
@@ -3,7 +3,7 @@
  *
  * PQ2ADS platform support
  *
- * Author: Kumar Gala <kumar.gala@freescale.com>
+ * Author: Kumar Gala <galak@kernel.crashing.org>
  * Derived from: est8260_setup.c by Allen Curtis
  *
  * Copyright 2004 Freescale Semiconductor, Inc.
diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h
index 2b56a4f..a7ce7da 100644
--- a/arch/ppc/syslib/ipic.h
+++ b/arch/ppc/syslib/ipic.h
@@ -3,7 +3,7 @@
  *
  * IPIC private definitions and structure.
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor, Inc
  *
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index f43fbf9..847df44 100644
--- a/arch/ppc/syslib/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -3,7 +3,7 @@
  *
  * MPC83xx Device descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
index da74344..a152398 100644
--- a/arch/ppc/syslib/mpc83xx_sys.c
+++ b/arch/ppc/syslib/mpc83xx_sys.c
@@ -3,7 +3,7 @@
  *
  * MPC83xx System descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index 2ede677..69949d2 100644
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -3,7 +3,7 @@
  *
  * MPC85xx Device descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c
index cb68d8c..397cfbc 100644
--- a/arch/ppc/syslib/mpc85xx_sys.c
+++ b/arch/ppc/syslib/mpc85xx_sys.c
@@ -3,7 +3,7 @@
  *
  * MPC85xx System descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c
index 2b5f0e7..92dc98b 100644
--- a/arch/ppc/syslib/mpc8xx_devices.c
+++ b/arch/ppc/syslib/mpc8xx_devices.c
@@ -3,7 +3,7 @@
  *
  * MPC8xx Device descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug<vbordug@ru.mvista.com>
  *
diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c
index 3cc27d2..d3c6175 100644
--- a/arch/ppc/syslib/mpc8xx_sys.c
+++ b/arch/ppc/syslib/mpc8xx_sys.c
@@ -3,7 +3,7 @@
  *
  * MPC8xx System descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
  *
diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c
index 4da168a..1b5fe9e 100644
--- a/arch/ppc/syslib/ppc83xx_setup.c
+++ b/arch/ppc/syslib/ppc83xx_setup.c
@@ -3,7 +3,7 @@
  *
  * MPC83XX common board code
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h
index c766c1a..a122a73 100644
--- a/arch/ppc/syslib/ppc83xx_setup.h
+++ b/arch/ppc/syslib/ppc83xx_setup.h
@@ -3,7 +3,7 @@
  *
  * MPC83XX common board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc85xx_common.c b/arch/ppc/syslib/ppc85xx_common.c
index da841da..19ad537 100644
--- a/arch/ppc/syslib/ppc85xx_common.c
+++ b/arch/ppc/syslib/ppc85xx_common.c
@@ -3,7 +3,7 @@
  *
  * MPC85xx support routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc85xx_common.h b/arch/ppc/syslib/ppc85xx_common.h
index 2c8f304..94edf32 100644
--- a/arch/ppc/syslib/ppc85xx_common.h
+++ b/arch/ppc/syslib/ppc85xx_common.h
@@ -3,7 +3,7 @@
  *
  * MPC85xx support routines
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c
index de2f905..1a47ff4 100644
--- a/arch/ppc/syslib/ppc85xx_setup.c
+++ b/arch/ppc/syslib/ppc85xx_setup.c
@@ -3,7 +3,7 @@
  *
  * MPC85XX common board code
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc85xx_setup.h b/arch/ppc/syslib/ppc85xx_setup.h
index 6e6cfe1..e340b05 100644
--- a/arch/ppc/syslib/ppc85xx_setup.h
+++ b/arch/ppc/syslib/ppc85xx_setup.h
@@ -3,7 +3,7 @@
  *
  * MPC85XX common board definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor Inc.
  *
diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c
index 603f011..c0b93c4 100644
--- a/arch/ppc/syslib/ppc_sys.c
+++ b/arch/ppc/syslib/ppc_sys.c
@@ -3,7 +3,7 @@
  *
  * PPC System library functions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c
index e960fe9..6ff3aab 100644
--- a/arch/ppc/syslib/pq2_devices.c
+++ b/arch/ppc/syslib/pq2_devices.c
@@ -3,7 +3,7 @@
  *
  * PQ2 Device descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * 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
diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c
index 7b6c9eb..36d6e21 100644
--- a/arch/ppc/syslib/pq2_sys.c
+++ b/arch/ppc/syslib/pq2_sys.c
@@ -3,7 +3,7 @@
  *
  * PQ2 System descriptions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * 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
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index fbad2c3..47cc26e 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -1261,6 +1261,7 @@
 	/* No #address-cells property for the root node, default to 1 */
 	return 1;
 }
+EXPORT_SYMBOL_GPL(prom_n_addr_cells);
 
 int
 prom_n_size_cells(struct device_node* np)
@@ -1276,6 +1277,7 @@
 	/* No #size-cells property for the root node, default to 1 */
 	return 1;
 }
+EXPORT_SYMBOL_GPL(prom_n_size_cells);
 
 /**
  * Work out the sense (active-low level / active-high edge)
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index 2e64e8c..cb3cf0f 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -37,17 +37,43 @@
 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
 	return ret;
 }
+EXPORT_SYMBOL(__atomic_add_return);
 
+int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(ATOMIC_HASH(v), flags);
+	ret = v->counter;
+	if (likely(ret == old))
+		v->counter = new;
+
+	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+	return ret;
+}
+
+int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(ATOMIC_HASH(v), flags);
+	ret = v->counter;
+	if (ret != u)
+		v->counter += a;
+	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+	return ret != u;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+/* Atomic operations are already serializing */
 void atomic_set(atomic_t *v, int i)
 {
 	unsigned long flags;
+
 	spin_lock_irqsave(ATOMIC_HASH(v), flags);
-
 	v->counter = i;
-
 	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
 }
-
-EXPORT_SYMBOL(__atomic_add_return);
 EXPORT_SYMBOL(atomic_set);
-
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 94b05e8..2e168d1 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/smp_lock.h>
+#include <linux/string.h>
 #include <linux/bitops.h>
 
 #include <asm/bitext.h>
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 3b5f47c..563301f 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -7,7 +7,6 @@
 	bool
 	default y
 
-# XXX: does UM have a mmu/swap?
 config MMU
 	bool
 	default y
@@ -36,12 +35,6 @@
 	bool
 	default y
 
-menu "Host processor type and features"
-
-source "arch/i386/Kconfig.cpu"
-
-endmenu
-
 menu "UML-specific options"
 
 config MODE_TT
@@ -209,7 +202,8 @@
 config SMP
 	bool "Symmetric multi-processing support (EXPERIMENTAL)"
 	default n
-	depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN)
+	#SMP_BROKEN is for x86_64.
+	depends on MODE_TT && EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
 	help
 	This option enables UML SMP support.
 	It is NOT related to having a real SMP box. Not directly, at least.
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index 5d92cac..c71b39a 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -1,3 +1,9 @@
+menu "Host processor type and features"
+
+source "arch/i386/Kconfig.cpu"
+
+endmenu
+
 config UML_X86
 	bool
 	default y
@@ -42,7 +48,3 @@
 config ARCH_REUSE_HOST_VSYSCALL_AREA
 	bool
 	default y
-
-config X86_CMPXCHG
-	bool
-	default y
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 1f7dcb0..7a0e04e 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -35,4 +35,3 @@
 
 CFLAGS += $(cflags-y)
 USER_CFLAGS += $(cflags-y)
-
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 16e7dc8..5b58fad 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -89,8 +89,7 @@
 	return(-EIO);
 }
 
-static int not_configged_console_write(int fd, const char *buf, int len,
-				       void *data)
+static int not_configged_console_write(int fd, const char *buf, int len)
 {
 	my_puts("Using a channel type which is configured out of "
 	       "UML\n");
@@ -299,7 +298,7 @@
 		chan = list_entry(ele, struct chan, list);
 		if(!chan->output || (chan->ops->console_write == NULL))
 			continue;
-		n = chan->ops->console_write(chan->fd, buf, len, chan->data);
+		n = chan->ops->console_write(chan->fd, buf, len);
 		if(chan->primary) ret = n;
 	}
 	return(ret);
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 1c55d58..5d50d4a 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -20,7 +20,7 @@
 #include "choose-mode.h"
 #include "mode.h"
 
-int generic_console_write(int fd, const char *buf, int n, void *unused)
+int generic_console_write(int fd, const char *buf, int n)
 {
 	struct termios save, new;
 	int err;
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index c1b03f7..1bb085b2 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -98,7 +98,7 @@
 		printk("daemon_open : control setup request failed, err = %d\n",
 		       -n);
 		err = -ENOTCONN;
-		goto out;		
+		goto out_free;
 	}
 
 	n = os_read_file(pri->control, sun, sizeof(*sun));
@@ -106,12 +106,14 @@
 		printk("daemon_open : read of data socket failed, err = %d\n",
 		       -n);
 		err = -ENOTCONN;
-		goto out_close;		
+		goto out_free;
 	}
 
 	pri->data_addr = sun;
 	return(fd);
 
+ out_free:
+	kfree(sun);
  out_close:
 	os_close_file(fd);
  out:
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index f0b888f..3296e86 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -76,13 +76,6 @@
 	}
 }
 
-static int fd_console_write(int fd, const char *buf, int n, void *d)
-{
-	struct fd_chan *data = d;
-
-	return(generic_console_write(fd, buf, n, &data->tt));
-}
-
 struct chan_ops fd_ops = {
 	.type		= "fd",
 	.init		= fd_init,
@@ -90,7 +83,7 @@
 	.close		= fd_close,
 	.read		= generic_read,
 	.write		= generic_write,
-	.console_write	= fd_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= generic_free,
 	.winch		= 1,
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index 5db136e..afe85bf 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -54,7 +54,7 @@
 	struct mcast_data *pri = data;
 	struct sockaddr_in *sin = pri->mcast_addr;
 	struct ip_mreq mreq;
-	int fd, yes = 1, err = 0;
+	int fd, yes = 1, err = -EINVAL;
 
 
 	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
@@ -63,40 +63,40 @@
 	fd = socket(AF_INET, SOCK_DGRAM, 0);
 
 	if (fd < 0){
+		err = -errno;
 		printk("mcast_open : data socket failed, errno = %d\n", 
 		       errno);
-		err = -errno;
 		goto out;
 	}
 
 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+		err = -errno;
 		printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
 			errno);
-		err = -errno;
 		goto out_close;
 	}
 
 	/* set ttl according to config */
 	if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
 		       sizeof(pri->ttl)) < 0) {
+		err = -errno;
 		printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
 			errno);
-		err = -errno;
 		goto out_close;
 	}
 
 	/* set LOOP, so data does get fed back to local sockets */
 	if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+		err = -errno;
 		printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
 			errno);
-		err = -errno;
 		goto out_close;
 	}
 
 	/* bind socket to mcast address */
 	if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
-		printk("mcast_open : data bind failed, errno = %d\n", errno);
 		err = -errno;
+		printk("mcast_open : data bind failed, errno = %d\n", errno);
 		goto out_close;
 	}		
 	
@@ -105,22 +105,22 @@
 	mreq.imr_interface.s_addr = 0;
 	if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, 
 		       &mreq, sizeof(mreq)) < 0) {
+		err = -errno;
 		printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
 			errno);
 		printk("There appears not to be a multicast-capable network "
 		       "interface on the host.\n");
 		printk("eth0 should be configured in order to use the "
 		       "multicast transport.\n");
-		err = -errno;
-                goto out_close;
+		goto out_close;
 	}
 
 	return fd;
 
  out_close:
-        os_close_file(fd);
+	os_close_file(fd);
  out:
-        return err;
+	return err;
 }
 
 static void mcast_close(int fd, void *data)
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index ed4a1a6..c43e8bb 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -100,13 +100,6 @@
 	os_close_file(fd);
 }
 
-static int port_console_write(int fd, const char *buf, int n, void *d)
-{
-	struct port_chan *data = d;
-
-	return(generic_console_write(fd, buf, n, &data->tt));
-}
-
 struct chan_ops port_ops = {
 	.type		= "port",
 	.init		= port_init,
@@ -114,7 +107,7 @@
 	.close		= port_close,
 	.read	        = generic_read,
 	.write		= generic_write,
-	.console_write	= port_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= port_free,
 	.winch		= 1,
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 0306a1b..1c555c3 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -118,13 +118,6 @@
 	return(fd);
 }
 
-static int pty_console_write(int fd, const char *buf, int n, void *d)
-{
-	struct pty_chan *data = d;
-
-	return(generic_console_write(fd, buf, n, &data->tt));
-}
-
 struct chan_ops pty_ops = {
 	.type		= "pty",
 	.init		= pty_chan_init,
@@ -132,7 +125,7 @@
 	.close		= generic_close,
 	.read		= generic_read,
 	.write		= generic_write,
-	.console_write	= pty_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= generic_free,
 	.winch		= 0,
@@ -145,7 +138,7 @@
 	.close		= generic_close,
 	.read		= generic_read,
 	.write		= generic_write,
-	.console_write	= pty_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= generic_free,
 	.winch		= 0,
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index 6fbb670..94c9265 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -60,13 +60,6 @@
 	return(fd);
 }
 
-static int tty_console_write(int fd, const char *buf, int n, void *d)
-{
-	struct tty_chan *data = d;
-
-	return(generic_console_write(fd, buf, n, &data->tt));
-}
-
 struct chan_ops tty_ops = {
 	.type		= "tty",
 	.init		= tty_chan_init,
@@ -74,7 +67,7 @@
 	.close		= generic_close,
 	.read		= generic_read,
 	.write		= generic_write,
-	.console_write	= tty_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= generic_free,
 	.winch		= 0,
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index b530f1a..aaa63666 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -194,13 +194,6 @@
 	free(d);
 }
 
-static int xterm_console_write(int fd, const char *buf, int n, void *d)
-{
-	struct xterm_chan *data = d;
-
-	return(generic_console_write(fd, buf, n, &data->tt));
-}
-
 struct chan_ops xterm_ops = {
 	.type		= "xterm",
 	.init		= xterm_init,
@@ -208,7 +201,7 @@
 	.close		= xterm_close,
 	.read		= generic_read,
 	.write		= generic_write,
-	.console_write	= xterm_console_write,
+	.console_write	= generic_console_write,
 	.window_size	= generic_window_size,
 	.free		= xterm_free,
 	.winch		= 1,
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index f77d9aa..659bb3c 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -25,7 +25,7 @@
 	void (*close)(int, void *);
 	int (*read)(int, char *, void *);
 	int (*write)(int, const char *, int, void *);
-	int (*console_write)(int, const char *, int, void *);
+	int (*console_write)(int, const char *, int);
 	int (*window_size)(int, void *, unsigned short *, unsigned short *);
 	void (*free)(void *);
 	int winch;
@@ -37,7 +37,7 @@
 extern void generic_close(int fd, void *unused);
 extern int generic_read(int fd, char *c_out, void *unused);
 extern int generic_write(int fd, const char *buf, int n, void *unused);
-extern int generic_console_write(int fd, const char *buf, int n, void *state);
+extern int generic_console_write(int fd, const char *buf, int n);
 extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
 			       unsigned short *cols_out);
 extern void generic_free(void *data);
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 84c0868..f8760a3 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -17,8 +17,25 @@
 #include "uaccess-skas.h"
 #endif
 
+#define __under_task_size(addr, size) \
+	(((unsigned long) (addr) < TASK_SIZE) && \
+         (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define __access_ok_vsyscall(type, addr, size) \
+	 ((type == VERIFY_READ) && \
+	  ((unsigned long) (addr) >= FIXADDR_USER_START) && \
+	  ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
+	  ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))
+
+#define __addr_range_nowrap(addr, size) \
+	((unsigned long) (addr) <= ((unsigned long) (addr) + (size)))
+
 #define access_ok(type, addr, size) \
-	CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
+	(__addr_range_nowrap(addr, size) && \
+	 (__under_task_size(addr, size) || \
+	  __access_ok_vsyscall(type, addr, size) || \
+	  segment_eq(get_fs(), KERNEL_DS) || \
+	  CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)))
 
 static inline int copy_from_user(void *to, const void __user *from, int n)
 {
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
index 7da0c2d..f611f83 100644
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -9,14 +9,8 @@
 #include "asm/errno.h"
 #include "asm/fixmap.h"
 
-#define access_ok_skas(type, addr, size) \
-	((segment_eq(get_fs(), KERNEL_DS)) || \
-	 (((unsigned long) (addr) < TASK_SIZE) && \
-	  ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
-	 ((type == VERIFY_READ ) && \
-	  ((unsigned long) (addr) >= FIXADDR_USER_START) && \
-	  ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
-	  ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
+/* No SKAS-specific checking. */
+#define access_ok_skas(type, addr, size) 0
 
 extern int copy_from_user_skas(void *to, const void __user *from, int n);
 extern int copy_to_user_skas(void __user *to, const void *from, int n);
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 7519528..a5a4752 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -143,7 +143,7 @@
 		return(0);
 	}
 
-	return(access_ok_skas(VERIFY_READ, from, n) ?
+	return(access_ok(VERIFY_READ, from, n) ?
 	       buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
 	       n);
 }
@@ -164,7 +164,7 @@
 		return(0);
 	}
 
-	return(access_ok_skas(VERIFY_WRITE, to, n) ?
+	return(access_ok(VERIFY_WRITE, to, n) ?
 	       buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
 	       n);
 }
@@ -193,7 +193,7 @@
 		return(strnlen(dst, count));
 	}
 
-	if(!access_ok_skas(VERIFY_READ, src, 1))
+	if(!access_ok(VERIFY_READ, src, 1))
 		return(-EFAULT);
 
 	n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
@@ -221,7 +221,7 @@
 		return(0);
 	}
 
-	return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+	return(access_ok(VERIFY_WRITE, mem, len) ?
 	       buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
 }
 
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 95c8f87..0d4c10a 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -95,7 +95,16 @@
 		pte = pte_offset_kernel(pmd, address);
 	} while(!pte_present(*pte));
 	err = 0;
+	/* The below warning was added in place of
+	 *	pte_mkyoung(); if (is_write) pte_mkdirty();
+	 * If it's triggered, we'd see normally a hang here (a clean pte is
+	 * marked read-only to emulate the dirty bit).
+	 * However, the generic code can mark a PTE writable but clean on a
+	 * concurrent read fault, triggering this harmlessly. So comment it out.
+	 */
+#if 0
 	WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
+#endif
 	flush_tlb_page(vma, address);
 out:
 	up_read(&mm->mmap_sem);
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
index dc2ebfa..b9bfe9c 100644
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -19,19 +19,13 @@
 extern unsigned long end_vm;
 extern unsigned long uml_physmem;
 
-#define under_task_size(addr, size) \
-	(((unsigned long) (addr) < TASK_SIZE) && \
-         (((unsigned long) (addr) + (size)) < TASK_SIZE))
-
 #define is_stack(addr, size) \
 	(((unsigned long) (addr) < STACK_TOP) && \
 	 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
 	 (((unsigned long) (addr) + (size)) <= STACK_TOP))
 
 #define access_ok_tt(type, addr, size) \
-	((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
-         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
-          (under_task_size(addr, size) || is_stack(addr, size))))
+	(is_stack(addr, size))
 
 extern unsigned long get_fault_addr(void);
 
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
index a72aa63..1cb6072 100644
--- a/arch/um/kernel/tt/uaccess.c
+++ b/arch/um/kernel/tt/uaccess.c
@@ -8,7 +8,7 @@
 
 int copy_from_user_tt(void *to, const void __user *from, int n)
 {
-	if(!access_ok_tt(VERIFY_READ, from, n))
+	if(!access_ok(VERIFY_READ, from, n))
 		return(n);
 
 	return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
@@ -17,7 +17,7 @@
 
 int copy_to_user_tt(void __user *to, const void *from, int n)
 {
-	if(!access_ok_tt(VERIFY_WRITE, to, n))
+	if(!access_ok(VERIFY_WRITE, to, n))
 		return(n);
 
 	return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
@@ -28,7 +28,7 @@
 {
 	int n;
 
-	if(!access_ok_tt(VERIFY_READ, src, 1))
+	if(!access_ok(VERIFY_READ, src, 1))
 		return(-EFAULT);
 
 	n = __do_strncpy_from_user(dst, src, count,
@@ -47,7 +47,7 @@
 
 int clear_user_tt(void __user *mem, int len)
 {
-	if(!access_ok_tt(VERIFY_WRITE, mem, len))
+	if(!access_ok(VERIFY_WRITE, mem, len))
 		return(len);
 
 	return(__do_clear_user(mem, len, &current->thread.fault_addr,
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index c6c9791..a9368d4 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -515,7 +515,7 @@
 }
 
 static struct sysdev_class timer_sysclass = {
-	set_kset_name("timer"),
+	set_kset_name("timer_pit"),
 	.resume		= timer_resume,
 };
 
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 6a4da417..606f873 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
 #ifdef CONFIG_X86
@@ -754,7 +755,7 @@
 	result = acpi_bus_init();
 
 	if (!result) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 		if (!PM_IS_ACTIVE())
 			pm_active = 1;
 		else {
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 98f6c02..59dacb6 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -526,18 +526,23 @@
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	int ret;
 	if (!arg) {
 		WARN_ON(1);
 		return 0;
 	}
 	daemonize("%s/%s", "firmware", fw_work->name);
-	_request_firmware(&fw, fw_work->name, fw_work->device,
+	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
 		fw_work->hotplug);
-	fw_work->cont(fw, fw_work->context);
-	release_firmware(fw);
+	if (ret < 0)
+		fw_work->cont(NULL, fw_work->context);
+	else {
+		fw_work->cont(fw, fw_work->context);
+		release_firmware(fw);
+	}
 	module_put(fw_work->module);
 	kfree(fw_work);
-	return 0;
+	return ret;
 }
 
 /**
@@ -586,6 +591,8 @@
 
 	if (ret < 0) {
 		fw_work->cont(NULL, fw_work->context);
+		module_put(fw_work->module);
+		kfree(fw_work);
 		return ret;
 	}
 	return 0;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 59e5982..c0233ef 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1188,7 +1188,7 @@
 	struct packet_data *pkt;
 	int i;
 
-	for (i = 0; i <= PACKET_NUM_STATES; i++)
+	for (i = 0; i < PACKET_NUM_STATES; i++)
 		states[i] = 0;
 
 	spin_lock(&pd->cdrw.active_list_lock);
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index c825531..50947e3 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -557,6 +557,10 @@
 		.device_id	= PCI_DEVICE_ID_APPLE_U3H_AGP,
 		.chipset_name	= "U3H",
 	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_IPID2_AGP,
+		.chipset_name	= "UniNorth/Intrepid2",
+	},
 };
 
 static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index d22bfdc..27c1179 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -18,5 +18,29 @@
 	  The module will be called synclinkmp.  If you want to do that, say M
 	  here.
 
+config CARDMAN_4000
+	tristate "Omnikey Cardman 4000 support"
+	depends on PCMCIA
+	help
+	  Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
+	  reader.
+
+	  This kernel driver requires additional userspace support, either
+	  by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
+	  or via the cm4000 backend of OpenCT (http://www.opensc.com/).
+
+config CARDMAN_4040
+	tristate "Omnikey CardMan 4040 support"
+	depends on PCMCIA
+	help
+	  Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard
+	  reader.
+
+	  This card is basically a USB CCID device connected to a FIFO
+	  in I/O space.  To use the kernel driver, you will need either the
+	  PC/SC ifdhandler provided from the Omnikey homepage
+	  (http://www.omnikey.com/), or a current development version of OpenCT
+	  (http://www.opensc.org/).
+
 endmenu
 
diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
index 1fcd4c5..0aae209 100644
--- a/drivers/char/pcmcia/Makefile
+++ b/drivers/char/pcmcia/Makefile
@@ -5,3 +5,5 @@
 #
 
 obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
+obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
+obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
new file mode 100644
index 0000000..ef011ef
--- /dev/null
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -0,0 +1,2078 @@
+ /*
+  * A driver for the PCMCIA Smartcard Reader "Omnikey CardMan Mobile 4000"
+  *
+  * cm4000_cs.c support.linux@omnikey.com
+  *
+  * Tue Oct 23 11:32:43 GMT 2001 herp - cleaned up header files
+  * Sun Jan 20 10:11:15 MET 2002 herp - added modversion header files
+  * Thu Nov 14 16:34:11 GMT 2002 mh   - added PPS functionality
+  * Tue Nov 19 16:36:27 GMT 2002 mh   - added SUSPEND/RESUME functionailty
+  * Wed Jul 28 12:55:01 CEST 2004 mh  - kernel 2.6 adjustments
+  *
+  * current version: 2.4.0gm4
+  *
+  * (C) 2000,2001,2002,2003,2004 Omnikey AG
+  *
+  * (C) 2005 Harald Welte <laforge@gnumonks.org>
+  * 	- Adhere to Kernel CodingStyle
+  * 	- Port to 2.6.13 "new" style PCMCIA
+  * 	- Check for copy_{from,to}_user return values
+  * 	- Use nonseekable_open()
+  *
+  * All rights reserved. Licensed under dual BSD/GPL license.
+  */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+#include <linux/cm4000_cs.h>
+
+/* #define ATR_CSUM */
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x)	(&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { 				\
+	if (pc_debug >= (n))						\
+		dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, 	\
+			   __FUNCTION__ , ## args);			\
+	} while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+static char *version = "cm4000_cs.c v2.4.0gm5 - All bugs added by Harald Welte";
+
+#define	T_1SEC		(HZ)
+#define	T_10MSEC	msecs_to_jiffies(10)
+#define	T_20MSEC	msecs_to_jiffies(20)
+#define	T_40MSEC	msecs_to_jiffies(40)
+#define	T_50MSEC	msecs_to_jiffies(50)
+#define	T_100MSEC	msecs_to_jiffies(100)
+#define	T_500MSEC	msecs_to_jiffies(500)
+
+static void cm4000_detach(dev_link_t *link);
+static void cm4000_release(dev_link_t *link);
+
+static int major;		/* major number we get from the kernel */
+
+/* note: the first state has to have number 0 always */
+
+#define	M_FETCH_ATR	0
+#define	M_TIMEOUT_WAIT	1
+#define	M_READ_ATR_LEN	2
+#define	M_READ_ATR	3
+#define	M_ATR_PRESENT	4
+#define	M_BAD_CARD	5
+#define M_CARDOFF	6
+
+#define	LOCK_IO			0
+#define	LOCK_MONITOR		1
+
+#define IS_AUTOPPS_ACT		 6
+#define	IS_PROCBYTE_PRESENT	 7
+#define	IS_INVREV		 8
+#define IS_ANY_T0		 9
+#define	IS_ANY_T1		10
+#define	IS_ATR_PRESENT		11
+#define	IS_ATR_VALID		12
+#define	IS_CMM_ABSENT		13
+#define	IS_BAD_LENGTH		14
+#define	IS_BAD_CSUM		15
+#define	IS_BAD_CARD		16
+
+#define REG_FLAGS0(x)		(x + 0)
+#define REG_FLAGS1(x)		(x + 1)
+#define REG_NUM_BYTES(x)	(x + 2)
+#define REG_BUF_ADDR(x)		(x + 3)
+#define REG_BUF_DATA(x)		(x + 4)
+#define REG_NUM_SEND(x)		(x + 5)
+#define REG_BAUDRATE(x)		(x + 6)
+#define REG_STOPBITS(x)		(x + 7)
+
+struct cm4000_dev {
+	dev_link_t link;		/* pcmcia link */
+	dev_node_t node;		/* OS node (major,minor) */
+
+	unsigned char atr[MAX_ATR];
+	unsigned char rbuf[512];
+	unsigned char sbuf[512];
+
+	wait_queue_head_t devq;		/* when removing cardman must not be
+					   zeroed! */
+
+	wait_queue_head_t ioq;		/* if IO is locked, wait on this Q */
+	wait_queue_head_t atrq;		/* wait for ATR valid */
+	wait_queue_head_t readq;	/* used by write to wake blk.read */
+
+	/* warning: do not move this fields.
+	 * initialising to zero depends on it - see ZERO_DEV below.  */
+	unsigned char atr_csum;
+	unsigned char atr_len_retry;
+	unsigned short atr_len;
+	unsigned short rlen;	/* bytes avail. after write */
+	unsigned short rpos;	/* latest read pos. write zeroes */
+	unsigned char procbyte;	/* T=0 procedure byte */
+	unsigned char mstate;	/* state of card monitor */
+	unsigned char cwarn;	/* slow down warning */
+	unsigned char flags0;	/* cardman IO-flags 0 */
+	unsigned char flags1;	/* cardman IO-flags 1 */
+	unsigned int mdelay;	/* variable monitor speeds, in jiffies */
+
+	unsigned int baudv;	/* baud value for speed */
+	unsigned char ta1;
+	unsigned char proto;	/* T=0, T=1, ... */
+	unsigned long flags;	/* lock+flags (MONITOR,IO,ATR) * for concurrent
+				   access */
+
+	unsigned char pts[4];
+
+	struct timer_list timer;	/* used to keep monitor running */
+	int monitor_running;
+};
+
+#define	ZERO_DEV(dev)  						\
+	memset(&dev->atr_csum,0,				\
+		sizeof(struct cm4000_dev) - 			\
+		/*link*/ sizeof(dev_link_t) - 			\
+		/*node*/ sizeof(dev_node_t) - 			\
+		/*atr*/ MAX_ATR*sizeof(char) - 			\
+		/*rbuf*/ 512*sizeof(char) - 			\
+		/*sbuf*/ 512*sizeof(char) - 			\
+		/*queue*/ 4*sizeof(wait_queue_head_t))
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM4000_MAX_DEV];
+
+/* This table doesn't use spaces after the comma between fields and thus
+ * violates CodingStyle.  However, I don't really think wrapping it around will
+ * make it any clearer to read -HW */
+static unsigned char fi_di_table[10][14] = {
+/*FI     00   01   02   03   04   05   06   07   08   09   10   11   12   13 */
+/*DI */
+/* 0 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 1 */ {0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x91,0x11,0x11,0x11,0x11},
+/* 2 */ {0x02,0x12,0x22,0x32,0x11,0x11,0x11,0x11,0x11,0x92,0xA2,0xB2,0x11,0x11},
+/* 3 */ {0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x11,0x11,0x93,0xA3,0xB3,0xC3,0xD3},
+/* 4 */ {0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x11,0x11,0x94,0xA4,0xB4,0xC4,0xD4},
+/* 5 */ {0x00,0x15,0x25,0x35,0x45,0x55,0x65,0x11,0x11,0x95,0xA5,0xB5,0xC5,0xD5},
+/* 6 */ {0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x11,0x11,0x96,0xA6,0xB6,0xC6,0xD6},
+/* 7 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 8 */ {0x08,0x11,0x28,0x38,0x48,0x58,0x68,0x11,0x11,0x98,0xA8,0xB8,0xC8,0xD8},
+/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9}
+};
+
+#ifndef PCMCIA_DEBUG
+#define	xoutb	outb
+#define	xinb	inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+	if (pc_debug >= 7)
+		printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+	outb(val, port);
+}
+static inline unsigned char xinb(unsigned short port)
+{
+	unsigned char val;
+
+	val = inb(port);
+	if (pc_debug >= 7)
+		printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+
+	return val;
+}
+#endif
+
+#define	b_0000	15
+#define	b_0001	14
+#define	b_0010	13
+#define	b_0011	12
+#define	b_0100	11
+#define	b_0101	10
+#define	b_0110	9
+#define	b_0111	8
+#define	b_1000	7
+#define	b_1001	6
+#define	b_1010	5
+#define	b_1011	4
+#define	b_1100	3
+#define	b_1101	2
+#define	b_1110	1
+#define	b_1111	0
+
+static unsigned char irtab[16] = {
+	b_0000, b_1000, b_0100, b_1100,
+	b_0010, b_1010, b_0110, b_1110,
+	b_0001, b_1001, b_0101, b_1101,
+	b_0011, b_1011, b_0111, b_1111
+};
+
+static void str_invert_revert(unsigned char *b, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
+}
+
+static unsigned char invert_revert(unsigned char ch)
+{
+	return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+}
+
+#define	ATRLENCK(dev,pos) \
+	if (pos>=dev->atr_len || pos>=MAX_ATR) \
+		goto return_0;
+
+static unsigned int calc_baudv(unsigned char fidi)
+{
+	unsigned int wcrcf, wbrcf, fi_rfu, di_rfu;
+
+	fi_rfu = 372;
+	di_rfu = 1;
+
+	/* FI */
+	switch ((fidi >> 4) & 0x0F) {
+	case 0x00:
+		wcrcf = 372;
+		break;
+	case 0x01:
+		wcrcf = 372;
+		break;
+	case 0x02:
+		wcrcf = 558;
+		break;
+	case 0x03:
+		wcrcf = 744;
+		break;
+	case 0x04:
+		wcrcf = 1116;
+		break;
+	case 0x05:
+		wcrcf = 1488;
+		break;
+	case 0x06:
+		wcrcf = 1860;
+		break;
+	case 0x07:
+		wcrcf = fi_rfu;
+		break;
+	case 0x08:
+		wcrcf = fi_rfu;
+		break;
+	case 0x09:
+		wcrcf = 512;
+		break;
+	case 0x0A:
+		wcrcf = 768;
+		break;
+	case 0x0B:
+		wcrcf = 1024;
+		break;
+	case 0x0C:
+		wcrcf = 1536;
+		break;
+	case 0x0D:
+		wcrcf = 2048;
+		break;
+	default:
+		wcrcf = fi_rfu;
+		break;
+	}
+
+	/* DI */
+	switch (fidi & 0x0F) {
+	case 0x00:
+		wbrcf = di_rfu;
+		break;
+	case 0x01:
+		wbrcf = 1;
+		break;
+	case 0x02:
+		wbrcf = 2;
+		break;
+	case 0x03:
+		wbrcf = 4;
+		break;
+	case 0x04:
+		wbrcf = 8;
+		break;
+	case 0x05:
+		wbrcf = 16;
+		break;
+	case 0x06:
+		wbrcf = 32;
+		break;
+	case 0x07:
+		wbrcf = di_rfu;
+		break;
+	case 0x08:
+		wbrcf = 12;
+		break;
+	case 0x09:
+		wbrcf = 20;
+		break;
+	default:
+		wbrcf = di_rfu;
+		break;
+	}
+
+	return (wcrcf / wbrcf);
+}
+
+static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+{
+	unsigned short tmp;
+
+	tmp = *s = 0;
+	do {
+		*s = tmp;
+		tmp = inb(REG_NUM_BYTES(iobase)) |
+				(inb(REG_FLAGS0(iobase)) & 4 ? 0x100 : 0);
+	} while (tmp != *s);
+
+	return *s;
+}
+
+static int parse_atr(struct cm4000_dev *dev)
+{
+	unsigned char any_t1, any_t0;
+	unsigned char ch, ifno;
+	int ix, done;
+
+	DEBUGP(3, dev, "-> parse_atr: dev->atr_len = %i\n", dev->atr_len);
+
+	if (dev->atr_len < 3) {
+		DEBUGP(5, dev, "parse_atr: atr_len < 3\n");
+		return 0;
+	}
+
+	if (dev->atr[0] == 0x3f)
+		set_bit(IS_INVREV, &dev->flags);
+	else
+		clear_bit(IS_INVREV, &dev->flags);
+	ix = 1;
+	ifno = 1;
+	ch = dev->atr[1];
+	dev->proto = 0;		/* XXX PROTO */
+	any_t1 = any_t0 = done = 0;
+	dev->ta1 = 0x11;	/* defaults to 9600 baud */
+	do {
+		if (ifno == 1 && (ch & 0x10)) {
+			/* read first interface byte and TA1 is present */
+			dev->ta1 = dev->atr[2];
+			DEBUGP(5, dev, "Card says FiDi is 0x%.2x\n", dev->ta1);
+			ifno++;
+		} else if ((ifno == 2) && (ch & 0x10)) { /* TA(2) */
+			dev->ta1 = 0x11;
+			ifno++;
+		}
+
+		DEBUGP(5, dev, "Yi=%.2x\n", ch & 0xf0);
+		ix += ((ch & 0x10) >> 4)	/* no of int.face chars */
+		    +((ch & 0x20) >> 5)
+		    + ((ch & 0x40) >> 6)
+		    + ((ch & 0x80) >> 7);
+		/* ATRLENCK(dev,ix); */
+		if (ch & 0x80) {	/* TDi */
+			ch = dev->atr[ix];
+			if ((ch & 0x0f)) {
+				any_t1 = 1;
+				DEBUGP(5, dev, "card is capable of T=1\n");
+			} else {
+				any_t0 = 1;
+				DEBUGP(5, dev, "card is capable of T=0\n");
+			}
+		} else
+			done = 1;
+	} while (!done);
+
+	DEBUGP(5, dev, "ix=%d noHist=%d any_t1=%d\n",
+	      ix, dev->atr[1] & 15, any_t1);
+	if (ix + 1 + (dev->atr[1] & 0x0f) + any_t1 != dev->atr_len) {
+		DEBUGP(5, dev, "length error\n");
+		return 0;
+	}
+	if (any_t0)
+		set_bit(IS_ANY_T0, &dev->flags);
+
+	if (any_t1) {		/* compute csum */
+		dev->atr_csum = 0;
+#ifdef ATR_CSUM
+		for (i = 1; i < dev->atr_len; i++)
+			dev->atr_csum ^= dev->atr[i];
+		if (dev->atr_csum) {
+			set_bit(IS_BAD_CSUM, &dev->flags);
+			DEBUGP(5, dev, "bad checksum\n");
+			goto return_0;
+		}
+#endif
+		if (any_t0 == 0)
+			dev->proto = 1;	/* XXX PROTO */
+		set_bit(IS_ANY_T1, &dev->flags);
+	}
+
+	return 1;
+}
+
+struct card_fixup {
+	char atr[12];
+	u_int8_t atr_len;
+	u_int8_t stopbits;
+};
+
+static struct card_fixup card_fixups[] = {
+	{	/* ACOS */
+		.atr = { 0x3b, 0xb3, 0x11, 0x00, 0x00, 0x41, 0x01 },
+		.atr_len = 7,
+		.stopbits = 0x03,
+	},
+	{	/* Motorola */
+		.atr = {0x3b, 0x76, 0x13, 0x00, 0x00, 0x80, 0x62, 0x07,
+			0x41, 0x81, 0x81 },
+		.atr_len = 11,
+		.stopbits = 0x04,
+	},
+};
+
+static void set_cardparameter(struct cm4000_dev *dev)
+{
+	int i;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+	u_int8_t stopbits = 0x02; /* ISO default */
+
+	DEBUGP(3, dev, "-> set_cardparameter\n");
+
+	dev->flags1 = dev->flags1 | (((dev->baudv - 1) & 0x0100) >> 8);
+	xoutb(dev->flags1, REG_FLAGS1(iobase));
+	DEBUGP(5, dev, "flags1 = 0x%02x\n", dev->flags1);
+
+	/* set baudrate */
+	xoutb((unsigned char)((dev->baudv - 1) & 0xFF), REG_BAUDRATE(iobase));
+
+	DEBUGP(5, dev, "baudv = %i -> write 0x%02x\n", dev->baudv,
+	      ((dev->baudv - 1) & 0xFF));
+
+	/* set stopbits */
+	for (i = 0; i < ARRAY_SIZE(card_fixups); i++) {
+		if (!memcmp(dev->atr, card_fixups[i].atr,
+			    card_fixups[i].atr_len))
+			stopbits = card_fixups[i].stopbits;
+	}
+	xoutb(stopbits, REG_STOPBITS(iobase));
+
+	DEBUGP(3, dev, "<- set_cardparameter\n");
+}
+
+static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
+{
+
+	unsigned long tmp, i;
+	unsigned short num_bytes_read;
+	unsigned char pts_reply[4];
+	ssize_t rc;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+
+	rc = 0;
+
+	DEBUGP(3, dev, "-> set_protocol\n");
+	DEBUGP(5, dev, "ptsreq->Protocol = 0x%.8x, ptsreq->Flags=0x%.8x, "
+		 "ptsreq->pts1=0x%.2x, ptsreq->pts2=0x%.2x, "
+		 "ptsreq->pts3=0x%.2x\n", (unsigned int)ptsreq->protocol,
+		 (unsigned int)ptsreq->flags, ptsreq->pts1, ptsreq->pts2,
+		 ptsreq->pts3);
+
+	/* Fill PTS structure */
+	dev->pts[0] = 0xff;
+	dev->pts[1] = 0x00;
+	tmp = ptsreq->protocol;
+	while ((tmp = (tmp >> 1)) > 0)
+		dev->pts[1]++;
+	dev->proto = dev->pts[1];	/* Set new protocol */
+	dev->pts[1] = (0x01 << 4) | (dev->pts[1]);
+
+	/* Correct Fi/Di according to CM4000 Fi/Di table */
+	DEBUGP(5, dev, "Ta(1) from ATR is 0x%.2x\n", dev->ta1);
+	/* set Fi/Di according to ATR TA(1) */
+	dev->pts[2] = fi_di_table[dev->ta1 & 0x0F][(dev->ta1 >> 4) & 0x0F];
+
+	/* Calculate PCK character */
+	dev->pts[3] = dev->pts[0] ^ dev->pts[1] ^ dev->pts[2];
+
+	DEBUGP(5, dev, "pts0=%.2x, pts1=%.2x, pts2=%.2x, pts3=%.2x\n",
+	       dev->pts[0], dev->pts[1], dev->pts[2], dev->pts[3]);
+
+	/* check card convention */
+	if (test_bit(IS_INVREV, &dev->flags))
+		str_invert_revert(dev->pts, 4);
+
+	/* reset SM */
+	xoutb(0x80, REG_FLAGS0(iobase));
+
+	/* Enable access to the message buffer */
+	DEBUGP(5, dev, "Enable access to the messages buffer\n");
+	dev->flags1 = 0x20	/* T_Active */
+	    | (test_bit(IS_INVREV, &dev->flags) ? 0x02 : 0x00) /* inv parity */
+	    | ((dev->baudv >> 8) & 0x01);	/* MSB-baud */
+	xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+	DEBUGP(5, dev, "Enable message buffer -> flags1 = 0x%.2x\n",
+	       dev->flags1);
+
+	/* write challenge to the buffer */
+	DEBUGP(5, dev, "Write challenge to buffer: ");
+	for (i = 0; i < 4; i++) {
+		xoutb(i, REG_BUF_ADDR(iobase));
+		xoutb(dev->pts[i], REG_BUF_DATA(iobase));	/* buf data */
+#ifdef PCMCIA_DEBUG
+		if (pc_debug >= 5)
+			printk("0x%.2x ", dev->pts[i]);
+	}
+	if (pc_debug >= 5)
+		printk("\n");
+#else
+	}
+#endif
+
+	/* set number of bytes to write */
+	DEBUGP(5, dev, "Set number of bytes to write\n");
+	xoutb(0x04, REG_NUM_SEND(iobase));
+
+	/* Trigger CARDMAN CONTROLLER */
+	xoutb(0x50, REG_FLAGS0(iobase));
+
+	/* Monitor progress */
+	/* wait for xmit done */
+	DEBUGP(5, dev, "Waiting for NumRecBytes getting valid\n");
+
+	for (i = 0; i < 100; i++) {
+		if (inb(REG_FLAGS0(iobase)) & 0x08) {
+			DEBUGP(5, dev, "NumRecBytes is valid\n");
+			break;
+		}
+		mdelay(10);
+	}
+	if (i == 100) {
+		DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting "
+		       "valid\n");
+		rc = -EIO;
+		goto exit_setprotocol;
+	}
+
+	DEBUGP(5, dev, "Reading NumRecBytes\n");
+	for (i = 0; i < 100; i++) {
+		io_read_num_rec_bytes(iobase, &num_bytes_read);
+		if (num_bytes_read >= 4) {
+			DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
+			break;
+		}
+		mdelay(10);
+	}
+
+	/* check whether it is a short PTS reply? */
+	if (num_bytes_read == 3)
+		i = 0;
+
+	if (i == 100) {
+		DEBUGP(5, dev, "Timeout reading num_bytes_read\n");
+		rc = -EIO;
+		goto exit_setprotocol;
+	}
+
+	DEBUGP(5, dev, "Reset the CARDMAN CONTROLLER\n");
+	xoutb(0x80, REG_FLAGS0(iobase));
+
+	/* Read PPS reply */
+	DEBUGP(5, dev, "Read PPS reply\n");
+	for (i = 0; i < num_bytes_read; i++) {
+		xoutb(i, REG_BUF_ADDR(iobase));
+		pts_reply[i] = inb(REG_BUF_DATA(iobase));
+	}
+
+#ifdef PCMCIA_DEBUG
+	DEBUGP(2, dev, "PTSreply: ");
+	for (i = 0; i < num_bytes_read; i++) {
+		if (pc_debug >= 5)
+			printk("0x%.2x ", pts_reply[i]);
+	}
+	printk("\n");
+#endif	/* PCMCIA_DEBUG */
+
+	DEBUGP(5, dev, "Clear Tactive in Flags1\n");
+	xoutb(0x20, REG_FLAGS1(iobase));
+
+	/* Compare ptsreq and ptsreply */
+	if ((dev->pts[0] == pts_reply[0]) &&
+	    (dev->pts[1] == pts_reply[1]) &&
+	    (dev->pts[2] == pts_reply[2]) && (dev->pts[3] == pts_reply[3])) {
+		/* setcardparameter according to PPS */
+		dev->baudv = calc_baudv(dev->pts[2]);
+		set_cardparameter(dev);
+	} else if ((dev->pts[0] == pts_reply[0]) &&
+		   ((dev->pts[1] & 0xef) == pts_reply[1]) &&
+		   ((pts_reply[0] ^ pts_reply[1]) == pts_reply[2])) {
+		/* short PTS reply, set card parameter to default values */
+		dev->baudv = calc_baudv(0x11);
+		set_cardparameter(dev);
+	} else
+		rc = -EIO;
+
+exit_setprotocol:
+	DEBUGP(3, dev, "<- set_protocol\n");
+	return rc;
+}
+
+static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+{
+
+	/* note: statemachine is assumed to be reset */
+	if (inb(REG_FLAGS0(iobase)) & 8) {
+		clear_bit(IS_ATR_VALID, &dev->flags);
+		set_bit(IS_CMM_ABSENT, &dev->flags);
+		return 0;	/* detect CMM = 1 -> failure */
+	}
+	/* xoutb(0x40, REG_FLAGS1(iobase)); detectCMM */
+	xoutb(dev->flags1 | 0x40, REG_FLAGS1(iobase));
+	if ((inb(REG_FLAGS0(iobase)) & 8) == 0) {
+		clear_bit(IS_ATR_VALID, &dev->flags);
+		set_bit(IS_CMM_ABSENT, &dev->flags);
+		return 0;	/* detect CMM=0 -> failure */
+	}
+	/* clear detectCMM again by restoring original flags1 */
+	xoutb(dev->flags1, REG_FLAGS1(iobase));
+	return 1;
+}
+
+static void terminate_monitor(struct cm4000_dev *dev)
+{
+
+	/* tell the monitor to stop and wait until
+	 * it terminates.
+	 */
+	DEBUGP(3, dev, "-> terminate_monitor\n");
+	wait_event_interruptible(dev->devq,
+				 test_and_set_bit(LOCK_MONITOR,
+						  (void *)&dev->flags));
+
+	/* now, LOCK_MONITOR has been set.
+	 * allow a last cycle in the monitor.
+	 * the monitor will indicate that it has
+	 * finished by clearing this bit.
+	 */
+	DEBUGP(5, dev, "Now allow last cycle of monitor!\n");
+	while (test_bit(LOCK_MONITOR, (void *)&dev->flags))
+		msleep(25);
+
+	DEBUGP(5, dev, "Delete timer\n");
+	del_timer_sync(&dev->timer);
+#ifdef PCMCIA_DEBUG
+	dev->monitor_running = 0;
+#endif
+
+	DEBUGP(3, dev, "<- terminate_monitor\n");
+}
+
+/*
+ * monitor the card every 50msec. as a side-effect, retrieve the
+ * atr once a card is inserted. another side-effect of retrieving the
+ * atr is that the card will be powered on, so there is no need to
+ * power on the card explictely from the application: the driver
+ * is already doing that for you.
+ */
+
+static void monitor_card(unsigned long p)
+{
+	struct cm4000_dev *dev = (struct cm4000_dev *) p;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+	unsigned short s;
+	struct ptsreq ptsreq;
+	int i, atrc;
+
+	DEBUGP(7, dev, "->  monitor_card\n");
+
+	/* if someone has set the lock for us: we're done! */
+	if (test_and_set_bit(LOCK_MONITOR, &dev->flags)) {
+		DEBUGP(4, dev, "About to stop monitor\n");
+		/* no */
+		dev->rlen =
+		    dev->rpos =
+		    dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+		dev->mstate = M_FETCH_ATR;
+		clear_bit(LOCK_MONITOR, &dev->flags);
+		/* close et al. are sleeping on devq, so wake it */
+		wake_up_interruptible(&dev->devq);
+		DEBUGP(2, dev, "<- monitor_card (we are done now)\n");
+		return;
+	}
+
+	/* try to lock io: if it is already locked, just add another timer */
+	if (test_and_set_bit(LOCK_IO, (void *)&dev->flags)) {
+		DEBUGP(4, dev, "Couldn't get IO lock\n");
+		goto return_with_timer;
+	}
+
+	/* is a card/a reader inserted at all ? */
+	dev->flags0 = xinb(REG_FLAGS0(iobase));
+	DEBUGP(7, dev, "dev->flags0 = 0x%2x\n", dev->flags0);
+	DEBUGP(7, dev, "smartcard present: %s\n",
+	       dev->flags0 & 1 ? "yes" : "no");
+	DEBUGP(7, dev, "cardman present: %s\n",
+	       dev->flags0 == 0xff ? "no" : "yes");
+
+	if ((dev->flags0 & 1) == 0	/* no smartcard inserted */
+	    || dev->flags0 == 0xff) {	/* no cardman inserted */
+		/* no */
+		dev->rlen =
+		    dev->rpos =
+		    dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+		dev->mstate = M_FETCH_ATR;
+
+		dev->flags &= 0x000000ff; /* only keep IO and MONITOR locks */
+
+		if (dev->flags0 == 0xff) {
+			DEBUGP(4, dev, "set IS_CMM_ABSENT bit\n");
+			set_bit(IS_CMM_ABSENT, &dev->flags);
+		} else if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+			DEBUGP(4, dev, "clear IS_CMM_ABSENT bit "
+			       "(card is removed)\n");
+			clear_bit(IS_CMM_ABSENT, &dev->flags);
+		}
+
+		goto release_io;
+	} else if ((dev->flags0 & 1) && test_bit(IS_CMM_ABSENT, &dev->flags)) {
+		/* cardman and card present but cardman was absent before
+		 * (after suspend with inserted card) */
+		DEBUGP(4, dev, "clear IS_CMM_ABSENT bit (card is inserted)\n");
+		clear_bit(IS_CMM_ABSENT, &dev->flags);
+	}
+
+	if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+		DEBUGP(7, dev, "believe ATR is already valid (do nothing)\n");
+		goto release_io;
+	}
+
+	switch (dev->mstate) {
+		unsigned char flags0;
+	case M_CARDOFF:
+		DEBUGP(4, dev, "M_CARDOFF\n");
+		flags0 = inb(REG_FLAGS0(iobase));
+		if (flags0 & 0x02) {
+			/* wait until Flags0 indicate power is off */
+			dev->mdelay = T_10MSEC;
+		} else {
+			/* Flags0 indicate power off and no card inserted now;
+			 * Reset CARDMAN CONTROLLER */
+			xoutb(0x80, REG_FLAGS0(iobase));
+
+			/* prepare for fetching ATR again: after card off ATR
+			 * is read again automatically */
+			dev->rlen =
+			    dev->rpos =
+			    dev->atr_csum =
+			    dev->atr_len_retry = dev->cwarn = 0;
+			dev->mstate = M_FETCH_ATR;
+
+			/* minimal gap between CARDOFF and read ATR is 50msec */
+			dev->mdelay = T_50MSEC;
+		}
+		break;
+	case M_FETCH_ATR:
+		DEBUGP(4, dev, "M_FETCH_ATR\n");
+		xoutb(0x80, REG_FLAGS0(iobase));
+		DEBUGP(4, dev, "Reset BAUDV to 9600\n");
+		dev->baudv = 0x173;	/* 9600 */
+		xoutb(0x02, REG_STOPBITS(iobase));	/* stopbits=2 */
+		xoutb(0x73, REG_BAUDRATE(iobase));	/* baud value */
+		xoutb(0x21, REG_FLAGS1(iobase));	/* T_Active=1, baud
+							   value */
+		/* warm start vs. power on: */
+		xoutb(dev->flags0 & 2 ? 0x46 : 0x44, REG_FLAGS0(iobase));
+		dev->mdelay = T_40MSEC;
+		dev->mstate = M_TIMEOUT_WAIT;
+		break;
+	case M_TIMEOUT_WAIT:
+		DEBUGP(4, dev, "M_TIMEOUT_WAIT\n");
+		/* numRecBytes */
+		io_read_num_rec_bytes(iobase, &dev->atr_len);
+		dev->mdelay = T_10MSEC;
+		dev->mstate = M_READ_ATR_LEN;
+		break;
+	case M_READ_ATR_LEN:
+		DEBUGP(4, dev, "M_READ_ATR_LEN\n");
+		/* infinite loop possible, since there is no timeout */
+
+#define	MAX_ATR_LEN_RETRY	100
+
+		if (dev->atr_len == io_read_num_rec_bytes(iobase, &s)) {
+			if (dev->atr_len_retry++ >= MAX_ATR_LEN_RETRY) {					/* + XX msec */
+				dev->mdelay = T_10MSEC;
+				dev->mstate = M_READ_ATR;
+			}
+		} else {
+			dev->atr_len = s;
+			dev->atr_len_retry = 0;	/* set new timeout */
+		}
+
+		DEBUGP(4, dev, "Current ATR_LEN = %i\n", dev->atr_len);
+		break;
+	case M_READ_ATR:
+		DEBUGP(4, dev, "M_READ_ATR\n");
+		xoutb(0x80, REG_FLAGS0(iobase));	/* reset SM */
+		for (i = 0; i < dev->atr_len; i++) {
+			xoutb(i, REG_BUF_ADDR(iobase));
+			dev->atr[i] = inb(REG_BUF_DATA(iobase));
+		}
+		/* Deactivate T_Active flags */
+		DEBUGP(4, dev, "Deactivate T_Active flags\n");
+		dev->flags1 = 0x01;
+		xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+		/* atr is present (which doesnt mean it's valid) */
+		set_bit(IS_ATR_PRESENT, &dev->flags);
+		if (dev->atr[0] == 0x03)
+			str_invert_revert(dev->atr, dev->atr_len);
+		atrc = parse_atr(dev);
+		if (atrc == 0) {	/* atr invalid */
+			dev->mdelay = 0;
+			dev->mstate = M_BAD_CARD;
+		} else {
+			dev->mdelay = T_50MSEC;
+			dev->mstate = M_ATR_PRESENT;
+			set_bit(IS_ATR_VALID, &dev->flags);
+		}
+
+		if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+			DEBUGP(4, dev, "monitor_card: ATR valid\n");
+ 			/* if ta1 == 0x11, no PPS necessary (default values) */
+			/* do not do PPS with multi protocol cards */
+			if ((test_bit(IS_AUTOPPS_ACT, &dev->flags) == 0) &&
+			    (dev->ta1 != 0x11) &&
+			    !(test_bit(IS_ANY_T0, &dev->flags) &&
+			    test_bit(IS_ANY_T1, &dev->flags))) {
+				DEBUGP(4, dev, "Perform AUTOPPS\n");
+				set_bit(IS_AUTOPPS_ACT, &dev->flags);
+				ptsreq.protocol = ptsreq.protocol =
+				    (0x01 << dev->proto);
+				ptsreq.flags = 0x01;
+				ptsreq.pts1 = 0x00;
+				ptsreq.pts2 = 0x00;
+				ptsreq.pts3 = 0x00;
+				if (set_protocol(dev, &ptsreq) == 0) {
+					DEBUGP(4, dev, "AUTOPPS ret SUCC\n");
+					clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+					wake_up_interruptible(&dev->atrq);
+				} else {
+					DEBUGP(4, dev, "AUTOPPS failed: "
+					       "repower using defaults\n");
+					/* prepare for repowering  */
+					clear_bit(IS_ATR_PRESENT, &dev->flags);
+					clear_bit(IS_ATR_VALID, &dev->flags);
+					dev->rlen =
+					    dev->rpos =
+					    dev->atr_csum =
+					    dev->atr_len_retry = dev->cwarn = 0;
+					dev->mstate = M_FETCH_ATR;
+
+					dev->mdelay = T_50MSEC;
+				}
+			} else {
+				/* for cards which use slightly different
+				 * params (extra guard time) */
+				set_cardparameter(dev);
+				if (test_bit(IS_AUTOPPS_ACT, &dev->flags) == 1)
+					DEBUGP(4, dev, "AUTOPPS already active "
+					       "2nd try:use default values\n");
+				if (dev->ta1 == 0x11)
+					DEBUGP(4, dev, "No AUTOPPS necessary "
+					       "TA(1)==0x11\n");
+				if (test_bit(IS_ANY_T0, &dev->flags)
+				    && test_bit(IS_ANY_T1, &dev->flags))
+					DEBUGP(4, dev, "Do NOT perform AUTOPPS "
+					       "with multiprotocol cards\n");
+				clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+				wake_up_interruptible(&dev->atrq);
+			}
+		} else {
+			DEBUGP(4, dev, "ATR invalid\n");
+			wake_up_interruptible(&dev->atrq);
+		}
+		break;
+	case M_BAD_CARD:
+		DEBUGP(4, dev, "M_BAD_CARD\n");
+		/* slow down warning, but prompt immediately after insertion */
+		if (dev->cwarn == 0 || dev->cwarn == 10) {
+			set_bit(IS_BAD_CARD, &dev->flags);
+			printk(KERN_WARNING MODULE_NAME ": device %s: ",
+			       dev->node.dev_name);
+			if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+				DEBUGP(4, dev, "ATR checksum (0x%.2x, should "
+				       "be zero) failed\n", dev->atr_csum);
+			}
+#ifdef PCMCIA_DEBUG
+			else if (test_bit(IS_BAD_LENGTH, &dev->flags)) {
+				DEBUGP(4, dev, "ATR length error\n");
+			} else {
+				DEBUGP(4, dev, "card damaged or wrong way "
+					"inserted\n");
+			}
+#endif
+			dev->cwarn = 0;
+			wake_up_interruptible(&dev->atrq);	/* wake open */
+		}
+		dev->cwarn++;
+		dev->mdelay = T_100MSEC;
+		dev->mstate = M_FETCH_ATR;
+		break;
+	default:
+		DEBUGP(7, dev, "Unknown action\n");
+		break;		/* nothing */
+	}
+
+release_io:
+	DEBUGP(7, dev, "release_io\n");
+	clear_bit(LOCK_IO, &dev->flags);
+	wake_up_interruptible(&dev->ioq);	/* whoever needs IO */
+
+return_with_timer:
+	DEBUGP(7, dev, "<- monitor_card (returns with timer)\n");
+	dev->timer.expires = jiffies + dev->mdelay;
+	add_timer(&dev->timer);
+	clear_bit(LOCK_MONITOR, &dev->flags);
+}
+
+/* Interface to userland (file_operations) */
+
+static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
+			loff_t *ppos)
+{
+	struct cm4000_dev *dev = filp->private_data;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+	ssize_t rc;
+	int i, j, k;
+
+	DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid);
+
+	if (count == 0)		/* according to manpage */
+		return 0;
+
+	if ((dev->link.state & DEV_PRESENT) == 0 ||	/* socket removed */
+	    test_bit(IS_CMM_ABSENT, &dev->flags))
+		return -ENODEV;
+
+	if (test_bit(IS_BAD_CSUM, &dev->flags))
+		return -EIO;
+
+	/* also see the note about this in cmm_write */
+	if (wait_event_interruptible
+	    (dev->atrq,
+	     ((filp->f_flags & O_NONBLOCK)
+	      || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		return -ERESTARTSYS;
+	}
+
+	if (test_bit(IS_ATR_VALID, &dev->flags) == 0)
+		return -EIO;
+
+	/* this one implements blocking IO */
+	if (wait_event_interruptible
+	    (dev->readq,
+	     ((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		return -ERESTARTSYS;
+	}
+
+	/* lock io */
+	if (wait_event_interruptible
+	    (dev->ioq,
+	     ((filp->f_flags & O_NONBLOCK)
+	      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		return -ERESTARTSYS;
+	}
+
+	rc = 0;
+	dev->flags0 = inb(REG_FLAGS0(iobase));
+	if ((dev->flags0 & 1) == 0	/* no smartcard inserted */
+	    || dev->flags0 == 0xff) {	/* no cardman inserted */
+		clear_bit(IS_ATR_VALID, &dev->flags);
+		if (dev->flags0 & 1) {
+			set_bit(IS_CMM_ABSENT, &dev->flags);
+			rc = -ENODEV;
+		}
+		rc = -EIO;
+		goto release_io;
+	}
+
+	DEBUGP(4, dev, "begin read answer\n");
+	j = min(count, (size_t)(dev->rlen - dev->rpos));
+	k = dev->rpos;
+	if (k + j > 255)
+		j = 256 - k;
+	DEBUGP(4, dev, "read1 j=%d\n", j);
+	for (i = 0; i < j; i++) {
+		xoutb(k++, REG_BUF_ADDR(iobase));
+		dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+	}
+	j = min(count, (size_t)(dev->rlen - dev->rpos));
+	if (k + j > 255) {
+		DEBUGP(4, dev, "read2 j=%d\n", j);
+		dev->flags1 |= 0x10;	/* MSB buf addr set */
+		xoutb(dev->flags1, REG_FLAGS1(iobase));
+		for (; i < j; i++) {
+			xoutb(k++, REG_BUF_ADDR(iobase));
+			dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+		}
+	}
+
+	if (dev->proto == 0 && count > dev->rlen - dev->rpos) {
+		DEBUGP(4, dev, "T=0 and count > buffer\n");
+		dev->rbuf[i] = dev->rbuf[i - 1];
+		dev->rbuf[i - 1] = dev->procbyte;
+		j++;
+	}
+	count = j;
+
+	dev->rpos = dev->rlen + 1;
+
+	/* Clear T1Active */
+	DEBUGP(4, dev, "Clear T1Active\n");
+	dev->flags1 &= 0xdf;
+	xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+	xoutb(0, REG_FLAGS1(iobase));	/* clear detectCMM */
+	/* last check before exit */
+	if (!io_detect_cm4000(iobase, dev))
+		count = -ENODEV;
+
+	if (test_bit(IS_INVREV, &dev->flags) && count > 0)
+		str_invert_revert(dev->rbuf, count);
+
+	if (copy_to_user(buf, dev->rbuf, count))
+		return -EFAULT;
+
+release_io:
+	clear_bit(LOCK_IO, &dev->flags);
+	wake_up_interruptible(&dev->ioq);
+
+	DEBUGP(2, dev, "<- cmm_read returns: rc = %Zi\n",
+	       (rc < 0 ? rc : count));
+	return rc < 0 ? rc : count;
+}
+
+static ssize_t cmm_write(struct file *filp, const char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+	unsigned short s;
+	unsigned char tmp;
+	unsigned char infolen;
+	unsigned char sendT0;
+	unsigned short nsend;
+	unsigned short nr;
+	ssize_t rc;
+	int i;
+
+	DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid);
+
+	if (count == 0)		/* according to manpage */
+		return 0;
+
+	if (dev->proto == 0 && count < 4) {
+		/* T0 must have at least 4 bytes */
+		DEBUGP(4, dev, "T0 short write\n");
+		return -EIO;
+	}
+
+	nr = count & 0x1ff;	/* max bytes to write */
+
+	sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0;
+
+	if ((dev->link.state & DEV_PRESENT) == 0 ||	/* socket removed */
+	    test_bit(IS_CMM_ABSENT, &dev->flags))
+		return -ENODEV;
+
+	if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+		DEBUGP(4, dev, "bad csum\n");
+		return -EIO;
+	}
+
+	/*
+	 * wait for atr to become valid.
+	 * note: it is important to lock this code. if we dont, the monitor
+	 * could be run between test_bit and the the call the sleep on the
+	 * atr-queue.  if *then* the monitor detects atr valid, it will wake up
+	 * any process on the atr-queue, *but* since we have been interrupted,
+	 * we do not yet sleep on this queue. this would result in a missed
+	 * wake_up and the calling process would sleep forever (until
+	 * interrupted).  also, do *not* restore_flags before sleep_on, because
+	 * this could result in the same situation!
+	 */
+	if (wait_event_interruptible
+	    (dev->atrq,
+	     ((filp->f_flags & O_NONBLOCK)
+	      || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		return -ERESTARTSYS;
+	}
+
+	if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {	/* invalid atr */
+		DEBUGP(4, dev, "invalid ATR\n");
+		return -EIO;
+	}
+
+	/* lock io */
+	if (wait_event_interruptible
+	    (dev->ioq,
+	     ((filp->f_flags & O_NONBLOCK)
+	      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		return -ERESTARTSYS;
+	}
+
+	if (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count)))
+		return -EFAULT;
+
+	rc = 0;
+	dev->flags0 = inb(REG_FLAGS0(iobase));
+	if ((dev->flags0 & 1) == 0	/* no smartcard inserted */
+	    || dev->flags0 == 0xff) {	/* no cardman inserted */
+		clear_bit(IS_ATR_VALID, &dev->flags);
+		if (dev->flags0 & 1) {
+			set_bit(IS_CMM_ABSENT, &dev->flags);
+			rc = -ENODEV;
+		} else {
+			DEBUGP(4, dev, "IO error\n");
+			rc = -EIO;
+		}
+		goto release_io;
+	}
+
+	xoutb(0x80, REG_FLAGS0(iobase));	/* reset SM  */
+
+	if (!io_detect_cm4000(iobase, dev)) {
+		rc = -ENODEV;
+		goto release_io;
+	}
+
+	/* reflect T=0 send/read mode in flags1 */
+	dev->flags1 |= (sendT0);
+
+	set_cardparameter(dev);
+
+	/* dummy read, reset flag procedure received */
+	tmp = inb(REG_FLAGS1(iobase));
+
+	dev->flags1 = 0x20	/* T_Active */
+	    | (sendT0)
+	    | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity  */
+	    | (((dev->baudv - 1) & 0x0100) >> 8);	/* MSB-Baud */
+	DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1);
+	xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+	/* xmit data */
+	DEBUGP(4, dev, "Xmit data\n");
+	for (i = 0; i < nr; i++) {
+		if (i >= 256) {
+			dev->flags1 = 0x20	/* T_Active */
+			    | (sendT0)	/* SendT0 */
+				/* inverse parity: */
+			    | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)
+			    | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */
+			    | 0x10;	/* set address high */
+			DEBUGP(4, dev, "dev->flags = 0x%.2x - set address "
+			       "high\n", dev->flags1);
+			xoutb(dev->flags1, REG_FLAGS1(iobase));
+		}
+		if (test_bit(IS_INVREV, &dev->flags)) {
+			DEBUGP(4, dev, "Apply inverse convention for 0x%.2x "
+				"-> 0x%.2x\n", (unsigned char)dev->sbuf[i],
+			      invert_revert(dev->sbuf[i]));
+			xoutb(i, REG_BUF_ADDR(iobase));
+			xoutb(invert_revert(dev->sbuf[i]),
+			      REG_BUF_DATA(iobase));
+		} else {
+			xoutb(i, REG_BUF_ADDR(iobase));
+			xoutb(dev->sbuf[i], REG_BUF_DATA(iobase));
+		}
+	}
+	DEBUGP(4, dev, "Xmit done\n");
+
+	if (dev->proto == 0) {
+		/* T=0 proto: 0 byte reply  */
+		if (nr == 4) {
+			DEBUGP(4, dev, "T=0 assumes 0 byte reply\n");
+			xoutb(i, REG_BUF_ADDR(iobase));
+			if (test_bit(IS_INVREV, &dev->flags))
+				xoutb(0xff, REG_BUF_DATA(iobase));
+			else
+				xoutb(0x00, REG_BUF_DATA(iobase));
+		}
+
+		/* numSendBytes */
+		if (sendT0)
+			nsend = nr;
+		else {
+			if (nr == 4)
+				nsend = 5;
+			else {
+				nsend = 5 + (unsigned char)dev->sbuf[4];
+				if (dev->sbuf[4] == 0)
+					nsend += 0x100;
+			}
+		}
+	} else
+		nsend = nr;
+
+	/* T0: output procedure byte */
+	if (test_bit(IS_INVREV, &dev->flags)) {
+		DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) "
+		       "0x%.2x\n", invert_revert(dev->sbuf[1]));
+		xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase));
+	} else {
+		DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]);
+		xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase));
+	}
+
+	DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n",
+	       (unsigned char)(nsend & 0xff));
+	xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase));
+
+	DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n",
+	       0x40	/* SM_Active */
+	      | (dev->flags0 & 2 ? 0 : 4)	/* power on if needed */
+	      |(dev->proto ? 0x10 : 0x08)	/* T=1/T=0 */
+	      |(nsend & 0x100) >> 8 /* MSB numSendBytes */ );
+	xoutb(0x40		/* SM_Active */
+	      | (dev->flags0 & 2 ? 0 : 4)	/* power on if needed */
+	      |(dev->proto ? 0x10 : 0x08)	/* T=1/T=0 */
+	      |(nsend & 0x100) >> 8,	/* MSB numSendBytes */
+	      REG_FLAGS0(iobase));
+
+	/* wait for xmit done */
+	if (dev->proto == 1) {
+		DEBUGP(4, dev, "Wait for xmit done\n");
+		for (i = 0; i < 1000; i++) {
+			if (inb(REG_FLAGS0(iobase)) & 0x08)
+				break;
+			msleep_interruptible(10);
+		}
+		if (i == 1000) {
+			DEBUGP(4, dev, "timeout waiting for xmit done\n");
+			rc = -EIO;
+			goto release_io;
+		}
+	}
+
+	/* T=1: wait for infoLen */
+
+	infolen = 0;
+	if (dev->proto) {
+		/* wait until infoLen is valid */
+		for (i = 0; i < 6000; i++) {	/* max waiting time of 1 min */
+			io_read_num_rec_bytes(iobase, &s);
+			if (s >= 3) {
+				infolen = inb(REG_FLAGS1(iobase));
+				DEBUGP(4, dev, "infolen=%d\n", infolen);
+				break;
+			}
+			msleep_interruptible(10);
+		}
+		if (i == 6000) {
+			DEBUGP(4, dev, "timeout waiting for infoLen\n");
+			rc = -EIO;
+			goto release_io;
+		}
+	} else
+		clear_bit(IS_PROCBYTE_PRESENT, &dev->flags);
+
+	/* numRecBytes | bit9 of numRecytes */
+	io_read_num_rec_bytes(iobase, &dev->rlen);
+	for (i = 0; i < 600; i++) {	/* max waiting time of 2 sec */
+		if (dev->proto) {
+			if (dev->rlen >= infolen + 4)
+				break;
+		}
+		msleep_interruptible(10);
+		/* numRecBytes | bit9 of numRecytes */
+		io_read_num_rec_bytes(iobase, &s);
+		if (s > dev->rlen) {
+			DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n");
+			i = 0;	/* reset timeout */
+			dev->rlen = s;
+		}
+		/* T=0: we are done when numRecBytes doesn't
+		 *      increment any more and NoProcedureByte
+		 *      is set and numRecBytes == bytes sent + 6
+		 *      (header bytes + data + 1 for sw2)
+		 *      except when the card replies an error
+		 *      which means, no data will be sent back.
+		 */
+		else if (dev->proto == 0) {
+			if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) {
+				/* no procedure byte received since last read */
+				DEBUGP(1, dev, "NoProcedure byte set\n");
+				/* i=0; */
+			} else {
+				/* procedure byte received since last read */
+				DEBUGP(1, dev, "NoProcedure byte unset "
+					"(reset timeout)\n");
+				dev->procbyte = inb(REG_FLAGS1(iobase));
+				DEBUGP(1, dev, "Read procedure byte 0x%.2x\n",
+				      dev->procbyte);
+				i = 0;	/* resettimeout */
+			}
+			if (inb(REG_FLAGS0(iobase)) & 0x08) {
+				DEBUGP(1, dev, "T0Done flag (read reply)\n");
+				break;
+			}
+		}
+		if (dev->proto)
+			infolen = inb(REG_FLAGS1(iobase));
+	}
+	if (i == 600) {
+		DEBUGP(1, dev, "timeout waiting for numRecBytes\n");
+		rc = -EIO;
+		goto release_io;
+	} else {
+		if (dev->proto == 0) {
+			DEBUGP(1, dev, "Wait for T0Done bit to be  set\n");
+			for (i = 0; i < 1000; i++) {
+				if (inb(REG_FLAGS0(iobase)) & 0x08)
+					break;
+				msleep_interruptible(10);
+			}
+			if (i == 1000) {
+				DEBUGP(1, dev, "timeout waiting for T0Done\n");
+				rc = -EIO;
+				goto release_io;
+			}
+
+			dev->procbyte = inb(REG_FLAGS1(iobase));
+			DEBUGP(4, dev, "Read procedure byte 0x%.2x\n",
+			      dev->procbyte);
+
+			io_read_num_rec_bytes(iobase, &dev->rlen);
+			DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen);
+
+		}
+	}
+	/* T=1: read offset=zero, T=0: read offset=after challenge */
+	dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr;
+	DEBUGP(4, dev, "dev->rlen = %i,  dev->rpos = %i, nr = %i\n",
+	      dev->rlen, dev->rpos, nr);
+
+release_io:
+	DEBUGP(4, dev, "Reset SM\n");
+	xoutb(0x80, REG_FLAGS0(iobase));	/* reset SM */
+
+	if (rc < 0) {
+		DEBUGP(4, dev, "Write failed but clear T_Active\n");
+		dev->flags1 &= 0xdf;
+		xoutb(dev->flags1, REG_FLAGS1(iobase));
+	}
+
+	clear_bit(LOCK_IO, &dev->flags);
+	wake_up_interruptible(&dev->ioq);
+	wake_up_interruptible(&dev->readq);	/* tell read we have data */
+
+	/* ITSEC E2: clear write buffer */
+	memset((char *)dev->sbuf, 0, 512);
+
+	/* return error or actually written bytes */
+	DEBUGP(2, dev, "<- cmm_write\n");
+	return rc < 0 ? rc : nr;
+}
+
+static void start_monitor(struct cm4000_dev *dev)
+{
+	DEBUGP(3, dev, "-> start_monitor\n");
+	if (!dev->monitor_running) {
+		DEBUGP(5, dev, "create, init and add timer\n");
+		init_timer(&dev->timer);
+		dev->monitor_running = 1;
+		dev->timer.expires = jiffies;
+		dev->timer.data = (unsigned long) dev;
+		dev->timer.function = monitor_card;
+		add_timer(&dev->timer);
+	} else
+		DEBUGP(5, dev, "monitor already running\n");
+	DEBUGP(3, dev, "<- start_monitor\n");
+}
+
+static void stop_monitor(struct cm4000_dev *dev)
+{
+	DEBUGP(3, dev, "-> stop_monitor\n");
+	if (dev->monitor_running) {
+		DEBUGP(5, dev, "stopping monitor\n");
+		terminate_monitor(dev);
+		/* reset monitor SM */
+		clear_bit(IS_ATR_VALID, &dev->flags);
+		clear_bit(IS_ATR_PRESENT, &dev->flags);
+	} else
+		DEBUGP(5, dev, "monitor already stopped\n");
+	DEBUGP(3, dev, "<- stop_monitor\n");
+}
+
+static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		     unsigned long arg)
+{
+	struct cm4000_dev *dev = filp->private_data;
+	ioaddr_t iobase = dev->link.io.BasePort1;
+	dev_link_t *link;
+	int size;
+	int rc;
+#ifdef PCMCIA_DEBUG
+	char *ioctl_names[CM_IOC_MAXNR + 1] = {
+		[_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS",
+		[_IOC_NR(CM_IOCGATR)] "CM_IOCGATR",
+		[_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF",
+		[_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS",
+		[_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL",
+	};
+#endif
+	DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
+	       iminor(inode), ioctl_names[_IOC_NR(cmd)]);
+
+	link = dev_table[iminor(inode)];
+	if (!(DEV_OK(link))) {
+		DEBUGP(4, dev, "DEV_OK false\n");
+		return -ENODEV;
+	}
+
+	if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+		DEBUGP(4, dev, "CMM_ABSENT flag set\n");
+		return -ENODEV;
+	}
+
+	if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) {
+		DEBUGP(4, dev, "ioctype mismatch\n");
+		return -EINVAL;
+	}
+	if (_IOC_NR(cmd) > CM_IOC_MAXNR) {
+		DEBUGP(4, dev, "iocnr mismatch\n");
+		return -EINVAL;
+	}
+	size = _IOC_SIZE(cmd);
+	rc = 0;
+	DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n",
+	      _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd);
+
+	if (_IOC_DIR(cmd) & _IOC_READ) {
+		if (!access_ok(VERIFY_WRITE, (void *)arg, size))
+			return -EFAULT;
+	}
+	if (_IOC_DIR(cmd) & _IOC_WRITE) {
+		if (!access_ok(VERIFY_READ, (void *)arg, size))
+			return -EFAULT;
+	}
+
+	switch (cmd) {
+	case CM_IOCGSTATUS:
+		DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n");
+		{
+			int status;
+
+			/* clear other bits, but leave inserted & powered as
+			 * they are */
+			status = dev->flags0 & 3;
+			if (test_bit(IS_ATR_PRESENT, &dev->flags))
+				status |= CM_ATR_PRESENT;
+			if (test_bit(IS_ATR_VALID, &dev->flags))
+				status |= CM_ATR_VALID;
+			if (test_bit(IS_CMM_ABSENT, &dev->flags))
+				status |= CM_NO_READER;
+			if (test_bit(IS_BAD_CARD, &dev->flags))
+				status |= CM_BAD_CARD;
+			if (copy_to_user((int *)arg, &status, sizeof(int)))
+				return -EFAULT;
+		}
+		return 0;
+	case CM_IOCGATR:
+		DEBUGP(4, dev, "... in CM_IOCGATR\n");
+		{
+			struct atreq *atreq = (struct atreq *) arg;
+			int tmp;
+			/* allow nonblocking io and being interrupted */
+			if (wait_event_interruptible
+			    (dev->atrq,
+			     ((filp->f_flags & O_NONBLOCK)
+			      || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+				  != 0)))) {
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				return -ERESTARTSYS;
+			}
+
+			if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {
+				tmp = -1;
+				if (copy_to_user(&(atreq->atr_len), &tmp,
+						 sizeof(int)))
+					return -EFAULT;
+			} else {
+				if (copy_to_user(atreq->atr, dev->atr,
+						 dev->atr_len))
+					return -EFAULT;
+
+				tmp = dev->atr_len;
+				if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int)))
+					return -EFAULT;
+			}
+			return 0;
+		}
+	case CM_IOCARDOFF:
+
+#ifdef PCMCIA_DEBUG
+		DEBUGP(4, dev, "... in CM_IOCARDOFF\n");
+		if (dev->flags0 & 0x01) {
+			DEBUGP(4, dev, "    Card inserted\n");
+		} else {
+			DEBUGP(2, dev, "    No card inserted\n");
+		}
+		if (dev->flags0 & 0x02) {
+			DEBUGP(4, dev, "    Card powered\n");
+		} else {
+			DEBUGP(2, dev, "    Card not powered\n");
+		}
+#endif
+
+		/* is a card inserted and powered? */
+		if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) {
+
+			/* get IO lock */
+			if (wait_event_interruptible
+			    (dev->ioq,
+			     ((filp->f_flags & O_NONBLOCK)
+			      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+				  == 0)))) {
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				return -ERESTARTSYS;
+			}
+			/* Set Flags0 = 0x42 */
+			DEBUGP(4, dev, "Set Flags0=0x42 \n");
+			xoutb(0x42, REG_FLAGS0(iobase));
+			clear_bit(IS_ATR_PRESENT, &dev->flags);
+			clear_bit(IS_ATR_VALID, &dev->flags);
+			dev->mstate = M_CARDOFF;
+			clear_bit(LOCK_IO, &dev->flags);
+			if (wait_event_interruptible
+			    (dev->atrq,
+			     ((filp->f_flags & O_NONBLOCK)
+			      || (test_bit(IS_ATR_VALID, (void *)&dev->flags) !=
+				  0)))) {
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				return -ERESTARTSYS;
+			}
+		}
+		/* release lock */
+		clear_bit(LOCK_IO, &dev->flags);
+		wake_up_interruptible(&dev->ioq);
+
+		return 0;
+	case CM_IOCSPTS:
+		{
+			struct ptsreq krnptsreq;
+
+			if (copy_from_user(&krnptsreq, (struct ptsreq *) arg,
+					   sizeof(struct ptsreq)))
+				return -EFAULT;
+
+			rc = 0;
+			DEBUGP(4, dev, "... in CM_IOCSPTS\n");
+			/* wait for ATR to get valid */
+			if (wait_event_interruptible
+			    (dev->atrq,
+			     ((filp->f_flags & O_NONBLOCK)
+			      || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+				  != 0)))) {
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				return -ERESTARTSYS;
+			}
+			/* get IO lock */
+			if (wait_event_interruptible
+			    (dev->ioq,
+			     ((filp->f_flags & O_NONBLOCK)
+			      || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+				  == 0)))) {
+				if (filp->f_flags & O_NONBLOCK)
+					return -EAGAIN;
+				return -ERESTARTSYS;
+			}
+
+			if ((rc = set_protocol(dev, &krnptsreq)) != 0) {
+				/* auto power_on again */
+				dev->mstate = M_FETCH_ATR;
+				clear_bit(IS_ATR_VALID, &dev->flags);
+			}
+			/* release lock */
+			clear_bit(LOCK_IO, &dev->flags);
+			wake_up_interruptible(&dev->ioq);
+
+		}
+		return rc;
+#ifdef PCMCIA_DEBUG
+	case CM_IOSDBGLVL:	/* set debug log level */
+		{
+			int old_pc_debug = 0;
+
+			old_pc_debug = pc_debug;
+			if (copy_from_user(&pc_debug, (int *)arg, sizeof(int)))
+				return -EFAULT;
+
+			if (old_pc_debug != pc_debug)
+				DEBUGP(0, dev, "Changed debug log level "
+				       "to %i\n", pc_debug);
+		}
+		return rc;
+#endif
+	default:
+		DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");
+		return -EINVAL;
+	}
+}
+
+static int cmm_open(struct inode *inode, struct file *filp)
+{
+	struct cm4000_dev *dev;
+	dev_link_t *link;
+	int rc, minor = iminor(inode);
+
+	if (minor >= CM4000_MAX_DEV)
+		return -ENODEV;
+
+	link = dev_table[minor];
+	if (link == NULL || !(DEV_OK(link)))
+		return -ENODEV;
+
+	if (link->open)
+		return -EBUSY;
+
+	dev = link->priv;
+	filp->private_data = dev;
+
+	DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n",
+	      imajor(inode), minor, current->comm, current->pid);
+
+	/* init device variables, they may be "polluted" after close
+	 * or, the device may never have been closed (i.e. open failed)
+	 */
+
+	ZERO_DEV(dev);
+
+	/* opening will always block since the
+	 * monitor will be started by open, which
+	 * means we have to wait for ATR becoming
+	 * vaild = block until valid (or card
+	 * inserted)
+	 */
+	if (filp->f_flags & O_NONBLOCK)
+		return -EAGAIN;
+
+	dev->mdelay = T_50MSEC;
+
+	/* start monitoring the cardstatus */
+	start_monitor(dev);
+
+	link->open = 1;		/* only one open per device */
+	rc = 0;
+
+	DEBUGP(2, dev, "<- cmm_open\n");
+	return nonseekable_open(inode, filp);
+}
+
+static int cmm_close(struct inode *inode, struct file *filp)
+{
+	struct cm4000_dev *dev;
+	dev_link_t *link;
+	int minor = iminor(inode);
+
+	if (minor >= CM4000_MAX_DEV)
+		return -ENODEV;
+
+	link = dev_table[minor];
+	if (link == NULL)
+		return -ENODEV;
+
+	dev = link->priv;
+
+	DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n",
+	       imajor(inode), minor);
+
+	stop_monitor(dev);
+
+	ZERO_DEV(dev);
+
+	link->open = 0;		/* only one open per device */
+	wake_up(&dev->devq);	/* socket removed? */
+
+	DEBUGP(2, dev, "cmm_close\n");
+	return 0;
+}
+
+static void cmm_cm4000_release(dev_link_t * link)
+{
+	struct cm4000_dev *dev = link->priv;
+
+	/* dont terminate the monitor, rather rely on
+	 * close doing that for us.
+	 */
+	DEBUGP(3, dev, "-> cmm_cm4000_release\n");
+	while (link->open) {
+		printk(KERN_INFO MODULE_NAME ": delaying release until "
+		       "process has terminated\n");
+		/* note: don't interrupt us:
+		 * close the applications which own
+		 * the devices _first_ !
+		 */
+		wait_event(dev->devq, (link->open == 0));
+	}
+	/* dev->devq=NULL;	this cannot be zeroed earlier */
+	DEBUGP(3, dev, "<- cmm_cm4000_release\n");
+	return;
+}
+
+/*==== Interface to PCMCIA Layer =======================================*/
+
+static void cm4000_config(dev_link_t * link, int devno)
+{
+	client_handle_t handle = link->handle;
+	struct cm4000_dev *dev;
+	tuple_t tuple;
+	cisparse_t parse;
+	config_info_t conf;
+	u_char buf[64];
+	int fail_fn, fail_rc;
+	int rc;
+
+	/* read the config-tuples */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+
+	if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+		fail_fn = GetFirstTuple;
+		goto cs_failed;
+	}
+	if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+		fail_fn = GetTupleData;
+		goto cs_failed;
+	}
+	if ((fail_rc =
+	     pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) {
+		fail_fn = ParseTuple;
+		goto cs_failed;
+	}
+	if ((fail_rc =
+	     pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) {
+		fail_fn = GetConfigurationInfo;
+		goto cs_failed;
+	}
+
+	link->state |= DEV_CONFIG;
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+	link->conf.Vcc = conf.Vcc;
+
+	link->io.BasePort2 = 0;
+	link->io.NumPorts2 = 0;
+	link->io.Attributes2 = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	for (rc = pcmcia_get_first_tuple(handle, &tuple);
+	     rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) {
+
+		rc = pcmcia_get_tuple_data(handle, &tuple);
+		if (rc != CS_SUCCESS)
+			continue;
+		rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+		if (rc != CS_SUCCESS)
+			continue;
+
+		link->conf.ConfigIndex = parse.cftable_entry.index;
+
+		if (!parse.cftable_entry.io.nwin)
+			continue;
+
+		/* Get the IOaddr */
+		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		link->io.IOAddrLines = parse.cftable_entry.io.flags
+		    & CISTPL_IO_LINES_MASK;
+
+		rc = pcmcia_request_io(handle, &link->io);
+		if (rc == CS_SUCCESS)
+			break;	/* we are done */
+	}
+	if (rc != CS_SUCCESS)
+		goto cs_release;
+
+	link->conf.IntType = 00000002;
+
+	if ((fail_rc =
+	     pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) {
+		fail_fn = RequestConfiguration;
+		goto cs_release;
+	}
+
+	dev = link->priv;
+	sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+	dev->node.major = major;
+	dev->node.minor = devno;
+	dev->node.next = NULL;
+	link->dev = &dev->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(handle, fail_fn, fail_rc);
+cs_release:
+	cm4000_release(link);
+
+	link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int cm4000_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+	dev_link_t *link;
+	struct cm4000_dev *dev;
+	int devno;
+
+	link = args->client_data;
+	dev = link->priv;
+
+	DEBUGP(3, dev, "-> cm4000_event\n");
+	for (devno = 0; devno < CM4000_MAX_DEV; devno++)
+		if (dev_table[devno] == link)
+			break;
+
+	if (devno == CM4000_MAX_DEV)
+		return CS_BAD_ADAPTER;
+
+	switch (event) {
+	case CS_EVENT_CARD_INSERTION:
+		DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		cm4000_config(link, devno);
+		break;
+	case CS_EVENT_CARD_REMOVAL:
+		DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+		link->state &= ~DEV_PRESENT;
+		stop_monitor(dev);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+		      "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+		link->state |= DEV_SUSPEND;
+		/* fall-through */
+	case CS_EVENT_RESET_PHYSICAL:
+		DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+		if (link->state & DEV_CONFIG) {
+			DEBUGP(5, dev, "ReleaseConfiguration\n");
+			pcmcia_release_configuration(link->handle);
+		}
+		stop_monitor(dev);
+		break;
+	case CS_EVENT_PM_RESUME:
+		DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+		      "(fall-through to CS_EVENT_CARD_RESET)\n");
+		link->state &= ~DEV_SUSPEND;
+		/* fall-through */
+	case CS_EVENT_CARD_RESET:
+		DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+		if ((link->state & DEV_CONFIG)) {
+			DEBUGP(5, dev, "RequestConfiguration\n");
+			pcmcia_request_configuration(link->handle, &link->conf);
+		}
+		if (link->open)
+			start_monitor(dev);
+		break;
+	default:
+		DEBUGP(5, dev, "unknown event %.2x\n", event);
+		break;
+	}
+	DEBUGP(3, dev, "<- cm4000_event\n");
+	return CS_SUCCESS;
+}
+
+static void cm4000_release(dev_link_t *link)
+{
+	cmm_cm4000_release(link->priv);	/* delay release until device closed */
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *cm4000_attach(void)
+{
+	struct cm4000_dev *dev;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int i;
+
+	for (i = 0; i < CM4000_MAX_DEV; i++)
+		if (dev_table[i] == NULL)
+			break;
+
+	if (i == CM4000_MAX_DEV) {
+		printk(KERN_NOTICE MODULE_NAME ": all devices in use\n");
+		return NULL;
+	}
+
+	/* create a new cm4000_cs device */
+	dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL);
+	if (dev == NULL)
+		return NULL;
+
+	link = &dev->link;
+	link->priv = dev;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	dev_table[i] = link;
+
+	/* register with card services */
+	client_reg.dev_info = &dev_info;
+	client_reg.EventMask =
+	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	i = pcmcia_register_client(&link->handle, &client_reg);
+	if (i) {
+		cs_error(link->handle, RegisterClient, i);
+		cm4000_detach(link);
+		return NULL;
+	}
+
+	init_waitqueue_head(&dev->devq);
+	init_waitqueue_head(&dev->ioq);
+	init_waitqueue_head(&dev->atrq);
+	init_waitqueue_head(&dev->readq);
+
+	return link;
+}
+
+static void cm4000_detach_by_devno(int devno, dev_link_t * link)
+{
+	struct cm4000_dev *dev = link->priv;
+
+	DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno);
+
+	if (link->state & DEV_CONFIG) {
+		DEBUGP(5, dev, "device still configured (try to release it)\n");
+		cm4000_release(link);
+	}
+
+	if (link->handle) {
+		pcmcia_deregister_client(link->handle);
+	}
+
+	dev_table[devno] = NULL;
+	kfree(dev);
+	return;
+}
+
+static void cm4000_detach(dev_link_t * link)
+{
+	int i;
+
+	/* find device */
+	for (i = 0; i < CM4000_MAX_DEV; i++)
+		if (dev_table[i] == link)
+			break;
+
+	if (i == CM4000_MAX_DEV)
+		return;
+
+	cm4000_detach_by_devno(i, link);
+	return;
+}
+
+static struct file_operations cm4000_fops = {
+	.owner	= THIS_MODULE,
+	.read	= cmm_read,
+	.write	= cmm_write,
+	.ioctl	= cmm_ioctl,
+	.open	= cmm_open,
+	.release= cmm_close,
+};
+
+static struct pcmcia_device_id cm4000_ids[] = {
+	PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
+	PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
+	PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);
+
+static struct pcmcia_driver cm4000_driver = {
+	.owner	  = THIS_MODULE,
+	.drv	  = {
+		.name = "cm4000_cs",
+		},
+	.attach   = cm4000_attach,
+	.detach   = cm4000_detach,
+	.event	  = cm4000_event,
+	.id_table = cm4000_ids,
+};
+
+static int __init cmm_init(void)
+{
+	printk(KERN_INFO "%s\n", version);
+	pcmcia_register_driver(&cm4000_driver);
+	major = register_chrdev(0, DEVICE_NAME, &cm4000_fops);
+	if (major < 0) {
+		printk(KERN_WARNING MODULE_NAME
+			": could not get major number\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void __exit cmm_exit(void)
+{
+	int i;
+
+	printk(KERN_INFO MODULE_NAME ": unloading\n");
+	pcmcia_unregister_driver(&cm4000_driver);
+	for (i = 0; i < CM4000_MAX_DEV; i++)
+		if (dev_table[i])
+			cm4000_detach_by_devno(i, dev_table[i]);
+	unregister_chrdev(major, DEVICE_NAME);
+};
+
+module_init(cmm_init);
+module_exit(cmm_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
new file mode 100644
index 0000000..4c698d9
--- /dev/null
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -0,0 +1,841 @@
+/*
+ * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040
+ *
+ * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/)
+ *
+ * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ * 	- add support for poll()
+ * 	- driver cleanup
+ * 	- add waitqueues
+ * 	- adhere to linux kernel coding style and policies
+ * 	- support 2.6.13 "new style" pcmcia interface
+ *
+ * The device basically is a USB CCID compliant device that has been
+ * attached to an I/O-Mapped FIFO.
+ *
+ * All rights reserved, Dual BSD/GPL Licensed.
+ */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+#include "cm4040_cs.h"
+
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x)	(&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { 				\
+	if (pc_debug >= (n)) 						\
+		dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, 	\
+			   __FUNCTION__ , ##args); 			\
+	} while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+
+static char *version =
+"OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte";
+
+#define	CCID_DRIVER_BULK_DEFAULT_TIMEOUT  	(150*HZ)
+#define	CCID_DRIVER_ASYNC_POWERUP_TIMEOUT 	(35*HZ)
+#define	CCID_DRIVER_MINIMUM_TIMEOUT 		(3*HZ)
+#define READ_WRITE_BUFFER_SIZE 512
+#define POLL_LOOP_COUNT				1000
+
+/* how often to poll for fifo status change */
+#define POLL_PERIOD 				msecs_to_jiffies(10)
+
+static void reader_release(dev_link_t *link);
+static void reader_detach(dev_link_t *link);
+
+static int major;
+
+#define		BS_READABLE	0x01
+#define		BS_WRITABLE	0x02
+
+struct reader_dev {
+	dev_link_t		link;
+	dev_node_t		node;
+	wait_queue_head_t	devq;
+	wait_queue_head_t	poll_wait;
+	wait_queue_head_t	read_wait;
+	wait_queue_head_t	write_wait;
+	unsigned long 	  	buffer_status;
+	unsigned long     	timeout;
+	unsigned char     	s_buf[READ_WRITE_BUFFER_SIZE];
+	unsigned char     	r_buf[READ_WRITE_BUFFER_SIZE];
+	struct timer_list 	poll_timer;
+};
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM_MAX_DEV];
+
+#ifndef PCMCIA_DEBUG
+#define	xoutb	outb
+#define	xinb	inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+	if (pc_debug >= 7)
+		printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+	outb(val, port);
+}
+
+static inline unsigned char xinb(unsigned short port)
+{
+	unsigned char val;
+
+	val = inb(port);
+	if (pc_debug >= 7)
+		printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+	return val;
+}
+#endif
+
+/* poll the device fifo status register.  not to be confused with
+ * the poll syscall. */
+static void cm4040_do_poll(unsigned long dummy)
+{
+	struct reader_dev *dev = (struct reader_dev *) dummy;
+	unsigned int obs = xinb(dev->link.io.BasePort1
+				+ REG_OFFSET_BUFFER_STATUS);
+
+	if ((obs & BSR_BULK_IN_FULL)) {
+		set_bit(BS_READABLE, &dev->buffer_status);
+		DEBUGP(4, dev, "waking up read_wait\n");
+		wake_up_interruptible(&dev->read_wait);
+	} else
+		clear_bit(BS_READABLE, &dev->buffer_status);
+
+	if (!(obs & BSR_BULK_OUT_FULL)) {
+		set_bit(BS_WRITABLE, &dev->buffer_status);
+		DEBUGP(4, dev, "waking up write_wait\n");
+		wake_up_interruptible(&dev->write_wait);
+	} else
+		clear_bit(BS_WRITABLE, &dev->buffer_status);
+
+	if (dev->buffer_status)
+		wake_up_interruptible(&dev->poll_wait);
+
+	mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+}
+
+static void cm4040_stop_poll(struct reader_dev *dev)
+{
+	del_timer_sync(&dev->poll_timer);
+}
+
+static int wait_for_bulk_out_ready(struct reader_dev *dev)
+{
+	int i, rc;
+	int iobase = dev->link.io.BasePort1;
+
+	for (i = 0; i < POLL_LOOP_COUNT; i++) {
+		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+		    & BSR_BULK_OUT_FULL) == 0) {
+			DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i);
+			return 1;
+		}
+	}
+
+	DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+		dev->timeout);
+	rc = wait_event_interruptible_timeout(dev->write_wait,
+					      test_and_clear_bit(BS_WRITABLE,
+						       &dev->buffer_status),
+					      dev->timeout);
+
+	if (rc > 0)
+		DEBUGP(4, dev, "woke up: BulkOut empty\n");
+	else if (rc == 0)
+		DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n");
+	else if (rc < 0)
+		DEBUGP(4, dev, "woke up: signal arrived\n");
+
+	return rc;
+}
+
+/* Write to Sync Control Register */
+static int write_sync_reg(unsigned char val, struct reader_dev *dev)
+{
+	int iobase = dev->link.io.BasePort1;
+	int rc;
+
+	rc = wait_for_bulk_out_ready(dev);
+	if (rc <= 0)
+		return rc;
+
+	xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL);
+	rc = wait_for_bulk_out_ready(dev);
+	if (rc <= 0)
+		return rc;
+
+	return 1;
+}
+
+static int wait_for_bulk_in_ready(struct reader_dev *dev)
+{
+	int i, rc;
+	int iobase = dev->link.io.BasePort1;
+
+	for (i = 0; i < POLL_LOOP_COUNT; i++) {
+		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+		    & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) {
+			DEBUGP(3, dev, "BulkIn full (i=%d)\n", i);
+			return 1;
+		}
+	}
+
+	DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+		dev->timeout);
+	rc = wait_event_interruptible_timeout(dev->read_wait,
+					      test_and_clear_bit(BS_READABLE,
+						 	&dev->buffer_status),
+					      dev->timeout);
+	if (rc > 0)
+		DEBUGP(4, dev, "woke up: BulkIn full\n");
+	else if (rc == 0)
+		DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n");
+	else if (rc < 0)
+		DEBUGP(4, dev, "woke up: signal arrived\n");
+
+	return rc;
+}
+
+static ssize_t cm4040_read(struct file *filp, char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	struct reader_dev *dev = filp->private_data;
+	int iobase = dev->link.io.BasePort1;
+	size_t bytes_to_read;
+	unsigned long i;
+	size_t min_bytes_to_read;
+	int rc;
+	unsigned char uc;
+
+	DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);
+
+	if (count == 0)
+		return 0;
+
+	if (count < 10)
+		return -EFAULT;
+
+	if (filp->f_flags & O_NONBLOCK) {
+		DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+		DEBUGP(2, dev, "<- cm4040_read (failure)\n");
+		return -EAGAIN;
+	}
+
+	if ((dev->link.state & DEV_PRESENT)==0)
+		return -ENODEV;
+
+	for (i = 0; i < 5; i++) {
+		rc = wait_for_bulk_in_ready(dev);
+		if (rc <= 0) {
+			DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+			DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+			if (rc == -ERESTARTSYS)
+				return rc;
+			return -EIO;
+		}
+	  	dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+		if (pc_debug >= 6)
+			printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+	}
+	printk("\n");
+#else
+	}
+#endif
+
+	bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);
+
+	DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);
+
+	min_bytes_to_read = min(count, bytes_to_read + 5);
+
+	DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);
+
+	for (i = 0; i < (min_bytes_to_read-5); i++) {
+		rc = wait_for_bulk_in_ready(dev);
+		if (rc <= 0) {
+			DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+			DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+			if (rc == -ERESTARTSYS)
+				return rc;
+			return -EIO;
+		}
+		dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+		if (pc_debug >= 6)
+			printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+	}
+	printk("\n");
+#else
+	}
+#endif
+
+	*ppos = min_bytes_to_read;
+	if (copy_to_user(buf, dev->r_buf, min_bytes_to_read))
+		return -EFAULT;
+
+	rc = wait_for_bulk_in_ready(dev);
+	if (rc <= 0) {
+		DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+		DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+		if (rc == -ERESTARTSYS)
+			return rc;
+		return -EIO;
+	}
+
+	rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev);
+	if (rc <= 0) {
+		DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc);
+		DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+		if (rc == -ERESTARTSYS)
+			return rc;
+		else
+			return -EIO;
+	}
+
+	uc = xinb(iobase + REG_OFFSET_BULK_IN);
+
+	DEBUGP(2, dev, "<- cm4040_read (successfully)\n");
+	return min_bytes_to_read;
+}
+
+static ssize_t cm4040_write(struct file *filp, const char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct reader_dev *dev = filp->private_data;
+	int iobase = dev->link.io.BasePort1;
+	ssize_t rc;
+	int i;
+	unsigned int bytes_to_write;
+
+	DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid);
+
+	if (count == 0) {
+		DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n");
+		return 0;
+	}
+
+	if (count < 5) {
+		DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count);
+		return -EIO;
+	}
+
+	if (filp->f_flags & O_NONBLOCK) {
+		DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+		DEBUGP(4, dev, "<- cm4040_write (failure)\n");
+		return -EAGAIN;
+	}
+
+	if ((dev->link.state & DEV_PRESENT) == 0)
+		return -ENODEV;
+
+	bytes_to_write = count;
+	if (copy_from_user(dev->s_buf, buf, bytes_to_write))
+		return -EFAULT;
+
+	switch (dev->s_buf[0]) {
+		case CMD_PC_TO_RDR_XFRBLOCK:
+		case CMD_PC_TO_RDR_SECURE:
+		case CMD_PC_TO_RDR_TEST_SECURE:
+		case CMD_PC_TO_RDR_OK_SECURE:
+			dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
+			break;
+
+		case CMD_PC_TO_RDR_ICCPOWERON:
+			dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
+			break;
+
+		case CMD_PC_TO_RDR_GETSLOTSTATUS:
+		case CMD_PC_TO_RDR_ICCPOWEROFF:
+		case CMD_PC_TO_RDR_GETPARAMETERS:
+		case CMD_PC_TO_RDR_RESETPARAMETERS:
+		case CMD_PC_TO_RDR_SETPARAMETERS:
+		case CMD_PC_TO_RDR_ESCAPE:
+		case CMD_PC_TO_RDR_ICCCLOCK:
+		default:
+			dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+			break;
+	}
+
+	rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
+	if (rc <= 0) {
+		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+		DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+		if (rc == -ERESTARTSYS)
+			return rc;
+		else
+			return -EIO;
+	}
+
+	DEBUGP(4, dev, "start \n");
+
+	for (i = 0; i < bytes_to_write; i++) {
+		rc = wait_for_bulk_out_ready(dev);
+		if (rc <= 0) {
+			DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
+			       rc);
+			DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+			if (rc == -ERESTARTSYS)
+				return rc;
+			else
+				return -EIO;
+		}
+
+		xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT);
+	}
+	DEBUGP(4, dev, "end\n");
+
+	rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
+
+	if (rc <= 0) {
+		DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+		DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+		if (rc == -ERESTARTSYS)
+			return rc;
+		else
+			return -EIO;
+	}
+
+	DEBUGP(2, dev, "<- cm4040_write (successfully)\n");
+	return count;
+}
+
+static unsigned int cm4040_poll(struct file *filp, poll_table *wait)
+{
+	struct reader_dev *dev = filp->private_data;
+	unsigned int mask = 0;
+
+	poll_wait(filp, &dev->poll_wait, wait);
+
+	if (test_and_clear_bit(BS_READABLE, &dev->buffer_status))
+		mask |= POLLIN | POLLRDNORM;
+	if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status))
+		mask |= POLLOUT | POLLWRNORM;
+
+	DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask);
+
+	return mask;
+}
+
+static int cm4040_open(struct inode *inode, struct file *filp)
+{
+	struct reader_dev *dev;
+	dev_link_t *link;
+	int minor = iminor(inode);
+
+	if (minor >= CM_MAX_DEV)
+		return -ENODEV;
+
+	link = dev_table[minor];
+	if (link == NULL || !(DEV_OK(link)))
+		return -ENODEV;
+
+	if (link->open)
+		return -EBUSY;
+
+	dev = link->priv;
+	filp->private_data = dev;
+
+	if (filp->f_flags & O_NONBLOCK) {
+		DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+		return -EAGAIN;
+	}
+
+	link->open = 1;
+
+	dev->poll_timer.data = (unsigned long) dev;
+	mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+
+	DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
+	return nonseekable_open(inode, filp);
+}
+
+static int cm4040_close(struct inode *inode, struct file *filp)
+{
+	struct reader_dev *dev = filp->private_data;
+	dev_link_t *link;
+	int minor = iminor(inode);
+
+	DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode),
+	      iminor(inode));
+
+	if (minor >= CM_MAX_DEV)
+		return -ENODEV;
+
+	link = dev_table[minor];
+	if (link == NULL)
+		return -ENODEV;
+
+	cm4040_stop_poll(dev);
+
+	link->open = 0;
+	wake_up(&dev->devq);
+
+	DEBUGP(2, dev, "<- cm4040_close\n");
+	return 0;
+}
+
+static void cm4040_reader_release(dev_link_t *link)
+{
+	struct reader_dev *dev = link->priv;
+
+	DEBUGP(3, dev, "-> cm4040_reader_release\n");
+	while (link->open) {
+		DEBUGP(3, dev, KERN_INFO MODULE_NAME ": delaying release "
+		       "until process has terminated\n");
+ 		wait_event(dev->devq, (link->open == 0));
+	}
+	DEBUGP(3, dev, "<- cm4040_reader_release\n");
+	return;
+}
+
+static void reader_config(dev_link_t *link, int devno)
+{
+	client_handle_t handle;
+	struct reader_dev *dev;
+	tuple_t tuple;
+	cisparse_t parse;
+	config_info_t conf;
+	u_char buf[64];
+	int fail_fn, fail_rc;
+	int rc;
+
+	handle = link->handle;
+
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+ 	tuple.TupleOffset = 0;
+
+	if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+		fail_fn = GetFirstTuple;
+		goto cs_failed;
+	}
+	if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+		fail_fn = GetTupleData;
+		goto cs_failed;
+	}
+	if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse))
+							!= CS_SUCCESS) {
+		fail_fn = ParseTuple;
+		goto cs_failed;
+	}
+	if ((fail_rc = pcmcia_get_configuration_info(handle, &conf))
+							!= CS_SUCCESS) {
+		fail_fn = GetConfigurationInfo;
+		goto cs_failed;
+	}
+
+	link->state |= DEV_CONFIG;
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+	link->conf.Vcc = conf.Vcc;
+
+	link->io.BasePort2 = 0;
+	link->io.NumPorts2 = 0;
+	link->io.Attributes2 = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	for (rc = pcmcia_get_first_tuple(handle, &tuple);
+	     rc == CS_SUCCESS;
+	     rc = pcmcia_get_next_tuple(handle, &tuple)) {
+		rc = pcmcia_get_tuple_data(handle, &tuple);
+		if (rc != CS_SUCCESS)
+			continue;
+		rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+		if (rc != CS_SUCCESS)
+			continue;
+
+		link->conf.ConfigIndex = parse.cftable_entry.index;
+
+		if (!parse.cftable_entry.io.nwin)
+			continue;
+
+		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+		if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+		if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+		link->io.IOAddrLines = parse.cftable_entry.io.flags
+						& CISTPL_IO_LINES_MASK;
+		rc = pcmcia_request_io(handle, &link->io);
+
+		dev_printk(KERN_INFO, &handle_to_dev(handle), "foo");
+		if (rc == CS_SUCCESS)
+			break;
+		else
+			dev_printk(KERN_INFO, &handle_to_dev(handle),
+				   "pcmcia_request_io failed 0x%x\n", rc);
+	}
+	if (rc != CS_SUCCESS)
+		goto cs_release;
+
+	link->conf.IntType = 00000002;
+
+	if ((fail_rc = pcmcia_request_configuration(handle,&link->conf))
+								!=CS_SUCCESS) {
+		fail_fn = RequestConfiguration;
+		dev_printk(KERN_INFO, &handle_to_dev(handle),
+			   "pcmcia_request_configuration failed 0x%x\n",
+			   fail_rc);
+		goto cs_release;
+	}
+
+	dev = link->priv;
+	sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+	dev->node.major = major;
+	dev->node.minor = devno;
+	dev->node.next = NULL;
+	link->dev = &dev->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
+	      link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
+	DEBUGP(2, dev, "<- reader_config (succ)\n");
+
+	return;
+
+cs_failed:
+	cs_error(handle, fail_fn, fail_rc);
+cs_release:
+	reader_release(link);
+	link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int reader_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+	dev_link_t *link;
+	struct reader_dev *dev;
+	int devno;
+
+	link = args->client_data;
+	dev = link->priv;
+	DEBUGP(3, dev, "-> reader_event\n");
+	for (devno = 0; devno < CM_MAX_DEV; devno++) {
+		if (dev_table[devno] == link)
+			break;
+	}
+	if (devno == CM_MAX_DEV)
+		return CS_BAD_ADAPTER;
+
+	switch (event) {
+		case CS_EVENT_CARD_INSERTION:
+			DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+			link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+			reader_config(link, devno);
+			break;
+		case CS_EVENT_CARD_REMOVAL:
+			DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+			link->state &= ~DEV_PRESENT;
+			break;
+		case CS_EVENT_PM_SUSPEND:
+			DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+			      "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+			link->state |= DEV_SUSPEND;
+
+		case CS_EVENT_RESET_PHYSICAL:
+			DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+			if (link->state & DEV_CONFIG) {
+		  		DEBUGP(5, dev, "ReleaseConfiguration\n");
+		  		pcmcia_release_configuration(link->handle);
+			}
+			break;
+		case CS_EVENT_PM_RESUME:
+			DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+			      "(fall-through to CS_EVENT_CARD_RESET)\n");
+			link->state &= ~DEV_SUSPEND;
+
+		case CS_EVENT_CARD_RESET:
+			DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+			if ((link->state & DEV_CONFIG)) {
+				DEBUGP(5, dev, "RequestConfiguration\n");
+		  		pcmcia_request_configuration(link->handle,
+							     &link->conf);
+			}
+			break;
+		default:
+			DEBUGP(5, dev, "reader_event: unknown event %.2x\n",
+			       event);
+			break;
+	}
+	DEBUGP(3, dev, "<- reader_event\n");
+	return CS_SUCCESS;
+}
+
+static void reader_release(dev_link_t *link)
+{
+	cm4040_reader_release(link->priv);
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *reader_attach(void)
+{
+	struct reader_dev *dev;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int i;
+
+	for (i = 0; i < CM_MAX_DEV; i++) {
+		if (dev_table[i] == NULL)
+			break;
+	}
+
+	if (i == CM_MAX_DEV)
+		return NULL;
+
+	dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL);
+	if (dev == NULL)
+		return NULL;
+
+	dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+	dev->buffer_status = 0;
+
+	link = &dev->link;
+	link->priv = dev;
+
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	dev_table[i] = link;
+
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask=
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	i = pcmcia_register_client(&link->handle, &client_reg);
+	if (i) {
+		cs_error(link->handle, RegisterClient, i);
+		reader_detach(link);
+		return NULL;
+	}
+	init_waitqueue_head(&dev->devq);
+	init_waitqueue_head(&dev->poll_wait);
+	init_waitqueue_head(&dev->read_wait);
+	init_waitqueue_head(&dev->write_wait);
+	init_timer(&dev->poll_timer);
+	dev->poll_timer.function = &cm4040_do_poll;
+
+	return link;
+}
+
+static void reader_detach_by_devno(int devno, dev_link_t *link)
+{
+	struct reader_dev *dev = link->priv;
+
+	if (link->state & DEV_CONFIG) {
+		DEBUGP(5, dev, "device still configured (try to release it)\n");
+		reader_release(link);
+	}
+
+	pcmcia_deregister_client(link->handle);
+	dev_table[devno] = NULL;
+	DEBUGP(5, dev, "freeing dev=%p\n", dev);
+	cm4040_stop_poll(dev);
+	kfree(dev);
+	return;
+}
+
+static void reader_detach(dev_link_t *link)
+{
+	int i;
+
+	/* find device */
+	for (i = 0; i < CM_MAX_DEV; i++) {
+		if (dev_table[i] == link)
+			break;
+	}
+	if (i == CM_MAX_DEV)
+		return;
+
+	reader_detach_by_devno(i, link);
+	return;
+}
+
+static struct file_operations reader_fops = {
+	.owner		= THIS_MODULE,
+	.read		= cm4040_read,
+	.write		= cm4040_write,
+	.open		= cm4040_open,
+	.release	= cm4040_close,
+	.poll		= cm4040_poll,
+};
+
+static struct pcmcia_device_id cm4040_ids[] = {
+	PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
+	PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
+				0xE32CDD8C, 0x8F23318B),
+	PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4040_ids);
+
+static struct pcmcia_driver reader_driver = {
+  	.owner		= THIS_MODULE,
+  	.drv		= {
+		.name	= "cm4040_cs",
+	},
+	.attach		= reader_attach,
+	.detach		= reader_detach,
+	.event		= reader_event,
+	.id_table	= cm4040_ids,
+};
+
+static int __init cm4040_init(void)
+{
+	printk(KERN_INFO "%s\n", version);
+	pcmcia_register_driver(&reader_driver);
+	major = register_chrdev(0, DEVICE_NAME, &reader_fops);
+	if (major < 0) {
+		printk(KERN_WARNING MODULE_NAME
+			": could not get major number\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void __exit cm4040_exit(void)
+{
+	int i;
+
+	printk(KERN_INFO MODULE_NAME ": unloading\n");
+	pcmcia_unregister_driver(&reader_driver);
+	for (i = 0; i < CM_MAX_DEV; i++) {
+		if (dev_table[i])
+			reader_detach_by_devno(i, dev_table[i]);
+	}
+	unregister_chrdev(major, DEVICE_NAME);
+}
+
+module_init(cm4040_init);
+module_exit(cm4040_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/char/pcmcia/cm4040_cs.h b/drivers/char/pcmcia/cm4040_cs.h
new file mode 100644
index 0000000..9a8b805
--- /dev/null
+++ b/drivers/char/pcmcia/cm4040_cs.h
@@ -0,0 +1,47 @@
+#ifndef	_CM4040_H_
+#define	_CM4040_H_
+
+#define	CM_MAX_DEV		4
+
+#define	DEVICE_NAME		"cmx"
+#define	MODULE_NAME		"cm4040_cs"
+
+#define REG_OFFSET_BULK_OUT      0
+#define REG_OFFSET_BULK_IN       0
+#define REG_OFFSET_BUFFER_STATUS 1
+#define REG_OFFSET_SYNC_CONTROL  2
+
+#define BSR_BULK_IN_FULL  0x02
+#define BSR_BULK_OUT_FULL 0x01
+
+#define SCR_HOST_TO_READER_START 0x80
+#define SCR_ABORT                0x40
+#define SCR_EN_NOTIFY            0x20
+#define SCR_ACK_NOTIFY           0x10
+#define SCR_READER_TO_HOST_DONE  0x08
+#define SCR_HOST_TO_READER_DONE  0x04
+#define SCR_PULSE_INTERRUPT      0x02
+#define SCR_POWER_DOWN           0x01
+
+
+#define  CMD_PC_TO_RDR_ICCPOWERON       0x62
+#define  CMD_PC_TO_RDR_GETSLOTSTATUS    0x65
+#define  CMD_PC_TO_RDR_ICCPOWEROFF      0x63
+#define  CMD_PC_TO_RDR_SECURE           0x69
+#define  CMD_PC_TO_RDR_GETPARAMETERS    0x6C
+#define  CMD_PC_TO_RDR_RESETPARAMETERS  0x6D
+#define  CMD_PC_TO_RDR_SETPARAMETERS    0x61
+#define  CMD_PC_TO_RDR_XFRBLOCK         0x6F
+#define  CMD_PC_TO_RDR_ESCAPE           0x6B
+#define  CMD_PC_TO_RDR_ICCCLOCK         0x6E
+#define  CMD_PC_TO_RDR_TEST_SECURE      0x74
+#define  CMD_PC_TO_RDR_OK_SECURE        0x89
+
+
+#define  CMD_RDR_TO_PC_SLOTSTATUS         0x81
+#define  CMD_RDR_TO_PC_DATABLOCK          0x80
+#define  CMD_RDR_TO_PC_PARAMETERS         0x82
+#define  CMD_RDR_TO_PC_ESCAPE             0x83
+#define  CMD_RDR_TO_PC_OK_SECURE          0x89
+
+#endif	/* _CM4040_H_ */
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 82c6abd..62aa0e5 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $
+ * $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -101,6 +101,7 @@
 #include <linux/termios.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/dma-mapping.h>
 
 #ifdef CONFIG_HDLC_MODULE
 #define CONFIG_HDLC 1
@@ -148,6 +149,7 @@
 	u32 link;	/* 32-bit flat link to next buffer entry */
 	char *virt_addr;	/* virtual address of data buffer */
 	u32 phys_entry;	/* physical address of this buffer entry */
+	dma_addr_t dma_addr;
 } DMABUFFERENTRY, *DMAPBUFFERENTRY;
 
 /* The queue of BH actions to be performed */
@@ -233,7 +235,8 @@
 	int ri_chkcount;
 
 	char *buffer_list;		/* virtual address of Rx & Tx buffer lists */
-	unsigned long buffer_list_phys;
+	u32 buffer_list_phys;
+	dma_addr_t buffer_list_dma_addr;
 
 	unsigned int rx_buffer_count;	/* count of total allocated Rx buffers */
 	DMABUFFERENTRY *rx_buffer_list;	/* list of receive buffer entries */
@@ -896,7 +899,7 @@
 module_param_array(txholdbufs, int, NULL, 0);
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.37 $";
+static char *driver_version = "$Revision: 4.38 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -3811,11 +3814,10 @@
 		/* inspect portions of the buffer while other portions are being */
 		/* updated by the adapter using Bus Master DMA. */
 
-		info->buffer_list = kmalloc(BUFFERLISTSIZE, GFP_KERNEL | GFP_DMA);
-		if ( info->buffer_list == NULL )
+		info->buffer_list = dma_alloc_coherent(NULL, BUFFERLISTSIZE, &info->buffer_list_dma_addr, GFP_KERNEL);
+		if (info->buffer_list == NULL)
 			return -ENOMEM;
-			
-		info->buffer_list_phys = isa_virt_to_bus(info->buffer_list);
+		info->buffer_list_phys = (u32)(info->buffer_list_dma_addr);
 	}
 
 	/* We got the memory for the buffer entry lists. */
@@ -3882,8 +3884,8 @@
  */
 static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
 {
-	if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
-		kfree(info->buffer_list);
+	if (info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI)
+		dma_free_coherent(NULL, BUFFERLISTSIZE, info->buffer_list, info->buffer_list_dma_addr);
 		
 	info->buffer_list = NULL;
 	info->rx_buffer_list = NULL;
@@ -3910,7 +3912,7 @@
 static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount)
 {
 	int i;
-	unsigned long phys_addr;
+	u32 phys_addr;
 
 	/* Allocate page sized buffers for the receive buffer list */
 
@@ -3922,11 +3924,10 @@
 			info->last_mem_alloc += DMABUFFERSIZE;
 		} else {
 			/* ISA adapter uses system memory. */
-			BufferList[i].virt_addr = 
-				kmalloc(DMABUFFERSIZE, GFP_KERNEL | GFP_DMA);
-			if ( BufferList[i].virt_addr == NULL )
+			BufferList[i].virt_addr = dma_alloc_coherent(NULL, DMABUFFERSIZE, &BufferList[i].dma_addr, GFP_KERNEL);
+			if (BufferList[i].virt_addr == NULL)
 				return -ENOMEM;
-			phys_addr = isa_virt_to_bus(BufferList[i].virt_addr);
+			phys_addr = (u32)(BufferList[i].dma_addr);
 		}
 		BufferList[i].phys_addr = phys_addr;
 	}
@@ -3957,7 +3958,7 @@
 		for ( i = 0 ; i < Buffercount ; i++ ) {
 			if ( BufferList[i].virt_addr ) {
 				if ( info->bus_type != MGSL_BUS_TYPE_PCI )
-					kfree(BufferList[i].virt_addr);
+					dma_free_coherent(NULL, DMABUFFERSIZE, BufferList[i].virt_addr, BufferList[i].dma_addr);
 				BufferList[i].virt_addr = NULL;
 			}
 		}
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 303f158..0b283d2 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -43,6 +43,13 @@
 {
 	struct tpm_chip *chip = (struct tpm_chip *) ptr;
 
+	schedule_work(&chip->work);
+}
+
+static void timeout_work(void * ptr)
+{
+	struct tpm_chip *chip = ptr;
+
 	down(&chip->buffer_mutex);
 	atomic_set(&chip->data_pending, 0);
 	memset(chip->data_buffer, 0, TPM_BUFSIZE);
@@ -428,8 +435,7 @@
 			ret_size = size;
 
 		down(&chip->buffer_mutex);
-		if (copy_to_user
-		    ((void __user *) buf, chip->data_buffer, ret_size))
+		if (copy_to_user(buf, chip->data_buffer, ret_size))
 			ret_size = -EFAULT;
 		up(&chip->buffer_mutex);
 	}
@@ -460,7 +466,7 @@
 	sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
 
 	dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
-		!(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
+		~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
 
 	kfree(chip);
 
@@ -528,6 +534,8 @@
 	init_MUTEX(&chip->tpm_mutex);
 	INIT_LIST_HEAD(&chip->list);
 
+	INIT_WORK(&chip->work, timeout_work, chip);
+
 	init_timer(&chip->user_read_timer);
 	chip->user_read_timer.function = user_reader_timeout;
 	chip->user_read_timer.data = (unsigned long) chip;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 9293bcc..159882c 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -50,7 +50,11 @@
 	u8 req_complete_mask;
 	u8 req_complete_val;
 	u8 req_canceled;
-	u16 base;		/* TPM base address */
+	void __iomem *iobase;		/* ioremapped address */
+	unsigned long base;		/* TPM base address */
+
+	int region_size;
+	int have_region;
 
 	int (*recv) (struct tpm_chip *, u8 *, size_t);
 	int (*send) (struct tpm_chip *, u8 *, size_t);
@@ -73,6 +77,7 @@
 	struct semaphore buffer_mutex;
 
 	struct timer_list user_read_timer;	/* user needs to claim result */
+	struct work_struct work;
 	struct semaphore tpm_mutex;	/* tpm is processing */
 
 	struct tpm_vendor_specific *vendor;
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 32e0145..deb4b5c 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -19,14 +19,8 @@
  * 
  */
 
-#include <linux/platform_device.h>
 #include "tpm.h"
-
-/* Atmel definitions */
-enum tpm_atmel_addr {
-	TPM_ATMEL_BASE_ADDR_LO = 0x08,
-	TPM_ATMEL_BASE_ADDR_HI = 0x09
-};
+#include "tpm_atmel.h"
 
 /* write status bits */
 enum tpm_atmel_write_status {
@@ -53,13 +47,13 @@
 		return -EIO;
 
 	for (i = 0; i < 6; i++) {
-		status = inb(chip->vendor->base + 1);
+		status = atmel_getb(chip, 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 			dev_err(chip->dev,
 				"error reading header\n");
 			return -EIO;
 		}
-		*buf++ = inb(chip->vendor->base);
+		*buf++ = atmel_getb(chip, 0);
 	}
 
 	/* size of the data received */
@@ -70,7 +64,7 @@
 		dev_err(chip->dev,
 			"Recv size(%d) less than available space\n", size);
 		for (; i < size; i++) {	/* clear the waiting data anyway */
-			status = inb(chip->vendor->base + 1);
+			status = atmel_getb(chip, 1);
 			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 				dev_err(chip->dev,
 					"error reading data\n");
@@ -82,17 +76,17 @@
 
 	/* read all the data available */
 	for (; i < size; i++) {
-		status = inb(chip->vendor->base + 1);
+		status = atmel_getb(chip, 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 			dev_err(chip->dev,
 				"error reading data\n");
 			return -EIO;
 		}
-		*buf++ = inb(chip->vendor->base);
+		*buf++ = atmel_getb(chip, 0);
 	}
 
 	/* make sure data available is gone */
-	status = inb(chip->vendor->base + 1);
+	status = atmel_getb(chip, 1);
 	if (status & ATML_STATUS_DATA_AVAIL) {
 		dev_err(chip->dev, "data available is stuck\n");
 		return -EIO;
@@ -108,7 +102,7 @@
 	dev_dbg(chip->dev, "tpm_atml_send:\n");
 	for (i = 0; i < count; i++) {
 		dev_dbg(chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
-		outb(buf[i], chip->vendor->base);
+		atmel_putb(buf[i], chip, 0);
 	}
 
 	return count;
@@ -116,12 +110,12 @@
 
 static void tpm_atml_cancel(struct tpm_chip *chip)
 {
-	outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+	atmel_putb(ATML_STATUS_ABORT, chip, 1);
 }
 
 static u8 tpm_atml_status(struct tpm_chip *chip)
 {
-	return inb(chip->vendor->base + 1);
+	return atmel_getb(chip, 1);
 }
 
 static struct file_operations atmel_ops = {
@@ -162,12 +156,16 @@
 
 static struct platform_device *pdev;
 
-static void __devexit tpm_atml_remove(struct device *dev)
+static void atml_plat_remove(void)
 {
-	struct tpm_chip *chip = dev_get_drvdata(dev);
+	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
 	if (chip) {
-		release_region(chip->vendor->base, 2);
+		if (chip->vendor->have_region)
+			atmel_release_region(chip->vendor->base, chip->vendor->region_size);
+		atmel_put_base_addr(chip->vendor);
 		tpm_remove_hardware(chip->dev);
+		platform_device_unregister(pdev);
 	}
 }
 
@@ -182,72 +180,40 @@
 static int __init init_atmel(void)
 {
 	int rc = 0;
-	int lo, hi;
 
 	driver_register(&atml_drv);
 
-	lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
-	hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
-
-	tpm_atmel.base = (hi<<8)|lo;
-
-	/* verify that it is an Atmel part */
-	if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
-	    || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
-		return -ENODEV;
+	if (atmel_get_base_addr(&tpm_atmel) != 0) {
+		rc = -ENODEV;
+		goto err_unreg_drv;
 	}
 
-	/* verify chip version number is 1.1 */
-	if (	(tpm_read_index(TPM_ADDR, 0x00) != 0x01) ||
-		(tpm_read_index(TPM_ADDR, 0x01) != 0x01 ))
-		return -ENODEV;
+	tpm_atmel.have_region = (atmel_request_region( tpm_atmel.base, tpm_atmel.region_size, "tpm_atmel0") == NULL) ? 0 : 1;
 
-	pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
-	if ( !pdev )
-		return -ENOMEM;
-
-	pdev->name = "tpm_atmel0";
-	pdev->id = -1;
-	pdev->num_resources = 0;
-	pdev->dev.release = tpm_atml_remove;
-	pdev->dev.driver = &atml_drv;
-
-	if ((rc = platform_device_register(pdev)) < 0) {
-		kfree(pdev);
-		pdev = NULL;
-		return rc;
+	if (IS_ERR(pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0 ))) {
+		rc = PTR_ERR(pdev);
+		goto err_rel_reg;
 	}
 
-	if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) {
-		platform_device_unregister(pdev);
-		kfree(pdev);
-		pdev = NULL;
-		return -EBUSY;
-	}
-
-	if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) {
-		release_region(tpm_atmel.base, 2);
-		platform_device_unregister(pdev);
-		kfree(pdev);
-		pdev = NULL;
-		return rc;
-	}
-
-	dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n",
-			tpm_atmel.base);
+	if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0)
+		goto err_unreg_dev;
 	return 0;
+
+err_unreg_dev:
+	platform_device_unregister(pdev);
+err_rel_reg:
+	if (tpm_atmel.have_region)
+		atmel_release_region(tpm_atmel.base, tpm_atmel.region_size);
+	atmel_put_base_addr(&tpm_atmel);
+err_unreg_drv:
+	driver_unregister(&atml_drv);
+	return rc;
 }
 
 static void __exit cleanup_atmel(void)
 {
-	if (pdev) {
-		tpm_atml_remove(&pdev->dev);
-		platform_device_unregister(pdev);
-		kfree(pdev);
-		pdev = NULL;
-	}
-
 	driver_unregister(&atml_drv);
+	atml_plat_remove();
 }
 
 module_init(init_atmel);
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
new file mode 100644
index 0000000..3c5b9a8
--- /dev/null
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
+ * License.
+ *
+ * These difference are required on power because the device must be
+ * discovered through the device tree and iomap must be used to get
+ * around the need for holes in the io_page_mask.  This does not happen
+ * automatically because the tpm is not a normal pci device and lives
+ * under the root node.
+ *
+ */
+
+#ifdef CONFIG_PPC64
+#define atmel_getb(chip, offset) readb(chip->vendor->iobase + offset);
+#define atmel_putb(val, chip, offset) writeb(val, chip->vendor->iobase + offset)
+#define atmel_request_region request_mem_region
+#define atmel_release_region release_mem_region
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+	iounmap(vendor->iobase);
+}
+
+static int atmel_get_base_addr(struct tpm_vendor_specific *vendor)
+{
+	struct device_node *dn;
+	unsigned long address, size;
+	unsigned int *reg;
+	int reglen;
+	int naddrc;
+	int nsizec;
+
+	dn = of_find_node_by_name(NULL, "tpm");
+
+	if (!dn)
+		return 1;
+
+	if (!device_is_compatible(dn, "AT97SC3201")) {
+		of_node_put(dn);
+		return 1;
+	}
+
+	reg = (unsigned int *) get_property(dn, "reg", &reglen);
+	naddrc = prom_n_addr_cells(dn);
+	nsizec = prom_n_size_cells(dn);
+
+	of_node_put(dn);
+
+
+	if (naddrc == 2)
+		address = ((unsigned long) reg[0] << 32) | reg[1];
+	else
+		address = reg[0];
+
+	if (nsizec == 2)
+		size =
+		    ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1];
+	else
+		size = reg[naddrc];
+
+	vendor->base = address;
+	vendor->region_size = size;
+	vendor->iobase = ioremap(address, size);
+	return 0;
+}
+#else
+#define atmel_getb(chip, offset) inb(chip->vendor->base + offset)
+#define atmel_putb(val, chip, offset) outb(val, chip->vendor->base + offset)
+#define atmel_request_region request_region
+#define atmel_release_region release_region
+/* Atmel definitions */
+enum tpm_atmel_addr {
+	TPM_ATMEL_BASE_ADDR_LO = 0x08,
+	TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
+
+/* Verify this is a 1.1 Atmel TPM */
+static int atmel_verify_tpm11(void)
+{
+
+	/* verify that it is an Atmel part */
+	if (tpm_read_index(TPM_ADDR, 4) != 'A' ||
+	    tpm_read_index(TPM_ADDR, 5) != 'T' ||
+	    tpm_read_index(TPM_ADDR, 6) != 'M' ||
+	    tpm_read_index(TPM_ADDR, 7) != 'L')
+		return 1;
+
+	/* query chip for its version number */
+	if (tpm_read_index(TPM_ADDR, 0x00) != 1 ||
+	    tpm_read_index(TPM_ADDR, 0x01) != 1)
+		return 1;
+
+	/* This is an atmel supported part */
+	return 0;
+}
+
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+}
+
+/* Determine where to talk to device */
+static unsigned long atmel_get_base_addr(struct tpm_vendor_specific
+					 *vendor)
+{
+	int lo, hi;
+
+	if (atmel_verify_tpm11() != 0)
+		return 1;
+
+	lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+	hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+	vendor->base = (hi << 8) | lo;
+	vendor->region_size = 2;
+
+	return 0;
+}
+#endif
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index abc30cc..65830ec 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
  * Watchdog timer for PowerPC Book-E systems
  *
  * Author: Matthew McClintock
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor Inc.
  *
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index ea0806c..8a5c7b2 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -399,34 +399,6 @@
 	return dev->irq;
 }
 
-static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
-	unsigned int rev;
-	u8 dma_state;
-
-	DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
-
-	hwif->autodma = 0;
-
-	if (!dma_base)
-		return;
-
-	dma_state = hwif->INB(dma_base + 2);
-	rev = sl82c105_bridge_revision(hwif->pci_dev);
-	if (rev <= 5) {
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-		dma_state &= ~0x60;
-	} else {
-		dma_state |= 0x60;
-		if (!noautodma)
-			hwif->autodma = 1;
-	}
-	hwif->OUTB(dma_state, dma_base + 2);
-
-	ide_setup_dma(hwif, dma_base, 8);
-}
-
 /*
  * Initialise the chip
  */
@@ -434,6 +406,8 @@
 static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int rev;
+	u8 dma_state;
 	u32 val;
 	
 	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
@@ -455,33 +429,54 @@
 	pci_read_config_dword(dev, 0x40, &val);
 	*((u32 *)&hwif->hwif_data) = val;
 	
+	hwif->atapi_dma = 0;
+	hwif->mwdma_mask = 0;
+	hwif->swdma_mask = 0;
+	hwif->autodma = 0;
+
 	if (!hwif->dma_base)
 		return;
 
-	hwif->atapi_dma = 1;
-	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
-
+	dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60;
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		/*
+		 * Never ever EVER under any circumstances enable
+		 * DMA when the bridge is this old.
+		 */
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+		       hwif->name, rev);
+	} else {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->ide_dma_check = &sl82c105_check_drive;
-	hwif->ide_dma_on = &sl82c105_ide_dma_on;
-	hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
-	hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
-	hwif->dma_start = &sl82c105_ide_dma_start;
-	hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+		dma_state |= 0x60;
 
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->drives[0].autodma = hwif->autodma;
-	hwif->drives[1].autodma = hwif->autodma;
+		hwif->atapi_dma = 1;
+		hwif->mwdma_mask = 0x07;
+		hwif->swdma_mask = 0x07;
+
+		hwif->ide_dma_check = &sl82c105_check_drive;
+		hwif->ide_dma_on = &sl82c105_ide_dma_on;
+		hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+		hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+		hwif->dma_start = &sl82c105_ide_dma_start;
+		hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+		if (!noautodma)
+			hwif->autodma = 1;
+		hwif->drives[0].autodma = hwif->autodma;
+		hwif->drives[1].autodma = hwif->autodma;
+
+		if (hwif->mate)
+			hwif->serialized = hwif->mate->serialized = 1;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+	hwif->OUTB(dma_state, hwif->dma_base + 2);
 }
 
 static ide_pci_device_t sl82c105_chipset __devinitdata = {
 	.name		= "W82C105",
 	.init_chipset	= init_chipset_sl82c105,
 	.init_hwif	= init_hwif_sl82c105,
-	.init_dma	= init_dma_sl82c105,
 	.channels	= 2,
 	.autodma	= NOAUTODMA,
 	.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index b3e65a6..136911a 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1667,11 +1667,16 @@
 };
 
 static struct pci_device_id pmac_ide_pci_match[] = {
-	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 };
 
 static struct pci_driver pmac_ide_pci_driver = {
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
index 4b71fd6..7972c73 100644
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -126,6 +126,66 @@
 };
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
 
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+	[ 0x59 ] = KEY_MUTE,
+	[ 0x4a ] = KEY_POWER,
+
+	[ 0x18 ] = KEY_TEXT,
+	[ 0x26 ] = KEY_TV,
+	[ 0x3d ] = KEY_PRINT,
+
+	[ 0x48 ] = KEY_RED,
+	[ 0x04 ] = KEY_GREEN,
+	[ 0x11 ] = KEY_YELLOW,
+	[ 0x00 ] = KEY_BLUE,
+
+	[ 0x2d ] = KEY_VOLUMEUP,
+	[ 0x1e ] = KEY_VOLUMEDOWN,
+
+	[ 0x49 ] = KEY_MENU,
+
+	[ 0x16 ] = KEY_CHANNELUP,
+	[ 0x17 ] = KEY_CHANNELDOWN,
+
+	[ 0x20 ] = KEY_UP,
+	[ 0x21 ] = KEY_DOWN,
+	[ 0x22 ] = KEY_LEFT,
+	[ 0x23 ] = KEY_RIGHT,
+	[ 0x0d ] = KEY_SELECT,
+
+
+
+	[ 0x08 ] = KEY_BACK,
+	[ 0x07 ] = KEY_REFRESH,
+
+	[ 0x2f ] = KEY_ZOOM,
+	[ 0x29 ] = KEY_RECORD,
+
+	[ 0x4b ] = KEY_PAUSE,
+	[ 0x4d ] = KEY_REWIND,
+	[ 0x2e ] = KEY_PLAY,
+	[ 0x4e ] = KEY_FORWARD,
+	[ 0x53 ] = KEY_PREVIOUS,
+	[ 0x4c ] = KEY_STOP,
+	[ 0x54 ] = KEY_NEXT,
+
+	[ 0x69 ] = KEY_KP0,
+	[ 0x6a ] = KEY_KP1,
+	[ 0x6b ] = KEY_KP2,
+	[ 0x6c ] = KEY_KP3,
+	[ 0x6d ] = KEY_KP4,
+	[ 0x6e ] = KEY_KP5,
+	[ 0x6f ] = KEY_KP6,
+	[ 0x70 ] = KEY_KP7,
+	[ 0x71 ] = KEY_KP8,
+	[ 0x72 ] = KEY_KP9,
+
+	[ 0x74 ] = KEY_CHANNEL,
+	[ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
 /* empty keytable, can be used as placeholder for not-yet created keytables */
 IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
 	[ 42 ] = KEY_COFFEE,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 199b011..1a3b3c7 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -333,4 +333,18 @@
 	  Say Y here to use the Renesas M64278E-800 camera module,
 	  which supports VGA(640x480 pixcels) size of images.
 
+config VIDEO_AUDIO_DECODER
+	tristate "Add support for additional audio chipsets"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Say Y here to compile drivers for WM8775 and CS53L32A audio
+	  decoders.
+
+config VIDEO_DECODER
+	tristate "Add support for additional video chipsets"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
+	  video  decoders.
+
 endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 3ac4659..82060f9 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -36,10 +36,11 @@
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
+obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -55,4 +56,6 @@
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
+obj-$(CONFIG_VIDEO_DECODER)     += saa7115.o cx25840/ saa7127.o
+
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 3413bac..e31ebb1 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -2133,7 +2133,10 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_dvb        = 1,
+		.has_remote	= 1,
+		.gpiomask	= 0x1b,
 		.no_gpioirq     = 1,
+		.any_irq		= 1,
 	},
 	[BTTV_BOARD_PV143] = {
 		/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2796,7 +2799,24 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
-
+		/* ---- card 0x8e ---------------------------------- */
+	[BTTV_BOARD_SABRENT_TVFM] = {
+		.name		= "Sabrent TV-FM (bttv version)",
+		.video_inputs	= 3,
+		.audio_inputs	= 1,
+		.tuner		= 0,
+		.svhs		= 2,
+		.gpiomask	= 0x108007,
+		.muxsel		= { 2, 3, 1, 1},
+		.audiomux	= { 100000, 100002, 100002, 100000},
+		.no_msp34xx	= 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.pll		= PLL_28,
+		.tuner_type	= TUNER_TNF_5335MF,
+		.tuner_addr	= ADDR_UNSET,
+		.has_radio      = 1,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3367,6 +3387,8 @@
 		btv->has_remote=1;
 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
 		btv->gpioirq=1;
+	if (bttv_tvcards[btv->c.type].any_irq)
+		btv->any_irq = 1;
 	if (bttv_tvcards[btv->c.type].audio_hook)
 		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
 
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 0005741..709099f 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -3667,6 +3667,10 @@
 	int handled = 0;
 
 	btv=(struct bttv *)dev_id;
+
+	if (btv->any_irq)
+		handled = bttv_any_irq(&btv->c);
+
 	count=0;
 	while (1) {
 		/* get/clear interrupt status bits */
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 575ce8b..616a5b7 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -113,6 +113,24 @@
 	}
 }
 
+int bttv_any_irq(struct bttv_core *core)
+{
+	struct bttv_sub_driver *drv;
+	struct bttv_sub_device *dev;
+	struct list_head *item;
+	int handled = 0;
+
+	list_for_each(item,&core->subs) {
+		dev = list_entry(item,struct bttv_sub_device,list);
+		drv = to_bttv_sub_drv(dev->dev.driver);
+		if (drv && drv->any_irq) {
+			if (drv->any_irq(dev))
+				handled = 1;
+		}
+	}
+	return handled;
+}
+
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 124ea41..93298f0 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -162,6 +162,7 @@
 #define BTTV_BOARD_PV_M4900                0x8b
 #define BTTV_BOARD_OSPREY440               0x8c
 #define BTTV_BOARD_ASOUND_SKYEYE	   0x8d
+#define BTTV_BOARD_SABRENT_TVFM   	   0x8e
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -234,6 +235,7 @@
 	unsigned int has_dvb:1;
 	unsigned int has_remote:1;
 	unsigned int no_gpioirq:1;
+	unsigned int any_irq:1;
 
 	/* other settings */
 	unsigned int pll;
@@ -333,6 +335,7 @@
 	struct device_driver   drv;
 	char                   wanted[BUS_ID_SIZE];
 	void                   (*gpio_irq)(struct bttv_sub_device *sub);
+	int                    (*any_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index 386f546..3aa9c6e 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -208,6 +208,7 @@
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 void bttv_gpio_irq(struct bttv_core *core);
+int bttv_any_irq(struct bttv_core *core);
 
 
 /* ---------------------------------------------------------- */
@@ -273,6 +274,7 @@
 	struct bttv_pll_info pll;
 	int triton1;
 	int gpioirq;
+	int any_irq;
 	int use_i2c_hw;
 
 	/* old gpio interface */
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
new file mode 100644
index 0000000..543ebac
--- /dev/null
+++ b/drivers/media/video/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs    := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+		   cx25840-vbi.o
+
+obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
new file mode 100644
index 0000000..740908f
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -0,0 +1,368 @@
+/* cx25840 audio 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, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+inline static int set_audclk_freq(struct i2c_client *client,
+				 enum v4l2_audio_clock_freq freq)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	/* assert soft reset */
+	cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
+	/* common for all inputs and rates */
+	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+	cx25840_write(client, 0x127, 0x50);
+
+	switch (state->audio_input) {
+	case AUDIO_TUNER:
+		switch (freq) {
+		case V4L2_AUDCLK_32_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f040610);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0xee39bb01);
+
+			/* src3/4/6_ctl = 0x0801f77f */
+			cx25840_write4(client, 0x900, 0x7ff70108);
+			cx25840_write4(client, 0x904, 0x7ff70108);
+			cx25840_write4(client, 0x90c, 0x7ff70108);
+			break;
+
+		case V4L2_AUDCLK_441_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f040910);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0xd66bec00);
+
+			/* src3/4/6_ctl = 0x08016d59 */
+			cx25840_write4(client, 0x900, 0x596d0108);
+			cx25840_write4(client, 0x904, 0x596d0108);
+			cx25840_write4(client, 0x90c, 0x596d0108);
+			break;
+
+		case V4L2_AUDCLK_48_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f040a10);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0xe5d69800);
+
+			/* src3/4/6_ctl = 0x08014faa */
+			cx25840_write4(client, 0x900, 0xaa4f0108);
+			cx25840_write4(client, 0x904, 0xaa4f0108);
+			cx25840_write4(client, 0x90c, 0xaa4f0108);
+			break;
+		}
+		break;
+
+	case AUDIO_EXTERN_1:
+	case AUDIO_EXTERN_2:
+	case AUDIO_INTERN:
+	case AUDIO_RADIO:
+		switch (freq) {
+		case V4L2_AUDCLK_32_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f04081e);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0x69082a01);
+
+			/* src1_ctl = 0x08010000 */
+			cx25840_write4(client, 0x8f8, 0x00000108);
+
+			/* src3/4/6_ctl = 0x08020000 */
+			cx25840_write4(client, 0x900, 0x00000208);
+			cx25840_write4(client, 0x904, 0x00000208);
+			cx25840_write4(client, 0x90c, 0x00000208);
+
+			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+			cx25840_write(client, 0x127, 0x54);
+			break;
+
+		case V4L2_AUDCLK_441_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f040918);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0xd66bec00);
+
+			/* src1_ctl = 0x08010000 */
+			cx25840_write4(client, 0x8f8, 0xcd600108);
+
+			/* src3/4/6_ctl = 0x08020000 */
+			cx25840_write4(client, 0x900, 0x85730108);
+			cx25840_write4(client, 0x904, 0x85730108);
+			cx25840_write4(client, 0x90c, 0x85730108);
+			break;
+
+		case V4L2_AUDCLK_48_KHZ:
+			/* VID_PLL and AUX_PLL */
+			cx25840_write4(client, 0x108, 0x0f040a18);
+
+			/* AUX_PLL_FRAC */
+			cx25840_write4(client, 0x110, 0xe5d69800);
+
+			/* src1_ctl = 0x08010000 */
+			cx25840_write4(client, 0x8f8, 0x00800108);
+
+			/* src3/4/6_ctl = 0x08020000 */
+			cx25840_write4(client, 0x900, 0x55550108);
+			cx25840_write4(client, 0x904, 0x55550108);
+			cx25840_write4(client, 0x90c, 0x55550108);
+			break;
+		}
+		break;
+	}
+
+	/* deassert soft reset */
+	cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+	state->audclk_freq = freq;
+
+	return 0;
+}
+
+static int set_input(struct i2c_client *client, int audio_input)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	cx25840_dbg("set audio input (%d)\n", audio_input);
+
+	/* stop microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0);
+
+	/* Mute everything to prevent the PFFT! */
+	cx25840_write(client, 0x8d3, 0x1f);
+
+	switch (audio_input) {
+	case AUDIO_TUNER:
+		/* Set Path1 to Analog Demod Main Channel */
+		cx25840_write4(client, 0x8d0, 0x7038061f);
+
+		/* When the microcontroller detects the
+		 * audio format, it will unmute the lines */
+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
+		break;
+
+	case AUDIO_EXTERN_1:
+	case AUDIO_EXTERN_2:
+	case AUDIO_INTERN:
+	case AUDIO_RADIO:
+		/* Set Path1 to Serial Audio Input */
+		cx25840_write4(client, 0x8d0, 0x12100101);
+
+		/* The microcontroller should not be started for the
+		 * non-tuner inputs: autodetection is specific for
+		 * TV audio. */
+		break;
+
+	default:
+		cx25840_dbg("Invalid audio input selection %d\n", audio_input);
+		return -EINVAL;
+	}
+
+	state->audio_input = audio_input;
+
+	return set_audclk_freq(client, state->audclk_freq);
+}
+
+inline static int get_volume(struct i2c_client *client)
+{
+	/* Volume runs +18dB to -96dB in 1/2dB steps
+	 * change to fit the msp3400 -114dB to +12dB range */
+
+	/* check PATH1_VOLUME */
+	int vol = 228 - cx25840_read(client, 0x8d4);
+	vol = (vol / 2) + 23;
+	return vol << 9;
+}
+
+inline static void set_volume(struct i2c_client *client, int volume)
+{
+	/* First convert the volume to msp3400 values (0-127) */
+	int vol = volume >> 9;
+	/* now scale it up to cx25840 values
+	 * -114dB to -96dB maps to 0
+	 * this should be 19, but in my testing that was 4dB too loud */
+	if (vol <= 23) {
+		vol = 0;
+	} else {
+		vol -= 23;
+	}
+
+	/* PATH1_VOLUME */
+	cx25840_write(client, 0x8d4, 228 - (vol * 2));
+}
+
+inline static int get_bass(struct i2c_client *client)
+{
+	/* bass is 49 steps +12dB to -12dB */
+
+	/* check PATH1_EQ_BASS_VOL */
+	int bass = cx25840_read(client, 0x8d9) & 0x3f;
+	bass = (((48 - bass) * 0xffff) + 47) / 48;
+	return bass;
+}
+
+inline static void set_bass(struct i2c_client *client, int bass)
+{
+	/* PATH1_EQ_BASS_VOL */
+	cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+inline static int get_treble(struct i2c_client *client)
+{
+	/* treble is 49 steps +12dB to -12dB */
+
+	/* check PATH1_EQ_TREBLE_VOL */
+	int treble = cx25840_read(client, 0x8db) & 0x3f;
+	treble = (((48 - treble) * 0xffff) + 47) / 48;
+	return treble;
+}
+
+inline static void set_treble(struct i2c_client *client, int treble)
+{
+	/* PATH1_EQ_TREBLE_VOL */
+	cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+inline static int get_balance(struct i2c_client *client)
+{
+	/* balance is 7 bit, 0 to -96dB */
+
+	/* check PATH1_BAL_LEVEL */
+	int balance = cx25840_read(client, 0x8d5) & 0x7f;
+	/* check PATH1_BAL_LEFT */
+	if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
+		balance = 0x80 - balance;
+	else
+		balance = 0x80 + balance;
+	return balance << 8;
+}
+
+inline static void set_balance(struct i2c_client *client, int balance)
+{
+	int bal = balance >> 8;
+	if (bal > 0x80) {
+		/* PATH1_BAL_LEFT */
+		cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
+		/* PATH1_BAL_LEVEL */
+		cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
+	} else {
+		/* PATH1_BAL_LEFT */
+		cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
+		/* PATH1_BAL_LEVEL */
+		cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
+	}
+}
+
+inline static int get_mute(struct i2c_client *client)
+{
+	/* check SRC1_MUTE_EN */
+	return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+inline static void set_mute(struct i2c_client *client, int mute)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	if (state->audio_input == AUDIO_TUNER) {
+		/* Must turn off microcontroller in order to mute sound.
+		 * Not sure if this is the best method, but it does work.
+		 * If the microcontroller is running, then it will undo any
+		 * changes to the mute register. */
+		if (mute) {
+			/* disable microcontroller */
+			cx25840_and_or(client, 0x803, ~0x10, 0x00);
+			cx25840_write(client, 0x8d3, 0x1f);
+		} else {
+			/* enable microcontroller */
+			cx25840_and_or(client, 0x803, ~0x10, 0x10);
+		}
+	} else {
+		/* SRC1_MUTE_EN */
+		cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+	}
+}
+
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct v4l2_control *ctrl = arg;
+
+	switch (cmd) {
+	case AUDC_SET_INPUT:
+		return set_input(client, *(int *)arg);
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+	case VIDIOC_G_CTRL:
+		switch (ctrl->id) {
+		case V4L2_CID_AUDIO_VOLUME:
+			ctrl->value = get_volume(client);
+			break;
+		case V4L2_CID_AUDIO_BASS:
+			ctrl->value = get_bass(client);
+			break;
+		case V4L2_CID_AUDIO_TREBLE:
+			ctrl->value = get_treble(client);
+			break;
+		case V4L2_CID_AUDIO_BALANCE:
+			ctrl->value = get_balance(client);
+			break;
+		case V4L2_CID_AUDIO_MUTE:
+			ctrl->value = get_mute(client);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case VIDIOC_S_CTRL:
+		switch (ctrl->id) {
+		case V4L2_CID_AUDIO_VOLUME:
+			set_volume(client, ctrl->value);
+			break;
+		case V4L2_CID_AUDIO_BASS:
+			set_bass(client, ctrl->value);
+			break;
+		case V4L2_CID_AUDIO_TREBLE:
+			set_treble(client, ctrl->value);
+			break;
+		case V4L2_CID_AUDIO_BALANCE:
+			set_balance(client, ctrl->value);
+			break;
+		case V4L2_CID_AUDIO_MUTE:
+			set_mute(client, ctrl->value);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
new file mode 100644
index 0000000..f6afeec
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -0,0 +1,1020 @@
+/* cx25840 - Conexant CX25840 audio/video decoder driver
+ *
+ * Copyright (C) 2004 Ulf Eklund
+ *
+ * Based on the saa7115 driver and on the first verison of Chris Kennedy's
+ * cx25840 driver.
+ *
+ * Changes by Tyler Trafford <tatrafford@comcast.net>
+ *    - cleanup/rewrite for V4L2 API (2005)
+ *
+ * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
+MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+int cx25840_debug = 0;
+
+module_param(cx25840_debug, bool, 0644);
+
+MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
+{
+	u8 buffer[3];
+	buffer[0] = addr >> 8;
+	buffer[1] = addr & 0xff;
+	buffer[2] = value;
+	return i2c_master_send(client, buffer, 3);
+}
+
+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;
+	return i2c_master_send(client, buffer, 6);
+}
+
+u8 cx25840_read(struct i2c_client * client, u16 addr)
+{
+	u8 buffer[2];
+	buffer[0] = addr >> 8;
+	buffer[1] = addr & 0xff;
+
+	if (i2c_master_send(client, buffer, 2) < 2)
+		return 0;
+
+	if (i2c_master_recv(client, buffer, 1) < 1)
+		return 0;
+
+	return buffer[0];
+}
+
+u32 cx25840_read4(struct i2c_client * client, u16 addr)
+{
+	u8 buffer[4];
+	buffer[0] = addr >> 8;
+	buffer[1] = addr & 0xff;
+
+	if (i2c_master_send(client, buffer, 2) < 2)
+		return 0;
+
+	if (i2c_master_recv(client, buffer, 4) < 4)
+		return 0;
+
+	return (buffer[0] << 24) | (buffer[1] << 16) |
+	    (buffer[2] << 8) | buffer[3];
+}
+
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+		   u8 or_value)
+{
+	return cx25840_write(client, addr,
+			     (cx25840_read(client, addr) & and_mask) |
+			     or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct i2c_client *, enum cx25840_input);
+static void input_change(struct i2c_client *);
+static void log_status(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+
+static inline void init_dll1(struct i2c_client *client)
+{
+	/* This is the Hauppauge sequence used to
+	 * initialize the Delay Lock Loop 1 (ADC DLL). */
+	cx25840_write(client, 0x159, 0x23);
+	cx25840_write(client, 0x15a, 0x87);
+	cx25840_write(client, 0x15b, 0x06);
+	cx25840_write(client, 0x159, 0xe1);
+	cx25840_write(client, 0x15a, 0x86);
+	cx25840_write(client, 0x159, 0xe0);
+	cx25840_write(client, 0x159, 0xe1);
+	cx25840_write(client, 0x15b, 0x10);
+}
+
+static inline void init_dll2(struct i2c_client *client)
+{
+	/* This is the Hauppauge sequence used to
+	 * initialize the Delay Lock Loop 2 (ADC DLL). */
+	cx25840_write(client, 0x15d, 0xe3);
+	cx25840_write(client, 0x15e, 0x86);
+	cx25840_write(client, 0x15f, 0x06);
+	cx25840_write(client, 0x15d, 0xe1);
+	cx25840_write(client, 0x15d, 0xe0);
+	cx25840_write(client, 0x15d, 0xe1);
+}
+
+static void cx25840_initialize(struct i2c_client *client, int loadfw)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	/* datasheet startup in numbered steps, refer to page 3-77 */
+	/* 2. */
+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+	/* The default of this register should be 4, but I get 0 instead.
+	 * Set this register to 4 manually. */
+	cx25840_write(client, 0x000, 0x04);
+	/* 3. */
+	init_dll1(client);
+	init_dll2(client);
+	cx25840_write(client, 0x136, 0x0a);
+	/* 4. */
+	cx25840_write(client, 0x13c, 0x01);
+	cx25840_write(client, 0x13c, 0x00);
+	/* 5. */
+	if (loadfw)
+		cx25840_loadfw(client);
+	/* 6. */
+	cx25840_write(client, 0x115, 0x8c);
+	cx25840_write(client, 0x116, 0x07);
+	cx25840_write(client, 0x118, 0x02);
+	/* 7. */
+	cx25840_write(client, 0x4a5, 0x80);
+	cx25840_write(client, 0x4a5, 0x00);
+	cx25840_write(client, 0x402, 0x00);
+	/* 8. */
+	cx25840_write(client, 0x401, 0x18);
+	cx25840_write(client, 0x4a2, 0x10);
+	cx25840_write(client, 0x402, 0x04);
+	/* 10. */
+	cx25840_write(client, 0x8d3, 0x1f);
+	cx25840_write(client, 0x8e3, 0x03);
+
+	cx25840_vbi_setup(client);
+
+	/* trial and error says these are needed to get audio */
+	cx25840_write(client, 0x914, 0xa0);
+	cx25840_write(client, 0x918, 0xa0);
+	cx25840_write(client, 0x919, 0x01);
+
+	/* stereo prefered */
+	cx25840_write(client, 0x809, 0x04);
+	/* AC97 shift */
+	cx25840_write(client, 0x8cf, 0x0f);
+
+	/* (re)set video input */
+	set_input(client, state->input);
+	/* (re)set audio input */
+	cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+
+	/* start microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct i2c_client *client)
+{
+	v4l2_std_id std = cx25840_get_v4lstd(client);
+
+	if (std & V4L2_STD_PAL) {
+		/* Follow tuner change procedure for PAL */
+		cx25840_write(client, 0x808, 0xff);
+		cx25840_write(client, 0x80b, 0x10);
+	} else if (std & V4L2_STD_SECAM) {
+		/* Select autodetect for SECAM */
+		cx25840_write(client, 0x808, 0xff);
+		cx25840_write(client, 0x80b, 0x10);
+	} else if (std & V4L2_STD_NTSC) {
+		/* NTSC */
+		cx25840_write(client, 0x808, 0xf6);
+		cx25840_write(client, 0x80b, 0x00);
+	}
+
+	if (cx25840_read(client, 0x803) & 0x10) {
+		/* restart audio decoder microcontroller */
+		cx25840_and_or(client, 0x803, ~0x10, 0x00);
+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
+	}
+}
+
+static int set_input(struct i2c_client *client, enum cx25840_input input)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	cx25840_dbg("decoder set input (%d)\n", input);
+
+	switch (input) {
+	case CX25840_TUNER:
+		cx25840_dbg("now setting Tuner input\n");
+
+		if (state->cardtype == CARDTYPE_PVR150) {
+			/* CH_SEL_ADC2=1 */
+			cx25840_and_or(client, 0x102, ~0x2, 0x02);
+		}
+
+		/* Video Input Control */
+		if (state->cardtype == CARDTYPE_PG600) {
+			cx25840_write(client, 0x103, 0x11);
+		} else {
+			cx25840_write(client, 0x103, 0x46);
+		}
+
+		/* INPUT_MODE=0 */
+		cx25840_and_or(client, 0x401, ~0x6, 0x00);
+		break;
+
+	case CX25840_COMPOSITE0:
+	case CX25840_COMPOSITE1:
+		cx25840_dbg("now setting Composite input\n");
+
+		/* Video Input Control */
+		if (state->cardtype == CARDTYPE_PG600) {
+			cx25840_write(client, 0x103, 0x00);
+		} else {
+			cx25840_write(client, 0x103, 0x02);
+		}
+
+		/* INPUT_MODE=0 */
+		cx25840_and_or(client, 0x401, ~0x6, 0x00);
+		break;
+
+	case CX25840_SVIDEO0:
+	case CX25840_SVIDEO1:
+		cx25840_dbg("now setting S-Video input\n");
+
+		/* CH_SEL_ADC2=0 */
+		cx25840_and_or(client, 0x102, ~0x2, 0x00);
+
+		/* Video Input Control */
+		if (state->cardtype == CARDTYPE_PG600) {
+			cx25840_write(client, 0x103, 0x02);
+		} else {
+			cx25840_write(client, 0x103, 0x10);
+		}
+
+		/* INPUT_MODE=1 */
+		cx25840_and_or(client, 0x401, ~0x6, 0x02);
+		break;
+
+	default:
+		cx25840_err("%d is not a valid input!\n", input);
+		return -EINVAL;
+	}
+
+	state->input = input;
+	input_change(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+	u8 fmt;
+
+	switch (std) {
+	/* zero is autodetect */
+	case 0: fmt = 0x0; break;
+	/* default ntsc to ntsc-m */
+	case V4L2_STD_NTSC:
+	case V4L2_STD_NTSC_M: fmt = 0x1; break;
+	case V4L2_STD_NTSC_M_JP: fmt = 0x2; break;
+	case V4L2_STD_NTSC_443: fmt = 0x3; break;
+	case V4L2_STD_PAL: fmt = 0x4; break;
+	case V4L2_STD_PAL_M: fmt = 0x5; break;
+	case V4L2_STD_PAL_N: fmt = 0x6; break;
+	case V4L2_STD_PAL_Nc: fmt = 0x7; break;
+	case V4L2_STD_PAL_60: fmt = 0x8; break;
+	case V4L2_STD_SECAM: fmt = 0xc; break;
+	default:
+		return -ERANGE;
+	}
+
+	cx25840_and_or(client, 0x400, ~0xf, fmt);
+	cx25840_vbi_setup(client);
+	return 0;
+}
+
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
+{
+	/* check VID_FMT_SEL first */
+	u8 fmt = cx25840_read(client, 0x400) & 0xf;
+
+	if (!fmt) {
+		/* check AFD_FMT_STAT if set to autodetect */
+		fmt = cx25840_read(client, 0x40d) & 0xf;
+	}
+
+	switch (fmt) {
+	case 0x1: return V4L2_STD_NTSC_M;
+	case 0x2: return V4L2_STD_NTSC_M_JP;
+	case 0x3: return V4L2_STD_NTSC_443;
+	case 0x4: return V4L2_STD_PAL;
+	case 0x5: return V4L2_STD_PAL_M;
+	case 0x6: return V4L2_STD_PAL_N;
+	case 0x7: return V4L2_STD_PAL_Nc;
+	case 0x8: return V4L2_STD_PAL_60;
+	case 0xc: return V4L2_STD_SECAM;
+	default: return V4L2_STD_UNKNOWN;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case CX25840_CID_CARDTYPE:
+		switch (ctrl->value) {
+		case CARDTYPE_PVR150:
+		case CARDTYPE_PG600:
+			state->cardtype = ctrl->value;
+			break;
+		default:
+			return -ERANGE;
+		}
+
+		set_input(client, state->input);
+		break;
+
+	case V4L2_CID_BRIGHTNESS:
+		if (ctrl->value < 0 || ctrl->value > 255) {
+			cx25840_err("invalid brightness setting %d\n",
+				    ctrl->value);
+			return -ERANGE;
+		}
+
+		cx25840_write(client, 0x414, ctrl->value - 128);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			cx25840_err("invalid contrast setting %d\n",
+				    ctrl->value);
+			return -ERANGE;
+		}
+
+		cx25840_write(client, 0x415, ctrl->value << 1);
+		break;
+
+	case V4L2_CID_SATURATION:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			cx25840_err("invalid saturation setting %d\n",
+				    ctrl->value);
+			return -ERANGE;
+		}
+
+		cx25840_write(client, 0x420, ctrl->value << 1);
+		cx25840_write(client, 0x421, ctrl->value << 1);
+		break;
+
+	case V4L2_CID_HUE:
+		if (ctrl->value < -127 || ctrl->value > 127) {
+			cx25840_err("invalid hue setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		cx25840_write(client, 0x422, ctrl->value);
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_MUTE:
+		return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+	}
+
+	return 0;
+}
+
+static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case CX25840_CID_CARDTYPE:
+		ctrl->value = state->cardtype;
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = cx25840_read(client, 0x414) + 128;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = cx25840_read(client, 0x415) >> 1;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = cx25840_read(client, 0x420) >> 1;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = cx25840_read(client, 0x422);
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_MUTE:
+		return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+	struct v4l2_pix_format *pix;
+	int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+	int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		pix = &(fmt->fmt.pix);
+
+		Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+		Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+
+		Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+		Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+
+		Vlines = pix->height + (is_pal ? 4 : 7);
+
+		if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+		    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+			cx25840_err("%dx%d is not a valid size!\n",
+				    pix->width, pix->height);
+			return -ERANGE;
+		}
+
+		HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+		VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+		VSC &= 0x1fff;
+
+		if (pix->width >= 385)
+			filter = 0;
+		else if (pix->width > 192)
+			filter = 1;
+		else if (pix->width > 96)
+			filter = 2;
+		else
+			filter = 3;
+
+		cx25840_dbg("decoder set size %dx%d -> scale  %ux%u\n",
+			    pix->width, pix->height, HSC, VSC);
+
+		/* HSCALE=HSC */
+		cx25840_write(client, 0x418, HSC & 0xff);
+		cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+		cx25840_write(client, 0x41a, HSC >> 16);
+		/* VSCALE=VSC */
+		cx25840_write(client, 0x41c, VSC & 0xff);
+		cx25840_write(client, 0x41d, VSC >> 8);
+		/* VS_INTRLACE=1 VFILT=filter */
+		cx25840_write(client, 0x41e, 0x8 | filter);
+		break;
+
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+			   void *arg)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	struct v4l2_tuner *vt = arg;
+	int result = 0;
+
+	switch (cmd) {
+	case 0:
+		break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	/* ioctls to allow direct access to the
+	 * cx25840 registers for testing */
+	case VIDIOC_INT_G_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_CX25840)
+			return -EINVAL;
+		reg->val = cx25840_read(client, reg->reg & 0x0fff);
+		break;
+	}
+
+	case VIDIOC_INT_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_CX25840)
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+		break;
+	}
+#endif
+
+	case VIDIOC_INT_DECODE_VBI_LINE:
+		return cx25840_vbi(client, cmd, arg);
+
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+	case AUDC_SET_INPUT:
+		result = cx25840_audio(client, cmd, arg);
+		break;
+
+	case VIDIOC_STREAMON:
+		cx25840_dbg("enable output\n");
+		cx25840_write(client, 0x115, 0x8c);
+		cx25840_write(client, 0x116, 0x07);
+		break;
+
+	case VIDIOC_STREAMOFF:
+		cx25840_dbg("disable output\n");
+		cx25840_write(client, 0x115, 0x00);
+		cx25840_write(client, 0x116, 0x00);
+		break;
+
+	case VIDIOC_LOG_STATUS:
+		log_status(client);
+		break;
+
+	case VIDIOC_G_CTRL:
+		result = get_v4lctrl(client, (struct v4l2_control *)arg);
+		break;
+
+	case VIDIOC_S_CTRL:
+		result = set_v4lctrl(client, (struct v4l2_control *)arg);
+		break;
+
+	case VIDIOC_G_STD:
+		*(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
+		break;
+
+	case VIDIOC_S_STD:
+		result = set_v4lstd(client, *(v4l2_std_id *)arg);
+		break;
+
+	case VIDIOC_G_INPUT:
+		*(int *)arg = state->input;
+		break;
+
+	case VIDIOC_S_INPUT:
+		result = set_input(client, *(int *)arg);
+		break;
+
+	case VIDIOC_S_FREQUENCY:
+		input_change(client);
+		break;
+
+	case VIDIOC_G_TUNER:
+	{
+		u8 mode = cx25840_read(client, 0x804);
+		u8 pref = cx25840_read(client, 0x809) & 0xf;
+		u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+		int val = 0;
+
+		vt->capability |=
+		    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+		    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+		vt->signal = vpres ? 0xffff : 0x0;
+
+		/* get rxsubchans and audmode */
+		if ((mode & 0xf) == 1)
+			val |= V4L2_TUNER_SUB_STEREO;
+		else
+			val |= V4L2_TUNER_SUB_MONO;
+
+		if (mode == 2 || mode == 4)
+			val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+		if (mode & 0x10)
+			val |= V4L2_TUNER_SUB_SAP;
+
+		vt->rxsubchans = val;
+
+		switch (pref) {
+		case 0:
+			vt->audmode = V4L2_TUNER_MODE_MONO;
+			break;
+		case 1:
+		case 2:
+			vt->audmode = V4L2_TUNER_MODE_LANG2;
+			break;
+		case 4:
+		default:
+			vt->audmode = V4L2_TUNER_MODE_STEREO;
+		}
+		break;
+	}
+
+	case VIDIOC_S_TUNER:
+		switch (vt->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+			/* Force PREF_MODE to MONO */
+			cx25840_and_or(client, 0x809, ~0xf, 0x00);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			/* Force PREF_MODE to STEREO */
+			cx25840_and_or(client, 0x809, ~0xf, 0x04);
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			/* Force PREF_MODE to LANG2 */
+			cx25840_and_or(client, 0x809, ~0xf, 0x01);
+			break;
+		}
+		break;
+
+	case VIDIOC_G_FMT:
+		result = get_v4lfmt(client, (struct v4l2_format *)arg);
+		break;
+
+	case VIDIOC_S_FMT:
+		result = set_v4lfmt(client, (struct v4l2_format *)arg);
+		break;
+
+	case VIDIOC_INT_RESET:
+		cx25840_initialize(client, 0);
+		break;
+
+	case VIDIOC_INT_G_CHIP_IDENT:
+		*(enum v4l2_chip_ident *)arg =
+			V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+		break;
+
+	default:
+		cx25840_err("invalid ioctl %x\n", cmd);
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840;
+
+static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+				 int kind)
+{
+	struct i2c_client *client;
+	struct cx25840_state *state;
+	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 = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_cx25840;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
+
+	cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+
+	device_id = cx25840_read(client, 0x101) << 8;
+	device_id |= cx25840_read(client, 0x100);
+
+	/* The high byte of the device ID should be
+	 * 0x84 if chip is present */
+	if ((device_id & 0xff00) != 0x8400) {
+		cx25840_dbg("cx25840 not found\n");
+		kfree(client);
+		return 0;
+	}
+
+	cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+		    (device_id & 0xfff0) >> 4,
+		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+		    address << 1, adapter->name);
+
+	state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, state);
+	memset(state, 0, sizeof(struct cx25840_state));
+	state->input = CX25840_TUNER;
+	state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+	state->audio_input = AUDIO_TUNER;
+	state->cardtype = CARDTYPE_PVR150;
+
+	cx25840_initialize(client, 1);
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int cx25840_attach_adapter(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+	if (adapter->id == I2C_HW_B_BT848)
+#endif
+		return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
+	return 0;
+}
+
+static int cx25840_detach_client(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);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840 = {
+	.name = "cx25840",
+
+	.id = I2C_DRIVERID_CX25840,
+	.flags = I2C_DF_NOTIFY,
+
+	.attach_adapter = cx25840_attach_adapter,
+	.detach_client = cx25840_detach_client,
+	.command = cx25840_command,
+	.owner = THIS_MODULE,
+};
+
+
+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_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 microctrl_vidfmt = cx25840_read(client, 0x80a);
+	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+	u8 gen_stat1 = cx25840_read(client, 0x40d);
+	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);
+	char *p;
+
+	cx25840_info("Video signal:              %spresent\n",
+		    (microctrl_vidfmt & 0x10) ? "" : "not ");
+	cx25840_info("Detected format:           %s\n",
+		    fmt_strs[gen_stat1 & 0xf]);
+
+	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";
+	}
+	cx25840_info("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";
+	}
+	cx25840_info("Detected audio standard:   %s\n", p);
+	cx25840_info("Audio muted:               %s\n",
+		    (mute_ctl & 0x2) ? "yes" : "no");
+	cx25840_info("Audio microcontroller:     %s\n",
+		    (download_ctl & 0x10) ? "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";
+	}
+	cx25840_info("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";
+		}
+		cx25840_info("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";
+		}
+		cx25840_info("Configured audio system:   %s\n", p);
+	}
+
+	cx25840_info("Specified standard:        %s\n",
+		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+	switch (state->input) {
+	case CX25840_COMPOSITE0: p = "Composite 0"; break;
+	case CX25840_COMPOSITE1: p = "Composite 1"; break;
+	case CX25840_SVIDEO0: p = "S-Video 0"; break;
+	case CX25840_SVIDEO1: p = "S-Video 1"; break;
+	case CX25840_TUNER: p = "Tuner"; break;
+	}
+	cx25840_info("Specified input:           %s\n", p);
+	cx25840_info("Specified audio input:     %s\n",
+		    state->audio_input == 0 ? "Tuner" : "External");
+
+	switch (state->audclk_freq) {
+	case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
+	case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
+	case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
+	default: p = "undefined";
+	}
+	cx25840_info("Specified audioclock freq: %s\n", p);
+
+	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";
+	}
+	cx25840_info("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";
+		}
+		cx25840_info("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";
+		}
+		cx25840_info("Selected 45 MHz format:    %s\n", p);
+	}
+}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
new file mode 100644
index 0000000..df9d50a
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -0,0 +1,167 @@
+/* cx25840 firmware 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, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+#define FWFILE "v4l-cx25840.fw"
+#define FWSEND 1024
+
+#define FWDEV(x) &((x)->adapter->dev)
+
+static int fastfw = 1;
+static char *firmware = FWFILE;
+
+module_param(fastfw, bool, 0444);
+module_param(firmware, charp, 0444);
+
+MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
+MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+
+static inline void set_i2c_delay(struct i2c_client *client, int delay)
+{
+	struct i2c_algo_bit_data *algod = client->adapter->algo_data;
+
+	/* We aren't guaranteed to be using algo_bit,
+	 * so avoid the null pointer dereference
+	 * and disable the 'fast firmware load' */
+	if (algod) {
+		algod->udelay = delay;
+	} else {
+		fastfw = 0;
+	}
+}
+
+static inline void start_fw_load(struct i2c_client *client)
+{
+	/* DL_ADDR_LB=0 DL_ADDR_HB=0 */
+	cx25840_write(client, 0x800, 0x00);
+	cx25840_write(client, 0x801, 0x00);
+	// DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
+	cx25840_write(client, 0x803, 0x0b);
+	/* AUTO_INC_DIS=1 */
+	cx25840_write(client, 0x000, 0x20);
+
+	if (fastfw)
+		set_i2c_delay(client, 3);
+}
+
+static inline void end_fw_load(struct i2c_client *client)
+{
+	if (fastfw)
+		set_i2c_delay(client, 10);
+
+	/* AUTO_INC_DIS=0 */
+	cx25840_write(client, 0x000, 0x00);
+	/* DL_ENABLE=0 */
+	cx25840_write(client, 0x803, 0x03);
+}
+
+static inline int check_fw_load(struct i2c_client *client, int size)
+{
+	/* DL_ADDR_HB DL_ADDR_LB */
+	int s = cx25840_read(client, 0x801) << 8;
+	s |= cx25840_read(client, 0x800);
+
+	if (size != s) {
+		cx25840_err("firmware %s load failed\n", firmware);
+		return -EINVAL;
+	}
+
+	cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+	return 0;
+}
+
+static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+{
+	if (i2c_master_send(client, data, size) < size) {
+
+		if (fastfw) {
+			cx25840_err("333MHz i2c firmware load failed\n");
+			fastfw = 0;
+			set_i2c_delay(client, 10);
+
+			if (i2c_master_send(client, data, size) < size) {
+				cx25840_err
+				    ("100MHz i2c firmware load failed\n");
+				return -ENOSYS;
+			}
+
+		} else {
+			cx25840_err("firmware load i2c failure\n");
+			return -ENOSYS;
+		}
+
+	}
+
+	return 0;
+}
+
+int cx25840_loadfw(struct i2c_client *client)
+{
+	const struct firmware *fw = NULL;
+	u8 buffer[4], *ptr;
+	int size, send, retval;
+
+	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
+		cx25840_err("unable to open firmware %s\n", firmware);
+		return -EINVAL;
+	}
+
+	start_fw_load(client);
+
+	buffer[0] = 0x08;
+	buffer[1] = 0x02;
+	buffer[2] = fw->data[0];
+	buffer[3] = fw->data[1];
+	retval = fw_write(client, buffer, 4);
+
+	if (retval < 0) {
+		release_firmware(fw);
+		return retval;
+	}
+
+	size = fw->size - 2;
+	ptr = fw->data;
+	while (size > 0) {
+		ptr[0] = 0x08;
+		ptr[1] = 0x02;
+		send = size > (FWSEND - 2) ? FWSEND : size + 2;
+		retval = fw_write(client, ptr, send);
+
+		if (retval < 0) {
+			release_firmware(fw);
+			return retval;
+		}
+
+		size -= FWSEND - 2;
+		ptr += FWSEND - 2;
+	}
+
+	end_fw_load(client);
+
+	size = fw->size;
+	release_firmware(fw);
+
+	return check_fw_load(client, size);
+}
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
new file mode 100644
index 0000000..13ba4e1
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -0,0 +1,315 @@
+/* cx25840 VBI 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, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+static inline int odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static inline int decode_vps(u8 * dst, u8 * p)
+{
+	static const u8 biphase_tbl[] = {
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+	};
+
+	u8 c, err = 0;
+	int i;
+
+	for (i = 0; i < 2 * 13; i += 2) {
+		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+		c = (biphase_tbl[p[i + 1]] & 0xf) |
+		    ((biphase_tbl[p[i]] & 0xf) << 4);
+		dst[i / 2] = c;
+	}
+
+	return err & 0xf0;
+}
+
+void cx25840_vbi_setup(struct i2c_client *client)
+{
+	v4l2_std_id std = cx25840_get_v4lstd(client);
+
+	if (std & ~V4L2_STD_NTSC) {
+		/* datasheet startup, step 8d */
+		cx25840_write(client, 0x49f, 0x11);
+
+		cx25840_write(client, 0x470, 0x84);
+		cx25840_write(client, 0x471, 0x00);
+		cx25840_write(client, 0x472, 0x2d);
+		cx25840_write(client, 0x473, 0x5d);
+
+		cx25840_write(client, 0x474, 0x24);
+		cx25840_write(client, 0x475, 0x40);
+		cx25840_write(client, 0x476, 0x24);
+		cx25840_write(client, 0x477, 0x28);
+
+		cx25840_write(client, 0x478, 0x1f);
+		cx25840_write(client, 0x479, 0x02);
+
+		if (std & V4L2_STD_SECAM) {
+			cx25840_write(client, 0x47a, 0x80);
+			cx25840_write(client, 0x47b, 0x00);
+			cx25840_write(client, 0x47c, 0x5f);
+			cx25840_write(client, 0x47d, 0x42);
+		} else {
+			cx25840_write(client, 0x47a, 0x90);
+			cx25840_write(client, 0x47b, 0x20);
+			cx25840_write(client, 0x47c, 0x63);
+			cx25840_write(client, 0x47d, 0x82);
+		}
+
+		cx25840_write(client, 0x47e, 0x0a);
+		cx25840_write(client, 0x47f, 0x01);
+	} else {
+		/* datasheet startup, step 8d */
+		cx25840_write(client, 0x49f, 0x14);
+
+		cx25840_write(client, 0x470, 0x7a);
+		cx25840_write(client, 0x471, 0x00);
+		cx25840_write(client, 0x472, 0x2d);
+		cx25840_write(client, 0x473, 0x5b);
+
+		cx25840_write(client, 0x474, 0x1a);
+		cx25840_write(client, 0x475, 0x70);
+		cx25840_write(client, 0x476, 0x1e);
+		cx25840_write(client, 0x477, 0x1e);
+
+		cx25840_write(client, 0x478, 0x1f);
+		cx25840_write(client, 0x479, 0x02);
+		cx25840_write(client, 0x47a, 0x50);
+		cx25840_write(client, 0x47b, 0x66);
+
+		cx25840_write(client, 0x47c, 0x1f);
+		cx25840_write(client, 0x47d, 0x7c);
+		cx25840_write(client, 0x47e, 0x08);
+		cx25840_write(client, 0x47f, 0x00);
+	}
+}
+
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct v4l2_format *fmt;
+	struct v4l2_sliced_vbi_format *svbi;
+
+	switch (cmd) {
+	case VIDIOC_G_FMT:
+	{
+		static u16 lcr2vbi[] = {
+			0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+			0, V4L2_SLICED_WSS_625, 0,	/* 4 */
+			V4L2_SLICED_CAPTION_525,	/* 6 */
+			0, 0, V4L2_SLICED_VPS, 0, 0,	/* 9 */
+			0, 0, 0, 0
+		};
+		int i;
+
+		fmt = arg;
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+		svbi = &fmt->fmt.sliced;
+		memset(svbi, 0, sizeof(*svbi));
+		/* we're done if raw VBI is active */
+		if ((cx25840_read(client, 0x404) & 0x10) == 0)
+			break;
+
+		for (i = 7; i <= 23; i++) {
+			u8 v = cx25840_read(client, 0x424 + i - 7);
+
+			svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+			svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+			svbi->service_set |=
+				 svbi->service_lines[0][i] | svbi->service_lines[1][i];
+		}
+		break;
+	}
+
+	case VIDIOC_S_FMT:
+	{
+		int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+		int vbi_offset = is_pal ? 1 : 0;
+		int i, x;
+		u8 lcr[24];
+
+		fmt = arg;
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+		svbi = &fmt->fmt.sliced;
+		if (svbi->service_set == 0) {
+			/* raw VBI */
+			memset(svbi, 0, sizeof(*svbi));
+
+			/* Setup VBI */
+			cx25840_vbi_setup(client);
+
+			/* VBI Offset */
+			cx25840_write(client, 0x47f, vbi_offset);
+			cx25840_write(client, 0x404, 0x2e);
+			break;
+		}
+
+		for (x = 0; x <= 23; x++)
+			lcr[x] = 0x00;
+
+		/* Setup VBI */
+		cx25840_vbi_setup(client);
+
+		/* Sliced VBI */
+		cx25840_write(client, 0x404, 0x36);	/* Ancillery data */
+		cx25840_write(client, 0x406, 0x13);
+		cx25840_write(client, 0x47f, vbi_offset);
+
+		if (is_pal) {
+			for (i = 0; i <= 6; i++)
+				svbi->service_lines[0][i] =
+					svbi->service_lines[1][i] = 0;
+		} else {
+			for (i = 0; i <= 9; i++)
+				svbi->service_lines[0][i] =
+					svbi->service_lines[1][i] = 0;
+
+			for (i = 22; i <= 23; i++)
+				svbi->service_lines[0][i] =
+					svbi->service_lines[1][i] = 0;
+		}
+
+		for (i = 7; i <= 23; i++) {
+			for (x = 0; x <= 1; x++) {
+				switch (svbi->service_lines[1-x][i]) {
+				case V4L2_SLICED_TELETEXT_B:
+					lcr[i] |= 1 << (4 * x);
+					break;
+				case V4L2_SLICED_WSS_625:
+					lcr[i] |= 4 << (4 * x);
+					break;
+				case V4L2_SLICED_CAPTION_525:
+					lcr[i] |= 6 << (4 * x);
+					break;
+				case V4L2_SLICED_VPS:
+					lcr[i] |= 9 << (4 * x);
+					break;
+				}
+			}
+		}
+
+		for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+			cx25840_write(client, i, lcr[6 + x]);
+		}
+
+		cx25840_write(client, 0x43c, 0x16);
+
+		if (is_pal) {
+			cx25840_write(client, 0x474, 0x2a);
+		} else {
+			cx25840_write(client, 0x474, 0x1a + 6);
+		}
+		break;
+	}
+
+	case VIDIOC_INT_DECODE_VBI_LINE:
+	{
+		struct v4l2_decode_vbi_line *vbi = arg;
+		u8 *p = vbi->p;
+		int id1, id2, l, err = 0;
+
+		if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+		    (p[3] != 0x55 && p[3] != 0x91)) {
+			vbi->line = vbi->type = 0;
+			break;
+		}
+
+		p += 4;
+		id1 = p[-1];
+		id2 = p[0] & 0xf;
+		l = p[2] & 0x3f;
+		l += 5;
+		p += 4;
+
+		switch (id2) {
+		case 1:
+			id2 = V4L2_SLICED_TELETEXT_B;
+			break;
+		case 4:
+			id2 = V4L2_SLICED_WSS_625;
+			break;
+		case 6:
+			id2 = V4L2_SLICED_CAPTION_525;
+			err = !odd_parity(p[0]) || !odd_parity(p[1]);
+			break;
+		case 9:
+			id2 = V4L2_SLICED_VPS;
+			if (decode_vps(p, p) != 0) {
+				err = 1;
+			}
+			break;
+		default:
+			id2 = 0;
+			err = 1;
+			break;
+		}
+
+		vbi->type = err ? 0 : id2;
+		vbi->line = err ? 0 : l;
+		vbi->is_second_field = err ? 0 : (id1 == 0x55);
+		vbi->p = p;
+		break;
+	}
+	}
+
+	return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
new file mode 100644
index 0000000..5c3f063
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -0,0 +1,85 @@
+/* cx25840 API header
+ *
+ * Copyright (C) 2003-2004 Chris Kennedy
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ */
+
+#ifndef _CX25840_H_
+#define _CX25840_H_
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern int cx25840_debug;
+
+#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
+	printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_cardtype {
+	CARDTYPE_PVR150,
+	CARDTYPE_PG600
+};
+
+enum cx25840_input {
+	CX25840_TUNER,
+	CX25840_COMPOSITE0,
+	CX25840_COMPOSITE1,
+	CX25840_SVIDEO0,
+	CX25840_SVIDEO1
+};
+
+struct cx25840_state {
+	enum cx25840_cardtype cardtype;
+	enum cx25840_input input;
+	int audio_input;
+	enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-core.c 							   */
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
+u8 cx25840_read(struct i2c_client *client, u16 addr);
+u32 cx25840_read4(struct i2c_client *client, u16 addr);
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-firmware.c                                                      */
+int cx25840_loadfw(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-audio.c                                                         */
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-vbi.c                                                           */
+void cx25840_vbi_setup(struct i2c_client *client);
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 9cce91e..99ea955 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -439,9 +439,6 @@
 	/* Put the analog decoder in standby to keep it quiet */
 	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
-	/* Put the analog decoder in standby to keep it quiet */
-	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
 	/* register everything */
 	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 32c49df..9b94f77 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -120,9 +120,6 @@
 	if (buf[1]==0xff)
 		return 0;
 
-	/* avoid fast reapeating */
-	if (buf[1]==ir->old)
-		return 0;
 	ir->old=buf[1];
 
 	/* Rearranges bits to the right order */
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index ed81934..5abfc0fb 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -221,24 +221,99 @@
 	[ 24 ] = KEY_MUTE         // mute/unmute
 };
 
+static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+	[0x00] = KEY_KP0,
+	[0x01] = KEY_KP1,
+	[0x02] = KEY_KP2,
+	[0x03] = KEY_KP3,
+	[0x04] = KEY_KP4,
+	[0x05] = KEY_KP5,
+	[0x06] = KEY_KP6,
+	[0x07] = KEY_KP7,
+	[0x08] = KEY_KP8,
+	[0x09] = KEY_KP9,
+	[0x0a] = KEY_TV,
+	[0x0b] = KEY_AUX,
+	[0x0c] = KEY_DVD,
+	[0x0d] = KEY_POWER,
+	[0x0e] = KEY_MHP,	/* labelled 'Picture' */
+	[0x0f] = KEY_AUDIO,
+	[0x10] = KEY_INFO,
+	[0x11] = KEY_F13,	/* 16:9 */
+	[0x12] = KEY_F14,	/* 14:9 */
+	[0x13] = KEY_EPG,
+	[0x14] = KEY_EXIT,
+	[0x15] = KEY_MENU,
+	[0x16] = KEY_UP,
+	[0x17] = KEY_DOWN,
+	[0x18] = KEY_LEFT,
+	[0x19] = KEY_RIGHT,
+	[0x1a] = KEY_ENTER,
+	[0x1b] = KEY_CHANNELUP,
+	[0x1c] = KEY_CHANNELDOWN,
+	[0x1d] = KEY_VOLUMEUP,
+	[0x1e] = KEY_VOLUMEDOWN,
+	[0x1f] = KEY_RED,
+	[0x20] = KEY_GREEN,
+	[0x21] = KEY_YELLOW,
+	[0x22] = KEY_BLUE,
+	[0x23] = KEY_SUBTITLE,
+	[0x24] = KEY_F15,	/* AD */
+	[0x25] = KEY_TEXT,
+	[0x26] = KEY_MUTE,
+	[0x27] = KEY_REWIND,
+	[0x28] = KEY_STOP,
+	[0x29] = KEY_PLAY,
+	[0x2a] = KEY_FASTFORWARD,
+	[0x2b] = KEY_F16,	/* chapter */
+	[0x2c] = KEY_PAUSE,
+	[0x2d] = KEY_PLAY,
+	[0x2e] = KEY_RECORD,
+	[0x2f] = KEY_F17,	/* picture in picture */
+	[0x30] = KEY_KPPLUS,	/* zoom in */
+	[0x31] = KEY_KPMINUS,	/* zoom out */
+	[0x32] = KEY_F18,	/* capture */
+	[0x33] = KEY_F19,	/* web */
+	[0x34] = KEY_EMAIL,
+	[0x35] = KEY_PHONE,
+	[0x36] = KEY_PC
+};
+
 struct IR {
 	struct bttv_sub_device  *sub;
 	struct input_dev        *input;
 	struct ir_input_state   ir;
 	char                    name[32];
 	char                    phys[32];
+
+	/* Usual gpio signalling */
+
 	u32                     mask_keycode;
 	u32                     mask_keydown;
 	u32                     mask_keyup;
-
-	int                     polling;
+	u32			polling;
 	u32                     last_gpio;
 	struct work_struct      work;
 	struct timer_list       timer;
+
+	/* RC5 gpio */
+
+	u32 rc5_gpio;
+	struct timer_list timer_end;	/* timer_end for code completion */
+	struct timer_list timer_keyup;	/* timer_end for key release */
+	u32 last_rc5;			/* last good rc5 code */
+	u32 last_bit;			/* last raw bit seen */
+	u32 code;			/* raw code under construction */
+	struct timeval base_time;	/* time of last seen code */
+	int active;			/* building raw code */
 };
 
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
+static int repeat_delay = 500;
+module_param(repeat_delay, int, 0644);
+static int repeat_period = 33;
+module_param(repeat_period, int, 0644);
 
 #define DEVNAME "ir-kbd-gpio"
 #define dprintk(fmt, arg...)	if (debug) \
@@ -254,7 +329,7 @@
 		.probe	= ir_probe,
 		.remove	= ir_remove,
 	},
-	.gpio_irq       = ir_irq,
+	.gpio_irq 	= ir_irq,
 };
 
 /* ---------------------------------------------------------------------- */
@@ -327,6 +402,173 @@
 	mod_timer(&ir->timer, timeout);
 }
 
+/* ---------------------------------------------------------------*/
+
+static int rc5_remote_gap = 885;
+module_param(rc5_remote_gap, int, 0644);
+static int rc5_key_timeout = 200;
+module_param(rc5_key_timeout, int, 0644);
+
+#define RC5_START(x)	(((x)>>12)&3)
+#define RC5_TOGGLE(x)	(((x)>>11)&1)
+#define RC5_ADDR(x)	(((x)>>6)&31)
+#define RC5_INSTR(x)	((x)&63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 rc5_decode(unsigned int code)
+{
+	unsigned int org_code = code;
+	unsigned int pair;
+	unsigned int rc5 = 0;
+	int i;
+
+	code = (code << 1) | 1;
+	for (i = 0; i < 14; ++i) {
+		pair = code & 0x3;
+		code >>= 2;
+
+		rc5 <<= 1;
+		switch (pair) {
+		case 0:
+		case 2:
+			break;
+		case 1:
+			rc5 |= 1;
+			break;
+		case 3:
+			dprintk("bad code: %x\n", org_code);
+			return 0;
+		}
+	}
+	dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+		"instr=%x\n", rc5, org_code, RC5_START(rc5),
+		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+	return rc5;
+}
+
+static int ir_rc5_irq(struct bttv_sub_device *sub)
+{
+	struct IR *ir = dev_get_drvdata(&sub->dev);
+	struct timeval tv;
+	u32 gpio;
+	u32 gap;
+	unsigned long current_jiffies, timeout;
+
+	/* read gpio port */
+	gpio = bttv_gpio_read(ir->sub->core);
+
+	/* remote IRQ? */
+	if (!(gpio & 0x20))
+		return 0;
+
+	/* get time of bit */
+	current_jiffies = jiffies;
+	do_gettimeofday(&tv);
+
+	/* avoid overflow with gap >1s */
+	if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+		gap = 200000;
+	} else {
+		gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+		    tv.tv_usec - ir->base_time.tv_usec;
+	}
+
+	/* active code => add bit */
+	if (ir->active) {
+		/* only if in the code (otherwise spurious IRQ or timer
+		   late) */
+		if (ir->last_bit < 28) {
+			ir->last_bit = (gap - rc5_remote_gap / 2) /
+			    rc5_remote_gap;
+			ir->code |= 1 << ir->last_bit;
+		}
+		/* starting new code */
+	} else {
+		ir->active = 1;
+		ir->code = 0;
+		ir->base_time = tv;
+		ir->last_bit = 0;
+
+		timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+		mod_timer(&ir->timer_end, timeout);
+	}
+
+	/* toggle GPIO pin 4 to reset the irq */
+	bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+	bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+	return 1;
+}
+
+static void ir_rc5_timer_end(unsigned long data)
+{
+	struct IR *ir = (struct IR *)data;
+	struct timeval tv;
+	unsigned long current_jiffies, timeout;
+	u32 gap;
+
+	/* get time */
+	current_jiffies = jiffies;
+	do_gettimeofday(&tv);
+
+	/* avoid overflow with gap >1s */
+	if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+		gap = 200000;
+	} else {
+		gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+		    tv.tv_usec - ir->base_time.tv_usec;
+	}
+
+	/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+	if (gap < 28000) {
+		dprintk("spurious timer_end\n");
+		return;
+	}
+
+	ir->active = 0;
+	if (ir->last_bit < 20) {
+		/* ignore spurious codes (caused by light/other remotes) */
+		dprintk("short code: %x\n", ir->code);
+	} else {
+		u32 rc5 = rc5_decode(ir->code);
+
+		/* two start bits? */
+		if (RC5_START(rc5) != 3) {
+			dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+			/* right address? */
+		} else if (RC5_ADDR(rc5) == 0x0) {
+			u32 toggle = RC5_TOGGLE(rc5);
+			u32 instr = RC5_INSTR(rc5);
+
+			/* Good code, decide if repeat/repress */
+			if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+			    instr != RC5_INSTR(ir->last_rc5)) {
+				dprintk("instruction %x, toggle %x\n", instr,
+					toggle);
+				ir_input_nokey(ir->input, &ir->ir);
+				ir_input_keydown(ir->input, &ir->ir, instr,
+						 instr);
+			}
+
+			/* Set/reset key-up timer */
+			timeout = current_jiffies + (500 + rc5_key_timeout
+						     * HZ) / 1000;
+			mod_timer(&ir->timer_keyup, timeout);
+
+			/* Save code for repeat test */
+			ir->last_rc5 = rc5;
+		}
+	}
+}
+
+static void ir_rc5_timer_keyup(unsigned long data)
+{
+	struct IR *ir = (struct IR *)data;
+
+	dprintk("key released\n");
+	ir_input_nokey(ir->input, &ir->ir);
+}
+
 /* ---------------------------------------------------------------------- */
 
 static int ir_probe(struct device *dev)
@@ -400,6 +642,12 @@
 		ir->mask_keyup   = 0x006000;
 		ir->polling      = 50; // ms
 		break;
+	case BTTV_BOARD_NEBULA_DIGITV:
+		ir_codes = ir_codes_nebula;
+		driver.any_irq = ir_rc5_irq;
+		driver.gpio_irq = NULL;
+		ir->rc5_gpio = 1;
+		 break;
 	}
 	if (NULL == ir_codes) {
 		kfree(ir);
@@ -407,9 +655,17 @@
 		return -ENODEV;
 	}
 
-	/* init hardware-specific stuff */
-	bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
-	ir->sub = sub;
+	if (ir->rc5_gpio) {
+		u32 gpio;
+		/* enable remote irq */
+		bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
+		gpio = bttv_gpio_read(sub->core);
+		bttv_gpio_write(sub->core, gpio & ~(1 << 4));
+		bttv_gpio_write(sub->core, gpio | (1 << 4));
+	} else {
+		/* init hardware-specific stuff */
+		bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+	}
 
 	/* init input device */
 	snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
@@ -417,6 +673,7 @@
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
 		 pci_name(sub->core->pci));
 
+	ir->sub = sub;
 	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
@@ -437,11 +694,25 @@
 		ir->timer.function = ir_timer;
 		ir->timer.data     = (unsigned long)ir;
 		schedule_work(&ir->work);
+	} else if (ir->rc5_gpio) {
+		/* set timer_end for code completion */
+		init_timer(&ir->timer_end);
+		ir->timer_end.function = ir_rc5_timer_end;
+		ir->timer_end.data = (unsigned long)ir;
+
+		init_timer(&ir->timer_keyup);
+		ir->timer_keyup.function = ir_rc5_timer_keyup;
+		ir->timer_keyup.data = (unsigned long)ir;
 	}
 
 	/* all done */
 	dev_set_drvdata(dev, ir);
 	input_register_device(ir->input);
+	printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+
+	/* the remote isn't as bouncy as a keyboard */
+	ir->input->rep[REP_DELAY] = repeat_delay;
+	ir->input->rep[REP_PERIOD] = repeat_period;
 
 	return 0;
 }
@@ -454,6 +725,15 @@
 		del_timer(&ir->timer);
 		flush_scheduled_work();
 	}
+	if (ir->rc5_gpio) {
+		u32 gpio;
+
+		del_timer(&ir->timer_end);
+		flush_scheduled_work();
+
+		gpio = bttv_gpio_read(ir->sub->core);
+		bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+	}
 
 	input_unregister_device(ir->input);
 	kfree(ir);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 0085567..801c736 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -183,6 +183,58 @@
 	return 1;
 }
 
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char b[4];
+	unsigned int start = 0,parity = 0,code = 0;
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(&ir->c,b,4)) {
+		dprintk(2,"read error\n");
+		return -EIO;
+	}
+
+	for (start = 0; start<4; start++) {
+		if (b[start] == 0x80) {
+			code=b[(start+3)%4];
+			parity=b[(start+2)%4];
+		}
+	}
+
+	/* Empty Request */
+	if (parity==0)
+		return 0;
+
+	/* Repeating... */
+	if (ir->old == parity)
+		return 0;
+
+
+	ir->old = parity;
+
+	/* Reduce code value to fit inside IR_KEYTAB_SIZE
+	 *
+	 * this is the only value that results in 42 unique
+	 * codes < 128
+	 */
+
+	code %= 0x88;
+
+	*ir_raw = code;
+	*ir_key = code;
+
+	dprintk(1,"Pinnacle PCTV key %02x\n", code);
+
+	return 1;
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle);
+
 /* ----------------------------------------------------------------------- */
 
 static void ir_key_poll(struct IR_i2c *ir)
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
new file mode 100644
index 0000000..0235cef
--- /dev/null
+++ b/drivers/media/video/saa7115.c
@@ -0,0 +1,1376 @@
+/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+ *
+ * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
+ * the saa7111 driver by Dave Perks.
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
+ * by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
+ * (2/17/2003)
+ *
+ * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define saa7115_dbg(fmt,arg...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+#define saa7115_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7115_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+struct saa7115_state {
+	v4l2_std_id std;
+	int input;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+	enum v4l2_chip_ident ident;
+	enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+	unsigned char reg, data;
+
+	while (*regs != 0x00) {
+		reg = *(regs++);
+		data = *(regs++);
+		if (saa7115_write(client, reg, data) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static inline int saa7115_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* If a value differs from the Hauppauge driver values, then the comment starts with
+   'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
+   Hauppauge driver sets. */
+
+static const unsigned char saa7115_init_auto_input[] = {
+	0x01, 0x48,		/* white peak control disabled */
+	0x03, 0x20,		/* was 0x30. 0x20: long vertical blanking */
+	0x04, 0x90,		/* analog gain set to 0 */
+	0x05, 0x90,		/* analog gain set to 0 */
+	0x06, 0xeb,		/* horiz sync begin = -21 */
+	0x07, 0xe0,		/* horiz sync stop = -17 */
+	0x0a, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
+	0x0b, 0x44,		/* was 0x48. decoder contrast, 0x44 is itu standard */
+	0x0c, 0x40,		/* was 0x47. decoder saturation, 0x40 is itu standard */
+	0x0d, 0x00,		/* chrominance hue control */
+	0x0f, 0x00,		/* chrominance gain control: use automicatic mode */
+	0x10, 0x06,		/* chrominance/luminance control: active adaptive combfilter */
+	0x11, 0x00,		/* delay control */
+	0x12, 0x9d,		/* RTS0 output control: VGATE */
+	0x13, 0x80,		/* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
+	0x14, 0x00,		/* analog/ADC/auto compatibility control */
+	0x18, 0x40,		/* raw data gain 0x00 = nominal */
+	0x19, 0x80,		/* raw data offset 0x80 = 0 LSB */
+	0x1a, 0x77,		/* color killer level control 0x77 = recommended */
+	0x1b, 0x42,		/* misc chroma control 0x42 = recommended */
+	0x1c, 0xa9,		/* combfilter control 0xA9 = recommended */
+	0x1d, 0x01,		/* combfilter control 0x01 = recommended */
+	0x88, 0xd0,		/* reset device */
+	0x88, 0xf0,		/* set device programmed, all in operational mode */
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_reset_scaler[] = {
+	0x87, 0x00,		/* disable I-port output */
+	0x88, 0xd0,		/* reset scaler */
+	0x88, 0xf0,		/* activate scaler */
+	0x87, 0x01,		/* enable I-port output */
+	0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates =============  */
+
+static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
+	0xcc, 0xd0,		/* hsize low (output), hor. output window size = 0x2d0 = 720 */
+	0xcd, 0x02,		/* hsize hi (output) */
+
+	/* Why not in 60hz-Land, too? */
+	0xd0, 0x01,		/* downscale = 1 */
+	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
+	0xd9, 0x04,
+	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+	0xdd, 0x02,		/* H-scaling incr chroma */
+
+	0x00, 0x00
+};
+static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
+	0xce, 0xf8,		/* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
+	0xcf, 0x00,		/* vsize hi (output) */
+
+	/* Why not in 60hz-Land, too? */
+	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
+	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
+
+	0xe0, 0x00,		/* V-scaling incr luma low */
+	0xe1, 0x04,		/* " hi */
+	0xe2, 0x00,		/* V-scaling incr chroma low */
+	0xe3, 0x04,		/* " hi */
+
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_60hz_video[] = {
+	0x80, 0x00,		/* reset tasks */
+	0x88, 0xd0,		/* reset scaler */
+
+	0x15, 0x03,		/* VGATE pulse start */
+	0x16, 0x11,		/* VGATE pulse stop */
+	0x17, 0x9c,		/* VGATE MSB and other values */
+
+	0x08, 0x68,		/* 0xBO: auto detection, 0x68 = NTSC */
+	0x0e, 0x07,		/* lots of different stuff... video autodetection is on */
+
+	0x5a, 0x06,		/* Vertical offset, standard 60hz value for ITU656 line counting */
+
+	/* Task A */
+	0x90, 0x80,		/* Task Handling Control */
+	0x91, 0x48,		/* X-port formats/config */
+	0x92, 0x40,		/* Input Ref. signal Def. */
+	0x93, 0x84,		/* I-port config */
+	0x94, 0x01,		/* hoffset low (input), 0x0002 is minimum */
+	0x95, 0x00,		/* hoffset hi (input) */
+	0x96, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
+	0x97, 0x02,		/* hsize hi (input) */
+	0x98, 0x05,		/* voffset low (input) */
+	0x99, 0x00,		/* voffset hi (input) */
+	0x9a, 0x0c,		/* vsize low (input), 0x0c = 12 */
+	0x9b, 0x00,		/* vsize hi (input) */
+	0x9c, 0xa0,		/* hsize low (output), 0x05a0 = 1440 */
+	0x9d, 0x05,		/* hsize hi (output) */
+	0x9e, 0x0c,		/* vsize low (output), 0x0c = 12 */
+	0x9f, 0x00,		/* vsize hi (output) */
+
+	/* Task B */
+	0xc0, 0x00,		/* Task Handling Control */
+	0xc1, 0x08,		/* X-port formats/config */
+	0xc2, 0x00,		/* Input Ref. signal Def. */
+	0xc3, 0x80,		/* I-port config */
+	0xc4, 0x02,		/* hoffset low (input), 0x0002 is minimum */
+	0xc5, 0x00,		/* hoffset hi (input) */
+	0xc6, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
+	0xc7, 0x02,		/* hsize hi (input) */
+	0xc8, 0x12,		/* voffset low (input), 0x12 = 18 */
+	0xc9, 0x00,		/* voffset hi (input) */
+	0xca, 0xf8,		/* vsize low (input), 0xf8 = 248 */
+	0xcb, 0x00,		/* vsize hi (input) */
+	0xcc, 0xd0,		/* hsize low (output), 0x02d0 = 720 */
+	0xcd, 0x02,		/* hsize hi (output) */
+
+	0xf0, 0xad,		/* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+	0xf1, 0x05,		/* low bit with 0xF0 */
+	0xf5, 0xad,		/* Set pulse generator register */
+	0xf6, 0x01,
+
+	0x87, 0x00,		/* Disable I-port output */
+	0x88, 0xd0,		/* reset scaler */
+	0x80, 0x20,		/* Activate only task "B", continuous mode (was 0xA0) */
+	0x88, 0xf0,		/* activate scaler */
+	0x87, 0x01,		/* Enable I-port output */
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
+	0xcc, 0xd0,		/* hsize low (output), 720 same as 60hz */
+	0xcd, 0x02,		/* hsize hi (output) */
+
+	0xd0, 0x01,		/* down scale = 1 */
+	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
+	0xd9, 0x04,
+	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+	0xdd, 0x02,		/* H-scaling incr chroma */
+
+	0x00, 0x00
+};
+static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
+	0xce, 0x20,		/* vsize low (output), 0x0120 = 288 */
+	0xcf, 0x01,		/* vsize hi (output) */
+
+	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
+	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
+
+	0xe0, 0x00,		/* V-scaling incr luma low */
+	0xe1, 0x04,		/* " hi */
+	0xe2, 0x00,		/* V-scaling incr chroma low */
+	0xe3, 0x04,		/* " hi */
+
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_video[] = {
+	0x80, 0x00,		/* reset tasks */
+	0x88, 0xd0,		/* reset scaler */
+
+	0x15, 0x37,		/* VGATE start */
+	0x16, 0x16,		/* VGATE stop */
+	0x17, 0x99,		/* VGATE MSB and other values */
+
+	0x08, 0x28,		/* 0x28 = PAL */
+	0x0e, 0x07,		/* chrominance control 1 */
+
+	0x5a, 0x03,		/* Vertical offset, standard 50hz value */
+
+	/* Task A */
+	0x90, 0x81,		/* Task Handling Control */
+	0x91, 0x48,		/* X-port formats/config */
+	0x92, 0x40,		/* Input Ref. signal Def. */
+	0x93, 0x84,		/* I-port config */
+	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
+	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+	0x94, 0x00,		/* hoffset low (input), 0x0002 is minimum */
+	0x95, 0x00,		/* hoffset hi (input) */
+	0x96, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
+	0x97, 0x02,		/* hsize hi (input) */
+	0x98, 0x03,		/* voffset low (input) */
+	0x99, 0x00,		/* voffset hi (input) */
+	0x9a, 0x12,		/* vsize low (input), 0x12 = 18 */
+	0x9b, 0x00,		/* vsize hi (input) */
+	0x9c, 0xa0,		/* hsize low (output), 0x05a0 = 1440 */
+	0x9d, 0x05,		/* hsize hi (output) */
+	0x9e, 0x12,		/* vsize low (output), 0x12 = 18 */
+	0x9f, 0x00,		/* vsize hi (output) */
+
+	/* Task B */
+	0xc0, 0x00,		/* Task Handling Control */
+	0xc1, 0x08,		/* X-port formats/config */
+	0xc2, 0x00,		/* Input Ref. signal Def. */
+	0xc3, 0x80,		/* I-port config */
+	0xc4, 0x00,		/* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
+	0xc5, 0x00,		/* hoffset hi (input) */
+	0xc6, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
+	0xc7, 0x02,		/* hsize hi (input) */
+	0xc8, 0x16,		/* voffset low (input), 0x16 = 22 */
+	0xc9, 0x00,		/* voffset hi (input) */
+	0xca, 0x20,		/* vsize low (input), 0x0120 = 288 */
+	0xcb, 0x01,		/* vsize hi (input) */
+	0xcc, 0xd0,		/* hsize low (output), 0x02d0 = 720 */
+	0xcd, 0x02,		/* hsize hi (output) */
+	0xce, 0x20,		/* vsize low (output), 0x0120 = 288 */
+	0xcf, 0x01,		/* vsize hi (output) */
+
+	0xf0, 0xb0,		/* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+	0xf1, 0x05,		/* low bit with 0xF0, (was 0x05) */
+	0xf5, 0xb0,		/* Set pulse generator register */
+	0xf6, 0x01,
+
+	0x87, 0x00,		/* Disable I-port output */
+	0x88, 0xd0,		/* reset scaler (was 0xD0) */
+	0x80, 0x20,		/* Activate only task "B" */
+	0x88, 0xf0,		/* activate scaler */
+	0x87, 0x01,		/* Enable I-port output */
+	0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates (end) =======  */
+
+static const unsigned char saa7115_cfg_vbi_on[] = {
+	0x80, 0x00,		/* reset tasks */
+	0x88, 0xd0,		/* reset scaler */
+	0x80, 0x30,		/* Activate both tasks */
+	0x88, 0xf0,		/* activate scaler */
+	0x87, 0x01,		/* Enable I-port output */
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_vbi_off[] = {
+	0x80, 0x00,		/* reset tasks */
+	0x88, 0xd0,		/* reset scaler */
+	0x80, 0x20,		/* Activate only task "B" */
+	0x88, 0xf0,		/* activate scaler */
+	0x87, 0x01,		/* Enable I-port output */
+	0x00, 0x00
+};
+
+static const unsigned char saa7115_init_misc[] = {
+	0x38, 0x03,		/* audio stuff */
+	0x39, 0x10,
+	0x3a, 0x08,
+
+	0x81, 0x01,		/* reg 0x15,0x16 define blanking window */
+	0x82, 0x00,
+	0x83, 0x01,		/* I port settings */
+	0x84, 0x20,
+	0x85, 0x21,
+	0x86, 0xc5,
+	0x87, 0x01,
+
+	/* Task A */
+	0xa0, 0x01,		/* down scale = 1 */
+	0xa1, 0x00,		/* prescale accumulation length = 1 */
+	0xa2, 0x00,		/* dc gain and fir prefilter control */
+	0xa4, 0x80,		/* Lum Brightness, nominal value = 0x80 */
+	0xa5, 0x40,		/* Lum contrast, nominal value = 0x40 */
+	0xa6, 0x40,		/* Chroma satur. nominal value = 0x80 */
+	0xa8, 0x00,		/* hor lum scaling 0x0200 = 2 zoom */
+	0xa9, 0x02,		/* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+	0xaa, 0x00,		/* H-phase offset Luma = 0 */
+	0xac, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+	0xad, 0x01,		/* H-scaling incr chroma */
+	0xae, 0x00,		/* H-phase offset chroma. must be offset luma / 2 */
+
+	0xb0, 0x00,		/* V-scaling incr luma low */
+	0xb1, 0x04,		/* " hi */
+	0xb2, 0x00,		/* V-scaling incr chroma low */
+	0xb3, 0x04,		/* " hi */
+	0xb4, 0x01,		/* V-scaling mode control */
+	0xb8, 0x00,		/* V-phase offset chroma 00 */
+	0xb9, 0x00,		/* V-phase offset chroma 01 */
+	0xba, 0x00,		/* V-phase offset chroma 10 */
+	0xbb, 0x00,		/* V-phase offset chroma 11 */
+	0xbc, 0x00,		/* V-phase offset luma 00 */
+	0xbd, 0x00,		/* V-phase offset luma 01 */
+	0xbe, 0x00,		/* V-phase offset luma 10 */
+	0xbf, 0x00,		/* V-phase offset luma 11 */
+
+	/* Task B */
+	0xd0, 0x01,		/* down scale = 1 */
+	0xd1, 0x00,		/* prescale accumulation length = 1 */
+	0xd2, 0x00,		/* dc gain and fir prefilter control */
+	0xd4, 0x80,		/* Lum Brightness, nominal value = 0x80 */
+	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
+	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
+	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
+	0xd9, 0x04,
+	0xda, 0x00,		/* H-phase offset Luma = 0 */
+	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+	0xdd, 0x02,		/* H-scaling incr chroma */
+	0xde, 0x00,		/* H-phase offset chroma. must be offset luma / 2 */
+
+	0xe0, 0x00,		/* V-scaling incr luma low */
+	0xe1, 0x04,		/* " hi */
+	0xe2, 0x00,		/* V-scaling incr chroma low */
+	0xe3, 0x04,		/* " hi */
+	0xe4, 0x01,		/* V-scaling mode control */
+	0xe8, 0x00,		/* V-phase offset chroma 00 */
+	0xe9, 0x00,		/* V-phase offset chroma 01 */
+	0xea, 0x00,		/* V-phase offset chroma 10 */
+	0xeb, 0x00,		/* V-phase offset chroma 11 */
+	0xec, 0x00,		/* V-phase offset luma 00 */
+	0xed, 0x00,		/* V-phase offset luma 01 */
+	0xee, 0x00,		/* V-phase offset luma 10 */
+	0xef, 0x00,		/* V-phase offset luma 11 */
+
+	0xf2, 0x50,		/* crystal clock = 24.576 MHz, target = 27MHz */
+	0xf3, 0x46,
+	0xf4, 0x00,
+	0xf7, 0x4b,		/* not the recommended settings! */
+	0xf8, 0x00,
+	0xf9, 0x4b,
+	0xfa, 0x00,
+	0xfb, 0x4b,
+	0xff, 0x88,		/* PLL2 lock detection settings: 71 lines 50% phase error */
+
+	/* Turn off VBI */
+	0x40, 0x20,             /* No framing code errors allowed. */
+	0x41, 0xff,
+	0x42, 0xff,
+	0x43, 0xff,
+	0x44, 0xff,
+	0x45, 0xff,
+	0x46, 0xff,
+	0x47, 0xff,
+	0x48, 0xff,
+	0x49, 0xff,
+	0x4a, 0xff,
+	0x4b, 0xff,
+	0x4c, 0xff,
+	0x4d, 0xff,
+	0x4e, 0xff,
+	0x4f, 0xff,
+	0x50, 0xff,
+	0x51, 0xff,
+	0x52, 0xff,
+	0x53, 0xff,
+	0x54, 0xff,
+	0x55, 0xff,
+	0x56, 0xff,
+	0x57, 0xff,
+	0x58, 0x40,
+	0x59, 0x47,
+	0x5b, 0x83,
+	0x5d, 0xbd,
+	0x5e, 0x35,
+
+	0x02, 0x84,		/* input tuner -> input 4, amplifier active */
+	0x09, 0x53,		/* 0x53, was 0x56 for 60hz. luminance control */
+
+	0x80, 0x20,		/* enable task B */
+	0x88, 0xd0,
+	0x88, 0xf0,
+	0x00, 0x00
+};
+
+/* ============== SAA7715 AUDIO settings ============= */
+
+/* 48.0 kHz */
+static const unsigned char saa7115_cfg_48_audio[] = {
+	0x34, 0xce,
+	0x35, 0xfb,
+	0x36, 0x30,
+	0x00, 0x00
+};
+
+/* 44.1 kHz */
+static const unsigned char saa7115_cfg_441_audio[] = {
+	0x34, 0xf2,
+	0x35, 0x00,
+	0x36, 0x2d,
+	0x00, 0x00
+};
+
+/* 32.0 kHz */
+static const unsigned char saa7115_cfg_32_audio[] = {
+	0x34, 0xdf,
+	0x35, 0xa7,
+	0x36, 0x20,
+	0x00, 0x00
+};
+
+/* 48.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_48_audio[] = {
+	0x30, 0xcd,
+	0x31, 0x20,
+	0x32, 0x03,
+	0x00, 0x00
+};
+
+/* 48.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_48_audio[] = {
+	0x30, 0x00,
+	0x31, 0xc0,
+	0x32, 0x03,
+	0x00, 0x00
+};
+
+/* 44.1 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_441_audio[] = {
+	0x30, 0xbc,
+	0x31, 0xdf,
+	0x32, 0x02,
+	0x00, 0x00
+};
+
+/* 44.1 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_441_audio[] = {
+	0x30, 0x00,
+	0x31, 0x72,
+	0x32, 0x03,
+	0x00, 0x00
+};
+
+/* 32.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_32_audio[] = {
+	0x30, 0xde,
+	0x31, 0x15,
+	0x32, 0x02,
+	0x00, 0x00
+};
+
+/* 32.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_32_audio[] = {
+	0x30, 0x00,
+	0x31, 0x80,
+	0x32, 0x02,
+	0x00, 0x00
+};
+
+static int saa7115_odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static int saa7115_decode_vps(u8 * dst, u8 * p)
+{
+	static const u8 biphase_tbl[] = {
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+	};
+	int i;
+	u8 c, err = 0;
+
+	for (i = 0; i < 2 * 13; i += 2) {
+		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+		c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
+		dst[i / 2] = c;
+	}
+	return err & 0xf0;
+}
+
+static int saa7115_decode_wss(u8 * p)
+{
+	static const int wss_bits[8] = {
+		0, 0, 0, 1, 0, 1, 1, 1
+	};
+	unsigned char parity;
+	int wss = 0;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		int b1 = wss_bits[p[i] & 7];
+		int b2 = wss_bits[(p[i] >> 3) & 7];
+
+		if (b1 == b2)
+			return -1;
+		wss |= b2 << i;
+	}
+	parity = wss & 15;
+	parity ^= parity >> 2;
+	parity ^= parity >> 1;
+
+	if (!(parity & 1))
+		return -1;
+
+	return wss;
+}
+
+
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+
+	saa7115_dbg("set audio clock freq: %d\n", freq);
+	switch (freq) {
+		case V4L2_AUDCLK_32_KHZ:
+			saa7115_writeregs(client, saa7115_cfg_32_audio);
+			if (state->std & V4L2_STD_525_60) {
+				saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
+			} else {
+				saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
+			}
+			break;
+		case V4L2_AUDCLK_441_KHZ:
+			saa7115_writeregs(client, saa7115_cfg_441_audio);
+			if (state->std & V4L2_STD_525_60) {
+				saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
+			} else {
+				saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
+			}
+			break;
+		case V4L2_AUDCLK_48_KHZ:
+			saa7115_writeregs(client, saa7115_cfg_48_audio);
+			if (state->std & V4L2_STD_525_60) {
+				saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+			} else {
+				saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
+			}
+			break;
+		default:
+			saa7115_dbg("invalid audio setting %d\n", freq);
+			return -EINVAL;
+	}
+	state->audclk_freq = freq;
+	return 0;
+}
+
+static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if (ctrl->value < 0 || ctrl->value > 255) {
+			saa7115_err("invalid brightness setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->bright = ctrl->value;
+		saa7115_write(client, 0x0a, state->bright);
+		break;
+
+	case V4L2_CID_CONTRAST:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			saa7115_err("invalid contrast setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->contrast = ctrl->value;
+		saa7115_write(client, 0x0b, state->contrast);
+		break;
+
+	case V4L2_CID_SATURATION:
+		if (ctrl->value < 0 || ctrl->value > 127) {
+			saa7115_err("invalid saturation setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->sat = ctrl->value;
+		saa7115_write(client, 0x0c, state->sat);
+		break;
+
+	case V4L2_CID_HUE:
+		if (ctrl->value < -127 || ctrl->value > 127) {
+			saa7115_err("invalid hue setting %d\n", ctrl->value);
+			return -ERANGE;
+		}
+
+		state->hue = ctrl->value;
+		saa7115_write(client, 0x0d, state->hue);
+		break;
+	}
+
+	return 0;
+}
+
+static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = state->bright;
+		break;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = state->contrast;
+		break;
+	case V4L2_CID_SATURATION:
+		ctrl->value = state->sat;
+		break;
+	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	int taskb = saa7115_read(client, 0x80) & 0x10;
+
+	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
+	if (std & V4L2_STD_525_60) {
+		saa7115_dbg("decoder set standard 60 Hz\n");
+		saa7115_writeregs(client, saa7115_cfg_60hz_video);
+	} else {
+		saa7115_dbg("decoder set standard 50 Hz\n");
+		saa7115_writeregs(client, saa7115_cfg_50hz_video);
+	}
+
+	state->std = std;
+
+	/* restart task B if needed */
+	if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+		saa7115_writeregs(client, saa7115_cfg_vbi_on);
+	}
+
+	/* switch audio mode too! */
+	saa7115_set_audio_clock_freq(client, state->audclk_freq);
+}
+
+static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+
+	return state->std;
+}
+
+static void saa7115_log_status(struct i2c_client *client)
+{
+	static const char * const audclk_freq_strs[] = {
+		"44.1 kHz",
+		"48 kHz",
+		"32 kHz"
+	};
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	int reg1e, reg1f;
+	int signalOk;
+	int vcr;
+
+	saa7115_info("Audio frequency: %s\n", audclk_freq_strs[state->audclk_freq]);
+	if (client->name[6] == '4') {
+		/* status for the saa7114 */
+		reg1f = saa7115_read(client, 0x1f);
+		signalOk = (reg1f & 0xc1) == 0x81;
+		saa7115_info("Video signal:    %s\n", signalOk ? "ok" : "bad");
+		saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+		return;
+	}
+
+	/* status for the saa7115 */
+	reg1e = saa7115_read(client, 0x1e);
+	reg1f = saa7115_read(client, 0x1f);
+
+	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+	vcr = !(reg1f & 0x10);
+
+	saa7115_info("Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+	saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+
+	switch (reg1e & 0x03) {
+		case 1:
+			saa7115_info("Detected format: NTSC\n");
+			break;
+		case 2:
+			saa7115_info("Detected format: PAL\n");
+			break;
+		case 3:
+			saa7115_info("Detected format: SECAM\n");
+			break;
+		default:
+			saa7115_info("Detected format: BW/No color\n");
+			break;
+	}
+}
+
+/* setup the sliced VBI lcr registers according to the sliced VBI format */
+static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	int is_50hz = (state->std & V4L2_STD_625_50);
+	u8 lcr[24];
+	int i, x;
+
+	/* saa7114 doesn't yet support VBI */
+	if (state->ident == V4L2_IDENT_SAA7114)
+		return;
+
+	for (i = 0; i <= 23; i++)
+		lcr[i] = 0xff;
+
+	if (fmt->service_set == 0) {
+		/* raw VBI */
+		if (is_50hz)
+			for (i = 6; i <= 23; i++)
+				lcr[i] = 0xdd;
+		else
+			for (i = 10; i <= 21; i++)
+				lcr[i] = 0xdd;
+	} else {
+		/* sliced VBI */
+		/* first clear lines that cannot be captured */
+		if (is_50hz) {
+			for (i = 0; i <= 5; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+		}
+		else {
+			for (i = 0; i <= 9; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+			for (i = 22; i <= 23; i++)
+				fmt->service_lines[0][i] =
+					fmt->service_lines[1][i] = 0;
+		}
+
+		/* Now set the lcr values according to the specified service */
+		for (i = 6; i <= 23; i++) {
+			lcr[i] = 0;
+			for (x = 0; x <= 1; x++) {
+				switch (fmt->service_lines[1-x][i]) {
+					case 0:
+						lcr[i] |= 0xf << (4 * x);
+						break;
+					case V4L2_SLICED_TELETEXT_B:
+						lcr[i] |= 1 << (4 * x);
+						break;
+					case V4L2_SLICED_CAPTION_525:
+						lcr[i] |= 4 << (4 * x);
+						break;
+					case V4L2_SLICED_WSS_625:
+						lcr[i] |= 5 << (4 * x);
+						break;
+					case V4L2_SLICED_VPS:
+						lcr[i] |= 7 << (4 * x);
+						break;
+				}
+			}
+		}
+	}
+
+	/* write the lcr registers */
+	for (i = 2; i <= 23; i++) {
+		saa7115_write(client, i - 2 + 0x41, lcr[i]);
+	}
+
+	/* enable/disable raw VBI capturing */
+	saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
+}
+
+static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+	static u16 lcr2vbi[] = {
+		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
+		0, V4L2_SLICED_CAPTION_525,	/* 4 */
+		V4L2_SLICED_WSS_625, 0,		/* 5 */
+		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */
+		0, 0, 0, 0
+	};
+	struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
+	int i;
+
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+	memset(sliced, 0, sizeof(*sliced));
+	/* done if using raw VBI */
+	if (saa7115_read(client, 0x80) & 0x10)
+		return 0;
+	for (i = 2; i <= 23; i++) {
+		u8 v = saa7115_read(client, i - 2 + 0x41);
+
+		sliced->service_lines[0][i] = lcr2vbi[v >> 4];
+		sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
+		sliced->service_set |=
+			sliced->service_lines[0][i] | sliced->service_lines[1][i];
+	}
+	return 0;
+}
+
+static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct v4l2_pix_format *pix;
+	int HPSC, HFSC;
+	int VSCY, Vsrc;
+	int is_50hz = state->std & V4L2_STD_625_50;
+
+	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+		saa7115_set_lcr(client, &fmt->fmt.sliced);
+		return 0;
+	}
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	pix = &(fmt->fmt.pix);
+
+	saa7115_dbg("decoder set size\n");
+
+	/* FIXME need better bounds checking here */
+	if ((pix->width < 1) || (pix->width > 1440))
+		return -EINVAL;
+	if ((pix->height < 1) || (pix->height > 960))
+		return -EINVAL;
+
+	/* probably have a valid size, let's set it */
+	/* Set output width/height */
+	/* width */
+	saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
+	saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
+	/* height */
+	saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
+	saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
+
+	/* Scaling settings */
+	/* Hprescaler is floor(inres/outres) */
+	/* FIXME hardcoding input res */
+	if (pix->width != 720) {
+		HPSC = (int)(720 / pix->width);
+		/* 0 is not allowed (div. by zero) */
+		HPSC = HPSC ? HPSC : 1;
+		HFSC = (int)((1024 * 720) / (HPSC * pix->width));
+
+		saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+		/* FIXME hardcodes to "Task B"
+		 * write H prescaler integer */
+		saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
+
+		/* write H fine-scaling (luminance) */
+		saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
+		saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
+		/* write H fine-scaling (chrominance)
+		 * must be lum/2, so i'll just bitshift :) */
+		saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
+		saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
+	} else {
+		if (is_50hz) {
+			saa7115_dbg("Setting full 50hz width\n");
+			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
+		} else {
+			saa7115_dbg("Setting full 60hz width\n");
+			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+		}
+	}
+
+	Vsrc = is_50hz ? 576 : 480;
+
+	if (pix->height != Vsrc) {
+		VSCY = (int)((1024 * Vsrc) / pix->height);
+		saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+		/* Correct Contrast and Luminance */
+		saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
+		saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
+
+		/* write V fine-scaling (luminance) */
+		saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
+		saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
+		/* write V fine-scaling (chrominance) */
+		saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
+		saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
+	} else {
+		if (is_50hz) {
+			saa7115_dbg("Setting full 50Hz height\n");
+			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
+		} else {
+			saa7115_dbg("Setting full 60hz height\n");
+			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+		}
+	}
+
+	saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+	return 0;
+}
+
+/* Decode the sliced VBI data stream as created by the saa7115.
+   The format is described in the saa7115 datasheet in Tables 25 and 26
+   and in Figure 33.
+   The current implementation uses SAV/EAV codes and not the ancillary data
+   headers. The vbi->p pointer points to the SDID byte right after the SAV
+   code. */
+static void saa7115_decode_vbi_line(struct i2c_client *client,
+				    struct v4l2_decode_vbi_line *vbi)
+{
+	static const char vbi_no_data_pattern[] = {
+		0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
+	};
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	u8 *p = vbi->p;
+	u32 wss;
+	int id1, id2;   /* the ID1 and ID2 bytes from the internal header */
+
+	vbi->type = 0;  /* mark result as a failure */
+	id1 = p[2];
+	id2 = p[3];
+	/* Note: the field bit is inverted for 60 Hz video */
+	if (state->std & V4L2_STD_525_60)
+		id1 ^= 0x40;
+
+	/* Skip internal header, p now points to the start of the payload */
+	p += 4;
+	vbi->p = p;
+
+	/* calculate field and line number of the VBI packet (1-23) */
+	vbi->is_second_field = ((id1 & 0x40) != 0);
+	vbi->line = (id1 & 0x3f) << 3;
+	vbi->line |= (id2 & 0x70) >> 4;
+
+	/* Obtain data type */
+	id2 &= 0xf;
+
+	/* If the VBI slicer does not detect any signal it will fill up
+	   the payload buffer with 0xa0 bytes. */
+	if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
+		return;
+
+	/* decode payloads */
+	switch (id2) {
+	case 1:
+		vbi->type = V4L2_SLICED_TELETEXT_B;
+		break;
+	case 4:
+		if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
+			return;
+		vbi->type = V4L2_SLICED_CAPTION_525;
+		break;
+	case 5:
+		wss = saa7115_decode_wss(p);
+		if (wss == -1)
+			return;
+		p[0] = wss & 0xff;
+		p[1] = wss >> 8;
+		vbi->type = V4L2_SLICED_WSS_625;
+		break;
+	case 7:
+		if (saa7115_decode_vps(p, p) != 0)
+			return;
+		vbi->type = V4L2_SLICED_VPS;
+		break;
+	default:
+		return;
+	}
+}
+
+/* ============ SAA7115 AUDIO settings (end) ============= */
+
+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct saa7115_state *state = i2c_get_clientdata(client);
+	int *iarg = arg;
+
+	/* ioctls to allow direct access to the saa7115 registers for testing */
+	switch (cmd) {
+	case VIDIOC_S_FMT:
+		return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
+
+	case VIDIOC_G_FMT:
+		return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
+
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *vt = arg;
+		int status;
+
+		status = saa7115_read(client, 0x1f);
+
+		saa7115_dbg("status: 0x%02x\n", status);
+		vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+		break;
+	}
+
+	case VIDIOC_LOG_STATUS:
+		saa7115_log_status(client);
+		break;
+
+	case VIDIOC_G_CTRL:
+		return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+	case VIDIOC_S_CTRL:
+		return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+	case VIDIOC_G_STD:
+		*(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
+		break;
+
+	case VIDIOC_S_STD:
+		saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
+		break;
+
+	case VIDIOC_G_INPUT:
+		*(int *)arg = state->input;
+		break;
+
+	case VIDIOC_S_INPUT:
+		saa7115_dbg("decoder set input %d\n", *iarg);
+		/* inputs from 0-9 are available */
+		if (*iarg < 0 || *iarg > 9) {
+			return -EINVAL;
+		}
+
+		if (state->input == *iarg)
+			break;
+		saa7115_dbg("now setting %s input\n",
+			*iarg >= 6 ? "S-Video" : "Composite");
+		state->input = *iarg;
+
+		/* select mode */
+		saa7115_write(client, 0x02,
+			      (saa7115_read(client, 0x02) & 0xf0) |
+			       state->input);
+
+		/* bypass chrominance trap for modes 6..9 */
+		saa7115_write(client, 0x09,
+			      (saa7115_read(client, 0x09) & 0x7f) |
+			       (state->input < 6 ? 0x0 : 0x80));
+		break;
+
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF:
+		saa7115_dbg("%s output\n",
+			(cmd == VIDIOC_STREAMON) ? "enable" : "disable");
+
+		if (state->enable != (cmd == VIDIOC_STREAMON)) {
+			state->enable = (cmd == VIDIOC_STREAMON);
+			saa7115_write(client, 0x87, state->enable);
+		}
+		break;
+
+	case VIDIOC_INT_DECODE_VBI_LINE:
+		saa7115_decode_vbi_line(client, arg);
+		break;
+
+	case VIDIOC_INT_RESET:
+		saa7115_dbg("decoder RESET\n");
+		saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+		break;
+
+	case VIDIOC_INT_G_VBI_DATA:
+	{
+		struct v4l2_sliced_vbi_data *data = arg;
+
+		switch (data->id) {
+		case V4L2_SLICED_WSS_625:
+			if (saa7115_read(client, 0x6b) & 0xc0)
+				return -EIO;
+			data->data[0] = saa7115_read(client, 0x6c);
+			data->data[1] = saa7115_read(client, 0x6d);
+			return 0;
+		case V4L2_SLICED_CAPTION_525:
+			if (data->field == 0) {
+				/* CC */
+				if (saa7115_read(client, 0x66) & 0xc0)
+					return -EIO;
+				data->data[0] = saa7115_read(client, 0x67);
+				data->data[1] = saa7115_read(client, 0x68);
+				return 0;
+			}
+			/* XDS */
+			if (saa7115_read(client, 0x66) & 0x30)
+				return -EIO;
+			data->data[0] = saa7115_read(client, 0x69);
+			data->data[1] = saa7115_read(client, 0x6a);
+			return 0;
+		default:
+			return -EINVAL;
+		}
+		break;
+	}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_INT_G_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+			return -EINVAL;
+		reg->val = saa7115_read(client, reg->reg & 0xff);
+		break;
+	}
+
+	case VIDIOC_INT_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
+		break;
+	}
+#endif
+
+	case VIDIOC_INT_G_CHIP_IDENT:
+		*iarg = state->ident;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7115;
+
+static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct saa7115_state *state;
+	u8 chip_id;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_saa7115;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+
+	saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+
+	saa7115_write(client, 0, 5);
+	chip_id = saa7115_read(client, 0) & 0x0f;
+	if (chip_id != 4 && chip_id != 5) {
+		saa7115_dbg("saa7115 not found\n");
+		kfree(client);
+		return 0;
+	}
+	if (chip_id == 4) {
+		snprintf(client->name, sizeof(client->name) - 1, "saa7114");
+	}
+	saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+
+	state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
+	i2c_set_clientdata(client, state);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	memset(state, 0, sizeof(struct saa7115_state));
+	state->std = V4L2_STD_NTSC;
+	state->input = -1;
+	state->enable = 1;
+	state->bright = 128;
+	state->contrast = 64;
+	state->hue = 0;
+	state->sat = 64;
+	state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+	state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+
+	saa7115_dbg("writing init values\n");
+
+	/* init to 60hz/48khz */
+	saa7115_writeregs(client, saa7115_init_auto_input);
+	saa7115_writeregs(client, saa7115_init_misc);
+	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+	saa7115_writeregs(client, saa7115_cfg_60hz_video);
+	saa7115_writeregs(client, saa7115_cfg_48_audio);
+	saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+	saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+
+	i2c_attach_client(client);
+
+	saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+		saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
+
+	return 0;
+}
+
+static int saa7115_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+	if (adapter->id == I2C_HW_B_BT848)
+#endif
+		return i2c_probe(adapter, &addr_data, &saa7115_attach);
+	return 0;
+}
+
+static int saa7115_detach(struct i2c_client *client)
+{
+	struct saa7115_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_saa7115 = {
+	.name = "saa7115",
+	.id = I2C_DRIVERID_SAA711X,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = saa7115_probe,
+	.detach_client = saa7115_detach,
+	.command = saa7115_command,
+	.owner = THIS_MODULE,
+};
+
+
+static int __init saa7115_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver_saa7115);
+}
+
+static void __exit saa7115_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver_saa7115);
+}
+
+module_init(saa7115_init_module);
+module_exit(saa7115_cleanup_module);
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 9aa8827..25b30f3 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -36,7 +36,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
new file mode 100644
index 0000000..843431f
--- /dev/null
+++ b/drivers/media/video/saa7127.c
@@ -0,0 +1,849 @@
+/*
+ * saa7127 - Philips SAA7127/SAA7129 video encoder driver
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * from the ivtv Project
+ *
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * Dual output support:
+ * Copyright (C) 2004 Eric Varsanyi
+ *
+ * NTSC Tuning and 7.5 IRE Setup
+ * Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+ *
+ * VBI additions & cleanup:
+ * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: the saa7126 is identical to the saa7127, and the saa7128 is
+ * identical to the saa7129, except that the saa7126 and saa7128 have
+ * macrovision anti-taping support. This driver will almost certainly
+ * work find for those chips, except of course for the missing anti-taping
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+static int debug = 0;
+static int test_image = 0;
+
+MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0644);
+module_param(test_image, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+MODULE_PARM_DESC(test_image, "test_image (0-1)");
+
+#define saa7127_dbg(fmt, arg...) \
+	do { \
+		if (debug >= 1) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+/* High volume debug. Use with care. */
+#define saa7127_dbg_highvol(fmt, arg...) \
+	do { \
+		if (debug == 2) \
+			printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
+	} while (0)
+
+#define saa7127_err(fmt, arg...) do { \
+	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7127_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS                           0x00
+#define SAA7127_REG_WIDESCREEN_CONFIG                0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE                0x27
+#define SAA7127_REG_BURST_START                      0x28
+#define SAA7127_REG_BURST_END                        0x29
+#define SAA7127_REG_COPYGEN_0                        0x2a
+#define SAA7127_REG_COPYGEN_1                        0x2b
+#define SAA7127_REG_COPYGEN_2                        0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL              0x2d
+#define SAA7127_REG_GAIN_LUMINANCE_RGB               0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB               0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1             0x3a
+#define SAA7129_REG_FADE_KEY_COL2		     0x4f
+#define SAA7127_REG_CHROMA_PHASE                     0x5a
+#define SAA7127_REG_GAINU                            0x5b
+#define SAA7127_REG_GAINV                            0x5c
+#define SAA7127_REG_BLACK_LEVEL                      0x5d
+#define SAA7127_REG_BLANKING_LEVEL                   0x5e
+#define SAA7127_REG_VBI_BLANKING                     0x5f
+#define SAA7127_REG_DAC_CONTROL                      0x61
+#define SAA7127_REG_BURST_AMP                        0x62
+#define SAA7127_REG_SUBC3                            0x63
+#define SAA7127_REG_SUBC2                            0x64
+#define SAA7127_REG_SUBC1                            0x65
+#define SAA7127_REG_SUBC0                            0x66
+#define SAA7127_REG_LINE_21_ODD_0                    0x67
+#define SAA7127_REG_LINE_21_ODD_1                    0x68
+#define SAA7127_REG_LINE_21_EVEN_0                   0x69
+#define SAA7127_REG_LINE_21_EVEN_1                   0x6a
+#define SAA7127_REG_RCV_PORT_CONTROL                 0x6b
+#define SAA7127_REG_VTRIG                            0x6c
+#define SAA7127_REG_HTRIG_HI                         0x6d
+#define SAA7127_REG_MULTI                            0x6e
+#define SAA7127_REG_CLOSED_CAPTION                   0x6f
+#define SAA7127_REG_RCV2_OUTPUT_START                0x70
+#define SAA7127_REG_RCV2_OUTPUT_END                  0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS                 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START              0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH       0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT        0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START           0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END             0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START          0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END            0x79
+#define SAA7127_REG_FIRST_ACTIVE                     0x7a
+#define SAA7127_REG_LAST_ACTIVE                      0x7b
+#define SAA7127_REG_MSB_VERTICAL                     0x7c
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0            0x7e
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1            0x7f
+
+/*
+ **********************************************************************
+ *
+ *  Arrays with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value {
+	unsigned char reg;
+	unsigned char value;
+};
+
+static const struct i2c_reg_value saa7129_init_config_extra[] = {
+	{ SAA7127_REG_OUTPUT_PORT_CONTROL, 		0x38 },
+	{ SAA7127_REG_VTRIG, 				0xfa },
+};
+
+static const struct i2c_reg_value saa7127_init_config_common[] = {
+	{ SAA7127_REG_WIDESCREEN_CONFIG, 		0x0d },
+	{ SAA7127_REG_WIDESCREEN_ENABLE, 		0x00 },
+	{ SAA7127_REG_COPYGEN_0, 			0x77 },
+	{ SAA7127_REG_COPYGEN_1, 			0x41 },
+	{ SAA7127_REG_COPYGEN_2, 			0x00 },	/* Macrovision enable/disable */
+	{ SAA7127_REG_OUTPUT_PORT_CONTROL, 		0x9e },
+	{ SAA7127_REG_GAIN_LUMINANCE_RGB, 		0x00 },
+	{ SAA7127_REG_GAIN_COLORDIFF_RGB, 		0x00 },
+	{ SAA7127_REG_INPUT_PORT_CONTROL_1, 		0x80 },	/* for color bars */
+	{ SAA7127_REG_LINE_21_ODD_0, 			0x77 },
+	{ SAA7127_REG_LINE_21_ODD_1, 			0x41 },
+	{ SAA7127_REG_LINE_21_EVEN_0, 			0x88 },
+	{ SAA7127_REG_LINE_21_EVEN_1, 			0x41 },
+	{ SAA7127_REG_RCV_PORT_CONTROL, 		0x12 },
+	{ SAA7127_REG_VTRIG, 				0xf9 },
+	{ SAA7127_REG_HTRIG_HI, 			0x00 },
+	{ SAA7127_REG_RCV2_OUTPUT_START, 		0x41 },
+	{ SAA7127_REG_RCV2_OUTPUT_END, 			0xc3 },
+	{ SAA7127_REG_RCV2_OUTPUT_MSBS, 		0x00 },
+	{ SAA7127_REG_TTX_REQUEST_H_START, 		0x3e },
+	{ SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 	0xb8 },
+	{ SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT,  	0x03 },
+	{ SAA7127_REG_TTX_ODD_REQ_VERT_START, 		0x15 },
+	{ SAA7127_REG_TTX_ODD_REQ_VERT_END, 		0x16 },
+	{ SAA7127_REG_TTX_EVEN_REQ_VERT_START, 		0x15 },
+	{ SAA7127_REG_TTX_EVEN_REQ_VERT_END, 		0x16 },
+	{ SAA7127_REG_FIRST_ACTIVE, 			0x1a },
+	{ SAA7127_REG_LAST_ACTIVE, 			0x01 },
+	{ SAA7127_REG_MSB_VERTICAL, 			0xc0 },
+	{ SAA7127_REG_DISABLE_TTX_LINE_LO_0, 		0x00 },
+	{ SAA7127_REG_DISABLE_TTX_LINE_LO_1, 		0x00 },
+	{ 0, 0 }
+};
+
+#define SAA7127_60HZ_DAC_CONTROL 0x15
+static const struct i2c_reg_value saa7127_init_config_60hz[] = {
+	{ SAA7127_REG_BURST_START, 			0x19 },
+	/* BURST_END is also used as a chip ID in saa7127_detect_client */
+	{ SAA7127_REG_BURST_END, 			0x1d },
+	{ SAA7127_REG_CHROMA_PHASE, 			0xa3 },
+	{ SAA7127_REG_GAINU, 				0x98 },
+	{ SAA7127_REG_GAINV, 				0xd3 },
+	{ SAA7127_REG_BLACK_LEVEL, 			0x39 },
+	{ SAA7127_REG_BLANKING_LEVEL, 			0x2e },
+	{ SAA7127_REG_VBI_BLANKING, 			0x2e },
+	{ SAA7127_REG_DAC_CONTROL, 			0x15 },
+	{ SAA7127_REG_BURST_AMP, 			0x4d },
+	{ SAA7127_REG_SUBC3, 				0x1f },
+	{ SAA7127_REG_SUBC2, 				0x7c },
+	{ SAA7127_REG_SUBC1, 				0xf0 },
+	{ SAA7127_REG_SUBC0, 				0x21 },
+	{ SAA7127_REG_MULTI, 				0x90 },
+	{ SAA7127_REG_CLOSED_CAPTION, 			0x11 },
+	{ 0, 0 }
+};
+
+#define SAA7127_50HZ_DAC_CONTROL 0x02
+struct i2c_reg_value saa7127_init_config_50hz[] = {
+	{ SAA7127_REG_BURST_START, 			0x21 },
+	/* BURST_END is also used as a chip ID in saa7127_detect_client */
+	{ SAA7127_REG_BURST_END, 			0x1d },
+	{ SAA7127_REG_CHROMA_PHASE, 			0x3f },
+	{ SAA7127_REG_GAINU, 				0x7d },
+	{ SAA7127_REG_GAINV, 				0xaf },
+	{ SAA7127_REG_BLACK_LEVEL, 			0x33 },
+	{ SAA7127_REG_BLANKING_LEVEL, 			0x35 },
+	{ SAA7127_REG_VBI_BLANKING, 			0x35 },
+	{ SAA7127_REG_DAC_CONTROL, 			0x02 },
+	{ SAA7127_REG_BURST_AMP, 			0x2f },
+	{ SAA7127_REG_SUBC3, 				0xcb },
+	{ SAA7127_REG_SUBC2, 				0x8a },
+	{ SAA7127_REG_SUBC1, 				0x09 },
+	{ SAA7127_REG_SUBC0, 				0x2a },
+	{ SAA7127_REG_MULTI, 				0xa0 },
+	{ SAA7127_REG_CLOSED_CAPTION, 			0x00 },
+	{ 0, 0 }
+};
+
+/* Enumeration for the Supported input types */
+enum saa7127_input_type {
+	SAA7127_INPUT_TYPE_NORMAL,
+	SAA7127_INPUT_TYPE_TEST_IMAGE
+};
+
+/* Enumeration for the Supported Output signal types */
+enum saa7127_output_type {
+	SAA7127_OUTPUT_TYPE_BOTH,
+	SAA7127_OUTPUT_TYPE_COMPOSITE,
+	SAA7127_OUTPUT_TYPE_SVIDEO,
+	SAA7127_OUTPUT_TYPE_RGB,
+	SAA7127_OUTPUT_TYPE_YUV_C,
+	SAA7127_OUTPUT_TYPE_YUV_V
+};
+
+/*
+ **********************************************************************
+ *
+ *  Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127_state {
+	v4l2_std_id std;
+	enum v4l2_chip_ident ident;
+	enum saa7127_input_type input_type;
+	enum saa7127_output_type output_type;
+	int video_enable;
+	int wss_enable;
+	u16 wss_mode;
+	int cc_enable;
+	u16 cc_data;
+	int xds_enable;
+	u16 xds_data;
+	int vps_enable;
+	u8 vps_data[5];
+	u8 reg_2d;
+	u8 reg_3a;
+	u8 reg_3a_cb;   /* colorbar bit */
+	u8 reg_61;
+};
+
+static const char * const output_strs[] =
+{
+	"S-Video + Composite",
+	"Composite",
+	"S-Video",
+	"RGB",
+	"YUV C",
+	"YUV V"
+};
+
+static const char * const wss_strs[] = {
+	"invalid",
+	"letterbox 14:9 center",
+	"letterbox 14:9 top",
+	"invalid",
+	"letterbox 16:9 top",
+	"invalid",
+	"invalid",
+	"16:9 full format anamorphic"
+	"4:3 full format",
+	"invalid",
+	"invalid",
+	"letterbox 16:9 center",
+	"invalid",
+	"letterbox >16:9 center",
+	"14:9 full format center",
+	"invalid",
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
+{
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		if (i2c_smbus_write_byte_data(client, reg, val) == 0)
+			return 0;
+	}
+	saa7127_err("I2C Write Problem\n");
+	return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct i2c_client *client,
+				 const struct i2c_reg_value *regs)
+{
+	while (regs->reg != 0) {
+		saa7127_write(client, regs->reg, regs->value);
+		regs++;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 16))
+		return -EINVAL;
+	if (state->vps_enable != enable) {
+		saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+		saa7127_write(client, 0x54, enable << 7);
+		state->vps_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	state->vps_data[0] = data->data[4];
+	state->vps_data[1] = data->data[10];
+	state->vps_data[2] = data->data[11];
+	state->vps_data[3] = data->data[12];
+	state->vps_data[4] = data->data[13];
+	saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+		state->vps_data[0], state->vps_data[1],
+		state->vps_data[2], state->vps_data[3],
+		state->vps_data[4]);
+	saa7127_write(client, 0x55, state->vps_data[0]);
+	saa7127_write(client, 0x56, state->vps_data[1]);
+	saa7127_write(client, 0x57, state->vps_data[2]);
+	saa7127_write(client, 0x58, state->vps_data[3]);
+	saa7127_write(client, 0x59, state->vps_data[4]);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	u16 cc = data->data[0] << 8 | data->data[1];
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 21))
+		return -EINVAL;
+	if (state->cc_enable != enable) {
+		saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+				(enable << 6) | 0x11);
+		state->cc_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	saa7127_dbg_highvol("CC data: %04x\n", cc);
+	saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+	saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+	state->cc_data = cc;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	u16 xds = data->data[1] << 8 | data->data[0];
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 1 || data->line != 21))
+		return -EINVAL;
+	if (state->xds_enable != enable) {
+		saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+				(enable << 7) | 0x11);
+		state->xds_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	saa7127_dbg_highvol("XDS data: %04x\n", xds);
+	saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+	saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+	state->xds_data = xds;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	int enable = (data->line != 0);
+
+	if (enable && (data->field != 0 || data->line != 23))
+		return -EINVAL;
+	if (state->wss_enable != enable) {
+		saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+		saa7127_write(client, 0x27, enable << 7);
+		state->wss_enable = enable;
+	}
+	if (!enable)
+		return 0;
+
+	saa7127_write(client, 0x26, data->data[0]);
+	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
+	saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_video_enable(struct i2c_client *client, int enable)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+
+	if (enable) {
+		saa7127_dbg("Enable Video Output\n");
+		saa7127_write(client, 0x2d, state->reg_2d);
+		saa7127_write(client, 0x61, state->reg_61);
+	} else {
+		saa7127_dbg("Disable Video Output\n");
+		saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
+		saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
+	}
+	state->video_enable = enable;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	const struct i2c_reg_value *inittab;
+
+	if (std & V4L2_STD_525_60) {
+		saa7127_dbg("Selecting 60 Hz video Standard\n");
+		inittab = saa7127_init_config_60hz;
+		state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+	} else {
+		saa7127_dbg("Selecting 50 Hz video Standard\n");
+		inittab = saa7127_init_config_50hz;
+		state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
+	}
+
+	/* Write Table */
+	saa7127_write_inittab(client, inittab);
+	state->std = std;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct i2c_client *client, int output)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+
+	switch (output) {
+	case SAA7127_OUTPUT_TYPE_RGB:
+		state->reg_2d = 0x0f;	/* RGB + CVBS (for sync) */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_COMPOSITE:
+		state->reg_2d = 0x08;	/* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_SVIDEO:
+		state->reg_2d = 0xff;	/* 11111111  croma -> R, luma -> CVBS + G + B */
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_YUV_V:
+		state->reg_2d = 0x4f;	/* reg 2D = 01001111, all DAC's on, RGB + VBS */
+		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_YUV_C:
+		state->reg_2d = 0x0f;	/* reg 2D = 00001111, all DAC's on, RGB + CVBS */
+		state->reg_3a = 0x0b;	/* reg 3A = 00001011, bypass RGB-matrix */
+		break;
+
+	case SAA7127_OUTPUT_TYPE_BOTH:
+		state->reg_2d = 0xbf;
+		state->reg_3a = 0x13;	/* by default switch YUV to RGB-matrix on */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+
+	/* Configure Encoder */
+	saa7127_write(client, 0x2d, state->reg_2d);
+	saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+	state->output_type = output;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_input_type(struct i2c_client *client, int input)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+
+	switch (input) {
+	case SAA7127_INPUT_TYPE_NORMAL:	/* avia */
+		saa7127_dbg("Selecting Normal Encoder Input\n");
+		state->reg_3a_cb = 0;
+		break;
+
+	case SAA7127_INPUT_TYPE_TEST_IMAGE:	/* color bar */
+		saa7127_dbg("Selecting Color Bar generator\n");
+		state->reg_3a_cb = 0x80;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+	state->input_type = input;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_command(struct i2c_client *client,
+			   unsigned int cmd, void *arg)
+{
+	struct saa7127_state *state = i2c_get_clientdata(client);
+	struct v4l2_format *fmt = arg;
+	int *iarg = arg;
+
+	switch (cmd) {
+	case VIDIOC_S_STD:
+		if (state->std == *(v4l2_std_id *)arg)
+			break;
+		return saa7127_set_std(client, *(v4l2_std_id *)arg);
+
+	case VIDIOC_G_STD:
+		*(v4l2_std_id *)arg = state->std;
+		break;
+
+	case VIDIOC_S_INPUT:
+		if (state->input_type == *iarg)
+			break;
+		return saa7127_set_input_type(client, *iarg);
+
+	case VIDIOC_S_OUTPUT:
+		if (state->output_type == *iarg)
+			break;
+		return saa7127_set_output_type(client, *iarg);
+
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF:
+		if (state->video_enable == (cmd == VIDIOC_STREAMON))
+			break;
+		return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
+
+	case VIDIOC_G_FMT:
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+
+		memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+		if (state->vps_enable)
+			fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+		if (state->wss_enable)
+			fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+		if (state->cc_enable) {
+			fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+			fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+		}
+		fmt->fmt.sliced.service_set =
+			(state->vps_enable ? V4L2_SLICED_VPS : 0) |
+			(state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+			(state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+		break;
+
+	case VIDIOC_LOG_STATUS:
+		saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+		saa7127_info("Input:    %s\n", state->input_type ?  "color bars" : "normal");
+		saa7127_info("Output:   %s\n", state->video_enable ?
+			output_strs[state->output_type] : "disabled");
+		saa7127_info("WSS:      %s\n", state->wss_enable ?
+			wss_strs[state->wss_mode] : "disabled");
+		saa7127_info("VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
+		saa7127_info("CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
+		break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_INT_G_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+			return -EINVAL;
+		reg->val = saa7127_read(client, reg->reg & 0xff);
+		break;
+	}
+
+	case VIDIOC_INT_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+		break;
+	}
+#endif
+
+	case VIDIOC_INT_S_VBI_DATA:
+	{
+		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;
+		}
+		break;
+	}
+
+	case VIDIOC_INT_G_CHIP_IDENT:
+		*(enum v4l2_chip_ident *)arg = state->ident;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127;
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	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 = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	memset(client, 0, sizeof(struct i2c_client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver_saa7127;
+	client->flags = I2C_CLIENT_ALLOW_USE;
+	snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+
+	saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+
+	/* First test register 0: Bits 5-7 are a version ID (should be 0),
+	   and bit 2 should also be 0.
+	   This is rather general, so the second test is more specific and
+	   looks at the 'ending point of burst in clock cycles' which is
+	   0x1d after a reset and not expected to ever change. */
+	if ((saa7127_read(client, 0) & 0xe4) != 0 ||
+			(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
+		saa7127_dbg("saa7127 not found\n");
+		kfree(client);
+		return 0;
+	}
+	state = kmalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+
+	if (state == NULL) {
+		kfree(client);
+		return (-ENOMEM);
+	}
+
+	i2c_set_clientdata(client, state);
+	memset(state, 0, sizeof(struct saa7127_state));
+
+	/* Configure Encoder */
+
+	saa7127_dbg("Configuring encoder\n");
+	saa7127_write_inittab(client, saa7127_init_config_common);
+	saa7127_set_std(client, V4L2_STD_NTSC);
+	saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
+	saa7127_set_vps(client, &vbi);
+	saa7127_set_wss(client, &vbi);
+	saa7127_set_cc(client, &vbi);
+	saa7127_set_xds(client, &vbi);
+	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 {
+		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) {
+		saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, 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 {
+		saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+		state->ident = V4L2_IDENT_SAA7127;
+	}
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+	if (adapter->id == I2C_HW_B_BT848)
+#endif
+		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);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127 = {
+	.name = "saa7127",
+	.id = I2C_DRIVERID_SAA7127,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = saa7127_probe,
+	.detach_client = saa7127_detach,
+	.command = saa7127_command,
+	.owner = THIS_MODULE,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+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 624e880..7bdeabe 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,10 +1,11 @@
 config VIDEO_SAA7134
 	tristate "Philips SAA7134 support"
-	depends on VIDEO_DEV && PCI && I2C && SOUND
+	depends on VIDEO_DEV && PCI && I2C && SOUND && SND
 	select VIDEO_BUF
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select CRC32
+	select SND_PCM_OSS
 	---help---
 	  This is a video4linux driver for Philips SAA713x based
 	  TV cards.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index e0b28f0..4226b61 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -1,10 +1,11 @@
 
 saa7134-objs :=	saa7134-cards.o saa7134-core.o saa7134-i2c.o	\
-		saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o	\
-		saa7134-vbi.o saa7134-video.o saa7134-input.o
+		saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o    \
+		saa7134-video.o saa7134-input.o
 
 obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
-				saa6752hs.o saa7134-alsa.o
+				saa6752hs.o saa7134-alsa.o \
+				saa7134-oss.o
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
 EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 4f3c423..5707c66 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -30,7 +30,9 @@
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/initval.h>
+#include <linux/interrupt.h>
 
 #include "saa7134.h"
 #include "saa7134-reg.h"
@@ -56,6 +58,8 @@
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
 
+int position;
+
 #define dprintk(fmt, arg...)    if (debug) \
         printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
 
@@ -68,7 +72,7 @@
 	int mixer_volume[MIXER_ADDR_LAST+1][2];
 	int capture_source[MIXER_ADDR_LAST+1][2];
 	struct pci_dev *pci;
-	struct saa7134_dev *saadev;
+	struct saa7134_dev *dev;
 
 	unsigned long iobase;
 	int irq;
@@ -83,12 +87,10 @@
  */
 
 typedef struct snd_card_saa7134_pcm {
-	struct saa7134_dev *saadev;
+	struct saa7134_dev *dev;
 
 	spinlock_t lock;
-	unsigned int pcm_size;		/* buffer size */
-	unsigned int pcm_count;		/* bytes per period */
-	unsigned int pcm_bps;		/* bytes per second */
+
 	snd_pcm_substream_t *substream;
 } snd_card_saa7134_pcm_t;
 
@@ -100,13 +102,11 @@
  *
  *   Called when the capture device is released or the buffer overflows
  *
- *   - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped
- *     if we just share dsp_dma_stop and use it here
+ *   - Copied verbatim from saa7134-oss's dsp_dma_stop.
  *
  */
 
 static void saa7134_dma_stop(struct saa7134_dev *dev)
-
 {
 	dev->dmasound.dma_blk     = -1;
 	dev->dmasound.dma_running = 0;
@@ -118,8 +118,7 @@
  *
  *   Called when preparing the capture device for use
  *
- *   - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped
- *     if we just share dsp_dma_start and use it here
+ *   - Copied verbatim from saa7134-oss's dsp_dma_start.
  *
  */
 
@@ -170,9 +169,9 @@
 	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
 		dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
 			dev->dmasound.bufsize, dev->dmasound.blocks);
+		spin_unlock(&dev->slock);
 		snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
-		saa7134_dma_stop(dev);
-		goto done;
+		return;
 	}
 
 	/* next block addr */
@@ -194,6 +193,7 @@
 		snd_pcm_period_elapsed(dev->dmasound.substream);
 		spin_lock(&dev->slock);
 	}
+
  done:
 	spin_unlock(&dev->slock);
 
@@ -209,7 +209,9 @@
 
 static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+        struct saa7134_dmasound *dmasound = dev_id;
+        struct saa7134_dev *dev = dmasound->priv_data;
+
 	unsigned long report, status;
 	int loop, handled = 0;
 
@@ -248,56 +250,23 @@
 					  int cmd)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
-	struct saa7134_dev *dev=saapcm->saadev;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+	struct saa7134_dev *dev=pcm->dev;
 	int err = 0;
 
-	spin_lock_irq(&dev->slock);
-        if (cmd == SNDRV_PCM_TRIGGER_START) {
+	spin_lock(&dev->slock);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
 		/* start dma */
 		saa7134_dma_start(dev);
-        } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
 		/* stop dma */
 		saa7134_dma_stop(dev);
-        } else {
-                err = -EINVAL;
-        }
-	spin_unlock_irq(&dev->slock);
+	} else {
+		err = -EINVAL;
+	}
+	spin_unlock(&dev->slock);
 
-        return err;
-}
-
-/*
- * DMA buffer config
- *
- *   Sets the values that will later be used as the size of the buffer,
- *  size of the fragments, and total number of fragments.
- *   Must be called during the preparation stage, before memory is
- *  allocated
- *
- *   - Copied verbatim from saa7134-oss. Can be dropped
- *     if we just share dsp_buffer_conf from OSS.
- */
-
-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;
+	return err;
 }
 
 /*
@@ -307,16 +276,16 @@
  *  ALSA, but I was unable to use ALSA's own DMA, and had to force the
  *  usage of V4L's
  *
- *   - Copied verbatim from saa7134-oss. Can be dropped
- *     if we just share dsp_buffer_init from OSS.
+ *   - Copied verbatim from saa7134-oss.
+ *
  */
 
 static int dsp_buffer_init(struct saa7134_dev *dev)
 {
 	int err;
 
-	if (!dev->dmasound.bufsize)
-		BUG();
+	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);
@@ -326,6 +295,28 @@
 }
 
 /*
+ * DMA buffer release
+ *
+ *   Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+	if (!dev->dmasound.blksize)
+		BUG();
+
+	videobuf_dma_free(&dev->dmasound.dma);
+
+	dev->dmasound.blocks  = 0;
+	dev->dmasound.blksize = 0;
+	dev->dmasound.bufsize = 0;
+
+       return 0;
+}
+
+
+/*
  * ALSA PCM preparation
  *
  *   - One of the ALSA capture callbacks.
@@ -340,84 +331,30 @@
 static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err, bswap, sign;
+	int bswap, sign;
 	u32 fmt, control;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev;
-	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
-	unsigned int bps;
-	unsigned long size;
-	unsigned count;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 
-	size = snd_pcm_lib_buffer_bytes(substream);
-	count = snd_pcm_lib_period_bytes(substream);
+	pcm->dev->dmasound.substream = substream;
 
-	saapcm->saadev->dmasound.substream = substream;
-	bps = runtime->rate * runtime->channels;
-	bps *= snd_pcm_format_width(runtime->format);
-	bps /= 8;
-	if (bps <= 0)
-		return -EINVAL;
-	saapcm->pcm_bps = bps;
-	saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
-	saapcm->pcm_count = snd_pcm_lib_period_bytes(substream);
+	dev = saa7134->dev;
 
-
-	dev=saa7134->saadev;
-
-	dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count));
-
-	err = dsp_buffer_init(dev);
-	if (0 != err)
-		goto fail2;
-
-	/* prepare buffer */
-	if (0 != (err = videobuf_dma_pci_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;
-
-
-
-	switch (runtime->format) {
-	  case SNDRV_PCM_FORMAT_U8:
-	  case SNDRV_PCM_FORMAT_S8:
+	if (snd_pcm_format_width(runtime->format) == 8)
 		fmt = 0x00;
-		break;
-	  case SNDRV_PCM_FORMAT_U16_LE:
-	  case SNDRV_PCM_FORMAT_U16_BE:
-	  case SNDRV_PCM_FORMAT_S16_LE:
-	  case SNDRV_PCM_FORMAT_S16_BE:
+	else
 		fmt = 0x01;
-		break;
-	  default:
-		err = -EINVAL;
-		return 1;
-	}
 
-	switch (runtime->format) {
-	  case SNDRV_PCM_FORMAT_S8:
-	  case SNDRV_PCM_FORMAT_S16_LE:
-	  case SNDRV_PCM_FORMAT_S16_BE:
+	if (snd_pcm_format_signed(runtime->format))
 		sign = 1;
-		break;
-	  default:
+	else
 		sign = 0;
-		break;
-	}
 
-	switch (runtime->format) {
-	  case SNDRV_PCM_FORMAT_U16_BE:
-	  case SNDRV_PCM_FORMAT_S16_BE:
-		bswap = 1; break;
-	  default:
-		bswap = 0; break;
-	}
+	if (snd_pcm_format_big_endian(runtime->format))
+		bswap = 1;
+	else
+		bswap = 0;
 
 	switch (dev->pci->device) {
 	  case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -445,7 +382,6 @@
 			fmt |= 0x04;
 		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
 		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
-		//saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210);
 		break;
 	}
 
@@ -459,12 +395,6 @@
 	if (bswap)
 		control |= SAA7134_RS_CONTROL_BSWAP;
 
-	/* I should be able to use runtime->dma_addr in the control
-	   byte, but it doesn't work. So I allocate the DMA using the
-	   V4L functions, and force ALSA to use that as the DMA area */
-
-	runtime->dma_area = dev->dmasound.dma.vmalloc;
-
 	saa_writel(SAA7134_RS_BA1(6),0);
 	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
 	saa_writel(SAA7134_RS_PITCH(6),0);
@@ -473,12 +403,6 @@
 	dev->dmasound.rate = runtime->rate;
 
 	return 0;
- fail2:
-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
- fail1:
-	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
-	return err;
-
 
 }
 
@@ -496,10 +420,8 @@
 static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
-	struct saa7134_dev *dev=saapcm->saadev;
-
-
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+	struct saa7134_dev *dev=pcm->dev;
 
 	if (dev->dmasound.read_count) {
 		dev->dmasound.read_count  -= snd_pcm_lib_period_bytes(substream);
@@ -540,9 +462,9 @@
 
 static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
 {
-	snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 
-	kfree(saapcm);
+	kfree(pcm);
 }
 
 
@@ -552,17 +474,76 @@
  *   - One of the ALSA capture callbacks.
  *
  *   Called on initialization, right before the PCM preparation
- *   Usually used in ALSA to allocate the DMA, but since we don't use the
- *  ALSA DMA it does nothing
  *
  */
 
 static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
 				    snd_pcm_hw_params_t * hw_params)
 {
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
+	unsigned int period_size, periods;
+	int err;
 
-	return 0;
+	period_size = params_period_bytes(hw_params);
+	periods = params_periods(hw_params);
 
+	snd_assert(period_size >= 0x100 && period_size <= 0x10000,
+		   return -EINVAL);
+	snd_assert(periods >= 2, return -EINVAL);
+	snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL);
+
+	dev = saa7134->dev;
+
+	if (dev->dmasound.blocks == periods &&
+	    dev->dmasound.blksize == period_size)
+		return 0;
+
+	/* release the old buffer */
+	if (substream->runtime->dma_area) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		substream->runtime->dma_area = NULL;
+	}
+	dev->dmasound.blocks  = periods;
+	dev->dmasound.blksize = period_size;
+	dev->dmasound.bufsize = period_size * periods;
+
+	err = dsp_buffer_init(dev);
+	if (0 != err) {
+		dev->dmasound.blocks  = 0;
+		dev->dmasound.blksize = 0;
+		dev->dmasound.bufsize = 0;
+		return err;
+	}
+
+	if (0 != (err = videobuf_dma_pci_map(dev->pci, &dev->dmasound.dma))) {
+		dsp_buffer_free(dev);
+		return err;
+	}
+	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
+		videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		return err;
+	}
+	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+						dev->dmasound.dma.sglist,
+						dev->dmasound.dma.sglen,
+						0))) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		return err;
+	}
+
+	/* I should be able to use runtime->dma_addr in the control
+	   byte, but it doesn't work. So I allocate the DMA using the
+	   V4L functions, and force ALSA to use that as the DMA area */
+
+	substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+	return 1;
 
 }
 
@@ -572,33 +553,23 @@
  *   - One of the ALSA capture callbacks.
  *
  *   Called after closing the device, but before snd_card_saa7134_capture_close
- *   Usually used in ALSA to free the DMA, but since we don't use the
- *  ALSA DMA I'm almost sure this isn't necessary.
+ *   It stops the DMA audio and releases the buffers.
  *
  */
 
 static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
 {
-	return 0;
-}
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev;
 
-/*
- * DMA buffer release
- *
- *   Called after closing the device, during snd_card_saa7134_capture_close
- *
- */
+	dev = saa7134->dev;
 
-static int dsp_buffer_free(struct saa7134_dev *dev)
-{
-	if (!dev->dmasound.blksize)
-		BUG();
-
-	videobuf_dma_free(&dev->dmasound.dma);
-
-	dev->dmasound.blocks  = 0;
-	dev->dmasound.blksize = 0;
-	dev->dmasound.bufsize = 0;
+	if (substream->runtime->dma_area) {
+		saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+		videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+		dsp_buffer_free(dev);
+		substream->runtime->dma_area = NULL;
+	}
 
 	return 0;
 }
@@ -608,21 +579,12 @@
  *
  *   - One of the ALSA capture callbacks.
  *
- *   Called after closing the device. It stops the DMA audio and releases
- *  the buffers
+ *   Called after closing the device.
  *
  */
 
 static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
 {
-	snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream);
-	struct saa7134_dev *dev = chip->saadev;
-
-	/* unlock buffer */
-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
-	videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
-
-	dsp_buffer_free(dev);
 	return 0;
 }
 
@@ -639,29 +601,28 @@
 static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_card_saa7134_pcm_t *saapcm;
+	snd_card_saa7134_pcm_t *pcm;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
-	struct saa7134_dev *dev = saa7134->saadev;
+	struct saa7134_dev *dev = saa7134->dev;
 	int err;
 
 	down(&dev->dmasound.lock);
 
-	dev->dmasound.afmt        = SNDRV_PCM_FORMAT_U8;
-	dev->dmasound.channels    = 2;
 	dev->dmasound.read_count  = 0;
 	dev->dmasound.read_offset = 0;
 
 	up(&dev->dmasound.lock);
 
-	saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL);
-	if (saapcm == NULL)
+	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+	if (pcm == NULL)
 		return -ENOMEM;
-	saapcm->saadev=saa7134->saadev;
 
-	spin_lock_init(&saapcm->lock);
+	pcm->dev=saa7134->dev;
 
-	saapcm->substream = substream;
-	runtime->private_data = saapcm;
+	spin_lock_init(&pcm->lock);
+
+	pcm->substream = substream;
+	runtime->private_data = pcm;
 	runtime->private_free = snd_card_saa7134_runtime_free;
 	runtime->hw = snd_card_saa7134_capture;
 
@@ -736,7 +697,6 @@
 static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
 	int change, addr = kcontrol->private_value;
 	int left, right;
 
@@ -750,12 +710,12 @@
 		right = 0;
 	if (right > 20)
 		right = 20;
-	spin_lock_irqsave(&chip->mixer_lock, flags);
+	spin_lock_irq(&chip->mixer_lock);
 	change = chip->mixer_volume[addr][0] != left ||
 		 chip->mixer_volume[addr][1] != right;
 	chip->mixer_volume[addr][0] = left;
 	chip->mixer_volume[addr][1] = right;
-	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+	spin_unlock_irq(&chip->mixer_lock);
 	return change;
 }
 
@@ -777,38 +737,37 @@
 static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
 	int addr = kcontrol->private_value;
 
-	spin_lock_irqsave(&chip->mixer_lock, flags);
+	spin_lock_irq(&chip->mixer_lock);
 	ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
 	ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
-	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+	spin_unlock_irq(&chip->mixer_lock);
+
 	return 0;
 }
 
 static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
 	int change, addr = kcontrol->private_value;
 	int left, right;
 	u32 anabar, xbarin;
 	int analog_io, rate;
 	struct saa7134_dev *dev;
 
-	dev = chip->saadev;
+	dev = chip->dev;
 
 	left = ucontrol->value.integer.value[0] & 1;
 	right = ucontrol->value.integer.value[1] & 1;
-	spin_lock_irqsave(&chip->mixer_lock, flags);
+	spin_lock_irq(&chip->mixer_lock);
 
 	change = chip->capture_source[addr][0] != left ||
 		 chip->capture_source[addr][1] != right;
 	chip->capture_source[addr][0] = left;
 	chip->capture_source[addr][1] = right;
 	dev->dmasound.input=addr;
-	spin_unlock_irqrestore(&chip->mixer_lock, flags);
+	spin_unlock_irq(&chip->mixer_lock);
 
 
 	if (change) {
@@ -898,43 +857,44 @@
 	return 0;
 }
 
-static int snd_saa7134_free(snd_card_saa7134_t *chip)
+static void snd_saa7134_free(snd_card_t * card)
 {
-	return 0;
-}
+	snd_card_saa7134_t *chip = card->private_data;
 
-static int snd_saa7134_dev_free(snd_device_t *device)
-{
-	snd_card_saa7134_t *chip = device->device_data;
-	return snd_saa7134_free(chip);
+	if (chip->dev->dmasound.priv_data == NULL)
+		return;
+
+	if (chip->irq >= 0) {
+		synchronize_irq(chip->irq);
+		free_irq(chip->irq, &chip->dev->dmasound);
+	}
+
+	chip->dev->dmasound.priv_data = NULL;
+
 }
 
 /*
  * ALSA initialization
  *
- *   Called by saa7134-core, it creates the basic structures and registers
- *  the ALSA devices
+ *   Called by the init routine, once for each saa7134 device present,
+ *  it creates the basic structures and registers the ALSA devices
  *
  */
 
-int alsa_card_saa7134_create (struct saa7134_dev *saadev)
+int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
 {
-	static int dev;
 
 	snd_card_t *card;
 	snd_card_saa7134_t *chip;
 	int err;
-	static snd_device_ops_t ops = {
-		.dev_free =     snd_saa7134_dev_free,
-	};
 
 
-	if (dev >= SNDRV_CARDS)
+	if (devnum >= SNDRV_CARDS)
 		return -ENODEV;
-	if (!enable[dev])
+	if (!enable[devnum])
 		return -ENODEV;
 
-	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t));
 
 	if (card == NULL)
 		return -ENOMEM;
@@ -943,34 +903,33 @@
 
 	/* Card "creation" */
 
-	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL) {
-		return -ENOMEM;
-	}
+	card->private_free = snd_saa7134_free;
+	chip = (snd_card_saa7134_t *) card->private_data;
 
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->mixer_lock);
 
-	chip->saadev = saadev;
+	chip->dev = dev;
 
 	chip->card = card;
 
-	chip->pci = saadev->pci;
-	chip->irq = saadev->pci->irq;
-	chip->iobase = pci_resource_start(saadev->pci, 0);
+	chip->pci = dev->pci;
+	chip->iobase = pci_resource_start(dev->pci, 0);
 
-	err = request_irq(saadev->pci->irq, saa7134_alsa_irq,
-				SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev);
+
+	err = request_irq(dev->pci->irq, saa7134_alsa_irq,
+				SA_SHIRQ | SA_INTERRUPT, dev->name,
+				(void*) &dev->dmasound);
 
 	if (err < 0) {
 		printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
-			saadev->name, saadev->pci->irq);
+			dev->name, dev->pci->irq);
 		goto __nodev;
 	}
 
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		goto __nodev;
-	}
+	chip->irq = dev->pci->irq;
+
+	init_MUTEX(&dev->dmasound.lock);
 
 	if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
 		goto __nodev;
@@ -984,16 +943,15 @@
 
 	strcpy(card->shortname, "SAA7134");
 	sprintf(card->longname, "%s at 0x%lx irq %d",
-		chip->saadev->name, chip->iobase, chip->irq);
+		chip->dev->name, chip->iobase, chip->irq);
 
 	if ((err = snd_card_register(card)) == 0) {
-		snd_saa7134_cards[dev] = card;
+		snd_saa7134_cards[devnum] = card;
 		return 0;
 	}
 
 __nodev:
 	snd_card_free(card);
-	kfree(chip);
 	return err;
 }
 
@@ -1007,21 +965,29 @@
 
 static int saa7134_alsa_init(void)
 {
-        struct saa7134_dev *saadev = NULL;
-        struct list_head *list;
+	struct saa7134_dev *dev = NULL;
+	struct list_head *list;
 
-	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+	position = 0;
 
-        list_for_each(list,&saa7134_devlist) {
-                saadev = list_entry(list, struct saa7134_dev, devlist);
-		alsa_card_saa7134_create(saadev);
-        }
+        printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
 
-	if (saadev == NULL)
+	list_for_each(list,&saa7134_devlist) {
+		dev = list_entry(list, struct saa7134_dev, devlist);
+		if (dev->dmasound.priv_data == NULL) {
+			dev->dmasound.priv_data = dev;
+			alsa_card_saa7134_create(dev,position);
+			position++;
+		} else {
+			printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
+			return -EBUSY;
+		}
+	}
+
+	if (dev == NULL)
 		printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
 
 	return 0;
-
 }
 
 /*
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 663d03e..75abc20 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2529,6 +2529,32 @@
 			.amux   = LINE1,
 		}},
 	},
+	[SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+		.name           = "MSI TV@Anywhere plus",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 0,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2970,6 +2996,12 @@
 		.subdevice    = 0x2018,
 		.driver_data  = SAA7134_BOARD_PHILIPS_TIGER,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462,
+		.subdevice    = 0x6231,
+		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 19b8874..4275d2d 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -53,13 +53,13 @@
 module_param(gpio_tracking, int, 0644);
 MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
 
-static unsigned int oss = 0;
-module_param(oss, int, 0444);
-MODULE_PARM_DESC(oss,"register oss devices (default: no)");
-
 static unsigned int alsa = 0;
-module_param(alsa, int, 0444);
-MODULE_PARM_DESC(alsa,"register alsa devices (default: no)");
+module_param(alsa, int, 0644);
+MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
+
+static unsigned int oss = 0;
+module_param(oss, int, 0644);
+MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
 
 static unsigned int latency = UNSET;
 module_param(latency, int, 0444);
@@ -68,24 +68,18 @@
 static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int tuner[]    = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int card[]     = {[0 ... (SAA7134_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_param_array(dsp_nr,   int, NULL, 0444);
-module_param_array(mixer_nr, int, NULL, 0444);
 module_param_array(tuner,    int, NULL, 0444);
 module_param_array(card,     int, NULL, 0444);
 
 MODULE_PARM_DESC(video_nr, "video device number");
 MODULE_PARM_DESC(vbi_nr,   "vbi device number");
 MODULE_PARM_DESC(radio_nr, "radio device number");
-MODULE_PARM_DESC(dsp_nr,   "oss dsp device number");
-MODULE_PARM_DESC(mixer_nr, "oss mixer device number");
 MODULE_PARM_DESC(tuner,    "tuner type");
 MODULE_PARM_DESC(card,     "card type");
 
@@ -195,6 +189,7 @@
 static int need_empress;
 static int need_dvb;
 static int need_alsa;
+static int need_oss;
 
 static int pending_call(struct notifier_block *self, unsigned long state,
 			void *module)
@@ -208,6 +203,8 @@
 		request_module("saa7134-dvb");
 	if (need_alsa)
 		request_module("saa7134-alsa");
+	if (need_oss)
+		request_module("saa7134-oss");
 	return NOTIFY_DONE;
 }
 
@@ -218,10 +215,11 @@
 
 static void request_module_depend(char *name, int *flag)
 {
+	int err;
 	switch (THIS_MODULE->state) {
 	case MODULE_STATE_COMING:
 		if (!pending_registered) {
-			register_module_notifier(&pending_notifier);
+			err = register_module_notifier(&pending_notifier);
 			pending_registered = 1;
 		}
 		*flag = 1;
@@ -578,12 +576,14 @@
 			goto out;
 		}
 
-		/* If alsa support is active and we get a sound report, exit
-		   and let the saa7134-alsa module deal with it */
+		/* If dmasound support is active and we get a sound report, exit
+		   and let the saa7134-alsa/oss module deal with it */
 
-		if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa)  {
+		if ((report & SAA7134_IRQ_REPORT_DONE_RA3) &&
+			(dev->dmasound.priv_data != NULL) )
+		{
 			if (irq_debug > 1)
-				printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n",
+				printk(KERN_DEBUG "%s/irq: ignoring interrupt for DMA sound\n",
 				       dev->name);
 			goto out;
 		}
@@ -609,12 +609,6 @@
 		    card_has_mpeg(dev))
 			saa7134_irq_ts_done(dev,status);
 
-		if ((report & SAA7134_IRQ_REPORT_DONE_RA3))  {
-			if (oss) {
-				saa7134_irq_oss_done(dev,status);
-			}
-		}
-
 		if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
 			       SAA7134_IRQ_REPORT_GPIO18)) &&
 		    dev->remote)
@@ -689,14 +683,6 @@
 	 * audio will not work.
 	 */
 
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		saa7134_oss_init1(dev);
-		break;
-	}
-
 	/* enable peripheral devices */
 	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 
@@ -728,8 +714,6 @@
 		irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
 			      SAA7134_IRQ2_INTE_GPIO18A |
 			      SAA7134_IRQ2_INTE_GPIO16  );
-	else if (dev->has_remote == SAA7134_REMOTE_I2C)
-		request_module("ir-kbd-i2c");
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -742,13 +726,6 @@
 {
 	dprintk("hwfini\n");
 
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		saa7134_oss_fini(dev);
-		break;
-	}
 	if (card_has_mpeg(dev))
 		saa7134_ts_fini(dev);
 	saa7134_input_fini(dev);
@@ -986,11 +963,12 @@
 	if (card_is_dvb(dev))
 		request_module_depend("saa7134-dvb",&need_dvb);
 
-	if (!oss && alsa) {
-		dprintk("Requesting ALSA module\n");
-		request_module_depend("saa7134-alsa",&need_alsa);
-	}
 
+	if (alsa)
+		request_module_depend("saa7134-alsa",&need_alsa);
+
+	if (oss)
+		request_module_depend("saa7134-oss",&need_oss);
 
 	v4l2_prio_init(&dev->prio);
 
@@ -1024,32 +1002,6 @@
 		       dev->name,dev->radio_dev->minor & 0x1f);
 	}
 
-	/* register oss devices */
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		if (oss) {
-			err = dev->dmasound.minor_dsp =
-				register_sound_dsp(&saa7134_dsp_fops,
-						   dsp_nr[dev->nr]);
-			if (err < 0) {
-				goto fail4;
-			}
-			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 fail5;
-			printk(KERN_INFO "%s: registered device mixer%d\n",
-			       dev->name,dev->dmasound.minor_mixer >> 4);
-		}
-		break;
-	}
-
 	/* everything worked */
 	pci_set_drvdata(pci_dev,dev);
 	saa7134_devcount++;
@@ -1064,17 +1016,9 @@
 
 	/* check for signal */
 	saa7134_irq_video_intl(dev);
+
 	return 0;
 
- fail5:
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		if (oss)
-			unregister_sound_dsp(dev->dmasound.minor_dsp);
-		break;
-	}
  fail4:
 	saa7134_unregister_video(dev);
 	saa7134_i2c_unregister(dev);
@@ -1125,19 +1069,16 @@
 	saa7134_devcount--;
 
 	saa7134_i2c_unregister(dev);
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		if (oss) {
-			unregister_sound_mixer(dev->dmasound.minor_mixer);
-			unregister_sound_dsp(dev->dmasound.minor_dsp);
-		}
-		break;
-	}
 	saa7134_unregister_video(dev);
 
-	/* release ressources */
+	/* the DMA sound modules should be unloaded before reaching
+	   this, but just in case they are still present... */
+	if (dev->dmasound.priv_data != NULL) {
+		free_irq(pci_dev->irq, &dev->dmasound);
+		dev->dmasound.priv_data = NULL;
+	}
+
+	/* release resources */
 	free_irq(pci_dev->irq, dev);
 	iounmap(dev->lmmio);
 	release_mem_region(pci_resource_start(pci_dev,0),
@@ -1225,7 +1166,7 @@
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
 
-/* ----------------- For ALSA -------------------------------- */
+/* ----------------- for the DMA sound modules --------------- */
 
 EXPORT_SYMBOL(saa7134_pgtable_free);
 EXPORT_SYMBOL(saa7134_pgtable_build);
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 329accd..e648cc3 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -485,64 +485,6 @@
 
 };
 
-static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
-	[ 0x59 ] = KEY_MUTE,
-	[ 0x4a ] = KEY_POWER,
-
-	[ 0x18 ] = KEY_TEXT,
-	[ 0x26 ] = KEY_TV,
-	[ 0x3d ] = KEY_PRINT,
-
-	[ 0x48 ] = KEY_RED,
-	[ 0x04 ] = KEY_GREEN,
-	[ 0x11 ] = KEY_YELLOW,
-	[ 0x00 ] = KEY_BLUE,
-
-	[ 0x2d ] = KEY_VOLUMEUP,
-	[ 0x1e ] = KEY_VOLUMEDOWN,
-
-	[ 0x49 ] = KEY_MENU,
-
-	[ 0x16 ] = KEY_CHANNELUP,
-	[ 0x17 ] = KEY_CHANNELDOWN,
-
-	[ 0x20 ] = KEY_UP,
-	[ 0x21 ] = KEY_DOWN,
-	[ 0x22 ] = KEY_LEFT,
-	[ 0x23 ] = KEY_RIGHT,
-	[ 0x0d ] = KEY_SELECT,
-
-
-
-	[ 0x08 ] = KEY_BACK,
-	[ 0x07 ] = KEY_REFRESH,
-
-	[ 0x2f ] = KEY_ZOOM,
-	[ 0x29 ] = KEY_RECORD,
-
-	[ 0x4b ] = KEY_PAUSE,
-	[ 0x4d ] = KEY_REWIND,
-	[ 0x2e ] = KEY_PLAY,
-	[ 0x4e ] = KEY_FORWARD,
-	[ 0x53 ] = KEY_PREVIOUS,
-	[ 0x4c ] = KEY_STOP,
-	[ 0x54 ] = KEY_NEXT,
-
-	[ 0x69 ] = KEY_KP0,
-	[ 0x6a ] = KEY_KP1,
-	[ 0x6b ] = KEY_KP2,
-	[ 0x6c ] = KEY_KP3,
-	[ 0x6d ] = KEY_KP4,
-	[ 0x6e ] = KEY_KP5,
-	[ 0x6f ] = KEY_KP6,
-	[ 0x70 ] = KEY_KP7,
-	[ 0x71 ] = KEY_KP8,
-	[ 0x72 ] = KEY_KP9,
-
-	[ 0x74 ] = KEY_CHANNEL,
-	[ 0x0a ] = KEY_BACKSPACE,
-};
-
 /* Mapping for the 28 key remote control as seen at
    http://www.sednacomputer.com/photo/cardbus-tv.jpg
    Pavel Mihaylov <bin@bash.info> */
@@ -635,57 +577,6 @@
 	return 1;
 }
 
-/* The new pinnacle PCTV remote (with the colored buttons)
- *
- * Ricardo Cerqueira <v4l@cerqueira.org>
- */
-
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-	unsigned char b[4];
-	unsigned int start = 0,parity = 0,code = 0;
-
-	/* poll IR chip */
-	if (4 != i2c_master_recv(&ir->c,b,4)) {
-		i2cdprintk("read error\n");
-		return -EIO;
-	}
-
-	for (start = 0; start<4; start++) {
-		if (b[start] == 0x80) {
-			code=b[(start+3)%4];
-			parity=b[(start+2)%4];
-		}
-	}
-
-	/* Empty Request */
-	if (parity==0)
-		return 0;
-
-	/* Repeating... */
-	if (ir->old == parity)
-		return 0;
-
-
-	ir->old = parity;
-
-	/* Reduce code value to fit inside IR_KEYTAB_SIZE
-	 *
-	 * this is the only value that results in 42 unique
-	 * codes < 128
-	 */
-
-	code %= 0x88;
-
-	*ir_raw = code;
-	*ir_key = code;
-
-	i2cdprintk("Pinnacle PCTV key %02x\n", code);
-
-	return 1;
-}
-
-
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
 	struct saa7134_ir *ir = dev->remote;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index fd53dfc..fd9ed11 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -4,6 +4,8 @@
  * oss dsp interface
  *
  * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *     2005 conversion to standalone module:
+ *         Ricardo Cerqueira <v4l@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
@@ -25,7 +27,9 @@
 #include <linux/module.h>
 #include <linux/moduleparam.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"
@@ -33,15 +37,23 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int oss_debug  = 0;
-module_param(oss_debug, int, 0644);
-MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
+static unsigned int debug  = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [oss]");
 
-static unsigned int oss_rate  = 0;
-module_param(oss_rate, int, 0444);
-MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
+static unsigned int rate  = 0;
+module_param(rate, int, 0444);
+MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
 
-#define dprintk(fmt, arg...)	if (oss_debug) \
+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)
 
 
@@ -369,7 +381,7 @@
 	int __user *p = argp;
 	int val = 0;
 
-	if (oss_debug > 1)
+	if (debug > 1)
 		saa7134_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case OSS_GETVERSION:
@@ -665,7 +677,7 @@
 	void __user *argp = (void __user *) arg;
 	int __user *p = argp;
 
-	if (oss_debug > 1)
+	if (debug > 1)
 		saa7134_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case OSS_GETVERSION:
@@ -768,8 +780,41 @@
 
 /* ------------------------------------------------------------------ */
 
+static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+        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,
+                         SA_SHIRQ | SA_INTERRUPT, dev->name,
+			(void*) &dev->dmasound)) < 0)
+		return -1;
+
 	/* general */
 	init_MUTEX(&dev->dmasound.lock);
 	init_waitqueue_head(&dev->dmasound.wq);
@@ -785,8 +830,8 @@
 
 	/* dsp */
 	dev->dmasound.rate = 32000;
-	if (oss_rate)
-		dev->dmasound.rate = oss_rate;
+	if (rate)
+		dev->dmasound.rate = rate;
 	dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
 
 	/* mixer */
@@ -840,7 +885,7 @@
 	/* next block addr */
 	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
 	saa_writel(reg,next_blk * dev->dmasound.blksize);
-	if (oss_debug > 2)
+	if (debug > 2)
 		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
 			(status & 0x10000000) ? "even" : "odd ", next_blk,
 			next_blk * dev->dmasound.blksize);
@@ -854,6 +899,98 @@
 	spin_unlock(&dev->slock);
 }
 
+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);
+
+	return 0;
+
+fail:
+        unregister_sound_dsp(dev->dmasound.minor_dsp);
+	return 0;
+
+
+}
+
+static int saa7134_oss_init(void)
+{
+        struct saa7134_dev *dev = NULL;
+        struct list_head *list;
+
+        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) {
+			dev->dmasound.priv_data = dev;
+			saa7134_oss_init1(dev);
+			saa7134_dsp_create(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;
+
+}
+
+void saa7134_oss_exit(void)
+{
+        struct saa7134_dev *dev = NULL;
+        struct list_head *list;
+
+        list_for_each(list,&saa7134_devlist) {
+                dev = list_entry(list, struct saa7134_dev, devlist);
+
+		/* Device isn't registered by OSS, probably ALSA's */
+		if (!dev->dmasound.minor_dsp)
+			continue;
+
+                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;
+
+        }
+
+        printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
+
+        return;
+}
+
+module_init(saa7134_oss_init);
+module_exit(saa7134_oss_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index fb97274..244e197 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -208,6 +208,7 @@
 #define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS     79
 #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
 #define SAA7134_BOARD_PHILIPS_TIGER  81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -383,6 +384,7 @@
 	unsigned int               dma_blk;
 	unsigned int               read_offset;
 	unsigned int               read_count;
+	void *			   priv_data;
 	snd_pcm_substream_t 	   *substream;
 };
 
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index b2dfe07..61d94dd 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -437,6 +437,10 @@
 		t->sgIF = 124;
 		t->tda8290_easy_mode = 0x20;
 		mode = "L";
+	} else if (t->std & V4L2_STD_SECAM_LC) {
+		t->sgIF = 20;
+		t->tda8290_easy_mode = 0x40;
+		mode = "LC";
 	}
     tuner_dbg("setting tda8290 to system %s\n", mode);
 }
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 73c4041..e58abdf 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -251,7 +251,7 @@
 
 static char pal[] = "-";
 module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
+static char secam[] = "--";
 module_param_string(secam, secam, sizeof(secam), 0644);
 
 /* get more precise norm info from insmod option */
@@ -307,8 +307,13 @@
 			break;
 		case 'l':
 		case 'L':
-			tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
-			t->std = V4L2_STD_SECAM_L;
+			if ((secam[1]=='C')||(secam[1]=='c')) {
+				tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
+				t->std = V4L2_STD_SECAM_LC;
+			} else {
+				tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
+				t->std = V4L2_STD_SECAM_L;
+			}
 			break;
 		case '-':
 			/* default parameter, do nothing */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index d832205..e0c9fdb 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -233,7 +233,7 @@
 	{ "Ymec TVision TVF-5533MF", Philips, NTSC,
 	  16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
 
-	/* 60-68 */
+	/* 60-69 */
 	{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
 	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
 	{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
@@ -252,6 +252,8 @@
 	  16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
 	{ "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
 	  16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
+	{ "Tena TNF 5335 MF", Philips, NTSC,
+	  16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 22f2862..a6936ad 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -5,6 +5,11 @@
  *
  * Based on saa7115 driver
  *
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ * - Cleanup
+ * - V4L2 API update
+ * - sound fixes
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -31,7 +36,7 @@
 #include <media/audiochip.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
-MODULE_AUTHOR("Ulf Eklund");
+MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
 #define wm8775_err(fmt, arg...) do { \
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 1e6bdba..166c9b0 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -22,7 +22,6 @@
 
 #include <asm/div64.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/scatterlist.h>
 #include <asm/sizes.h>
 #include <asm/hardware/amba.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 48638c8..846a533 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -94,7 +94,7 @@
 
 config MTD_TS5500
 	tristate "JEDEC Flash device mapped on Technologic Systems TS-5500"
-	depends on ELAN
+	depends on X86
 	select MTD_PARTITIONS
 	select MTD_JEDECPROBE
 	select MTD_CFI_AMDSTD
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 977935a..824e430 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -84,6 +84,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
 #include <linux/spinlock.h>
@@ -173,7 +174,7 @@
 	/* skb send-queue */
 	int head, size;
 	struct sk_buff *queue[SKB_QUEUE_SIZE];
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 	struct pm_dev *pmdev;
 #endif
 	enum {
@@ -200,7 +201,7 @@
 static void el3_down(struct net_device *dev);
 static void el3_up(struct net_device *dev);
 static struct ethtool_ops ethtool_ops;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 static int el3_suspend(struct pm_dev *pdev);
 static int el3_resume(struct pm_dev *pdev);
 static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
@@ -361,7 +362,7 @@
 	struct el3_private *lp = netdev_priv(dev);
 
 	(void) lp;				/* Keep gcc quiet... */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 	if (lp->pmdev)
 		pm_unregister(lp->pmdev);
 #endif
@@ -571,7 +572,7 @@
 	if (err)
 		goto out1;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 	/* register power management */
 	lp->pmdev = pm_register(PM_ISA_DEV, card_idx, el3_pm_callback);
 	if (lp->pmdev) {
@@ -1479,7 +1480,7 @@
 }
 
 /* Power Management support functions */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 
 static int
 el3_suspend(struct pm_dev *pdev)
@@ -1548,7 +1549,7 @@
 	return 0;
 }
 
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
 
 /* Parameters that may be passed into the module. */
 static int debug = -1;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index e3a3295..0f030b7 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -6,7 +6,7 @@
  * Based on 8260_io/fcc_enet.c
  *
  * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
  *
  * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
  *
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 220084e..5065ba8 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -6,7 +6,7 @@
  * Based on 8260_io/fcc_enet.c
  *
  * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
  *
  * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
  *
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 5a2d810..cfa3cd7 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -6,7 +6,7 @@
  *  Based on e1000 ethtool support
  *
  *  Author: Andy Fleming
- *  Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *  Maintainer: Kumar Gala
  *
  *  Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
  *
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 9544279..04a462c 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -5,7 +5,7 @@
  * Provides Bus interface for MIIM regs
  *
  * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
  *
  * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
  *
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index 56e5665..e85eb21 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -5,7 +5,7 @@
  * Driver for the MDIO bus controller in the Gianfar register space
  *
  * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
  *
  * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
  *
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 9bf3468..2e7882e 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -40,6 +40,7 @@
 #include <asm/byteorder.h>
 
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 805714e..ee717d0 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -59,6 +59,7 @@
 #include <asm/byteorder.h>
 
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index a10cd18..5c2824b 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -100,14 +100,14 @@
 #define SMC_IO_SHIFT		0
 #define SMC_NOWAIT		1
 
-#define SMC_inb(a, r)		inb((a) + (r))
-#define SMC_insb(a, r, p, l)	insb((a) + (r), p, (l))
-#define SMC_inw(a, r)		inw((a) + (r))
-#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
-#define SMC_outb(v, a, r)	outb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l)	outsb((a) + (r), p, (l))
-#define SMC_outw(v, a, r)	outw(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
+#define SMC_inb(a, r)		readb((a) + (r))
+#define SMC_insb(a, r, p, l)	readsb((a) + (r), p, (l))
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+#define SMC_outb(v, a, r)	writeb(v, (a) + (r))
+#define SMC_outsb(a, r, p, l)	writesb((a) + (r), p, (l))
+#define SMC_outw(v, a, r)	writew(v, (a) + (r))
+#define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
 
 #define set_irq_type(irq, type) do {} while (0)
 
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index de39956..081717d 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -128,6 +128,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_SUNGEM,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_GMAC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 4a3cecc..2387e75 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -31,6 +31,8 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
+
 #include "../pci.h"
 #include "pciehp.h"
 
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index a7859a8..4b35097 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -253,7 +253,7 @@
 	if (!dn || !dn->child)
 		return NULL;
 
-	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
+	if (_machine == PLATFORM_PSERIES_LPAR) {
 		of_scan_bus(dn, bus);
 		if (list_empty(&bus->devices)) {
 			err("%s: No new device found\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 40905a6..9987a6f 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -31,6 +31,8 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
+
 #include "shpchp.h"
 
 #ifdef DEBUG
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 234cdca..a30aa74 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -513,6 +513,11 @@
 	ret = socket_setup(skt, setup_delay);
 	if (ret == CS_SUCCESS) {
 		skt->state |= SOCKET_PRESENT;
+
+		printk(KERN_NOTICE "pccard: %s card inserted into slot %d\n",
+		       (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
+		       skt->sock);
+
 #ifdef CONFIG_CARDBUS
 		if (skt->state & SOCKET_CARDBUS) {
 			cb_alloc(skt);
@@ -598,6 +603,7 @@
 
 static void socket_remove(struct pcmcia_socket *skt)
 {
+	printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock);
 	socket_shutdown(skt);
 	cs_socket_put(skt);
 }
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 39d096b..7f8219f 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -544,6 +544,9 @@
 	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
+	printk(KERN_NOTICE "pcmcia: registering new device %s\n",
+	       p_dev->devname);
+
 	pcmcia_device_query(p_dev);
 
 	if (device_register(&p_dev->dev)) {
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 4ddd762..4d56bc9 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1339,10 +1339,7 @@
 	.resume = pcmcia_socket_dev_resume,
 };
 
-static struct platform_device i82365_device = {
-	.name = "i82365",
-	.id = 0,
-};
+static struct platform_device *i82365_device;
 
 static int __init init_i82365(void)
 {
@@ -1352,7 +1349,14 @@
     if (ret)
 	return ret;
 
-    ret = platform_device_register(&i82365_device);
+    i82365_device = platform_device_alloc("i82365", 0);
+    if (i82365_device) {
+	    ret = platform_device_add(i82365_device);
+	    if (ret)
+		    platform_device_put(i82365_device);
+    } else
+	    ret = -ENOMEM;
+
     if (ret) {
 	driver_unregister(&i82365_driver);
 	return ret;
@@ -1365,7 +1369,7 @@
 
     if (sockets == 0) {
 	printk("not found.\n");
-	platform_device_unregister(&i82365_device);
+	platform_device_unregister(i82365_device);
 	release_region(i365_base, 2);
 	driver_unregister(&i82365_driver);
 	return -ENODEV;
@@ -1377,7 +1381,7 @@
     
     /* register sockets with the pcmcia core */
     for (i = 0; i < sockets; i++) {
-	    socket[i].socket.dev.dev = &i82365_device.dev;
+	    socket[i].socket.dev.dev = &i82365_device->dev;
 	    socket[i].socket.ops = &pcic_operations;
 	    socket[i].socket.resource_ops = &pccard_nonstatic_ops;
 	    socket[i].socket.owner = THIS_MODULE;
@@ -1415,7 +1419,7 @@
 	    if (socket[i].flags & IS_REGISTERED)
 		    pcmcia_unregister_socket(&socket[i].socket);
     }
-    platform_device_unregister(&i82365_device);
+    platform_device_unregister(i82365_device);
     if (poll_interval != 0)
 	del_timer_sync(&poll_timer);
     if (grab_irq != 0)
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index e51d9a8..d81db3a 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -532,8 +532,7 @@
  *	@fis: Buffer from which data will be input
  *	@tf: Taskfile to output
  *
- *	Converts a standard ATA taskfile to a Serial ATA
- *	FIS structure (Register - Host to Device).
+ *	Converts a serial ATA FIS structure to a standard ATA taskfile.
  *
  *	LOCKING:
  *	Inherited from caller.
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 261be24..0df4b68 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -2276,6 +2276,12 @@
 		tf->device = scsicmd[8];
 		tf->command = scsicmd[9];
 	}
+	/*
+	 * If slave is possible, enforce correct master/slave bit
+	*/
+	if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
+		tf->device = qc->dev->devno ?
+			tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
 
 	/*
 	 * Filter SET_FEATURES - XFER MODE command -- otherwise,
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index d3198d9..55e744d 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -687,6 +687,7 @@
 	struct sil24_port_priv *pp = ap->private_data;
 
 	sil24_cblk_free(pp, dev);
+	ata_pad_free(ap, dev);
 	kfree(pp);
 }
 
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 2efb317..67e9afa 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -34,6 +34,7 @@
 #include <linux/keyboard.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 
@@ -1343,7 +1344,7 @@
 	printk("MC68328 serial driver version 1.00\n");
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 /* Serial Power management
  *  The console (currently fixed at line 0) is a special case for power
  *  management because the kernel is so chatty. The console will be 
@@ -1393,7 +1394,7 @@
 	struct m68k_serial *info = &m68k_soft[0];
 	startup(info);
 }
-#endif
+#endif /* CONFIG_PM_LEGACY */
 
 
 static struct tty_operations rs_ops = {
@@ -1486,7 +1487,7 @@
 			    IRQ_FLG_STD,
 			    "M68328_UART", NULL))
                 panic("Unable to attach 68328 serial interrupt\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 	    serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
 	    if (serial_pm[i])
 		    serial_pm[i]->data = info;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 3742753..e08510d 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -999,7 +999,10 @@
 	serial_outp(up, UART_MCR, save_mcr);
 	serial8250_clear_fifos(up);
 	(void)serial_in(up, UART_RX);
-	serial_outp(up, UART_IER, 0);
+	if (up->capabilities & UART_CAP_UUE)
+		serial_outp(up, UART_IER, UART_IER_UUE);
+	else
+		serial_outp(up, UART_IER, 0);
 
  out:	
 	spin_unlock_irqrestore(&up->port.lock, flags);
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 5d8660a..b79ed06 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -323,6 +323,8 @@
 	{	"USR9180",		0	},
 	/* U.S. Robotics 56K Voice INT PnP*/
 	{	"USR9190",		0	},
+	/* HP Compaq Tablet PC tc1100 Wacom tablet */
+	{	"WACF005",		0	},
 	/* Rockwell's (PORALiNK) 33600 INT PNP */
 	{	"WCI0003",		0	},
 	/* Unkown PnP modems */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 25825f2..987d22b 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -7,7 +7,7 @@
  *  Based on ppc8xx.c by Thomas Gleixner
  *  Based on drivers/serial/amba.c by Russell King
  *
- *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
  *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
  *
  *  Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 4b0786e..d789ee5 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -3,7 +3,7 @@
  *
  *  Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
  *
- *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
  *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
  *
  *  Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 15ad58d..fd9e53e 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -3,7 +3,7 @@
  *
  *  Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
  *
- *  Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
  *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
  * 
  *  Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index e63b9df..4d8516d 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -1,9 +1,9 @@
 /*
- * dz.c: Serial port driver for DECStations equiped 
+ * dz.c: Serial port driver for DECStations equiped
  *       with the DZ chipset.
  *
- * Copyright (C) 1998 Olivier A. D. Lebaillif 
- *             
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
  * Email: olivier.lebaillif@ifrsys.com
  *
  * [31-AUG-98] triemer
@@ -11,14 +11,14 @@
  * removed base_addr code - moving address assignment to setup.c
  * Changed name of dz_init to rs_init to be consistent with tc code
  * [13-NOV-98] triemer fixed code to receive characters
- *    after patches by harald to irq code.  
+ *    after patches by harald to irq code.
  * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
  *            field from "current" - somewhere between 2.1.121 and 2.1.131
  Qua Jun 27 15:02:26 BRT 2001
  * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
- *  
- * Parts (C) 1999 David Airlie, airlied@linux.ie 
- * [07-SEP-99] Bugfixes 
+ *
+ * Parts (C) 1999 David Airlie, airlied@linux.ie
+ * [07-SEP-99] Bugfixes
  *
  * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
  * Converted to new serial core
@@ -64,7 +64,7 @@
 
 #ifdef DEBUG_DZ
 /*
- * debugging code to send out chars via prom 
+ * debugging code to send out chars via prom
  */
 static void debug_console(const char *s, int count)
 {
@@ -82,7 +82,7 @@
  * ------------------------------------------------------------
  * dz_in () and dz_out ()
  *
- * These routines are used to access the registers of the DZ 
+ * These routines are used to access the registers of the DZ
  * chip, hiding relocation differences between implementation.
  * ------------------------------------------------------------
  */
@@ -106,8 +106,8 @@
  * ------------------------------------------------------------
  * rs_stop () and rs_start ()
  *
- * These routines are called before setting or resetting 
- * tty->stopped. They enable or disable transmitter interrupts, 
+ * These routines are called before setting or resetting
+ * tty->stopped. They enable or disable transmitter interrupts,
  * as necessary.
  * ------------------------------------------------------------
  */
@@ -156,17 +156,17 @@
 
 /*
  * ------------------------------------------------------------
- * Here starts the interrupt handling routines.  All of the 
- * following subroutines are declared as inline and are folded 
- * into dz_interrupt.  They were separated out for readability's 
- * sake. 
+ * Here starts the interrupt handling routines.  All of the
+ * following subroutines are declared as inline and are folded
+ * into dz_interrupt.  They were separated out for readability's
+ * sake.
  *
  * Note: rs_interrupt() is a "fast" interrupt, which means that it
  * runs with interrupts turned off.  People who may want to modify
  * rs_interrupt() should try to keep the interrupt handler as fast as
  * possible.  After you are done making modifications, it is not a bad
  * idea to do:
- * 
+ *
  *	make drivers/serial/dz.s
  *
  * and look at the resulting assemble code in dz.s.
@@ -403,7 +403,7 @@
  * startup ()
  *
  * various initialization tasks
- * ------------------------------------------------------------------- 
+ * -------------------------------------------------------------------
  */
 static int dz_startup(struct uart_port *uport)
 {
@@ -430,13 +430,13 @@
 	return 0;
 }
 
-/* 
+/*
  * -------------------------------------------------------------------
  * shutdown ()
  *
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
- * ------------------------------------------------------------------- 
+ * -------------------------------------------------------------------
  */
 static void dz_shutdown(struct uart_port *uport)
 {
@@ -451,7 +451,7 @@
  *          release the bus after transmitting. This must be done when
  *          the transmit shift register is empty, not be done when the
  *          transmit holding register is empty.  This functionality
- *          allows an RS485 driver to be written in user space. 
+ *          allows an RS485 driver to be written in user space.
  */
 static unsigned int dz_tx_empty(struct uart_port *uport)
 {
@@ -645,9 +645,9 @@
 
 	if (mips_machtype == MACH_DS23100 ||
 	    mips_machtype == MACH_DS5100)
-		base = (unsigned long) KN01_DZ11_BASE;
+		base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_DZ11);
 	else
-		base = (unsigned long) KN02_DZ11_BASE;
+		base = CKSEG1ADDR(KN02_SLOT_BASE + KN02_DZ11);
 
 	for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
 		spin_lock_init(&dport->port.lock);
@@ -695,13 +695,13 @@
 
 	spin_unlock_irqrestore(&dport->port.lock, flags);
 }
-/* 
+/*
  * -------------------------------------------------------------------
  * dz_console_print ()
  *
  * dz_console_print is registered for printk.
  * The console must be locked when we get here.
- * ------------------------------------------------------------------- 
+ * -------------------------------------------------------------------
  */
 static void dz_console_print(struct console *cons,
 			     const char *str,
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 5d3cb84..b8727d9 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -725,7 +725,7 @@
 	int i, idx, ret;
 
 	/* Check validity & presence */
-	idx = pdev->id;
+	idx = dev->id;
 	if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
 		return -EINVAL;
 
@@ -748,7 +748,7 @@
 	port->ops	= &mpc52xx_uart_ops;
 
 	/* Search for IRQ and mapbase */
-	for (i=0 ; i<pdev->num_resources ; i++, res++) {
+	for (i=0 ; i<dev->num_resources ; i++, res++) {
 		if (res->flags & IORESOURCE_MEM)
 			port->mapbase = res->start;
 		else if (res->flags & IORESOURCE_IRQ)
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index fd9deee..0e3daf6 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -156,7 +156,7 @@
 }
 
 /*
- * interrupts may not be disabled on entry
+ * port locked and interrupts disabled
  */
 static void sa1100_start_tx(struct uart_port *port)
 {
@@ -164,11 +164,9 @@
 	unsigned long flags;
 	u32 utcr3;
 
-	spin_lock_irqsave(&sport->port.lock, flags);
 	utcr3 = UART_GET_UTCR3(sport);
 	sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
 	UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
-	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 /*
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 427a238..2331296 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -209,33 +209,45 @@
 	struct uart_info *info = state->info;
 	struct uart_port *port = state->port;
 
-	if (!(info->flags & UIF_INITIALIZED))
-		return;
+	/*
+	 * Set the TTY IO error marker
+	 */
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	if (info->flags & UIF_INITIALIZED) {
+		info->flags &= ~UIF_INITIALIZED;
+
+		/*
+		 * Turn off DTR and RTS early.
+		 */
+		if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+			uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+		/*
+		 * clear delta_msr_wait queue to avoid mem leaks: we may free
+		 * the irq here so the queue might never be woken up.  Note
+		 * that we won't end up waiting on delta_msr_wait again since
+		 * any outstanding file descriptors should be pointing at
+		 * hung_up_tty_fops now.
+		 */
+		wake_up_interruptible(&info->delta_msr_wait);
+
+		/*
+		 * Free the IRQ and disable the port.
+		 */
+		port->ops->shutdown(port);
+
+		/*
+		 * Ensure that the IRQ handler isn't running on another CPU.
+		 */
+		synchronize_irq(port->irq);
+	}
 
 	/*
-	 * Turn off DTR and RTS early.
+	 * kill off our tasklet
 	 */
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-		uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-
-	/*
-	 * clear delta_msr_wait queue to avoid mem leaks: we may free
-	 * the irq here so the queue might never be woken up.  Note
-	 * that we won't end up waiting on delta_msr_wait again since
-	 * any outstanding file descriptors should be pointing at
-	 * hung_up_tty_fops now.
-	 */
-	wake_up_interruptible(&info->delta_msr_wait);
-
-	/*
-	 * Free the IRQ and disable the port.
-	 */
-	port->ops->shutdown(port);
-
-	/*
-	 * Ensure that the IRQ handler isn't running on another CPU.
-	 */
-	synchronize_irq(port->irq);
+	tasklet_kill(&info->tlet);
 
 	/*
 	 * Free the transmit buffer page.
@@ -244,15 +256,6 @@
 		free_page((unsigned long)info->xmit.buf);
 		info->xmit.buf = NULL;
 	}
-
-	/*
-	 * kill off our tasklet
-	 */
-	tasklet_kill(&info->tlet);
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->flags &= ~UIF_INITIALIZED;
 }
 
 /**
@@ -1928,14 +1931,25 @@
 
 	if (state->info && state->info->flags & UIF_INITIALIZED) {
 		struct uart_ops *ops = port->ops;
+		int ret;
 
 		ops->set_mctrl(port, 0);
-		ops->startup(port);
-		uart_change_speed(state, NULL);
-		spin_lock_irq(&port->lock);
-		ops->set_mctrl(port, port->mctrl);
-		ops->start_tx(port);
-		spin_unlock_irq(&port->lock);
+		ret = ops->startup(port);
+		if (ret == 0) {
+			uart_change_speed(state, NULL);
+			spin_lock_irq(&port->lock);
+			ops->set_mctrl(port, port->mctrl);
+			ops->start_tx(port);
+			spin_unlock_irq(&port->lock);
+		} else {
+			/*
+			 * Failed to resume - maybe hardware went away?
+			 * Clear the "initialized" flag so we won't try
+			 * to call the low level drivers shutdown method.
+			 */
+			state->info->flags &= ~UIF_INITIALIZED;
+			uart_shutdown(state);
+		}
 	}
 
 	up(&state->sem);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index e7802ff..bcea87c 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -106,8 +106,7 @@
 	FBCON_LOGO_DONTSHOW	= -3	/* do not show the logo */
 };
 
-struct display fb_display[MAX_NR_CONSOLES];
-EXPORT_SYMBOL(fb_display);
+static struct display fb_display[MAX_NR_CONSOLES];
 
 static signed char con2fb_map[MAX_NR_CONSOLES];
 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
@@ -653,13 +652,12 @@
 {
 	struct fbcon_ops *ops = info->fbcon_par;
 
+	ops->p = (p) ? p : &fb_display[vc->vc_num];
+
 	if ((info->flags & FBINFO_MISC_TILEBLITTING))
 		fbcon_set_tileops(vc, info, p, ops);
 	else {
-		struct display *disp;
-
-		disp = (p) ? p : &fb_display[vc->vc_num];
-		fbcon_set_rotation(info, disp);
+		fbcon_set_rotation(info, ops->p);
 		fbcon_set_bitops(ops);
 	}
 }
@@ -668,11 +666,10 @@
 			      struct display *p)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *disp;
 
 	info->flags &= ~FBINFO_MISC_TILEBLITTING;
-	disp = (p) ? p : &fb_display[vc->vc_num];
-	fbcon_set_rotation(info, disp);
+	ops->p = (p) ? p : &fb_display[vc->vc_num];
+	fbcon_set_rotation(info, ops->p);
 	fbcon_set_bitops(ops);
 }
 #endif /* CONFIG_MISC_TILEBLITTING */
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index accfd7bd..6892e7f 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -52,8 +52,6 @@
     struct fb_videomode *mode;
 };
 
-extern struct display fb_display[];
-
 struct fbcon_ops {
 	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
 		      int sx, int dy, int dx, int height, int width);
@@ -73,6 +71,7 @@
 	struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
 	struct timer_list cursor_timer; /* Cursor timer */
 	struct fb_cursor cursor_state;
+	struct display *p;
         int    currcon;	                /* Current VC. */
 	int    cursor_flash;
 	int    cursor_reset;
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 680aaba..3afd1ee 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -63,9 +63,9 @@
 static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
 
 	area.sx = sy * vc->vc_font.height;
 	area.sy = vyres - ((sx + width) * vc->vc_font.width);
@@ -80,10 +80,10 @@
 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_fillrect region;
 	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
 
 	region.color = attr_bgcol_ec(bgshift,vc);
 	region.dx = sy * vc->vc_font.height;
@@ -131,7 +131,6 @@
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct display *p = &fb_display[vc->vc_num];
 	struct fbcon_ops *ops = info->fbcon_par;
 	u32 width = (vc->vc_font.height + 7)/8;
 	u32 cellsize = width * vc->vc_font.width;
@@ -141,7 +140,7 @@
 	u32 cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
 
 	if (!ops->fontbuffer)
 		return;
@@ -397,9 +396,8 @@
 int ccw_update_start(struct fb_info *info)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *p = &fb_display[ops->currcon];
 	u32 yoffset;
-	u32 vyres = GETVYRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
 	int err;
 
 	yoffset = (vyres - info->var.yres) - ops->var.xoffset;
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index 6c6f3b6..6d92b84 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -49,9 +49,9 @@
 static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	area.sx = vxres - ((sy + height) * vc->vc_font.height);
 	area.sy = sx * vc->vc_font.width;
@@ -66,10 +66,10 @@
 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_fillrect region;
 	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	region.color = attr_bgcol_ec(bgshift,vc);
 	region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -117,7 +117,6 @@
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct display *p = &fb_display[vc->vc_num];
 	struct fbcon_ops *ops = info->fbcon_par;
 	u32 width = (vc->vc_font.height + 7)/8;
 	u32 cellsize = width * vc->vc_font.width;
@@ -127,7 +126,7 @@
 	u32 cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	if (!ops->fontbuffer)
 		return;
@@ -381,8 +380,7 @@
 int cw_update_start(struct fb_info *info)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *p = &fb_display[ops->currcon];
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 	u32 xoffset;
 	int err;
 
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index 2e1d9d4..c4d7c89 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -48,10 +48,10 @@
 static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int dy, int dx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_copyarea area;
-	u32 vyres = GETVYRES(p->scrollmode, info);
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	area.sy = vyres - ((sy + height) * vc->vc_font.height);
 	area.sx = vxres - ((sx + width) * vc->vc_font.width);
@@ -66,11 +66,11 @@
 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
 		     int sx, int height, int width)
 {
-	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
 	struct fb_fillrect region;
 	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-	u32 vyres = GETVYRES(p->scrollmode, info);
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	region.color = attr_bgcol_ec(bgshift,vc);
 	region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -153,7 +153,6 @@
 		      int fg, int bg)
 {
 	struct fb_image image;
-	struct display *p = &fb_display[vc->vc_num];
 	struct fbcon_ops *ops = info->fbcon_par;
 	u32 width = (vc->vc_font.width + 7)/8;
 	u32 cellsize = width * vc->vc_font.height;
@@ -163,8 +162,8 @@
 	u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
 	u32 attribute = get_attribute(info, scr_readw(s));
 	u8 *dst, *buf = NULL;
-	u32 vyres = GETVYRES(p->scrollmode, info);
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
 	if (!ops->fontbuffer)
 		return;
@@ -421,10 +420,9 @@
 int ud_update_start(struct fb_info *info)
 {
 	struct fbcon_ops *ops = info->fbcon_par;
-	struct display *p = &fb_display[ops->currcon];
 	u32 xoffset, yoffset;
-	u32 vyres = GETVYRES(p->scrollmode, info);
-	u32 vxres = GETVXRES(p->scrollmode, info);
+	u32 vyres = GETVYRES(ops->p->scrollmode, info);
+	u32 vxres = GETVXRES(ops->p->scrollmode, info);
 	int err;
 
 	xoffset = (vxres - info->var.xres) - ops->var.xoffset;
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index f60b1f4..3353103 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -42,7 +42,7 @@
 #define nvidia_probe_i2c_connector(p, c, edid) (-1)
 #endif
 
-#ifdef CONFIG_FB_OF
+#ifdef CONFIG_PPC_OF
 int nvidia_probe_of_connector(struct fb_info *info, int conn,
 			      u8 ** out_edid);
 #else
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 0b40a2a..bee09c6 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -1301,7 +1301,7 @@
 	struct nvidia_par *par = info->par;
 	u32 total;
 
-	total = info->var.yoffset * info->fix.line_length + info->var.xoffset;
+	total = var->yoffset * info->fix.line_length + var->xoffset;
 
 	NVSetStartAddress(par, total);
 
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 2c3aa2f..3e58ddc 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -413,6 +413,7 @@
 	 * region already (FIXME) */
 	request_region(0x3c0, 32, "vesafb");
 
+#ifdef CONFIG_MTRR
 	if (mtrr) {
 		unsigned int temp_size = size_total;
 		unsigned int type = 0;
@@ -450,6 +451,7 @@
 			} while (temp_size >= PAGE_SIZE && rc == -EINVAL);
 		}
 	}
+#endif
 	
 	info->fbops = &vesafb_ops;
 	info->var = vesafb_defined;
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index daa4605..f6e24ee 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -514,7 +514,7 @@
 	if (remapped_fbuf == NULL)
 		goto out;
 
-	info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
+	info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
 	if (!info) {
 		err = -ENOMEM;
 		goto out;
diff --git a/fs/aio.c b/fs/aio.c
index 20bb919..5a28b69 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -457,6 +457,8 @@
 
 static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
 {
+	assert_spin_locked(&ctx->ctx_lock);
+
 	if (req->ki_dtor)
 		req->ki_dtor(req);
 	kmem_cache_free(kiocb_cachep, req);
@@ -498,6 +500,8 @@
 	dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n",
 		req, atomic_read(&req->ki_filp->f_count));
 
+	assert_spin_locked(&ctx->ctx_lock);
+
 	req->ki_users --;
 	if (unlikely(req->ki_users < 0))
 		BUG();
@@ -619,14 +623,13 @@
  * the kiocb (to tell the caller to activate the work
  * queue to process it), or 0, if it found that it was
  * already queued.
- *
- * Should be called with the spin lock iocb->ki_ctx->ctx_lock
- * held
  */
 static inline int __queue_kicked_iocb(struct kiocb *iocb)
 {
 	struct kioctx *ctx = iocb->ki_ctx;
 
+	assert_spin_locked(&ctx->ctx_lock);
+
 	if (list_empty(&iocb->ki_run_list)) {
 		list_add_tail(&iocb->ki_run_list,
 			&ctx->run_list);
@@ -771,13 +774,15 @@
  * 	Process all pending retries queued on the ioctx
  * 	run list.
  * Assumes it is operating within the aio issuer's mm
- * context. Expects to be called with ctx->ctx_lock held
+ * context.
  */
 static int __aio_run_iocbs(struct kioctx *ctx)
 {
 	struct kiocb *iocb;
 	LIST_HEAD(run_list);
 
+	assert_spin_locked(&ctx->ctx_lock);
+
 	list_splice_init(&ctx->run_list, &run_list);
 	while (!list_empty(&run_list)) {
 		iocb = list_entry(run_list.next, struct kiocb,
@@ -937,28 +942,19 @@
 	unsigned long	tail;
 	int		ret;
 
-	/* Special case handling for sync iocbs: events go directly
-	 * into the iocb for fast handling.  Note that this will not 
-	 * work if we allow sync kiocbs to be cancelled. in which
-	 * case the usage count checks will have to move under ctx_lock
-	 * for all cases.
+	/*
+	 * Special case handling for sync iocbs:
+	 *  - events go directly into the iocb for fast handling
+	 *  - the sync task with the iocb in its stack holds the single iocb
+	 *    ref, no other paths have a way to get another ref
+	 *  - the sync task helpfully left a reference to itself in the iocb
 	 */
 	if (is_sync_kiocb(iocb)) {
-		int ret;
-
+		BUG_ON(iocb->ki_users != 1);
 		iocb->ki_user_data = res;
-		if (iocb->ki_users == 1) {
-			iocb->ki_users = 0;
-			ret = 1;
-		} else {
-			spin_lock_irq(&ctx->ctx_lock);
-			iocb->ki_users--;
-			ret = (0 == iocb->ki_users);
-			spin_unlock_irq(&ctx->ctx_lock);
-		}
-		/* sync iocbs put the task here for us */
+		iocb->ki_users = 0;
 		wake_up_process(iocb->ki_obj.tsk);
-		return ret;
+		return 1;
 	}
 
 	info = &ctx->ring_info;
@@ -1613,12 +1609,14 @@
 
 /* lookup_kiocb
  *	Finds a given iocb for cancellation.
- *	MUST be called with ctx->ctx_lock held.
  */
 static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb,
 				  u32 key)
 {
 	struct list_head *pos;
+
+	assert_spin_locked(&ctx->ctx_lock);
+
 	/* TODO: use a hash or array, this sucks. */
 	list_for_each(pos, &ctx->active_reqs) {
 		struct kiocb *kiocb = list_kiocb(pos);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e4ed4b3..522fa70 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -881,7 +881,7 @@
 	}
 	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
 		ext2_warning(sb, __FUNCTION__,
-			"mounting ext3 filesystem as ext2\n");
+			"mounting ext3 filesystem as ext2");
 	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
 	percpu_counter_mod(&sbi->s_freeblocks_counter,
 				ext2_count_free_blocks(sb));
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 5d9b00e..8824e84 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1384,8 +1384,10 @@
 		ClearPageChecked(page);
 		ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
 					ext3_get_block);
-		if (ret != 0)
+		if (ret != 0) {
+			ext3_journal_stop(handle);
 			goto out_unlock;
+		}
 		ret = walk_page_buffers(handle, page_buffers(page), 0,
 			PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
 
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 0e7456e..3e51dd1 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -284,9 +284,6 @@
 		D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen));
 		return -EIO;
 	}
-	D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
-	D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		  buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]));
 	return 0;
 }
 
diff --git a/fs/locks.c b/fs/locks.c
index a1e8b22..250ef53 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1105,7 +1105,6 @@
 			before = &fl->fl_next;
 			continue;
 		}
-		printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid);
 		lease_modify(before, fl->fl_type & ~F_INPROGRESS);
 		if (fl == *before)	/* lease_modify may have freed fl */
 			before = &fl->fl_next;
@@ -1430,7 +1429,7 @@
 	lock_kernel();
 
 	error = __setlease(filp, arg, &flp);
-	if (error)
+	if (error || arg == F_UNLCK)
 		goto out_unlock;
 
 	error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index d2fa420..9ab97ce 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -195,7 +195,7 @@
 
 static int show_map(struct seq_file *m, void *v)
 {
-	return show_map_internal(m, v, 0);
+	return show_map_internal(m, v, NULL);
 }
 
 static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index 20ac3d9..36505bb 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -177,6 +177,18 @@
 	return result;
 }
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
 
diff --git a/include/asm-arm/arch-pxa/akita.h b/include/asm-arm/arch-pxa/akita.h
index 4a1fbcf..5d8cc1d 100644
--- a/include/asm-arm/arch-pxa/akita.h
+++ b/include/asm-arm/arch-pxa/akita.h
@@ -25,6 +25,8 @@
 /* Default Values */
 #define AKITA_IOEXP_IO_OUT	(AKITA_IOEXP_IR_ON | AKITA_IOEXP_AKIN_PULLUP)
 
+extern struct platform_device akitaioexp_device;
+
 void akita_set_ioexp(struct device *dev, unsigned char bitmask);
 void akita_reset_ioexp(struct device *dev, unsigned char bitmask);
 
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index 2885972..75b8027 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -80,6 +80,23 @@
 	return result;
 }
 
+static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
+{
+	u32 oldval, res;
+
+	do {
+		__asm__ __volatile__("@ atomic_cmpxchg\n"
+		"ldrex	%1, [%2]\n"
+		"teq	%1, %3\n"
+		"strexeq %0, %4, [%2]\n"
+		    : "=&r" (res), "=&r" (oldval)
+		    : "r" (&ptr->counter), "Ir" (old), "r" (new)
+		    : "cc");
+	} while (res);
+
+	return oldval;
+}
+
 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 {
 	unsigned long tmp, tmp2;
@@ -131,6 +148,20 @@
 	return val;
 }
 
+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;
+}
+
 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 {
 	unsigned long flags;
@@ -142,6 +173,17 @@
 
 #endif /* __LINUX_ARM_ARCH__ */
 
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+
+	c = atomic_read(v);
+	while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+		c = old;
+	return c != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_add(i, v)	(void) atomic_add_return(i, v)
 #define atomic_inc(v)		(void) atomic_add_return(1, v)
 #define atomic_sub(i, v)	(void) atomic_sub_return(i, v)
diff --git a/include/asm-arm26/atomic.h b/include/asm-arm26/atomic.h
index 4a88235..a47cadc 100644
--- a/include/asm-arm26/atomic.h
+++ b/include/asm-arm26/atomic.h
@@ -62,6 +62,35 @@
         return val;
 }
 
+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;
+}
+
+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 long mask, unsigned long *addr)
 {
         unsigned long flags;
diff --git a/include/asm-cris/atomic.h b/include/asm-cris/atomic.h
index 8c2e783..683b05a 100644
--- a/include/asm-cris/atomic.h
+++ b/include/asm-cris/atomic.h
@@ -123,6 +123,33 @@
 	return retval;
 }
 
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+	int ret;
+	unsigned long flags;
+
+	cris_atomic_save(v, flags);
+	ret = v->counter;
+	if (likely(ret == old))
+		v->counter = new;
+	cris_atomic_restore(v, flags);
+	return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int ret;
+	unsigned long flags;
+
+	cris_atomic_save(v, flags);
+	ret = v->counter;
+	if (ret != u)
+		v->counter += a;
+	cris_atomic_restore(v, flags);
+	return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()    barrier()
 #define smp_mb__after_atomic_dec()     barrier()
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index e759684..f6539ff 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -414,4 +414,16 @@
 
 #endif
 
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #endif /* _ASM_ATOMIC_H */
diff --git a/include/asm-h8300/atomic.h b/include/asm-h8300/atomic.h
index 7230f65..f23d868 100644
--- a/include/asm-h8300/atomic.h
+++ b/include/asm-h8300/atomic.h
@@ -82,6 +82,33 @@
 	return ret == 0;
 }
 
+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;
+}
+
+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 long mask, unsigned long *v)
 {
 	__asm__ __volatile__("stc ccr,r1l\n\t"
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index 509720b..c68557a 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -215,6 +215,27 @@
 	return atomic_add_return(-i,v);
 }
 
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_inc_return(v)  (atomic_add_return(1,v))
 #define atomic_dec_return(v)  (atomic_sub_return(1,v))
 
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 97d52ac..772f85d 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -263,6 +263,10 @@
 
 #ifdef CONFIG_X86_CMPXCHG
 #define __HAVE_ARCH_CMPXCHG 1
+#define cmpxchg(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
+#endif
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
@@ -291,10 +295,42 @@
 	return old;
 }
 
-#define cmpxchg(ptr,o,n)\
-	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-					(unsigned long)(n),sizeof(*(ptr))))
+#ifndef CONFIG_X86_CMPXCHG
+/*
+ * Building a kernel capable running on 80386. It may be necessary to
+ * simulate the cmpxchg on the 80386 CPU. For that purpose we define
+ * a function for each of the sizes we support.
+ */
 
+extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
+extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
+extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
+
+static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	switch (size) {
+	case 1:
+		return cmpxchg_386_u8(ptr, old, new);
+	case 2:
+		return cmpxchg_386_u16(ptr, old, new);
+	case 4:
+		return cmpxchg_386_u32(ptr, old, new);
+	}
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						\
+({									\
+	__typeof__(*(ptr)) __ret;					\
+	if (likely(boot_cpu_data.x86 > 3))				\
+		__ret = __cmpxchg((ptr), (unsigned long)(o),		\
+					(unsigned long)(n), sizeof(*(ptr))); \
+	else								\
+		__ret = cmpxchg_386((ptr), (unsigned long)(o),		\
+					(unsigned long)(n), sizeof(*(ptr))); \
+	__ret;								\
+})
 #endif
 
 #ifdef CONFIG_X86_CMPXCHG64
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index 874a6f8..2fbebf8 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -88,6 +88,18 @@
 	return new;
 }
 
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_add_return(i,v)						\
 ({									\
 	int __ia64_aar_i = (i);						\
diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h
index 38f3043..e3c962e 100644
--- a/include/asm-m68k/atomic.h
+++ b/include/asm-m68k/atomic.h
@@ -139,6 +139,18 @@
 	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
 }
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()	barrier()
 #define smp_mb__after_atomic_dec()	barrier()
diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
index df1575d..7982285 100644
--- a/include/asm-m68k/processor.h
+++ b/include/asm-m68k/processor.h
@@ -14,6 +14,7 @@
 #define current_text_addr() ({ __label__ _l; _l: &&_l;})
 
 #include <linux/config.h>
+#include <linux/thread_info.h>
 #include <asm/segment.h>
 #include <asm/fpu.h>
 #include <asm/ptrace.h>
@@ -55,17 +56,6 @@
 #endif
 #define TASK_UNMAPPED_ALIGN(addr, off)	PAGE_ALIGN(addr)
 
-struct task_work {
-	unsigned char sigpending;
-	unsigned char notify_resume;	/* request for notification on
-					   userspace execution resumption */
-	char          need_resched;
-	unsigned char delayed_trace;	/* single step a syscall */
-	unsigned char syscall_trace;	/* count of syscall interceptors */
-	unsigned char memdie;		/* task was selected to be killed */
-	unsigned char pad[2];
-};
-
 struct thread_struct {
 	unsigned long  ksp;		/* kernel stack pointer */
 	unsigned long  usp;		/* user stack pointer */
@@ -78,7 +68,7 @@
 	unsigned long  fp[8*3];
 	unsigned long  fpcntl[3];	/* fp control regs */
 	unsigned char  fpstate[FPSTATESIZE];  /* floating point state */
-	struct task_work work;
+	struct thread_info info;
 };
 
 #define INIT_THREAD  {							\
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index 2aed24f..9532ca3 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -2,17 +2,15 @@
 #define _ASM_M68K_THREAD_INFO_H
 
 #include <asm/types.h>
-#include <asm/processor.h>
 #include <asm/page.h>
 
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
+	unsigned long		flags;
 	struct exec_domain	*exec_domain;	/* execution domain */
 	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
 	__u32 cpu; /* should always be 0 on m68k */
 	struct restart_block    restart_block;
-
-	__u8			supervisor_stack[0];
 };
 
 #define PREEMPT_ACTIVE		0x4000000
@@ -35,84 +33,29 @@
 #define free_thread_info(ti)  free_pages((unsigned long)(ti),1)
 #endif /* PAGE_SHIFT == 13 */
 
-//#define init_thread_info	(init_task.thread.info)
+#define init_thread_info	(init_task.thread.info)
 #define init_stack		(init_thread_union.stack)
 
-#define current_thread_info()	(current->thread_info)
-
+#define task_thread_info(tsk)	(&(tsk)->thread.info)
+#define current_thread_info()	task_thread_info(current)
 
 #define __HAVE_THREAD_FUNCTIONS
 
-#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
-#define TIF_DELAYED_TRACE	1	/* single step a syscall */
-#define TIF_NOTIFY_RESUME	2	/* resumption notification requested */
-#define TIF_SIGPENDING		3	/* signal pending */
-#define TIF_NEED_RESCHED	4	/* rescheduling necessary */
-#define TIF_MEMDIE		5
+#define setup_thread_stack(p, org) ({			\
+	*(struct task_struct **)(p)->thread_info = (p);	\
+	task_thread_info(p)->task = (p);		\
+})
 
-extern int thread_flag_fixme(void);
+#define end_of_stack(p) ((unsigned long *)(p)->thread_info + 1)
 
-/*
- * flag set/clear/test wrappers
- * - pass TIF_xxxx constants to these functions
+/* entry.S relies on these definitions!
+ * bits 0-7 are tested at every exception exit
+ * bits 8-15 are also tested at syscall exit
  */
-
-#define __set_tsk_thread_flag(tsk, flag, val) ({	\
-	switch (flag) {					\
-	case TIF_SIGPENDING:				\
-		tsk->thread.work.sigpending = val;	\
-		break;					\
-	case TIF_NEED_RESCHED:				\
-		tsk->thread.work.need_resched = val;	\
-		break;					\
-	case TIF_SYSCALL_TRACE:				\
-		tsk->thread.work.syscall_trace = val;	\
-		break;					\
-	case TIF_MEMDIE:				\
-		tsk->thread.work.memdie = val;		\
-		break;					\
-	default:					\
-		thread_flag_fixme();			\
-	}						\
-})
-
-#define __get_tsk_thread_flag(tsk, flag) ({		\
-	int ___res;					\
-	switch (flag) {					\
-	case TIF_SIGPENDING:				\
-		___res = tsk->thread.work.sigpending;	\
-		break;					\
-	case TIF_NEED_RESCHED:				\
-		___res = tsk->thread.work.need_resched;	\
-		break;					\
-	case TIF_SYSCALL_TRACE:				\
-		___res = tsk->thread.work.syscall_trace;\
-		break;					\
-	case TIF_MEMDIE:				\
-		___res = tsk->thread.work.memdie;\
-		break;					\
-	default:					\
-		___res = thread_flag_fixme();		\
-	}						\
-	___res;						\
-})
-
-#define __get_set_tsk_thread_flag(tsk, flag, val) ({	\
-	int __res = __get_tsk_thread_flag(tsk, flag);	\
-	__set_tsk_thread_flag(tsk, flag, val);		\
-	__res;						\
-})
-
-#define set_tsk_thread_flag(tsk, flag) __set_tsk_thread_flag(tsk, flag, ~0)
-#define clear_tsk_thread_flag(tsk, flag) __set_tsk_thread_flag(tsk, flag, 0)
-#define test_and_set_tsk_thread_flag(tsk, flag) __get_set_tsk_thread_flag(tsk, flag, ~0)
-#define test_tsk_thread_flag(tsk, flag) __get_tsk_thread_flag(tsk, flag)
-
-#define set_thread_flag(flag) set_tsk_thread_flag(current, flag)
-#define clear_thread_flag(flag) clear_tsk_thread_flag(current, flag)
-#define test_thread_flag(flag) test_tsk_thread_flag(current, flag)
-
-#define set_need_resched() set_thread_flag(TIF_NEED_RESCHED)
-#define clear_need_resched() clear_thread_flag(TIF_NEED_RESCHED)
+#define TIF_SIGPENDING		6	/* signal pending */
+#define TIF_NEED_RESCHED	7	/* rescheduling necessary */
+#define TIF_DELAYED_TRACE	14	/* single step a syscall */
+#define TIF_SYSCALL_TRACE	15	/* syscall trace active */
+#define TIF_MEMDIE		16
 
 #endif	/* _ASM_M68K_THREAD_INFO_H */
diff --git a/include/asm-m68knommu/atomic.h b/include/asm-m68knommu/atomic.h
index a83631e..3c1cc15 100644
--- a/include/asm-m68knommu/atomic.h
+++ b/include/asm-m68knommu/atomic.h
@@ -128,6 +128,18 @@
 	return temp;
 }
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 6202eb8..2c87b41 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -287,6 +287,27 @@
 	return result;
 }
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 048a2c7..983e9a2 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -164,6 +164,26 @@
 }
 
 /* exported interface */
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_add(i,v)	((void)(__atomic_add_return( ((int)i),(v))))
 #define atomic_sub(i,v)	((void)(__atomic_add_return(-((int)i),(v))))
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 9c0b372..ec4b144 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -164,6 +164,33 @@
 	return t;
 }
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)							 \
+({															 \
+	   int c, old;											 \
+	   c = atomic_read(v);									 \
+	   for (;;) {											  \
+			   if (unlikely(c == (u)))						 \
+					   break;								  \
+			   old = atomic_cmpxchg((v), c, c + (a));		  \
+			   if (likely(old == c))						   \
+					   break;								  \
+			   c = old;										\
+	   }													   \
+	   c != (u);											   \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
 #define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
 
diff --git a/include/asm-ppc/immap_85xx.h b/include/asm-ppc/immap_85xx.h
index 50fb5e4..9383d0c 100644
--- a/include/asm-ppc/immap_85xx.h
+++ b/include/asm-ppc/immap_85xx.h
@@ -3,7 +3,7 @@
  *
  * MPC85xx Internal Memory Map
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor, Inc
  *
diff --git a/include/asm-ppc/ipic.h b/include/asm-ppc/ipic.h
index 9092b92..0fe396a 100644
--- a/include/asm-ppc/ipic.h
+++ b/include/asm-ppc/ipic.h
@@ -3,7 +3,7 @@
  *
  * IPIC external definitions and structure.
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor, Inc
  *
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
index ce21220..7cdf60f 100644
--- a/include/asm-ppc/mpc83xx.h
+++ b/include/asm-ppc/mpc83xx.h
@@ -3,7 +3,7 @@
  *
  * MPC83xx definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor, Inc
  *
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index d98db98..9d14bae 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -3,7 +3,7 @@
  *
  * MPC85xx definitions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor, Inc
  *
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index bba5305..83d8c77 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -3,7 +3,7 @@
  *
  * PPC system definitions and library functions
  *
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2005 Freescale Semiconductor, Inc
  *
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
index 9d86ba6..b3bd4f6 100644
--- a/include/asm-s390/atomic.h
+++ b/include/asm-s390/atomic.h
@@ -198,6 +198,18 @@
         return retval;
 }
 
+#define atomic_cmpxchg(v, o, n) (atomic_compare_and_swap((o), (n), &((v)->counter)))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define smp_mb__before_atomic_dec()	smp_mb()
 #define smp_mb__after_atomic_dec()	smp_mb()
 #define smp_mb__before_atomic_inc()	smp_mb()
diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
index 3c4f805d..aabfd33 100644
--- a/include/asm-sh/atomic.h
+++ b/include/asm-sh/atomic.h
@@ -87,6 +87,35 @@
 #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;
+}
+
+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)
 {
 	unsigned long flags;
diff --git a/include/asm-sh64/atomic.h b/include/asm-sh64/atomic.h
index 8c3872d..927a2bc 100644
--- a/include/asm-sh64/atomic.h
+++ b/include/asm-sh64/atomic.h
@@ -99,6 +99,35 @@
 #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;
+}
+
+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)
 {
 	unsigned long flags;
diff --git a/include/asm-sparc/atomic.h b/include/asm-sparc/atomic.h
index 37f6ab6..62bec7a 100644
--- a/include/asm-sparc/atomic.h
+++ b/include/asm-sparc/atomic.h
@@ -19,6 +19,8 @@
 #define ATOMIC_INIT(i)  { (i) }
 
 extern int __atomic_add_return(int, atomic_t *);
+extern int atomic_cmpxchg(atomic_t *, int, int);
+extern int atomic_add_unless(atomic_t *, int, int);
 extern void atomic_set(atomic_t *, int);
 
 #define atomic_read(v)          ((v)->counter)
@@ -48,6 +50,8 @@
 #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
 #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
 
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 /* This is the old 24-bit implementation.  It's still used internally
  * by some sparc-specific code, notably the semaphore implementation.
  */
diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h
index e175afc..8198c3d 100644
--- a/include/asm-sparc64/atomic.h
+++ b/include/asm-sparc64/atomic.h
@@ -70,6 +70,18 @@
 #define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
 #define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 /* Atomic operations are already serializing */
 #ifdef CONFIG_SMP
 #define smp_mb__before_atomic_dec()	membar_storeload_loadload();
diff --git a/include/asm-v850/atomic.h b/include/asm-v850/atomic.h
index 395268a..bede317 100644
--- a/include/asm-v850/atomic.h
+++ b/include/asm-v850/atomic.h
@@ -90,6 +90,36 @@
 #define atomic_dec_and_test(v)		(atomic_sub_return (1, (v)) == 0)
 #define atomic_add_negative(i,v)	(atomic_add_return ((i), (v)) < 0)
 
+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;
+}
+
+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)
+
 /* Atomic operations are already serializing on ARM */
 #define smp_mb__before_atomic_dec()	barrier()
 #define smp_mb__after_atomic_dec()	barrier()
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index fc4c595..0866ef6 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -360,6 +360,27 @@
 	return atomic_add_return(-i,v);
 }
 
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
 #define atomic_inc_return(v)  (atomic_add_return(1,v))
 #define atomic_dec_return(v)  (atomic_sub_return(1,v))
 
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 68ac3c6..b837820 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -129,9 +129,16 @@
 
 static inline void set_tss_desc(unsigned cpu, void *addr)
 { 
-	set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr, 
-			      DESC_TSS,
-			      sizeof(struct tss_struct) - 1);
+	/*
+	 * sizeof(unsigned long) coming from an extra "long" at the end
+	 * of the iobitmap. See tss_struct definition in processor.h
+	 *
+	 * -1? seg base+limit should be pointing to the address of the
+	 * last valid byte
+	 */
+	set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS],
+		(unsigned long)addr, DESC_TSS,
+		IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
 } 
 
 static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
index 12b5732..3670cc7 100644
--- a/include/asm-xtensa/atomic.h
+++ b/include/asm-xtensa/atomic.h
@@ -223,6 +223,26 @@
  */
 #define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
 
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (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)
 {
diff --git a/include/linux/acct.h b/include/linux/acct.h
index 93c5b3c..9a66401 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -16,6 +16,8 @@
 #define _LINUX_ACCT_H
 
 #include <linux/types.h>
+#include <linux/jiffies.h>
+
 #include <asm/param.h>
 #include <asm/byteorder.h>
 
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 403d71d..49fd376 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -124,7 +124,7 @@
 		(x)->ki_users = 1;			\
 		(x)->ki_key = KIOCB_SYNC_KEY;		\
 		(x)->ki_filp = (filp);			\
-		(x)->ki_ctx = &tsk->active_mm->default_kioctx;	\
+		(x)->ki_ctx = NULL;			\
 		(x)->ki_cancel = NULL;			\
 		(x)->ki_dtor = NULL;			\
 		(x)->ki_obj.tsk = tsk;			\
@@ -210,8 +210,15 @@
 int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
 				  struct iocb *iocb));
 
-#define get_ioctx(kioctx)	do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0)
-#define put_ioctx(kioctx)	do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0)
+#define get_ioctx(kioctx) do {						\
+	BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0));		\
+	atomic_inc(&(kioctx)->users);					\
+} while (0)
+#define put_ioctx(kioctx) do {						\
+	BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0));		\
+	if (unlikely(atomic_dec_and_test(&(kioctx)->users))) 		\
+		__put_ioctx(kioctx);					\
+} while (0)
 
 #define in_aio() !is_sync_wait(current->io_wait)
 /* may be used for debugging */
diff --git a/include/linux/cm4000_cs.h b/include/linux/cm4000_cs.h
new file mode 100644
index 0000000..605ebe2
--- /dev/null
+++ b/include/linux/cm4000_cs.h
@@ -0,0 +1,66 @@
+#ifndef	_CM4000_H_
+#define	_CM4000_H_
+
+#define	MAX_ATR			33
+
+#define	CM4000_MAX_DEV		4
+
+/* those two structures are passed via ioctl() from/to userspace.  They are
+ * used by existing userspace programs, so I kepth the awkward "bIFSD" naming
+ * not to break compilation of userspace apps. -HW */
+
+typedef struct atreq {
+	int32_t atr_len;
+	unsigned char atr[64];
+	int32_t power_act;
+	unsigned char bIFSD;
+	unsigned char bIFSC;
+} atreq_t;
+
+
+/* what is particularly stupid in the original driver is the arch-dependant
+ * member sizes. This leads to CONFIG_COMPAT breakage, since 32bit userspace
+ * will lay out the structure members differently than the 64bit kernel.
+ *
+ * I've changed "ptsreq.protocol" from "unsigned long" to "u_int32_t".
+ * On 32bit this will make no difference.  With 64bit kernels, it will make
+ * 32bit apps work, too.
+ */
+
+typedef struct ptsreq {
+	u_int32_t protocol; /*T=0: 2^0, T=1:  2^1*/
+ 	unsigned char flags;
+ 	unsigned char pts1;
+ 	unsigned char pts2;
+	unsigned char pts3;
+} ptsreq_t;
+
+#define	CM_IOC_MAGIC		'c'
+#define	CM_IOC_MAXNR	        255
+
+#define	CM_IOCGSTATUS		_IOR (CM_IOC_MAGIC, 0, unsigned char *)
+#define	CM_IOCGATR		_IOWR(CM_IOC_MAGIC, 1, atreq_t *)
+#define	CM_IOCSPTS		_IOW (CM_IOC_MAGIC, 2, ptsreq_t *)
+#define	CM_IOCSRDR		_IO  (CM_IOC_MAGIC, 3)
+#define CM_IOCARDOFF            _IO  (CM_IOC_MAGIC, 4)
+
+#define CM_IOSDBGLVL            _IOW(CM_IOC_MAGIC, 250, int*)
+
+/* card and device states */
+#define	CM_CARD_INSERTED		0x01
+#define	CM_CARD_POWERED			0x02
+#define	CM_ATR_PRESENT			0x04
+#define	CM_ATR_VALID	 		0x08
+#define	CM_STATE_VALID			0x0f
+/* extra info only from CM4000 */
+#define	CM_NO_READER			0x10
+#define	CM_BAD_CARD			0x20
+
+
+#ifdef __KERNEL__
+
+#define	DEVICE_NAME		"cmm"
+#define	MODULE_NAME		"cm4000_cs"
+
+#endif	/* __KERNEL__ */
+#endif	/* _CM4000_H_ */
diff --git a/include/linux/file.h b/include/linux/file.h
index d3b1a15..418b610 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -33,13 +33,13 @@
  * Open file table structure
  */
 struct files_struct {
-        atomic_t count;
-        spinlock_t file_lock;     /* Protects all the below members.  Nests inside tsk->alloc_lock */
+	atomic_t count;
 	struct fdtable *fdt;
 	struct fdtable fdtab;
-        fd_set close_on_exec_init;
-        fd_set open_fds_init;
-        struct file * fd_array[NR_OPEN_DEFAULT];
+	fd_set close_on_exec_init;
+	fd_set open_fds_init;
+	struct file * fd_array[NR_OPEN_DEFAULT];
+	spinlock_t file_lock;     /* Protects concurrent writers.  Nests inside tsk->alloc_lock */
 };
 
 #define files_fdtable(files) (rcu_dereference((files)->fdt))
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 114d5d5..934aa9b 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -4,7 +4,7 @@
  * Definitions for any platform device related flags or structures for
  * Freescale processor devices
  *
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
  * Copyright 2004 Freescale Semiconductor, Inc
  *
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index c377943..23279d8 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -39,8 +39,7 @@
 #define __GFP_COMP	((__force gfp_t)0x4000u)/* Add compound page metadata */
 #define __GFP_ZERO	((__force gfp_t)0x8000u)/* Return zeroed page on success */
 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
-#define __GFP_NORECLAIM  ((__force gfp_t)0x20000u) /* No realy zone reclaim during allocation */
-#define __GFP_HARDWALL   ((__force gfp_t)0x40000u) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
 
 #define __GFP_BITS_SHIFT 20	/* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -49,7 +48,7 @@
 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
 			__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
 			__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
-			__GFP_NOMEMALLOC|__GFP_NORECLAIM|__GFP_HARDWALL)
+			__GFP_NOMEMALLOC|__GFP_HARDWALL)
 
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_NOIO	(__GFP_WAIT)
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 5912874..71d2b8a 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -90,6 +90,8 @@
 #define nmi_enter()		irq_enter()
 #define nmi_exit()		sub_preempt_count(HARDIRQ_OFFSET)
 
+struct task_struct;
+
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 static inline void account_user_vtime(struct task_struct *tsk)
 {
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 0cea162..1056717 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -102,8 +102,8 @@
 #define hugetlb_fault(mm, vma, addr, write)	({ BUG(); 0; })
 
 #ifndef HPAGE_MASK
-#define HPAGE_MASK	0		/* Keep the compiler happy */
-#define HPAGE_SIZE	0
+#define HPAGE_MASK	PAGE_MASK		/* Keep the compiler happy */
+#define HPAGE_SIZE	PAGE_SIZE
 #endif
 
 #endif /* !CONFIG_HUGETLB_PAGE */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 74abaec..1543daa 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -107,6 +107,7 @@
 #define I2C_DRIVERID_CX25840	71	/* cx2584x video encoder	*/
 #define I2C_DRIVERID_SAA7127	72	/* saa7124 video encoder	*/
 #define I2C_DRIVERID_SAA711X	73	/* saa711x video encoders	*/
+#define I2C_DRIVERID_AKITAIOEXP	74	/* IO Expander on Sharp SL-C1000 */
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 68ab5f2..dcfd2ec 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -51,7 +51,6 @@
 	.page_table_lock =  SPIN_LOCK_UNLOCKED, 		\
 	.mmlist		= LIST_HEAD_INIT(name.mmlist),		\
 	.cpu_vm_mask	= CPU_MASK_ALL,				\
-	.default_kioctx = INIT_KIOCTX(name.default_kioctx, name),	\
 }
 
 #define INIT_SIGNALS(sig) {	\
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0a90205..41f150a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -9,6 +9,7 @@
 #include <linux/preempt.h>
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
+#include <linux/sched.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index f5fa308..6cfb114 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -329,7 +329,7 @@
 void build_all_zonelists(void);
 void wakeup_kswapd(struct zone *zone, int order);
 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
-		int alloc_type, int can_try_harder, gfp_t gfp_high);
+		int classzone_idx, int alloc_flags);
 
 #ifdef CONFIG_HAVE_MEMORY_PRESENT
 void memory_present(int nid, unsigned long start, unsigned long end);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index ba6c310..ee700c6 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -53,12 +53,12 @@
 
 static inline struct page *page_cache_alloc(struct address_space *x)
 {
-	return alloc_pages(mapping_gfp_mask(x)|__GFP_NORECLAIM, 0);
+	return alloc_pages(mapping_gfp_mask(x), 0);
 }
 
 static inline struct page *page_cache_alloc_cold(struct address_space *x)
 {
-	return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD|__GFP_NORECLAIM, 0);
+	return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
 }
 
 typedef int filler_t(void *, struct page *);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d00f8ba..d4c1c8f 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -805,6 +805,10 @@
 #define PCI_DEVICE_ID_APPLE_SH_SUNGEM   0x0051
 #define PCI_DEVICE_ID_APPLE_U3L_AGP	0x0058
 #define PCI_DEVICE_ID_APPLE_U3H_AGP	0x0059
+#define PCI_DEVICE_ID_APPLE_IPID2_AGP	0x0066
+#define PCI_DEVICE_ID_APPLE_IPID2_ATA	0x0069
+#define PCI_DEVICE_ID_APPLE_IPID2_FW	0x006a
+#define PCI_DEVICE_ID_APPLE_IPID2_GMAC	0x006b
 #define PCI_DEVICE_ID_APPLE_TIGON3	0x1645
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 5451eb1..fb8d2d2 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -38,7 +38,7 @@
 
 #else /* CONFIG_SMP */
 
-#define per_cpu_ptr(ptr, cpu) (ptr)
+#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
 
 static inline void *__alloc_percpu(size_t size, size_t align)
 {
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1514098..5be87ba 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -94,55 +94,6 @@
 	struct list_head entry;
 };
 
-#ifdef CONFIG_PM
-
-extern int pm_active;
-
-#define PM_IS_ACTIVE() (pm_active != 0)
-
-/*
- * Register a device with power management
- */
-struct pm_dev __deprecated *
-pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
-
-/*
- * Unregister a device with power management
- */
-void __deprecated pm_unregister(struct pm_dev *dev);
-
-/*
- * Unregister all devices with matching callback
- */
-void __deprecated pm_unregister_all(pm_callback callback);
-
-/*
- * Send a request to all devices
- */
-int __deprecated pm_send_all(pm_request_t rqst, void *data);
-
-#else /* CONFIG_PM */
-
-#define PM_IS_ACTIVE() 0
-
-static inline struct pm_dev *pm_register(pm_dev_t type,
-					 unsigned long id,
-					 pm_callback callback)
-{
-	return NULL;
-}
-
-static inline void pm_unregister(struct pm_dev *dev) {}
-
-static inline void pm_unregister_all(pm_callback callback) {}
-
-static inline int pm_send_all(pm_request_t rqst, void *data)
-{
-	return 0;
-}
-
-#endif /* CONFIG_PM */
-
 /* Functions above this comment are list-based old-style power
  * managment. Please avoid using them.  */
 
diff --git a/include/linux/pm_legacy.h b/include/linux/pm_legacy.h
new file mode 100644
index 0000000..1252b45
--- /dev/null
+++ b/include/linux/pm_legacy.h
@@ -0,0 +1,56 @@
+#ifndef __LINUX_PM_LEGACY_H__
+#define __LINUX_PM_LEGACY_H__
+
+#include <linux/config.h>
+
+#ifdef CONFIG_PM_LEGACY
+
+extern int pm_active;
+
+#define PM_IS_ACTIVE() (pm_active != 0)
+
+/*
+ * Register a device with power management
+ */
+struct pm_dev __deprecated *
+pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
+
+/*
+ * Unregister a device with power management
+ */
+void __deprecated pm_unregister(struct pm_dev *dev);
+
+/*
+ * Unregister all devices with matching callback
+ */
+void __deprecated pm_unregister_all(pm_callback callback);
+
+/*
+ * Send a request to all devices
+ */
+int __deprecated pm_send_all(pm_request_t rqst, void *data);
+
+#else /* CONFIG_PM_LEGACY */
+
+#define PM_IS_ACTIVE() 0
+
+static inline struct pm_dev *pm_register(pm_dev_t type,
+					 unsigned long id,
+					 pm_callback callback)
+{
+	return NULL;
+}
+
+static inline void pm_unregister(struct pm_dev *dev) {}
+
+static inline void pm_unregister_all(pm_callback callback) {}
+
+static inline int pm_send_all(pm_request_t rqst, void *data)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PM_LEGACY */
+
+#endif /* __LINUX_PM_LEGACY_H__ */
+
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index dd98c54..d9a2f52 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/thread_info.h>
 #include <linux/linkage.h>
 
 #ifdef CONFIG_DEBUG_PREEMPT
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2bbf968..2038bd2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -357,7 +357,6 @@
 	/* aio bits */
 	rwlock_t		ioctx_list_lock;
 	struct kioctx		*ioctx_list;
-	struct kioctx		default_kioctx;
 };
 
 struct sighand_struct {
@@ -1233,32 +1232,49 @@
 	spin_unlock(&p->alloc_lock);
 }
 
+#ifndef __HAVE_THREAD_FUNCTIONS
+
+#define task_thread_info(task) (task)->thread_info
+
+static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
+{
+	*task_thread_info(p) = *task_thread_info(org);
+	task_thread_info(p)->task = p;
+}
+
+static inline unsigned long *end_of_stack(struct task_struct *p)
+{
+	return (unsigned long *)(p->thread_info + 1);
+}
+
+#endif
+
 /* set thread flags in other task's structures
  * - see asm/thread_info.h for TIF_xxxx flags available
  */
 static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
-	set_ti_thread_flag(tsk->thread_info,flag);
+	set_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
 static inline void clear_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
-	clear_ti_thread_flag(tsk->thread_info,flag);
+	clear_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
 static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
-	return test_and_set_ti_thread_flag(tsk->thread_info,flag);
+	return test_and_set_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
 static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
-	return test_and_clear_ti_thread_flag(tsk->thread_info,flag);
+	return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
 static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
-	return test_ti_thread_flag(tsk->thread_info,flag);
+	return test_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
 static inline void set_tsk_need_resched(struct task_struct *tsk)
@@ -1329,12 +1345,12 @@
 
 static inline unsigned int task_cpu(const struct task_struct *p)
 {
-	return p->thread_info->cpu;
+	return task_thread_info(p)->cpu;
 }
 
 static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
 {
-	p->thread_info->cpu = cpu;
+	task_thread_info(p)->cpu = cpu;
 }
 
 #else
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h
index b63ce70..fa1ff3b 100644
--- a/include/linux/smp_lock.h
+++ b/include/linux/smp_lock.h
@@ -2,11 +2,10 @@
 #define __LINUX_SMPLOCK_H
 
 #include <linux/config.h>
+#ifdef CONFIG_LOCK_KERNEL
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 
-#ifdef CONFIG_LOCK_KERNEL
-
 #define kernel_locked()		(current->lock_depth >= 0)
 
 extern int __lockfunc __reacquire_kernel_lock(void);
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index d252f45..1c4eb41 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -27,31 +27,6 @@
  * - pass TIF_xxxx constants to these functions
  */
 
-static inline void set_thread_flag(int flag)
-{
-	set_bit(flag,&current_thread_info()->flags);
-}
-
-static inline void clear_thread_flag(int flag)
-{
-	clear_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_and_set_thread_flag(int flag)
-{
-	return test_and_set_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_and_clear_thread_flag(int flag)
-{
-	return test_and_clear_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_thread_flag(int flag)
-{
-	return test_bit(flag,&current_thread_info()->flags);
-}
-
 static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
 {
 	set_bit(flag,&ti->flags);
@@ -77,15 +52,19 @@
 	return test_bit(flag,&ti->flags);
 }
 
-static inline void set_need_resched(void)
-{
-	set_thread_flag(TIF_NEED_RESCHED);
-}
+#define set_thread_flag(flag) \
+	set_ti_thread_flag(current_thread_info(), flag)
+#define clear_thread_flag(flag) \
+	clear_ti_thread_flag(current_thread_info(), flag)
+#define test_and_set_thread_flag(flag) \
+	test_and_set_ti_thread_flag(current_thread_info(), flag)
+#define test_and_clear_thread_flag(flag) \
+	test_and_clear_ti_thread_flag(current_thread_info(), flag)
+#define test_thread_flag(flag) \
+	test_ti_thread_flag(current_thread_info(), flag)
 
-static inline void clear_need_resched(void)
-{
-	clear_thread_flag(TIF_NEED_RESCHED);
-}
+#define set_need_resched()	set_thread_flag(TIF_NEED_RESCHED)
+#define clear_need_resched()	clear_thread_flag(TIF_NEED_RESCHED)
 
 #endif
 
diff --git a/include/linux/time.h b/include/linux/time.h
index 8e83f4e..bfbe92d 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -101,7 +101,7 @@
 static inline void
 set_normalized_timespec (struct timespec *ts, time_t sec, long nsec)
 {
-	while (nsec > NSEC_PER_SEC) {
+	while (nsec >= NSEC_PER_SEC) {
 		nsec -= NSEC_PER_SEC;
 		++sec;
 	}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 748d043..856d232 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -819,7 +819,7 @@
  */
 struct urb
 {
-	/* private, usb core and host controller only fields in the urb */
+	/* private: usb core and host controller only fields in the urb */
 	struct kref kref;		/* reference count of the URB */
 	spinlock_t lock;		/* lock for the URB */
 	void *hcpriv;			/* private data for host controller */
@@ -827,7 +827,7 @@
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
 
-	/* public, documented fields in the urb that can be used by drivers */
+	/* public: documented fields in the urb that can be used by drivers */
 	struct list_head urb_list;	/* list head for use by the urb's
 					 * current owner */
 	struct usb_device *dev; 	/* (in) pointer to associated device */
@@ -1045,7 +1045,7 @@
 	size_t			bytes;
 
 	/* 
-	 * members below are private to usbcore,
+	 * members below are private: to usbcore,
 	 * and are not provided for driver access!
 	 */
 	spinlock_t		lock;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index a114fff..1cded68 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -636,6 +636,7 @@
 #define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
 #define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
 #define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
 
 /* ATSC/HDTV */
 #define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 0f1ba95..ad3e9bb 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -49,6 +49,7 @@
 
 extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 00fa57e..730f21e 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -19,4 +19,6 @@
 	char                   phys[32];
 	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
+
+int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 #endif
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 9184e53..faa0f8e 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -113,6 +113,7 @@
 #define TUNER_PHILIPS_TD1316		67
 
 #define TUNER_PHILIPS_TUV1236D		68	/* ATI HDTV Wonder */
+#define TUNER_TNF_5335MF                69	/* Sabrent Bt848   */
 
 #define NOTUNER 0
 #define PAL     1	/* PAL_BG */
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
new file mode 100644
index 0000000..d3fd481
--- /dev/null
+++ b/include/media/v4l2-common.h
@@ -0,0 +1,110 @@
+/*
+    v4l2 common internal API header
+
+    This header contains internal shared ioctl definitions for use by the
+    internal low-level v4l2 drivers.
+    Each ioctl begins with VIDIOC_INT_ to clearly mark that it is an internal
+    define,
+
+    Copyright (C) 2005  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You 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 V4L2_COMMON_H_
+#define V4L2_COMMON_H_
+
+/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
+enum v4l2_audio_clock_freq {
+	V4L2_AUDCLK_32_KHZ  = 32000,
+	V4L2_AUDCLK_441_KHZ = 44100,
+	V4L2_AUDCLK_48_KHZ  = 48000,
+};
+
+/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
+struct v4l2_register {
+	u32 i2c_id; 		/* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
+	unsigned long reg;
+	u32 val;
+};
+
+/* VIDIOC_INT_DECODE_VBI_LINE */
+struct v4l2_decode_vbi_line {
+	u32 is_second_field;	/* Set to 0 for the first (odd) field,
+				   set to 1 for the second (even) field. */
+	u8 *p; 			/* Pointer to the sliced VBI data from the decoder.
+				   On exit points to the start of the payload. */
+	u32 line;		/* Line number of the sliced VBI data (1-23) */
+	u32 type;		/* VBI service type (V4L2_SLICED_*). 0 if no service found */
+};
+
+/* VIDIOC_INT_G_CHIP_IDENT: identifies the actual chip installed on the board */
+enum v4l2_chip_ident {
+	/* general idents: reserved range 0-49 */
+	V4L2_IDENT_UNKNOWN = 0,
+
+	/* module saa7115: reserved range 100-149 */
+	V4L2_IDENT_SAA7114 = 104,
+	V4L2_IDENT_SAA7115 = 105,
+
+	/* module saa7127: reserved range 150-199 */
+	V4L2_IDENT_SAA7127 = 157,
+	V4L2_IDENT_SAA7129 = 159,
+
+	/* module cx25840: reserved range 200-249 */
+	V4L2_IDENT_CX25840 = 240,
+	V4L2_IDENT_CX25841 = 241,
+	V4L2_IDENT_CX25842 = 242,
+	V4L2_IDENT_CX25843 = 243,
+};
+
+/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
+#define	VIDIOC_INT_S_REGISTER 		_IOR ('d', 100, struct v4l2_register)
+#define	VIDIOC_INT_G_REGISTER 		_IOWR('d', 101, struct v4l2_register)
+
+/* Reset the I2C chip */
+#define VIDIOC_INT_RESET            	_IO  ('d', 102)
+
+/* Set the frequency of the audio clock output.
+   Used to slave an audio processor to the video decoder, ensuring that audio
+   and video remain synchronized. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ 	_IOR ('d', 103, enum v4l2_audio_clock_freq)
+
+/* Video decoders that support sliced VBI need to implement this ioctl.
+   Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
+   data that was generated by the decoder. The driver then parses the sliced
+   VBI data and sets the other fields in the struct accordingly. The pointer p
+   is updated to point to the start of the payload which can be copied
+   verbatim into the data field of the v4l2_sliced_vbi_data struct. If no
+   valid VBI data was found, then the type field is set to 0 on return. */
+#define VIDIOC_INT_DECODE_VBI_LINE  	_IOWR('d', 104, struct v4l2_decode_vbi_line)
+
+/* Used to generate VBI signals on a video signal. v4l2_sliced_vbi_data is
+   filled with the data packets that should be output. Note that if you set
+   the line field to 0, then that VBI signal is disabled. */
+#define VIDIOC_INT_S_VBI_DATA 		_IOW ('d', 105, struct v4l2_sliced_vbi_data)
+
+/* Used to obtain the sliced VBI packet from a readback register. Not all
+   video decoders support this. If no data is available because the readback
+   register contains invalid or erroneous data -EIO is returned. Note that
+   you must fill in the 'id' member and the 'field' member (to determine
+   whether CC data from the first or second field should be obtained). */
+#define VIDIOC_INT_G_VBI_DATA 		_IOWR('d', 106, struct v4l2_sliced_vbi_data *)
+
+/* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
+   be made. */
+#define VIDIOC_INT_G_CHIP_IDENT		_IOR ('d', 107, enum v4l2_chip_ident *)
+
+#endif /* V4L2_COMMON_H_ */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 5a737ed..7430640 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1809,11 +1809,12 @@
 	if (gfp_mask & __GFP_HARDWALL)	/* If hardwall request, stop here */
 		return 0;
 
+	if (current->flags & PF_EXITING) /* Let dying task have memory */
+		return 1;
+
 	/* Not hardwall and node outside mems_allowed: scan up cpusets */
 	down(&callback_sem);
 
-	if (current->flags & PF_EXITING) /* Let dying task have memory */
-		return 1;
 	task_lock(current);
 	cs = nearest_exclusive_ancestor(current->cpuset);
 	task_unlock(current);
diff --git a/kernel/exit.c b/kernel/exit.c
index 452a1d1..ee51568 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -859,7 +859,7 @@
 	if (group_dead && tsk->signal->leader)
 		disassociate_ctty(1);
 
-	module_put(tsk->thread_info->exec_domain->module);
+	module_put(task_thread_info(tsk)->exec_domain->module);
 	if (tsk->binfmt)
 		module_put(tsk->binfmt->module);
 
diff --git a/kernel/fork.c b/kernel/fork.c
index 158710d..e0d0b77 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -171,10 +171,9 @@
 		return NULL;
 	}
 
-	*ti = *orig->thread_info;
 	*tsk = *orig;
 	tsk->thread_info = ti;
-	ti->task = tsk;
+	setup_thread_stack(tsk, orig);
 
 	/* One for us, one for whoever does the "release_task()" (usually parent) */
 	atomic_set(&tsk->usage,2);
@@ -324,7 +323,6 @@
 	spin_lock_init(&mm->page_table_lock);
 	rwlock_init(&mm->ioctx_list_lock);
 	mm->ioctx_list = NULL;
-	mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
 
@@ -919,7 +917,7 @@
 	if (nr_threads >= max_threads)
 		goto bad_fork_cleanup_count;
 
-	if (!try_module_get(p->thread_info->exec_domain->module))
+	if (!try_module_get(task_thread_info(p)->exec_domain->module))
 		goto bad_fork_cleanup_count;
 
 	if (p->binfmt && !try_module_get(p->binfmt->module))
@@ -1180,7 +1178,7 @@
 	if (p->binfmt)
 		module_put(p->binfmt->module);
 bad_fork_cleanup_put_domain:
-	module_put(p->thread_info->exec_domain->module);
+	module_put(task_thread_info(p)->exec_domain->module);
 bad_fork_cleanup_count:
 	put_group_info(p->group_info);
 	atomic_dec(&p->user->processes);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index ea55c7a..5870efb 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -270,7 +270,7 @@
 	long sec = tp->tv_sec;
 	long nsec = tp->tv_nsec + res - 1;
 
-	if (nsec > NSEC_PER_SEC) {
+	if (nsec >= NSEC_PER_SEC) {
 		sec++;
 		nsec -= NSEC_PER_SEC;
 	}
@@ -1209,13 +1209,9 @@
 
 	do_posix_clock_monotonic_gettime_parts(tp, &wall_to_mono);
 
-	tp->tv_sec += wall_to_mono.tv_sec;
-	tp->tv_nsec += wall_to_mono.tv_nsec;
+	set_normalized_timespec(tp, tp->tv_sec + wall_to_mono.tv_sec,
+				tp->tv_nsec + wall_to_mono.tv_nsec);
 
-	if ((tp->tv_nsec - NSEC_PER_SEC) > 0) {
-		tp->tv_nsec -= NSEC_PER_SEC;
-		tp->tv_sec++;
-	}
 	return 0;
 }
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 46a5e5a..5ec248c 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -19,6 +19,15 @@
 	  will issue the hlt instruction if nothing is to be done, thereby
 	  sending the processor to sleep and saving power.
 
+config PM_LEGACY
+	bool "Legacy Power Management API"
+	depends on PM
+	default y
+	---help---
+	   Support for pm_register() and friends.
+
+	   If unsure, say Y.
+
 config PM_DEBUG
 	bool "Power Management Debug Support"
 	depends on PM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index c71eb45..04be7d0 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -3,7 +3,8 @@
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
-obj-y				:= main.o process.o console.o pm.o
+obj-y				:= main.o process.o console.o
+obj-$(CONFIG_PM_LEGACY)		+= pm.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o snapshot.o
 
 obj-$(CONFIG_SUSPEND_SMP)	+= smp.o
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
index 1591493..33c508e 100644
--- a/kernel/power/pm.c
+++ b/kernel/power/pm.c
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/interrupt.h>
 
 int pm_active;
diff --git a/kernel/printk.c b/kernel/printk.c
index e9be027..ac8a08f 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -491,7 +491,10 @@
 	return sched_clock();
 }
 
-/*
+/**
+ * printk - print a kernel message
+ * @fmt: format string
+ *
  * This is printk.  It can be called from any context.  We want it to work.
  *
  * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
@@ -503,6 +506,9 @@
  * One effect of this deferred printing is that code which calls printk() and
  * then changes console_loglevel may break. This is because console_loglevel
  * is inspected when the actual printing occurs.
+ *
+ * See also:
+ * printf(3)
  */
 
 asmlinkage int printk(const char *fmt, ...)
@@ -655,6 +661,9 @@
 
 /**
  * add_preferred_console - add a device to the list of preferred consoles.
+ * @name: device name
+ * @idx: device index
+ * @options: options for this console
  *
  * The last preferred console added will be used for kernel messages
  * and stdin/out/err for init.  Normally this is used by console_setup
@@ -764,7 +773,8 @@
 }
 EXPORT_SYMBOL(release_console_sem);
 
-/** console_conditional_schedule - yield the CPU if required
+/**
+ * console_conditional_schedule - yield the CPU if required
  *
  * If the console code is currently allowed to sleep, and
  * if this CPU should yield the CPU to another task, do
@@ -976,6 +986,8 @@
 
 /**
  * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
  *
  * This is used for messages that need to be redirected to a specific tty.
  * We don't put it into the syslog queue right now maybe in the future if
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b88d418..17ee7e5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -470,7 +470,7 @@
 
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_put_task_struct;
 	}
 
 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 9b58f1e..eb6719c 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -195,6 +195,8 @@
 	static DEFINE_RCU_RANDOM(rand);
 
 	VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
+	set_user_nice(current, 19);
+
 	do {
 		schedule_timeout_uninterruptible(1);
 		if (rcu_batches_completed() == oldbatch)
@@ -238,6 +240,8 @@
 	int pipe_count;
 
 	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
+	set_user_nice(current, 19);
+
 	do {
 		rcu_read_lock();
 		completed = rcu_batches_completed();
diff --git a/kernel/sched.c b/kernel/sched.c
index b650667..6f46c94 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1437,7 +1437,7 @@
 #endif
 #ifdef CONFIG_PREEMPT
 	/* Want to start with kernel preemption disabled. */
-	p->thread_info->preempt_count = 1;
+	task_thread_info(p)->preempt_count = 1;
 #endif
 	/*
 	 * Share the timeslice between parent and child, thus the
@@ -4327,10 +4327,10 @@
 #endif
 #ifdef CONFIG_DEBUG_STACK_USAGE
 	{
-		unsigned long *n = (unsigned long *) (p->thread_info+1);
+		unsigned long *n = end_of_stack(p);
 		while (!*n)
 			n++;
-		free = (unsigned long) n - (unsigned long)(p->thread_info+1);
+		free = (unsigned long)n - (unsigned long)end_of_stack(p);
 	}
 #endif
 	printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
@@ -4410,9 +4410,9 @@
 
 	/* Set the preempt count _outside_ the spinlocks! */
 #if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)
-	idle->thread_info->preempt_count = (idle->lock_depth >= 0);
+	task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0);
 #else
-	idle->thread_info->preempt_count = 0;
+	task_thread_info(idle)->preempt_count = 0;
 #endif
 }
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 80789a5..d7611f1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -513,16 +513,7 @@
 {
 	int sig = 0;
 
-	/* SIGKILL must have priority, otherwise it is quite easy
-	 * to create an unkillable process, sending sig < SIGKILL
-	 * to self */
-	if (unlikely(sigismember(&pending->signal, SIGKILL))) {
-		if (!sigismember(mask, SIGKILL))
-			sig = SIGKILL;
-	}
-
-	if (likely(!sig))
-		sig = next_signal(pending, mask);
+	sig = next_signal(pending, mask);
 	if (sig) {
 		if (current->notifier) {
 			if (sigismember(current->notifier_mask, sig)) {
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 84a9d18..b3d4dc8 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -119,13 +119,12 @@
 		return ret;
 	}
 
-	/* Don't schedule us away at this point, please. */
-	local_irq_disable();
-
 	/* Now they are all started, make them hold the CPUs, ready. */
+	preempt_disable();
 	stopmachine_set_state(STOPMACHINE_PREPARE);
 
 	/* Make them disable irqs. */
+	local_irq_disable();
 	stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
 
 	return 0;
@@ -135,6 +134,7 @@
 {
 	stopmachine_set_state(STOPMACHINE_EXIT);
 	local_irq_enable();
+	preempt_enable_no_resched();
 }
 
 struct stop_machine_data
diff --git a/mm/memory.c b/mm/memory.c
index 0f60baf..2998cfc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -549,10 +549,10 @@
 	return 0;
 }
 
-static void zap_pte_range(struct mmu_gather *tlb,
+static unsigned long zap_pte_range(struct mmu_gather *tlb,
 				struct vm_area_struct *vma, pmd_t *pmd,
 				unsigned long addr, unsigned long end,
-				struct zap_details *details)
+				long *zap_work, struct zap_details *details)
 {
 	struct mm_struct *mm = tlb->mm;
 	pte_t *pte;
@@ -563,10 +563,15 @@
 	pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
 	do {
 		pte_t ptent = *pte;
-		if (pte_none(ptent))
+		if (pte_none(ptent)) {
+			(*zap_work)--;
 			continue;
+		}
 		if (pte_present(ptent)) {
 			struct page *page = NULL;
+
+			(*zap_work) -= PAGE_SIZE;
+
 			if (!(vma->vm_flags & VM_RESERVED)) {
 				unsigned long pfn = pte_pfn(ptent);
 				if (unlikely(!pfn_valid(pfn)))
@@ -624,16 +629,18 @@
 		if (!pte_file(ptent))
 			free_swap_and_cache(pte_to_swp_entry(ptent));
 		pte_clear_full(mm, addr, pte, tlb->fullmm);
-	} while (pte++, addr += PAGE_SIZE, addr != end);
+	} while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
 
 	add_mm_rss(mm, file_rss, anon_rss);
 	pte_unmap_unlock(pte - 1, ptl);
+
+	return addr;
 }
 
-static inline void zap_pmd_range(struct mmu_gather *tlb,
+static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
 				struct vm_area_struct *vma, pud_t *pud,
 				unsigned long addr, unsigned long end,
-				struct zap_details *details)
+				long *zap_work, struct zap_details *details)
 {
 	pmd_t *pmd;
 	unsigned long next;
@@ -641,16 +648,21 @@
 	pmd = pmd_offset(pud, addr);
 	do {
 		next = pmd_addr_end(addr, end);
-		if (pmd_none_or_clear_bad(pmd))
+		if (pmd_none_or_clear_bad(pmd)) {
+			(*zap_work)--;
 			continue;
-		zap_pte_range(tlb, vma, pmd, addr, next, details);
-	} while (pmd++, addr = next, addr != end);
+		}
+		next = zap_pte_range(tlb, vma, pmd, addr, next,
+						zap_work, details);
+	} while (pmd++, addr = next, (addr != end && *zap_work > 0));
+
+	return addr;
 }
 
-static inline void zap_pud_range(struct mmu_gather *tlb,
+static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
 				struct vm_area_struct *vma, pgd_t *pgd,
 				unsigned long addr, unsigned long end,
-				struct zap_details *details)
+				long *zap_work, struct zap_details *details)
 {
 	pud_t *pud;
 	unsigned long next;
@@ -658,15 +670,21 @@
 	pud = pud_offset(pgd, addr);
 	do {
 		next = pud_addr_end(addr, end);
-		if (pud_none_or_clear_bad(pud))
+		if (pud_none_or_clear_bad(pud)) {
+			(*zap_work)--;
 			continue;
-		zap_pmd_range(tlb, vma, pud, addr, next, details);
-	} while (pud++, addr = next, addr != end);
+		}
+		next = zap_pmd_range(tlb, vma, pud, addr, next,
+						zap_work, details);
+	} while (pud++, addr = next, (addr != end && *zap_work > 0));
+
+	return addr;
 }
 
-static void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+static unsigned long unmap_page_range(struct mmu_gather *tlb,
+				struct vm_area_struct *vma,
 				unsigned long addr, unsigned long end,
-				struct zap_details *details)
+				long *zap_work, struct zap_details *details)
 {
 	pgd_t *pgd;
 	unsigned long next;
@@ -679,11 +697,16 @@
 	pgd = pgd_offset(vma->vm_mm, addr);
 	do {
 		next = pgd_addr_end(addr, end);
-		if (pgd_none_or_clear_bad(pgd))
+		if (pgd_none_or_clear_bad(pgd)) {
+			(*zap_work)--;
 			continue;
-		zap_pud_range(tlb, vma, pgd, addr, next, details);
-	} while (pgd++, addr = next, addr != end);
+		}
+		next = zap_pud_range(tlb, vma, pgd, addr, next,
+						zap_work, details);
+	} while (pgd++, addr = next, (addr != end && *zap_work > 0));
 	tlb_end_vma(tlb, vma);
+
+	return addr;
 }
 
 #ifdef CONFIG_PREEMPT
@@ -724,7 +747,7 @@
 		unsigned long end_addr, unsigned long *nr_accounted,
 		struct zap_details *details)
 {
-	unsigned long zap_bytes = ZAP_BLOCK_SIZE;
+	long zap_work = ZAP_BLOCK_SIZE;
 	unsigned long tlb_start = 0;	/* For tlb_finish_mmu */
 	int tlb_start_valid = 0;
 	unsigned long start = start_addr;
@@ -745,26 +768,24 @@
 			*nr_accounted += (end - start) >> PAGE_SHIFT;
 
 		while (start != end) {
-			unsigned long block;
-
 			if (!tlb_start_valid) {
 				tlb_start = start;
 				tlb_start_valid = 1;
 			}
 
-			if (is_vm_hugetlb_page(vma)) {
-				block = end - start;
+			if (unlikely(is_vm_hugetlb_page(vma))) {
 				unmap_hugepage_range(vma, start, end);
-			} else {
-				block = min(zap_bytes, end - start);
-				unmap_page_range(*tlbp, vma, start,
-						start + block, details);
-			}
+				zap_work -= (end - start) /
+						(HPAGE_SIZE / PAGE_SIZE);
+				start = end;
+			} else
+				start = unmap_page_range(*tlbp, vma,
+						start, end, &zap_work, details);
 
-			start += block;
-			zap_bytes -= block;
-			if ((long)zap_bytes > 0)
-				continue;
+			if (zap_work > 0) {
+				BUG_ON(start != end);
+				break;
+			}
 
 			tlb_finish_mmu(*tlbp, tlb_start, start);
 
@@ -779,7 +800,7 @@
 
 			*tlbp = tlb_gather_mmu(vma->vm_mm, fullmm);
 			tlb_start_valid = 0;
-			zap_bytes = ZAP_BLOCK_SIZE;
+			zap_work = ZAP_BLOCK_SIZE;
 		}
 	}
 out:
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 987225b..3c5cf66 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -732,9 +732,7 @@
 		}
 		local_irq_restore(flags);
 		put_cpu();
-	}
-
-	if (page == NULL) {
+	} else {
 		spin_lock_irqsave(&zone->lock, flags);
 		page = __rmqueue(zone, order);
 		spin_unlock_irqrestore(&zone->lock, flags);
@@ -754,20 +752,25 @@
 	return page;
 }
 
+#define ALLOC_NO_WATERMARKS	0x01 /* don't check watermarks at all */
+#define ALLOC_HARDER		0x02 /* try to alloc harder */
+#define ALLOC_HIGH		0x04 /* __GFP_HIGH set */
+#define ALLOC_CPUSET		0x08 /* check for correct cpuset */
+
 /*
  * Return 1 if free pages are above 'mark'. This takes into account the order
  * of the allocation.
  */
 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
-		      int classzone_idx, int can_try_harder, gfp_t gfp_high)
+		      int classzone_idx, int alloc_flags)
 {
 	/* free_pages my go negative - that's OK */
 	long min = mark, free_pages = z->free_pages - (1 << order) + 1;
 	int o;
 
-	if (gfp_high)
+	if (alloc_flags & ALLOC_HIGH)
 		min -= min / 2;
-	if (can_try_harder)
+	if (alloc_flags & ALLOC_HARDER)
 		min -= min / 4;
 
 	if (free_pages <= min + z->lowmem_reserve[classzone_idx])
@@ -785,14 +788,40 @@
 	return 1;
 }
 
-static inline int
-should_reclaim_zone(struct zone *z, gfp_t gfp_mask)
+/*
+ * get_page_from_freeliest goes through the zonelist trying to allocate
+ * a page.
+ */
+static struct page *
+get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
+		struct zonelist *zonelist, int alloc_flags)
 {
-	if (!z->reclaim_pages)
-		return 0;
-	if (gfp_mask & __GFP_NORECLAIM)
-		return 0;
-	return 1;
+	struct zone **z = zonelist->zones;
+	struct page *page = NULL;
+	int classzone_idx = zone_idx(*z);
+
+	/*
+	 * Go through the zonelist once, looking for a zone with enough free.
+	 * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+	 */
+	do {
+		if ((alloc_flags & ALLOC_CPUSET) &&
+				!cpuset_zone_allowed(*z, gfp_mask))
+			continue;
+
+		if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
+			if (!zone_watermark_ok(*z, order, (*z)->pages_low,
+				    classzone_idx, alloc_flags))
+				continue;
+		}
+
+		page = buffered_rmqueue(*z, order, gfp_mask);
+		if (page) {
+			zone_statistics(zonelist, *z);
+			break;
+		}
+	} while (*(++z) != NULL);
+	return page;
 }
 
 /*
@@ -803,105 +832,75 @@
 		struct zonelist *zonelist)
 {
 	const gfp_t wait = gfp_mask & __GFP_WAIT;
-	struct zone **zones, *z;
+	struct zone **z;
 	struct page *page;
 	struct reclaim_state reclaim_state;
 	struct task_struct *p = current;
-	int i;
-	int classzone_idx;
 	int do_retry;
-	int can_try_harder;
+	int alloc_flags;
 	int did_some_progress;
 
 	might_sleep_if(wait);
 
-	/*
-	 * The caller may dip into page reserves a bit more if the caller
-	 * cannot run direct reclaim, or is the caller has realtime scheduling
-	 * policy
-	 */
-	can_try_harder = (unlikely(rt_task(p)) && !in_interrupt()) || !wait;
+	z = zonelist->zones;  /* the list of zones suitable for gfp_mask */
 
-	zones = zonelist->zones;  /* the list of zones suitable for gfp_mask */
-
-	if (unlikely(zones[0] == NULL)) {
+	if (unlikely(*z == NULL)) {
 		/* Should this ever happen?? */
 		return NULL;
 	}
-
-	classzone_idx = zone_idx(zones[0]);
-
 restart:
+	page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+				zonelist, ALLOC_CPUSET);
+	if (page)
+		goto got_pg;
+
+	do
+		wakeup_kswapd(*z, order);
+	while (*(++z));
+
 	/*
-	 * Go through the zonelist once, looking for a zone with enough free.
-	 * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+	 * OK, we're below the kswapd watermark and have kicked background
+	 * reclaim. Now things get more complex, so set up alloc_flags according
+	 * to how we want to proceed.
+	 *
+	 * The caller may dip into page reserves a bit more if the caller
+	 * cannot run direct reclaim, or if the caller has realtime scheduling
+	 * policy.
 	 */
-	for (i = 0; (z = zones[i]) != NULL; i++) {
-		int do_reclaim = should_reclaim_zone(z, gfp_mask);
-
-		if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
-			continue;
-
-		/*
-		 * If the zone is to attempt early page reclaim then this loop
-		 * will try to reclaim pages and check the watermark a second
-		 * time before giving up and falling back to the next zone.
-		 */
-zone_reclaim_retry:
-		if (!zone_watermark_ok(z, order, z->pages_low,
-				       classzone_idx, 0, 0)) {
-			if (!do_reclaim)
-				continue;
-			else {
-				zone_reclaim(z, gfp_mask, order);
-				/* Only try reclaim once */
-				do_reclaim = 0;
-				goto zone_reclaim_retry;
-			}
-		}
-
-		page = buffered_rmqueue(z, order, gfp_mask);
-		if (page)
-			goto got_pg;
-	}
-
-	for (i = 0; (z = zones[i]) != NULL; i++)
-		wakeup_kswapd(z, order);
+	alloc_flags = 0;
+	if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait)
+		alloc_flags |= ALLOC_HARDER;
+	if (gfp_mask & __GFP_HIGH)
+		alloc_flags |= ALLOC_HIGH;
+	if (wait)
+		alloc_flags |= ALLOC_CPUSET;
 
 	/*
 	 * Go through the zonelist again. Let __GFP_HIGH and allocations
-	 * coming from realtime tasks to go deeper into reserves
+	 * coming from realtime tasks go deeper into reserves.
 	 *
 	 * This is the last chance, in general, before the goto nopage.
 	 * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
 	 * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
 	 */
-	for (i = 0; (z = zones[i]) != NULL; i++) {
-		if (!zone_watermark_ok(z, order, z->pages_min,
-				       classzone_idx, can_try_harder,
-				       gfp_mask & __GFP_HIGH))
-			continue;
-
-		if (wait && !cpuset_zone_allowed(z, gfp_mask))
-			continue;
-
-		page = buffered_rmqueue(z, order, gfp_mask);
-		if (page)
-			goto got_pg;
-	}
+	page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);
+	if (page)
+		goto got_pg;
 
 	/* This allocation should allow future memory freeing. */
 
 	if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))
 			&& !in_interrupt()) {
 		if (!(gfp_mask & __GFP_NOMEMALLOC)) {
+nofail_alloc:
 			/* go through the zonelist yet again, ignoring mins */
-			for (i = 0; (z = zones[i]) != NULL; i++) {
-				if (!cpuset_zone_allowed(z, gfp_mask))
-					continue;
-				page = buffered_rmqueue(z, order, gfp_mask);
-				if (page)
-					goto got_pg;
+			page = get_page_from_freelist(gfp_mask, order,
+				zonelist, ALLOC_NO_WATERMARKS|ALLOC_CPUSET);
+			if (page)
+				goto got_pg;
+			if (gfp_mask & __GFP_NOFAIL) {
+				blk_congestion_wait(WRITE, HZ/50);
+				goto nofail_alloc;
 			}
 		}
 		goto nopage;
@@ -919,7 +918,7 @@
 	reclaim_state.reclaimed_slab = 0;
 	p->reclaim_state = &reclaim_state;
 
-	did_some_progress = try_to_free_pages(zones, gfp_mask);
+	did_some_progress = try_to_free_pages(zonelist->zones, gfp_mask);
 
 	p->reclaim_state = NULL;
 	p->flags &= ~PF_MEMALLOC;
@@ -927,19 +926,10 @@
 	cond_resched();
 
 	if (likely(did_some_progress)) {
-		for (i = 0; (z = zones[i]) != NULL; i++) {
-			if (!zone_watermark_ok(z, order, z->pages_min,
-					       classzone_idx, can_try_harder,
-					       gfp_mask & __GFP_HIGH))
-				continue;
-
-			if (!cpuset_zone_allowed(z, gfp_mask))
-				continue;
-
-			page = buffered_rmqueue(z, order, gfp_mask);
-			if (page)
-				goto got_pg;
-		}
+		page = get_page_from_freelist(gfp_mask, order,
+						zonelist, alloc_flags);
+		if (page)
+			goto got_pg;
 	} else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
 		/*
 		 * Go through the zonelist yet one more time, keep
@@ -947,18 +937,10 @@
 		 * a parallel oom killing, we must fail if we're still
 		 * under heavy pressure.
 		 */
-		for (i = 0; (z = zones[i]) != NULL; i++) {
-			if (!zone_watermark_ok(z, order, z->pages_high,
-					       classzone_idx, 0, 0))
-				continue;
-
-			if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
-				continue;
-
-			page = buffered_rmqueue(z, order, gfp_mask);
-			if (page)
-				goto got_pg;
-		}
+		page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+						zonelist, ALLOC_CPUSET);
+		if (page)
+			goto got_pg;
 
 		out_of_memory(gfp_mask, order);
 		goto restart;
@@ -991,9 +973,7 @@
 		dump_stack();
 		show_mem();
 	}
-	return NULL;
 got_pg:
-	zone_statistics(zonelist, z);
 	return page;
 }
 
@@ -2417,13 +2397,18 @@
 	}
 
 	for_each_zone(zone) {
+		unsigned long tmp;
 		spin_lock_irqsave(&zone->lru_lock, flags);
+		tmp = (pages_min * zone->present_pages) / lowmem_pages;
 		if (is_highmem(zone)) {
 			/*
-			 * Often, highmem doesn't need to reserve any pages.
-			 * But the pages_min/low/high values are also used for
-			 * batching up page reclaim activity so we need a
-			 * decent value here.
+			 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
+			 * need highmem pages, so cap pages_min to a small
+			 * value here.
+			 *
+			 * The (pages_high-pages_low) and (pages_low-pages_min)
+			 * deltas controls asynch page reclaim, and so should
+			 * not be capped for highmem.
 			 */
 			int min_pages;
 
@@ -2434,19 +2419,15 @@
 				min_pages = 128;
 			zone->pages_min = min_pages;
 		} else {
-			/* if it's a lowmem zone, reserve a number of pages
+			/*
+			 * If it's a lowmem zone, reserve a number of pages
 			 * proportionate to the zone's size.
 			 */
-			zone->pages_min = (pages_min * zone->present_pages) /
-			                   lowmem_pages;
+			zone->pages_min = tmp;
 		}
 
-		/*
-		 * When interpreting these watermarks, just keep in mind that:
-		 * zone->pages_min == (zone->pages_min * 4) / 4;
-		 */
-		zone->pages_low   = (zone->pages_min * 5) / 4;
-		zone->pages_high  = (zone->pages_min * 6) / 4;
+		zone->pages_low   = zone->pages_min + tmp / 4;
+		zone->pages_high  = zone->pages_min + tmp / 2;
 		spin_unlock_irqrestore(&zone->lru_lock, flags);
 	}
 }
diff --git a/mm/slab.c b/mm/slab.c
index 8a73dcfc6..e5ec26e 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -565,14 +565,29 @@
 #define	BREAK_GFP_ORDER_LO	0
 static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
 
-/* Macros for storing/retrieving the cachep and or slab from the
+/* Functions for storing/retrieving the cachep and or slab from the
  * global 'mem_map'. These are used to find the slab an obj belongs to.
  * With kfree(), these are used to find the cache which an obj belongs to.
  */
-#define	SET_PAGE_CACHE(pg,x)  ((pg)->lru.next = (struct list_head *)(x))
-#define	GET_PAGE_CACHE(pg)    ((kmem_cache_t *)(pg)->lru.next)
-#define	SET_PAGE_SLAB(pg,x)   ((pg)->lru.prev = (struct list_head *)(x))
-#define	GET_PAGE_SLAB(pg)     ((struct slab *)(pg)->lru.prev)
+static inline void page_set_cache(struct page *page, struct kmem_cache *cache)
+{
+	page->lru.next = (struct list_head *)cache;
+}
+
+static inline struct kmem_cache *page_get_cache(struct page *page)
+{
+	return (struct kmem_cache *)page->lru.next;
+}
+
+static inline void page_set_slab(struct page *page, struct slab *slab)
+{
+	page->lru.prev = (struct list_head *)slab;
+}
+
+static inline struct slab *page_get_slab(struct page *page)
+{
+	return (struct slab *)page->lru.prev;
+}
 
 /* These are the default caches for kmalloc. Custom caches can have other sizes. */
 struct cache_sizes malloc_sizes[] = {
@@ -1190,11 +1205,7 @@
 	int i;
 
 	flags |= cachep->gfpflags;
-	if (likely(nodeid == -1)) {
-		page = alloc_pages(flags, cachep->gfporder);
-	} else {
-		page = alloc_pages_node(nodeid, flags, cachep->gfporder);
-	}
+	page = alloc_pages_node(nodeid, flags, cachep->gfporder);
 	if (!page)
 		return NULL;
 	addr = page_address(page);
@@ -1368,7 +1379,7 @@
 		/* Print some data about the neighboring objects, if they
 		 * exist:
 		 */
-		struct slab *slabp = GET_PAGE_SLAB(virt_to_page(objp));
+		struct slab *slabp = page_get_slab(virt_to_page(objp));
 		int objnr;
 
 		objnr = (objp-slabp->s_mem)/cachep->objsize;
@@ -2138,8 +2149,8 @@
 	i = 1 << cachep->gfporder;
 	page = virt_to_page(objp);
 	do {
-		SET_PAGE_CACHE(page, cachep);
-		SET_PAGE_SLAB(page, slabp);
+		page_set_cache(page, cachep);
+		page_set_slab(page, slabp);
 		page++;
 	} while (--i);
 }
@@ -2269,14 +2280,14 @@
 	kfree_debugcheck(objp);
 	page = virt_to_page(objp);
 
-	if (GET_PAGE_CACHE(page) != cachep) {
+	if (page_get_cache(page) != cachep) {
 		printk(KERN_ERR "mismatch in kmem_cache_free: expected cache %p, got %p\n",
-				GET_PAGE_CACHE(page),cachep);
+				page_get_cache(page),cachep);
 		printk(KERN_ERR "%p is %s.\n", cachep, cachep->name);
-		printk(KERN_ERR "%p is %s.\n", GET_PAGE_CACHE(page), GET_PAGE_CACHE(page)->name);
+		printk(KERN_ERR "%p is %s.\n", page_get_cache(page), page_get_cache(page)->name);
 		WARN_ON(1);
 	}
-	slabp = GET_PAGE_SLAB(page);
+	slabp = page_get_slab(page);
 
 	if (cachep->flags & SLAB_RED_ZONE) {
 		if (*dbg_redzone1(cachep, objp) != RED_ACTIVE || *dbg_redzone2(cachep, objp) != RED_ACTIVE) {
@@ -2628,7 +2639,7 @@
 		struct slab *slabp;
 		unsigned int objnr;
 
-		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+		slabp = page_get_slab(virt_to_page(objp));
 		l3 = cachep->nodelists[node];
 		list_del(&slabp->list);
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
@@ -2744,7 +2755,7 @@
 #ifdef CONFIG_NUMA
 	{
 		struct slab *slabp;
-		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+		slabp = page_get_slab(virt_to_page(objp));
 		if (unlikely(slabp->nodeid != numa_node_id())) {
 			struct array_cache *alien = NULL;
 			int nodeid = slabp->nodeid;
@@ -2830,7 +2841,7 @@
 	page = virt_to_page(ptr);
 	if (unlikely(!PageSlab(page)))
 		goto out;
-	if (unlikely(GET_PAGE_CACHE(page) != cachep))
+	if (unlikely(page_get_cache(page) != cachep))
 		goto out;
 	return 1;
 out:
@@ -3026,7 +3037,7 @@
 		return;
 	local_irq_save(flags);
 	kfree_debugcheck(objp);
-	c = GET_PAGE_CACHE(virt_to_page(objp));
+	c = page_get_cache(virt_to_page(objp));
 	__cache_free(c, (void*)objp);
 	local_irq_restore(flags);
 }
@@ -3596,7 +3607,7 @@
 	if (unlikely(objp == NULL))
 		return 0;
 
-	return obj_reallen(GET_PAGE_CACHE(virt_to_page(objp)));
+	return obj_reallen(page_get_cache(virt_to_page(objp)));
 }
 
 
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 135bf8c..2813054 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1074,7 +1074,7 @@
 					continue;
 
 				if (!zone_watermark_ok(zone, order,
-						zone->pages_high, 0, 0, 0)) {
+						zone->pages_high, 0, 0)) {
 					end_zone = i;
 					goto scan;
 				}
@@ -1111,7 +1111,7 @@
 
 			if (nr_pages == 0) {	/* Not software suspend */
 				if (!zone_watermark_ok(zone, order,
-						zone->pages_high, end_zone, 0, 0))
+						zone->pages_high, end_zone, 0))
 					all_zones_ok = 0;
 			}
 			zone->temp_priority = priority;
@@ -1259,7 +1259,7 @@
 		return;
 
 	pgdat = zone->zone_pgdat;
-	if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0, 0))
+	if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
 		return;
 	if (pgdat->kswapd_max_order < order)
 		pgdat->kswapd_max_order = order;
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 8aaf74e6..2f45fd2 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -117,6 +117,8 @@
 # struct my_struct {
 #     int a;
 #     int b;
+# /* private: */
+#     int c;
 # };
 #
 # All descriptions can be multiline, except the short function description.
@@ -1304,6 +1306,12 @@
 	# ignore embedded structs or unions
 	$members =~ s/{.*?}//g;
 
+	# ignore members marked private:
+	$members =~ s/\/\*.*?private:.*?public:.*?\*\///gos;
+	$members =~ s/\/\*.*?private:.*//gos;
+	# strip comments:
+	$members =~ s/\/\*.*?\*\///gos;
+
 	create_parameterlist($members, ';', $file);
 
 	output_declaration($declaration_name,
@@ -1329,6 +1337,7 @@
     my $x = shift;
     my $file = shift;
 
+    $x =~ s@/\*.*?\*/@@gos;	# strip comments.
     if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
         $declaration_name = $1;
         my $members = $2;
@@ -1365,6 +1374,7 @@
     my $x = shift;
     my $file = shift;
 
+    $x =~ s@/\*.*?\*/@@gos;	# strip comments.
     while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
         $x =~ s/\(*.\)\s*;$/;/;
 	$x =~ s/\[*.\]\s*;$/;/;
@@ -1420,7 +1430,7 @@
 	    $type = $arg;
 	    $type =~ s/([^\(]+\(\*)$param/$1/;
 	    push_parameter($param, $type, $file);
-	} else {
+	} elsif ($arg) {
 	    $arg =~ s/\s*:\s*/:/g;
 	    $arg =~ s/\s*\[/\[/g;
 
@@ -1628,7 +1638,6 @@
     my $x = shift;
     my $file = shift;
 
-    $x =~ s@/\*.*?\*/@@gos;	# strip comments.
     $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
     $x =~ s@^\s+@@gos; # strip leading spaces
     $x =~ s@\s+$@@gos; # strip trailing spaces
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 7c835ab..3f30c57 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -47,6 +47,7 @@
 #include <linux/module.h>
 #include <linux/stddef.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/isapnp.h>
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
index d0d3963..adc6896 100644
--- a/sound/oss/cs4281/cs4281m.c
+++ b/sound/oss/cs4281/cs4281m.c
@@ -298,6 +298,7 @@
 	struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
 };
 
+#include <linux/pm_legacy.h>
 #include "cs4281pm-24.c"
 
 #if CSDEBUG
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
index 3dce504..3abd354 100644
--- a/sound/oss/maestro.c
+++ b/sound/oss/maestro.c
@@ -231,6 +231,7 @@
 #include <asm/uaccess.h>
 
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d);
 
 #include "maestro.h"
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
index 6697006..0ce2c404 100644
--- a/sound/oss/nm256_audio.c
+++ b/sound/oss/nm256_audio.c
@@ -25,6 +25,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include "sound_config.h"
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
index 2efbd86..cd41d0e 100644
--- a/sound/oss/opl3sa2.c
+++ b/sound/oss/opl3sa2.c
@@ -70,6 +70,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
 #include "sound_config.h"
 
 #include "ad1848.h"
@@ -138,7 +139,7 @@
 	struct pnp_dev* pdev;
 	int activated;			/* Whether said devices have been activated */
 #endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 	unsigned int	in_suspend;
 	struct pm_dev	*pmdev;
 #endif
@@ -341,7 +342,7 @@
 }
 
 /* Currently only used for power management */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 static void opl3sa2_mixer_restore(opl3sa2_state_t* devc)
 {
 	if (devc) {
@@ -354,7 +355,7 @@
 		}
 	}
 }
-#endif
+#endif /* CONFIG_PM_LEGACY */
 
 static inline void arg_to_vol_mono(unsigned int vol, int* value)
 {
@@ -831,7 +832,8 @@
 
 /* End of component functions */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
+
 static DEFINE_SPINLOCK(opl3sa2_lock);
 
 /* Power Management support functions */
@@ -906,7 +908,7 @@
 	}
 	return 0;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
 
 /*
  * Install OPL3-SA2 based card(s).
@@ -1019,12 +1021,12 @@
 
 		/* ewww =) */
 		opl3sa2_state[card].card = card;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 		/* register our power management capabilities */
 		opl3sa2_state[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback);
 		if (opl3sa2_state[card].pmdev)
 			opl3sa2_state[card].pmdev->data = &opl3sa2_state[card];
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
 
 		/*
 		 * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and
@@ -1081,7 +1083,7 @@
 	int card;
 
 	for(card = 0; card < opl3sa2_cards_num; card++) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
 		if (opl3sa2_state[card].pmdev)
 			pm_unregister(opl3sa2_state[card].pmdev);
 #endif