Merge commit 'v2.6.27-rc6' into core/resources
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 680fb56..8362860 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -144,8 +144,8 @@
 	void (*kill_sb) (struct super_block *);
 locking rules:
 		may block	BKL
-get_sb		yes		yes
-kill_sb		yes		yes
+get_sb		yes		no
+kill_sb		yes		no
 
 ->get_sb() returns error or 0 with locked superblock attached to the vfsmount
 (exclusive on ->s_umount).
@@ -409,12 +409,12 @@
 unlocked_ioctl:		no	(see below)
 compat_ioctl:		no
 mmap:			no
-open:			maybe	(see below)
+open:			no
 flush:			no
 release:		no
 fsync:			no	(see below)
 aio_fsync:		no
-fasync:			yes	(see below)
+fasync:			no
 lock:			yes
 readv:			no
 writev:			no
@@ -431,13 +431,6 @@
 semaphore.  Note some filesystems (i.e. remote ones) provide no
 protection for i_size so you will need to use the BKL.
 
-->open() locking is in-transit: big lock partially moved into the methods.
-The only exception is ->open() in the instances of file_operations that never
-end up in ->i_fop/->proc_fops, i.e. ones that belong to character devices
-(chrdev_open() takes lock before replacing ->f_op and calling the secondary
-method. As soon as we fix the handling of module reference counters all
-instances of ->open() will be called without the BKL.
-
 Note: ext2_release() was *the* source of contention on fs-intensive
 loads and dropping BKL on ->release() helps to get rid of that (we still
 grab BKL for cases when we close a file that had been opened r/w, but that
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 02dc748..71f0fe1 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -44,7 +44,7 @@
 	- LCD brightness control
 	- Volume control
 	- Fan control and monitoring: fan speed, fan enable/disable
-	- Experimental: WAN enable and disable
+	- WAN enable and disable
 
 A compatibility table by model and feature is maintained on the web
 site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -1375,18 +1375,13 @@
 would be the safest choice, though).
 
 
-EXPERIMENTAL: WAN
------------------
+WAN
+---
 
 procfs: /proc/acpi/ibm/wan
 sysfs device attribute: wwan_enable (deprecated)
 sysfs rfkill class: switch "tpacpi_wwan_sw"
 
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
-
 This feature shows the presence and current state of a W-WAN (Sierra
 Wireless EV-DO) device.
 
diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828
index eedc399..aa05e5b 100644
--- a/Documentation/video4linux/CARDLIST.au0828
+++ b/Documentation/video4linux/CARDLIST.au0828
@@ -3,3 +3,4 @@
   2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
   3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
   4 -> Hauppauge HVR950Q rev xxF8               (au0828)        [2040:7201,2040:7211,2040:7281]
+  5 -> Hauppauge Woodbury                       (au0828)        [2040:8200]
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 78a863a..0f03900 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -88,14 +88,14 @@
 zc3xx		0471:0326	Philips SPC 300 NC
 sonixj		0471:0327	Philips SPC 600 NC
 sonixj		0471:0328	Philips SPC 700 NC
-zc3xx		0471:032d	Philips spc210nc
-zc3xx		0471:032e	Philips spc315nc
-sonixj		0471:0330	Philips SPC 710NC
+zc3xx		0471:032d	Philips SPC 210 NC
+zc3xx		0471:032e	Philips SPC 315 NC
+sonixj		0471:0330	Philips SPC 710 NC
 spca501		0497:c001	Smile International
 sunplus		04a5:3003	Benq DC 1300
 sunplus		04a5:3008	Benq DC 1500
-sunplus		04a5:300a	Benq DC3410
-spca500		04a5:300c	Benq DC1016
+sunplus		04a5:300a	Benq DC 3410
+spca500		04a5:300c	Benq DC 1016
 sunplus		04f1:1001	JVC GC A50
 spca561		04fc:0561	Flexcam 100
 sunplus		04fc:500c	Sunplus CA500C
@@ -175,19 +175,21 @@
 tv8532		0923:010f	ICM532 cams
 mars		093a:050f	Mars-Semi Pc-Camera
 pac207		093a:2460	PAC207 Qtec Webcam 100
-pac207		093a:2463	Philips spc200nc pac207
+pac207		093a:2463	Philips SPC 220 NC
 pac207		093a:2464	Labtec Webcam 1200
 pac207		093a:2468	PAC207
 pac207		093a:2470	Genius GF112
-pac207		093a:2471	PAC207 Genius VideoCam ge111
-pac207		093a:2472	PAC207 Genius VideoCam ge110
+pac207		093a:2471	Genius VideoCam ge111
+pac207		093a:2472	Genius VideoCam ge110
 pac7311		093a:2600	PAC7311 Typhoon
-pac7311		093a:2601	PAC7311 Phillips SPC610NC
+pac7311		093a:2601	Philips SPC 610 NC
 pac7311		093a:2603	PAC7312
-pac7311		093a:2608	PAC7311 Trust WB-3300p
-pac7311		093a:260e	PAC7311 Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
-pac7311		093a:260f	PAC7311 SnakeCam
+pac7311		093a:2608	Trust WB-3300p
+pac7311		093a:260e	Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
+pac7311		093a:260f	SnakeCam
 pac7311		093a:2621	PAC731x
+pac7311		093a:2624	PAC7302
+pac7311		093a:2626	Labtec 2200
 zc3xx		0ac8:0302	Z-star Vimicro zc0302
 vc032x		0ac8:0321	Vimicro generic vc0321
 vc032x		0ac8:0323	Vimicro Vc0323
@@ -220,6 +222,7 @@
 sonixj		0c45:60ec	SN9C105+MO4000
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fc	LG-LIC300
+sonixj		0c45:6128	Microdia/Sonix SNP325
 sonixj		0c45:612a	Avant Camera
 sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix
 sonixj		0c45:6130	Sonix Pccam
@@ -234,7 +237,7 @@
 spca561		10fd:7e50	FlyCam Usb 100
 zc3xx		10fd:8050	Typhoon Webshot II USB 300k
 spca501		1776:501c	Arowana 300K CMOS Camera
-t613		17a1:0128	T613/TAS5130A
+t613		17a1:0128	TASCORP JPEG Webcam, NGS Cyclops
 vc032x		17ef:4802	Lenovo Vc0323+MI1310_SOC
 pac207		2001:f115	D-Link DSB-C120
 spca500		2899:012c	Toptro Industrial
diff --git a/MAINTAINERS b/MAINTAINERS
index ced3c20..186be3b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -222,8 +222,7 @@
 S:	Maintained
 
 ACPI
-P:	Andi Kleen
-M:	ak@linux.intel.com
+P:	Len Brown
 M:	lenb@kernel.org
 L:	linux-acpi@vger.kernel.org
 W:	http://www.lesswatts.org/projects/acpi/
@@ -751,11 +750,13 @@
 M:	syrjala@sci.fi
 S:	Maintained
 
-ATL1 ETHERNET DRIVER
+ATLX ETHERNET DRIVERS
 P:	Jay Cliburn
 M:	jcliburn@gmail.com
 P:	Chris Snook
 M:	csnook@redhat.com
+P:	Jie Yang
+M:	jie.yang@atheros.com
 L:	atl1-devel@lists.sourceforge.net
 W:	http://sourceforge.net/projects/atl1
 W:	http://atl1.sourceforge.net
@@ -1594,7 +1595,7 @@
 EMBEDDED LINUX
 P:	Paul Gortmaker
 M:	paul.gortmaker@windriver.com
-P	David Woodhouse
+P:	David Woodhouse
 M:	dwmw2@infradead.org
 L:	linux-embedded@vger.kernel.org
 S:	Maintained
diff --git a/Makefile b/Makefile
index f448e00..4ff83ea 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 27
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Rotary Wombat
 
 # *DOCUMENTATION*
diff --git a/arch/arm/include/asm/byteorder.h b/arch/arm/include/asm/byteorder.h
index d04a7a2..4fbfb22 100644
--- a/arch/arm/include/asm/byteorder.h
+++ b/arch/arm/include/asm/byteorder.h
@@ -18,15 +18,7 @@
 #include <linux/compiler.h>
 #include <asm/types.h>
 
-#ifdef __ARMEB__
-# define __BIG_ENDIAN
-#else
-# define __LITTLE_ENDIAN
-#endif
-
-#define __SWAB_64_THRU_32__
-
-static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
+static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
 {
 	__u32 t;
 
@@ -48,8 +40,19 @@
 
 	return x;
 }
-#define __arch_swab32 __arch_swab32
 
-#include <linux/byteorder.h>
+#define __arch__swab32(x) ___arch__swab32(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#ifdef __ARMEB__
+#include <linux/byteorder/big_endian.h>
+#else
+#include <linux/byteorder/little_endian.h>
+#endif
 
 #endif
+
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 94a95d7..71934856 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -61,8 +61,9 @@
 #define MT_DEVICE_NONSHARED	1
 #define MT_DEVICE_CACHED	2
 #define MT_DEVICE_IXP2000	3
+#define MT_DEVICE_WC		4
 /*
- * types 4 onwards can be found in asm/mach/map.h and are undefined
+ * types 5 onwards can be found in asm/mach/map.h and are undefined
  * for ioremap
  */
 
@@ -215,11 +216,13 @@
 #define ioremap(cookie,size)		__arm_ioremap(cookie, size, MT_DEVICE)
 #define ioremap_nocache(cookie,size)	__arm_ioremap(cookie, size, MT_DEVICE)
 #define ioremap_cached(cookie,size)	__arm_ioremap(cookie, size, MT_DEVICE_CACHED)
+#define ioremap_wc(cookie,size)		__arm_ioremap(cookie, size, MT_DEVICE_WC)
 #define iounmap(cookie)			__iounmap(cookie)
 #else
 #define ioremap(cookie,size)		__arch_ioremap((cookie), (size), MT_DEVICE)
 #define ioremap_nocache(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE)
 #define ioremap_cached(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
+#define ioremap_wc(cookie,size)		__arch_ioremap((cookie), (size), MT_DEVICE_WC)
 #define iounmap(cookie)			__arch_iounmap(cookie)
 #endif
 
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 06f583b..9eb936e 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -18,13 +18,13 @@
 	unsigned int type;
 };
 
-/* types 0-3 are defined in asm/io.h */
-#define MT_CACHECLEAN		4
-#define MT_MINICLEAN		5
-#define MT_LOW_VECTORS		6
-#define MT_HIGH_VECTORS		7
-#define MT_MEMORY		8
-#define MT_ROM			9
+/* types 0-4 are defined in asm/io.h */
+#define MT_CACHECLEAN		5
+#define MT_MINICLEAN		6
+#define MT_LOW_VECTORS		7
+#define MT_HIGH_VECTORS		8
+#define MT_MEMORY		9
+#define MT_ROM			10
 
 #define MT_NONSHARED_DEVICE	MT_DEVICE_NONSHARED
 #define MT_IXP2000_DEVICE	MT_DEVICE_IXP2000
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index 826010d..2baeaeb 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -159,6 +159,7 @@
 #ifdef CONFIG_ARCH_OMAP730
 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
 	{
+		.phys_base	= OMAP730_MCBSP1_BASE,
 		.virt_base	= io_p2v(OMAP730_MCBSP1_BASE),
 		.dma_rx_sync	= OMAP_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP1_TX,
@@ -167,6 +168,7 @@
 		.ops		= &omap1_mcbsp_ops,
 	},
 	{
+		.phys_base	= OMAP730_MCBSP2_BASE,
 		.virt_base	= io_p2v(OMAP730_MCBSP2_BASE),
 		.dma_rx_sync	= OMAP_DMA_MCBSP3_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP3_TX,
@@ -184,6 +186,7 @@
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
 	{
+		.phys_base	= OMAP1510_MCBSP1_BASE,
 		.virt_base	= OMAP1510_MCBSP1_BASE,
 		.dma_rx_sync	= OMAP_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP1_TX,
@@ -193,6 +196,7 @@
 		.clk_name	= "mcbsp_clk",
 		},
 	{
+		.phys_base	= OMAP1510_MCBSP2_BASE,
 		.virt_base	= io_p2v(OMAP1510_MCBSP2_BASE),
 		.dma_rx_sync	= OMAP_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP2_TX,
@@ -201,6 +205,7 @@
 		.ops		= &omap1_mcbsp_ops,
 	},
 	{
+		.phys_base	= OMAP1510_MCBSP3_BASE,
 		.virt_base	= OMAP1510_MCBSP3_BASE,
 		.dma_rx_sync	= OMAP_DMA_MCBSP3_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP3_TX,
@@ -219,6 +224,7 @@
 #ifdef CONFIG_ARCH_OMAP16XX
 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
 	{
+		.phys_base	= OMAP1610_MCBSP1_BASE,
 		.virt_base	= OMAP1610_MCBSP1_BASE,
 		.dma_rx_sync	= OMAP_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP1_TX,
@@ -228,6 +234,7 @@
 		.clk_name	= "mcbsp_clk",
 	},
 	{
+		.phys_base	= OMAP1610_MCBSP2_BASE,
 		.virt_base	= io_p2v(OMAP1610_MCBSP2_BASE),
 		.dma_rx_sync	= OMAP_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP2_TX,
@@ -236,6 +243,7 @@
 		.ops		= &omap1_mcbsp_ops,
 	},
 	{
+		.phys_base	= OMAP1610_MCBSP3_BASE,
 		.virt_base	= OMAP1610_MCBSP3_BASE,
 		.dma_rx_sync	= OMAP_DMA_MCBSP3_RX,
 		.dma_tx_sync	= OMAP_DMA_MCBSP3_TX,
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index 27eb6e3..b261f1f 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -134,6 +134,7 @@
 #ifdef CONFIG_ARCH_OMAP24XX
 static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
 	{
+		.phys_base	= OMAP24XX_MCBSP1_BASE,
 		.virt_base	= IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
@@ -143,6 +144,7 @@
 		.clk_name	= "mcbsp_clk",
 	},
 	{
+		.phys_base	= OMAP24XX_MCBSP2_BASE,
 		.virt_base	= IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
@@ -161,6 +163,7 @@
 #ifdef CONFIG_ARCH_OMAP34XX
 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 	{
+		.phys_base	= OMAP34XX_MCBSP1_BASE,
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP1_BASE),
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
@@ -170,6 +173,7 @@
 		.clk_name	= "mcbsp_clk",
 	},
 	{
+		.phys_base	= OMAP34XX_MCBSP2_BASE,
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP2_BASE),
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 25d9a11..a713e40 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -211,6 +211,12 @@
 				  PMD_SECT_TEX(1),
 		.domain		= DOMAIN_IO,
 	},
+	[MT_DEVICE_WC] = {	/* ioremap_wc */
+		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_l1	= PMD_TYPE_TABLE,
+		.prot_sect	= PROT_SECT_DEVICE,
+		.domain		= DOMAIN_IO,
+	},
 	[MT_CACHECLEAN] = {
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
 		.domain    = DOMAIN_KERNEL,
@@ -273,6 +279,20 @@
 	}
 
 	/*
+	 * On non-Xscale3 ARMv5-and-older systems, use CB=01
+	 * (Uncached/Buffered) for ioremap_wc() mappings.  On XScale3
+	 * and ARMv6+, use TEXCB=00100 mappings (Inner/Outer Uncacheable
+	 * in xsc3 parlance, Uncached Normal in ARMv6 parlance).
+	 */
+	if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) {
+		mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1);
+		mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1);
+	} else {
+		mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_BUFFERABLE;
+		mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE;
+	}
+
+	/*
 	 * ARMv5 and lower, bit 4 must be set for page tables.
 	 * (was: cache "update-able on write" bit on ARM610)
 	 * However, Xscale cores require this bit to be cleared.
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 2f86272..0a38f0b 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -37,7 +37,6 @@
 #include <linux/proc_fs.h>
 #include <linux/semaphore.h>
 #include <linux/string.h>
-#include <linux/version.h>
 
 #include <mach/clock.h>
 
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 3e76ee2..9e1341e 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -1488,7 +1488,7 @@
 		bank->chip.set = gpio_set;
 		if (bank_is_mpuio(bank)) {
 			bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP1
+#ifdef CONFIG_ARCH_OMAP16XX
 			bank->chip.dev = &omap_mpuio_device.dev;
 #endif
 			bank->chip.base = OMAP_MPUIO(0);
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index 6eb44a9..8fdb95e 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -315,6 +315,7 @@
 };
 
 struct omap_mcbsp_platform_data {
+	unsigned long phys_base;
 	u32 virt_base;
 	u8 dma_rx_sync, dma_tx_sync;
 	u16 rx_irq, tx_irq;
@@ -324,6 +325,7 @@
 
 struct omap_mcbsp {
 	struct device *dev;
+	unsigned long phys_base;
 	u32 io_base;
 	u8 id;
 	u8 free;
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index d084405..014d265 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -651,7 +651,7 @@
 	omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
 				 src_port,
 				 OMAP_DMA_AMODE_CONSTANT,
-				 mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
+				 mcbsp[id].phys_base + OMAP_MCBSP_REG_DXR1,
 				 0, 0);
 
 	omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
@@ -712,7 +712,7 @@
 	omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
 				src_port,
 				OMAP_DMA_AMODE_CONSTANT,
-				mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
+				mcbsp[id].phys_base + OMAP_MCBSP_REG_DRR1,
 				0, 0);
 
 	omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
@@ -830,6 +830,7 @@
 	mcbsp[id].dma_tx_lch = -1;
 	mcbsp[id].dma_rx_lch = -1;
 
+	mcbsp[id].phys_base = pdata->phys_base;
 	mcbsp[id].io_base = pdata->virt_base;
 	/* Default I/O is IRQ based */
 	mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO;
diff --git a/arch/avr32/kernel/asm-offsets.c b/arch/avr32/kernel/asm-offsets.c
index e4796c6..d6a8193 100644
--- a/arch/avr32/kernel/asm-offsets.c
+++ b/arch/avr32/kernel/asm-offsets.c
@@ -4,6 +4,8 @@
  * to extract and format the required data.
  */
 
+#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/kbuild.h>
 
@@ -17,4 +19,8 @@
 	OFFSET(TI_rar_saved, thread_info, rar_saved);
 	OFFSET(TI_rsr_saved, thread_info, rsr_saved);
 	OFFSET(TI_restart_block, thread_info, restart_block);
+	BLANK();
+	OFFSET(TSK_active_mm, task_struct, active_mm);
+	BLANK();
+	OFFSET(MM_pgd, mm_struct, pgd);
 }
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index 2b398ca..33d4937 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -334,9 +334,64 @@
 
 	/* Low-level exception handlers */
 handle_critical:
+	/*
+	 * AT32AP700x errata:
+	 *
+	 * After a Java stack overflow or underflow trap, any CPU
+	 * memory access may cause erratic behavior. This will happen
+	 * when the four least significant bits of the JOSP system
+	 * register contains any value between 9 and 15 (inclusive).
+	 *
+	 * Possible workarounds:
+	 *   - Don't use the Java Extension Module
+	 *   - Ensure that the stack overflow and underflow trap
+	 *     handlers do not do any memory access or trigger any
+	 *     exceptions before the overflow/underflow condition is
+	 *     cleared (by incrementing or decrementing the JOSP)
+	 *   - Make sure that JOSP does not contain any problematic
+	 *     value before doing any exception or interrupt
+	 *     processing.
+	 *   - Set up a critical exception handler which writes a
+	 *     known-to-be-safe value, e.g. 4, to JOSP before doing
+	 *     any further processing.
+	 *
+	 * We'll use the last workaround for now since we cannot
+	 * guarantee that user space processes don't use Java mode.
+	 * Non-well-behaving userland will be terminated with extreme
+	 * prejudice.
+	 */
+#ifdef CONFIG_CPU_AT32AP700X
+	/*
+	 * There's a chance we can't touch memory, so temporarily
+	 * borrow PTBR to save the stack pointer while we fix things
+	 * up...
+	 */
+	mtsr	SYSREG_PTBR, sp
+	mov	sp, 4
+	mtsr	SYSREG_JOSP, sp
+	mfsr	sp, SYSREG_PTBR
+	sub	pc, -2
+
+	/* Push most of pt_regs on stack. We'll do the rest later */
 	sub	sp, 4
-	stmts	--sp, r0-lr
-	rcall	save_full_context_ex
+	pushm	r0-r12
+
+	/* PTBR mirrors current_thread_info()->task->active_mm->pgd */
+	get_thread_info r0
+	ld.w	r1, r0[TI_task]
+	ld.w	r2, r1[TSK_active_mm]
+	ld.w	r3, r2[MM_pgd]
+	mtsr	SYSREG_PTBR, r3
+#else
+	sub	sp, 4
+	pushm	r0-r12
+#endif
+	sub	r0, sp, -(14 * 4)
+	mov	r1, lr
+	mfsr	r2, SYSREG_RAR_EX
+	mfsr	r3, SYSREG_RSR_EX
+	pushm	r0-r3
+
 	mfsr	r12, SYSREG_ECR
 	mov	r11, sp
 	rcall	do_critical_exception
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S
index 5be4de6..17503b0 100644
--- a/arch/avr32/mach-at32ap/pm-at32ap700x.S
+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
@@ -134,7 +134,7 @@
 	mov	r11, SDRAMC_LPR_LPCB_SELF_RFR
 	bfins	r10, r11, 0, 2		/* LPCB <- self Refresh */
 	sync	0			/* flush write buffer */
-	st.w	r12[SDRAMC_LPR], r11	/* put SDRAM in self-refresh mode */
+	st.w	r12[SDRAMC_LPR], r10	/* put SDRAM in self-refresh mode */
 	ld.w	r11, r12[SDRAMC_LPR]
 	unmask_interrupts
 	sleep	CPU_SLEEP_FROZEN
diff --git a/arch/ia64/include/asm/sections.h b/arch/ia64/include/asm/sections.h
index 7286e4a..a7acad2 100644
--- a/arch/ia64/include/asm/sections.h
+++ b/arch/ia64/include/asm/sections.h
@@ -21,5 +21,8 @@
 extern char __start_unwind[], __end_unwind[];
 extern char __start_ivt_text[], __end_ivt_text[];
 
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+
 #endif /* _ASM_IA64_SECTIONS_H */
 
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index 29aad34..545626f 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -31,9 +31,11 @@
 #include <linux/elf.h>
 #include <linux/moduleloader.h>
 #include <linux/string.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 
 #include <asm/patch.h>
+#include <asm/sections.h>
 #include <asm/unaligned.h>
 
 #define ARCH_MODULE_DEBUG 0
@@ -941,3 +943,13 @@
 	if (mod->arch.core_unw_table)
 		unw_remove_unwind_table(mod->arch.core_unw_table);
 }
+
+void *dereference_function_descriptor(void *ptr)
+{
+	struct fdesc *desc = ptr;
+	void *p;
+
+	if (!probe_kernel_address(&desc->ip, p))
+		ptr = p;
+	return ptr;
+}
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4da736e..49896a2 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1886,6 +1886,15 @@
 
 source "init/Kconfig"
 
+config PROBE_INITRD_HEADER
+	bool "Probe initrd header created by addinitrd"
+	depends on BLK_DEV_INITRD
+	help
+	  Probe initrd header at the last page of kernel image.
+	  Say Y here if you are using arch/mips/boot/addinitrd.c to
+	  add initrd or initramfs image to the kernel image.
+	  Otherwise, say N.
+
 menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)"
 
 config HW_HAS_EISA
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 2aae76b..16f8edf 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -160,30 +160,33 @@
 static unsigned long __init init_initrd(void)
 {
 	unsigned long end;
-	u32 *initrd_header;
 
 	/*
 	 * Board specific code or command line parser should have
 	 * already set up initrd_start and initrd_end. In these cases
 	 * perfom sanity checks and use them if all looks good.
 	 */
-	if (initrd_start && initrd_end > initrd_start)
-		goto sanitize;
+	if (!initrd_start || initrd_end <= initrd_start) {
+#ifdef CONFIG_PROBE_INITRD_HEADER
+		u32 *initrd_header;
 
-	/*
-	 * See if initrd has been added to the kernel image by
-	 * arch/mips/boot/addinitrd.c. In that case a header is
-	 * prepended to initrd and is made up by 8 bytes. The fisrt
-	 * word is a magic number and the second one is the size of
-	 * initrd.  Initrd start must be page aligned in any cases.
-	 */
-	initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
-	if (initrd_header[0] != 0x494E5244)
+		/*
+		 * See if initrd has been added to the kernel image by
+		 * arch/mips/boot/addinitrd.c. In that case a header is
+		 * prepended to initrd and is made up by 8 bytes. The first
+		 * word is a magic number and the second one is the size of
+		 * initrd.  Initrd start must be page aligned in any cases.
+		 */
+		initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
+		if (initrd_header[0] != 0x494E5244)
+			goto disable;
+		initrd_start = (unsigned long)(initrd_header + 2);
+		initrd_end = initrd_start + initrd_header[1];
+#else
 		goto disable;
-	initrd_start = (unsigned long)(initrd_header + 2);
-	initrd_end = initrd_start + initrd_header[1];
+#endif
+	}
 
-sanitize:
 	if (initrd_start & ~PAGE_MASK) {
 		pr_err("initrd start must be page aligned\n");
 		goto disable;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 426cced..6bee290 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -373,8 +373,8 @@
 	do_exit(SIGSEGV);
 }
 
-extern const struct exception_table_entry __start___dbe_table[];
-extern const struct exception_table_entry __stop___dbe_table[];
+extern struct exception_table_entry __start___dbe_table[];
+extern struct exception_table_entry __stop___dbe_table[];
 
 __asm__(
 "	.section	__dbe_table, \"a\"\n"
@@ -1200,7 +1200,7 @@
 	if (n == 0 && cpu_has_divec) {
 		*(u32 *)(ebase + 0x200) = 0x08000000 |
 					  (0x03ffffff & (handler >> 2));
-		flush_icache_range(ebase + 0x200, ebase + 0x204);
+		local_flush_icache_range(ebase + 0x200, ebase + 0x204);
 	}
 	return (void *)old_handler;
 }
@@ -1283,7 +1283,8 @@
 		*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
 		w = (u32 *)(b + ori_offset);
 		*w = (*w & 0xffff0000) | ((u32)handler & 0xffff);
-		flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len));
+		local_flush_icache_range((unsigned long)b,
+					 (unsigned long)(b+handler_len));
 	}
 	else {
 		/*
@@ -1295,7 +1296,8 @@
 		w = (u32 *)b;
 		*w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */
 		*w = 0;
-		flush_icache_range((unsigned long)b, (unsigned long)(b+8));
+		local_flush_icache_range((unsigned long)b,
+					 (unsigned long)(b+8));
 	}
 
 	return (void *)old_handler;
@@ -1515,7 +1517,7 @@
 void __init set_handler(unsigned long offset, void *addr, unsigned long size)
 {
 	memcpy((void *)(ebase + offset), addr, size);
-	flush_icache_range(ebase + offset, ebase + offset + size);
+	local_flush_icache_range(ebase + offset, ebase + offset + size);
 }
 
 static char panic_null_cerr[] __cpuinitdata =
@@ -1680,6 +1682,8 @@
 	signal32_init();
 #endif
 
-	flush_icache_range(ebase, ebase + 0x400);
+	local_flush_icache_range(ebase, ebase + 0x400);
 	flush_tlb_handlers();
+
+	sort_extable(__start___dbe_table, __stop___dbe_table);
 }
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 27a5b46..5500c20 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -320,6 +320,7 @@
 	flush_cache_range = r3k_flush_cache_range;
 	flush_cache_page = r3k_flush_cache_page;
 	flush_icache_range = r3k_flush_icache_range;
+	local_flush_icache_range = r3k_flush_icache_range;
 
 	flush_cache_sigtramp = r3k_flush_cache_sigtramp;
 	local_flush_data_cache_page = local_r3k_flush_data_cache_page;
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 71df339..6e99665 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -543,12 +543,8 @@
 	unsigned long end;
 };
 
-static inline void local_r4k_flush_icache_range(void *args)
+static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
-	struct flush_icache_range_args *fir_args = args;
-	unsigned long start = fir_args->start;
-	unsigned long end = fir_args->end;
-
 	if (!cpu_has_ic_fills_f_dc) {
 		if (end - start >= dcache_size) {
 			r4k_blast_dcache();
@@ -564,6 +560,15 @@
 		protected_blast_icache_range(start, end);
 }
 
+static inline void local_r4k_flush_icache_range_ipi(void *args)
+{
+	struct flush_icache_range_args *fir_args = args;
+	unsigned long start = fir_args->start;
+	unsigned long end = fir_args->end;
+
+	local_r4k_flush_icache_range(start, end);
+}
+
 static void r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
 	struct flush_icache_range_args args;
@@ -571,7 +576,7 @@
 	args.start = start;
 	args.end = end;
 
-	r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1);
+	r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args, 1);
 	instruction_hazard();
 }
 
@@ -1375,6 +1380,7 @@
 	local_flush_data_cache_page	= local_r4k_flush_data_cache_page;
 	flush_data_cache_page	= r4k_flush_data_cache_page;
 	flush_icache_range	= r4k_flush_icache_range;
+	local_flush_icache_range	= local_r4k_flush_icache_range;
 
 #if defined(CONFIG_DMA_NONCOHERENT)
 	if (coherentio) {
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index a9f7f1f..f7c8f9c 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -362,6 +362,7 @@
 		flush_cache_range	= (void *) tx39h_flush_icache_all;
 		flush_cache_page	= (void *) tx39h_flush_icache_all;
 		flush_icache_range	= (void *) tx39h_flush_icache_all;
+		local_flush_icache_range = (void *) tx39h_flush_icache_all;
 
 		flush_cache_sigtramp	= (void *) tx39h_flush_icache_all;
 		local_flush_data_cache_page	= (void *) tx39h_flush_icache_all;
@@ -390,6 +391,7 @@
 		flush_cache_range = tx39_flush_cache_range;
 		flush_cache_page = tx39_flush_cache_page;
 		flush_icache_range = tx39_flush_icache_range;
+		local_flush_icache_range = tx39_flush_icache_range;
 
 		flush_cache_sigtramp = tx39_flush_cache_sigtramp;
 		local_flush_data_cache_page = local_tx39_flush_data_cache_page;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 034e850..1eb7c71 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -29,6 +29,7 @@
 void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
 	unsigned long pfn);
 void (*flush_icache_range)(unsigned long start, unsigned long end);
+void (*local_flush_icache_range)(unsigned long start, unsigned long end);
 
 void (*__flush_cache_vmap)(void);
 void (*__flush_cache_vunmap)(void);
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 76da73a..979cf91 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -1273,10 +1273,10 @@
 
 void __cpuinit flush_tlb_handlers(void)
 {
-	flush_icache_range((unsigned long)handle_tlbl,
+	local_flush_icache_range((unsigned long)handle_tlbl,
 			   (unsigned long)handle_tlbl + sizeof(handle_tlbl));
-	flush_icache_range((unsigned long)handle_tlbs,
+	local_flush_icache_range((unsigned long)handle_tlbs,
 			   (unsigned long)handle_tlbs + sizeof(handle_tlbs));
-	flush_icache_range((unsigned long)handle_tlbm,
+	local_flush_icache_range((unsigned long)handle_tlbm,
 			   (unsigned long)handle_tlbm + sizeof(handle_tlbm));
 }
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
index 6014123..52486c4d 100644
--- a/arch/mips/sgi-ip22/ip22-platform.c
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -150,7 +150,7 @@
 		return res;
 
 	/* Second HPC is missing? */
-	if (!ip22_is_fullhouse() ||
+	if (ip22_is_fullhouse() ||
 	    get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]))
 		return 0;
 
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index 0afe94c..fe6bee0 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -53,6 +53,7 @@
 		txx9_ce_res[i].name = txx9_ce_res_name[i];
 	}
 
+	txx9_pcode = pcode;
 	sprintf(txx9_pcode_str, "TX%x", pcode);
 	if (base) {
 		txx9_reg_res.start = base & 0xfffffffffULL;
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index fdacdd4..44138c3 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -47,7 +47,9 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/uaccess.h>
 
+#include <asm/sections.h>
 #include <asm/unwind.h>
 
 #if 0
@@ -860,3 +862,15 @@
 	deregister_unwind_table(mod);
 	module_bug_cleanup(mod);
 }
+
+#ifdef CONFIG_64BIT
+void *dereference_function_descriptor(void *ptr)
+{
+	Elf64_Fdesc *desc = ptr;
+	void *p;
+
+	if (!probe_kernel_address(&desc->addr, p))
+		ptr = p;
+	return ptr;
+}
+#endif
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 14174aa..717a3bc 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -49,7 +49,7 @@
 zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
 zliblinuxheader := zlib.h zconf.h zutil.h
 
-$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
+$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \
 	$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 
 src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 916018e..7710e9e 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -16,6 +16,9 @@
 	return 0;
 }
 
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index ee6a298..ad79de2 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -21,8 +21,9 @@
 #include <linux/err.h>
 #include <linux/vmalloc.h>
 #include <linux/bug.h>
+#include <linux/uaccess.h>
 #include <asm/module.h>
-#include <asm/uaccess.h>
+#include <asm/sections.h>
 #include <asm/firmware.h>
 #include <asm/code-patching.h>
 #include <linux/sort.h>
@@ -451,3 +452,13 @@
 
 	return 0;
 }
+
+void *dereference_function_descriptor(void *ptr)
+{
+	struct ppc64_opd_entry *desc = ptr;
+	void *p;
+
+	if (!probe_kernel_address(&desc->funcaddr, p))
+		ptr = p;
+	return ptr;
+}
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 1c1b627..67595bc 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -643,9 +643,10 @@
 			    !(tmp->flags & SPU_CREATE_NOSCHED) &&
 			    (!victim || tmp->prio > victim->prio)) {
 				victim = spu->ctx;
-				get_spu_context(victim);
 			}
 		}
+		if (victim)
+			get_spu_context(victim);
 		mutex_unlock(&cbe_spu_info[node].list_mutex);
 
 		if (victim) {
@@ -727,17 +728,33 @@
 	/* not a candidate for interruptible because it's called either
 	   from the scheduler thread or from spu_deactivate */
 	mutex_lock(&ctx->state_mutex);
-	__spu_schedule(spu, ctx);
+	if (ctx->state == SPU_STATE_SAVED)
+		__spu_schedule(spu, ctx);
 	spu_release(ctx);
 }
 
-static void spu_unschedule(struct spu *spu, struct spu_context *ctx)
+/**
+ * spu_unschedule - remove a context from a spu, and possibly release it.
+ * @spu:	The SPU to unschedule from
+ * @ctx:	The context currently scheduled on the SPU
+ * @free_spu	Whether to free the SPU for other contexts
+ *
+ * Unbinds the context @ctx from the SPU @spu. If @free_spu is non-zero, the
+ * SPU is made available for other contexts (ie, may be returned by
+ * spu_get_idle). If this is zero, the caller is expected to schedule another
+ * context to this spu.
+ *
+ * Should be called with ctx->state_mutex held.
+ */
+static void spu_unschedule(struct spu *spu, struct spu_context *ctx,
+		int free_spu)
 {
 	int node = spu->node;
 
 	mutex_lock(&cbe_spu_info[node].list_mutex);
 	cbe_spu_info[node].nr_active--;
-	spu->alloc_state = SPU_FREE;
+	if (free_spu)
+		spu->alloc_state = SPU_FREE;
 	spu_unbind_context(spu, ctx);
 	ctx->stats.invol_ctx_switch++;
 	spu->stats.invol_ctx_switch++;
@@ -837,7 +854,7 @@
 	if (spu) {
 		new = grab_runnable_context(max_prio, spu->node);
 		if (new || force) {
-			spu_unschedule(spu, ctx);
+			spu_unschedule(spu, ctx, new == NULL);
 			if (new) {
 				if (new->flags & SPU_CREATE_NOSCHED)
 					wake_up(&new->stop_wq);
@@ -910,7 +927,7 @@
 
 	new = grab_runnable_context(ctx->prio + 1, spu->node);
 	if (new) {
-		spu_unschedule(spu, ctx);
+		spu_unschedule(spu, ctx, 0);
 		if (test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
 			spu_add_to_rq(ctx);
 	} else {
diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h
index cde81fa..a2be3a9 100644
--- a/arch/s390/kernel/compat_ptrace.h
+++ b/arch/s390/kernel/compat_ptrace.h
@@ -42,6 +42,7 @@
 	u32 gprs[NUM_GPRS];
 	u32 acrs[NUM_ACRS];
 	u32 orig_gpr2;
+	/* nb: there's a 4-byte hole here */
 	s390_fp_regs fp_regs;
 	/*
 	 * These per registers are in here so that gdb can modify them
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2815bfe..c8b0828 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -170,6 +170,13 @@
 		 */
 		tmp = (addr_t) task_pt_regs(child)->orig_gpr2;
 
+	} else if (addr < (addr_t) &dummy->regs.fp_regs) {
+		/*
+		 * prevent reads of padding hole between
+		 * orig_gpr2 and fp_regs on s390.
+		 */
+		tmp = 0;
+
 	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
 		/* 
 		 * floating point regs. are stored in the thread structure
@@ -270,6 +277,13 @@
 		 */
 		task_pt_regs(child)->orig_gpr2 = data;
 
+	} else if (addr < (addr_t) &dummy->regs.fp_regs) {
+		/*
+		 * prevent writes of padding hole between
+		 * orig_gpr2 and fp_regs on s390.
+		 */
+		return 0;
+
 	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure
@@ -428,6 +442,13 @@
 		 */
 		tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4);
 
+	} else if (addr < (addr_t) &dummy32->regs.fp_regs) {
+		/*
+		 * prevent reads of padding hole between
+		 * orig_gpr2 and fp_regs on s390.
+		 */
+		tmp = 0;
+
 	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure 
@@ -514,6 +535,13 @@
 		 */
 		*(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp;
 
+	} else if (addr < (addr_t) &dummy32->regs.fp_regs) {
+		/*
+		 * prevent writess of padding hole between
+		 * orig_gpr2 and fp_regs on s390.
+		 */
+		return 0;
+
 	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure 
diff --git a/arch/sh/configs/ap325rxa_defconfig b/arch/sh/configs/ap325rxa_defconfig
index 29926a9..851c870 100644
--- a/arch/sh/configs/ap325rxa_defconfig
+++ b/arch/sh/configs/ap325rxa_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26
-# Wed Jul 30 01:18:59 2008
+# Linux kernel version: 2.6.27-rc4
+# Tue Aug 26 14:21:17 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -11,6 +11,7 @@
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
@@ -20,7 +21,6 @@
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -58,7 +58,6 @@
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_KALLSYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
@@ -89,6 +88,7 @@
 # CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
 CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
@@ -261,9 +261,10 @@
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
-# CONFIG_SCHED_HRTICK is not set
+CONFIG_SCHED_HRTICK=y
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
 # CONFIG_PREEMPT_NONE is not set
 # CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
@@ -289,10 +290,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -647,6 +644,7 @@
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
 
 #
 # Multimedia devices
@@ -690,7 +688,10 @@
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
 
 #
 # File systems
@@ -854,6 +855,7 @@
 # CONFIG_DEBUG_KERNEL is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_SAMPLES is not set
 # CONFIG_SH_STANDARD_BIOS is not set
 # CONFIG_EARLY_SCIF_CONSOLE is not set
diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig
index c4b3e1d..4f8b197 100644
--- a/arch/sh/configs/migor_defconfig
+++ b/arch/sh/configs/migor_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26
-# Wed Jul 30 01:44:41 2008
+# Linux kernel version: 2.6.27-rc4
+# Tue Aug 26 14:18:17 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -11,6 +11,7 @@
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
@@ -21,7 +22,6 @@
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -87,6 +87,7 @@
 # CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
 CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
@@ -270,6 +271,7 @@
 # CONFIG_SCHED_HRTICK is not set
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
+CONFIG_SECCOMP=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
@@ -294,10 +296,6 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -649,6 +647,7 @@
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 # CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
 
 #
 # I2C Hardware Bus support
@@ -709,6 +708,7 @@
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
 
 #
 # Multimedia devices
@@ -755,6 +755,8 @@
 # CONFIG_USB is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -842,7 +844,10 @@
 #
 CONFIG_RTC_DRV_SH=y
 # CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_UIO_SMX is not set
 
 #
 # File systems
diff --git a/arch/sh/include/asm/uaccess_64.h b/arch/sh/include/asm/uaccess_64.h
index 81b3d51..5580fd4 100644
--- a/arch/sh/include/asm/uaccess_64.h
+++ b/arch/sh/include/asm/uaccess_64.h
@@ -76,4 +76,6 @@
 extern long __put_user_asm_q(void *, long);
 extern void __put_user_unknown(void);
 
+extern long __strnlen_user(const char *__s, long __n);
+
 #endif /* __ASM_SH_UACCESS_64_H */
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index 04c7da9..e640c63 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -2,7 +2,7 @@
  * arch/sh/kernel/cpu/sh5/entry.S
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2004 - 2007  Paul Mundt
+ * Copyright (C) 2004 - 2008  Paul Mundt
  * Copyright (C) 2003, 2004  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -923,6 +923,8 @@
 	blink   tr0, ZERO
 
 resume_kernel:
+	CLI()
+
 	pta	restore_all, tr0
 
 	getcon	KCR0, r6
@@ -939,19 +941,11 @@
 	andi	r7, 0xf0, r7
 	bne	r7, ZERO, tr0
 
-	movi	((PREEMPT_ACTIVE >> 16) & 65535), r8
-	shori	(PREEMPT_ACTIVE & 65535), r8
-	st.l	r6, TI_PRE_COUNT, r8
-
-	STI()
-	movi	schedule, r7
+	movi	preempt_schedule_irq, r7
 	ori	r7, 1, r7
 	ptabs	r7, tr1
 	blink	tr1, LINK
 
-	st.l	r6, TI_PRE_COUNT, ZERO
-	CLI()
-
 	pta	need_resched, tr1
 	blink	tr1, ZERO
 #endif
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 0bc17de..efbb426 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -92,6 +92,7 @@
 	bra	resume_userspace
 	 nop
 ENTRY(resume_kernel)
+	cli
 	mov.l	@(TI_PRE_COUNT,r8), r0	! current_thread_info->preempt_count
 	tst	r0, r0
 	bf	noresched
@@ -105,28 +106,9 @@
 	and	#0xf0, r0		! interrupts off (exception path)?
 	cmp/eq	#0xf0, r0
 	bt	noresched
-
-	mov.l	1f, r0
-	mov.l	r0, @(TI_PRE_COUNT,r8)
-
-#ifdef CONFIG_TRACE_IRQFLAGS
 	mov.l	3f, r0
-	jsr	@r0
+	jsr	@r0			! call preempt_schedule_irq
 	 nop
-#endif
-	sti
-	mov.l	2f, r0
-	jsr	@r0
-	 nop
-	mov	#0, r0
-	mov.l	r0, @(TI_PRE_COUNT,r8)
-	cli
-#ifdef CONFIG_TRACE_IRQFLAGS
-	mov.l	4f, r0
-	jsr	@r0
-	 nop
-#endif
-
 	bra	need_resched
 	 nop
 
@@ -137,10 +119,7 @@
 	.align 2
 1:	.long	PREEMPT_ACTIVE
 2:	.long	schedule
-#ifdef CONFIG_TRACE_IRQFLAGS
-3:	.long	trace_hardirqs_on
-4:	.long	trace_hardirqs_off
-#endif
+3:	.long	preempt_schedule_irq
 #endif
 
 ENTRY(resume_userspace)
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 4703dff..94df56b 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -102,7 +102,7 @@
 
 	/* now call it */
 	rnk = (relocate_new_kernel_t) reboot_code_buffer;
-	(*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
+	(*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg);
 }
 
 void arch_crash_save_vmcoreinfo(void)
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index 5922edd..9c64248 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -131,6 +131,8 @@
 
 void user_disable_single_step(struct task_struct *child)
 {
+	struct pt_regs *regs = child->thread.uregs;
+
 	regs->sr &= ~SR_SSTEP;
 }
 
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index a352076..de83205 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -171,6 +171,7 @@
 				(unsigned long)(free_mem >> 20));
 		crashk_res.start = crash_base;
 		crashk_res.end   = crash_base + crash_size - 1;
+		insert_resource(&iomem_resource, &crashk_res);
 	}
 }
 #else
@@ -204,11 +205,6 @@
 	request_resource(res, &data_resource);
 	request_resource(res, &bss_resource);
 
-#ifdef CONFIG_KEXEC
-	if (crashk_res.start != crashk_res.end)
-		request_resource(res, &crashk_res);
-#endif
-
 	add_active_range(nid, start_pfn, end_pfn);
 }
 
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index 59cd285..9061b86 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -170,7 +170,7 @@
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
-	if (call <= SEMCTL)
+	if (call <= SEMTIMEDOP)
 		switch (call) {
 		case SEMOP:
 			return sys_semtimedop(first,
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index 895bb3f..64b8f7f 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -101,7 +101,7 @@
 }
 __setup("memchunk.", memchunk_setup);
 
-static void memchunk_cmdline_override(char *name, unsigned long *sizep)
+static void __init memchunk_cmdline_override(char *name, unsigned long *sizep)
 {
 	char *p = boot_command_line;
 	int k = strlen(name);
@@ -118,8 +118,8 @@
 	}
 }
 
-int platform_resource_setup_memory(struct platform_device *pdev,
-				   char *name, unsigned long memsize)
+int __init platform_resource_setup_memory(struct platform_device *pdev,
+					  char *name, unsigned long memsize)
 {
 	struct resource *r;
 	dma_addr_t dma_handle;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 9b6689d..2396388 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -792,6 +792,8 @@
 		}
 		spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
 	}
+
+	tick_ops->disable_irq();
 }
 #endif
 
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 743ccad..2be166c 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -80,8 +80,6 @@
 			   i, cpu_data(i).clock_tick);
 }
 
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
-
 extern void setup_sparc64_timer(void);
 
 static volatile unsigned long callin_flag = 0;
@@ -120,9 +118,9 @@
 	while (!cpu_isset(cpuid, smp_commenced_mask))
 		rmb();
 
-	spin_lock(&call_lock);
+	ipi_call_lock();
 	cpu_set(cpuid, cpu_online_map);
-	spin_unlock(&call_lock);
+	ipi_call_unlock();
 
 	/* idle thread is expected to have preempt disabled */
 	preempt_disable();
@@ -1305,10 +1303,6 @@
 	c->core_id = 0;
 	c->proc_id = -1;
 
-	spin_lock(&call_lock);
-	cpu_clear(cpu, cpu_online_map);
-	spin_unlock(&call_lock);
-
 	smp_wmb();
 
 	/* Make sure no interrupts point to this cpu.  */
@@ -1318,6 +1312,10 @@
 	mdelay(1);
 	local_irq_disable();
 
+	ipi_call_lock();
+	cpu_clear(cpu, cpu_online_map);
+	ipi_call_unlock();
+
 	return 0;
 }
 
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 2c518fb..b225219 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -382,14 +382,17 @@
 # P6_NOPs are a relatively minor optimization that require a family >=
 # 6 processor, except that it is broken on certain VIA chips.
 # Furthermore, AMD chips prefer a totally different sequence of NOPs
-# (which work on all CPUs).  As a result, disallow these if we're
-# compiling X86_GENERIC but not X86_64 (these NOPs do work on all
-# x86-64 capable chips); the list of processors in the right-hand clause
-# are the cores that benefit from this optimization.
+# (which work on all CPUs).  In addition, it looks like Virtual PC
+# does not understand them.
+#
+# As a result, disallow these if we're not compiling for X86_64 (these
+# NOPs do work on all x86-64 capable chips); the list of processors in
+# the right-hand clause are the cores that benefit from this optimization.
 #
 config X86_P6_NOP
 	def_bool y
-	depends on (X86_64 || !X86_GENERIC) && (M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || MPENTIUM4 || MPSC)
+	depends on X86_64
+	depends on (MCORE2 || MPENTIUM4 || MPSC)
 
 config X86_TSC
 	def_bool y
diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c
index 4b9ae7c..4d3ff03 100644
--- a/arch/x86/boot/cpucheck.c
+++ b/arch/x86/boot/cpucheck.c
@@ -38,12 +38,12 @@
 {
 	REQUIRED_MASK0,
 	REQUIRED_MASK1,
-	REQUIRED_MASK2,
-	REQUIRED_MASK3,
+	0, /* REQUIRED_MASK2 not implemented in this file */
+	0, /* REQUIRED_MASK3 not implemented in this file */
 	REQUIRED_MASK4,
-	REQUIRED_MASK5,
+	0, /* REQUIRED_MASK5 not implemented in this file */
 	REQUIRED_MASK6,
-	REQUIRED_MASK7,
+	0, /* REQUIRED_MASK7 not implemented in this file */
 };
 
 #define A32(a, b, c, d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 2763cb3..65a0c1b 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -145,35 +145,25 @@
 extern char __vsyscall_0;
 const unsigned char *const *find_nop_table(void)
 {
-	return boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
-	       boot_cpu_data.x86 < 6 ? k8_nops : p6_nops;
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+	    boot_cpu_has(X86_FEATURE_NOPL))
+		return p6_nops;
+	else
+		return k8_nops;
 }
 
 #else /* CONFIG_X86_64 */
 
-static const struct nop {
-	int cpuid;
-	const unsigned char *const *noptable;
-} noptypes[] = {
-	{ X86_FEATURE_K8, k8_nops },
-	{ X86_FEATURE_K7, k7_nops },
-	{ X86_FEATURE_P4, p6_nops },
-	{ X86_FEATURE_P3, p6_nops },
-	{ -1, NULL }
-};
-
 const unsigned char *const *find_nop_table(void)
 {
-	const unsigned char *const *noptable = intel_nops;
-	int i;
-
-	for (i = 0; noptypes[i].cpuid >= 0; i++) {
-		if (boot_cpu_has(noptypes[i].cpuid)) {
-			noptable = noptypes[i].noptable;
-			break;
-		}
-	}
-	return noptable;
+	if (boot_cpu_has(X86_FEATURE_K8))
+		return k8_nops;
+	else if (boot_cpu_has(X86_FEATURE_K7))
+		return k7_nops;
+	else if (boot_cpu_has(X86_FEATURE_NOPL))
+		return p6_nops;
+	else
+		return intel_nops;
 }
 
 #endif /* CONFIG_X86_64 */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index cae9cab..18514ed 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -31,6 +31,11 @@
 		if (c->x86_power & (1<<8))
 			set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 	}
+
+	/*  Set MTRR capability flag if appropriate */
+	if (c->x86_model == 13 || c->x86_model == 9 ||
+	   (c->x86_model == 8 && c->x86_mask >= 8))
+		set_cpu_cap(c, X86_FEATURE_K6_MTRR);
 }
 
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
@@ -166,10 +171,6 @@
 						mbytes);
 				}
 
-				/*  Set MTRR capability flag if appropriate */
-				if (c->x86_model == 13 || c->x86_model == 9 ||
-				   (c->x86_model == 8 && c->x86_mask >= 8))
-					set_cpu_cap(c, X86_FEATURE_K6_MTRR);
 				break;
 			}
 
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index e0f45ed..a0534c0 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -314,6 +314,16 @@
 		EAMD3D		= 1<<20,
 };
 
+static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
+{
+	switch (c->x86) {
+	case 5:
+		/* Emulate MTRRs using Centaur's MCR. */
+		set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
+		break;
+	}
+}
+
 static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
 {
 
@@ -462,6 +472,7 @@
 static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
 	.c_vendor	= "Centaur",
 	.c_ident	= { "CentaurHauls" },
+	.c_early_init	= early_init_centaur,
 	.c_init		= init_centaur,
 	.c_size_cache	= centaur_size_cache,
 };
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 80ab20d..8aab851 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -13,6 +13,7 @@
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/pat.h>
+#include <asm/asm.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/mpspec.h>
 #include <asm/apic.h>
@@ -334,11 +335,40 @@
 
 	get_cpu_vendor(c, 1);
 
+	early_get_cap(c);
+
 	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
 	    cpu_devs[c->x86_vendor]->c_early_init)
 		cpu_devs[c->x86_vendor]->c_early_init(c);
+}
 
-	early_get_cap(c);
+/*
+ * The NOPL instruction is supposed to exist on all CPUs with
+ * family >= 6, unfortunately, that's not true in practice because
+ * of early VIA chips and (more importantly) broken virtualizers that
+ * are not easy to detect.  Hence, probe for it based on first
+ * principles.
+ */
+static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
+{
+	const u32 nopl_signature = 0x888c53b1; /* Random number */
+	u32 has_nopl = nopl_signature;
+
+	clear_cpu_cap(c, X86_FEATURE_NOPL);
+	if (c->x86 >= 6) {
+		asm volatile("\n"
+			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
+			     "2:\n"
+			     "        .section .fixup,\"ax\"\n"
+			     "3:      xor %0,%0\n"
+			     "        jmp 2b\n"
+			     "        .previous\n"
+			     _ASM_EXTABLE(1b,3b)
+			     : "+a" (has_nopl));
+
+		if (has_nopl == nopl_signature)
+			set_cpu_cap(c, X86_FEATURE_NOPL);
+	}
 }
 
 static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
@@ -395,8 +425,8 @@
 		}
 
 		init_scattered_cpuid_features(c);
+		detect_nopl(c);
 	}
-
 }
 
 static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c
index dd6e3f1..a11f5d4 100644
--- a/arch/x86/kernel/cpu/common_64.c
+++ b/arch/x86/kernel/cpu/common_64.c
@@ -18,6 +18,7 @@
 #include <asm/mtrr.h>
 #include <asm/mce.h>
 #include <asm/pat.h>
+#include <asm/asm.h>
 #include <asm/numa.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/mpspec.h>
@@ -215,6 +216,39 @@
 	}
 }
 
+/*
+ * The NOPL instruction is supposed to exist on all CPUs with
+ * family >= 6, unfortunately, that's not true in practice because
+ * of early VIA chips and (more importantly) broken virtualizers that
+ * are not easy to detect.  Hence, probe for it based on first
+ * principles.
+ *
+ * Note: no 64-bit chip is known to lack these, but put the code here
+ * for consistency with 32 bits, and to make it utterly trivial to
+ * diagnose the problem should it ever surface.
+ */
+static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
+{
+	const u32 nopl_signature = 0x888c53b1; /* Random number */
+	u32 has_nopl = nopl_signature;
+
+	clear_cpu_cap(c, X86_FEATURE_NOPL);
+	if (c->x86 >= 6) {
+		asm volatile("\n"
+			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
+			     "2:\n"
+			     "        .section .fixup,\"ax\"\n"
+			     "3:      xor %0,%0\n"
+			     "        jmp 2b\n"
+			     "        .previous\n"
+			     _ASM_EXTABLE(1b,3b)
+			     : "+a" (has_nopl));
+
+		if (has_nopl == nopl_signature)
+			set_cpu_cap(c, X86_FEATURE_NOPL);
+	}
+}
+
 static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
 
 void __init early_cpu_init(void)
@@ -313,6 +347,8 @@
 		c->x86_phys_bits = eax & 0xff;
 	}
 
+	detect_nopl(c);
+
 	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
 	    cpu_devs[c->x86_vendor]->c_early_init)
 		cpu_devs[c->x86_vendor]->c_early_init(c);
@@ -493,17 +529,20 @@
 		/* others are initialized in smpboot.c */
 		pda->pcurrent = &init_task;
 		pda->irqstackptr = boot_cpu_stack;
+		pda->irqstackptr += IRQSTACKSIZE - 64;
 	} else {
-		pda->irqstackptr = (char *)
-			__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
-		if (!pda->irqstackptr)
-			panic("cannot allocate irqstack for cpu %d", cpu);
+		if (!pda->irqstackptr) {
+			pda->irqstackptr = (char *)
+				__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
+			if (!pda->irqstackptr)
+				panic("cannot allocate irqstack for cpu %d",
+				      cpu);
+			pda->irqstackptr += IRQSTACKSIZE - 64;
+		}
 
 		if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
 			pda->nodenumber = cpu_to_node(cpu);
 	}
-
-	pda->irqstackptr += IRQSTACKSIZE-64;
 }
 
 char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
@@ -601,19 +640,22 @@
 	/*
 	 * set up and load the per-CPU TSS
 	 */
-	for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+	if (!orig_ist->ist[0]) {
 		static const unsigned int order[N_EXCEPTION_STACKS] = {
-			[0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
-			[DEBUG_STACK - 1] = DEBUG_STACK_ORDER
+		  [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
+		  [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
 		};
-		if (cpu) {
-			estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
-			if (!estacks)
-				panic("Cannot allocate exception stack %ld %d\n",
-				      v, cpu);
+		for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+			if (cpu) {
+				estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
+				if (!estacks)
+					panic("Cannot allocate exception "
+					      "stack %ld %d\n", v, cpu);
+			}
+			estacks += PAGE_SIZE << order[v];
+			orig_ist->ist[v] = t->x86_tss.ist[v] =
+					(unsigned long)estacks;
 		}
-		estacks += PAGE_SIZE << order[v];
-		orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks;
 	}
 
 	t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index e710a21..898a5a2 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -15,13 +15,11 @@
 /*
  * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
-static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+static void __cpuinit __do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
 	unsigned char ccr2, ccr3;
-	unsigned long flags;
 
 	/* we test for DEVID by checking whether CCR3 is writable */
-	local_irq_save(flags);
 	ccr3 = getCx86(CX86_CCR3);
 	setCx86(CX86_CCR3, ccr3 ^ 0x80);
 	getCx86(0xc0);   /* dummy to change bus */
@@ -44,9 +42,16 @@
 		*dir0 = getCx86(CX86_DIR0);
 		*dir1 = getCx86(CX86_DIR1);
 	}
-	local_irq_restore(flags);
 }
 
+static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	__do_cyrix_devid(dir0, dir1);
+	local_irq_restore(flags);
+}
 /*
  * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
  * order to identify the Cyrix CPU model after we're out of setup.c
@@ -161,6 +166,24 @@
 	local_irq_restore(flags);
 }
 
+static void __cpuinit early_init_cyrix(struct cpuinfo_x86 *c)
+{
+	unsigned char dir0, dir0_msn, dir1 = 0;
+
+	__do_cyrix_devid(&dir0, &dir1);
+	dir0_msn = dir0 >> 4; /* identifies CPU "family"   */
+
+	switch (dir0_msn) {
+	case 3: /* 6x86/6x86L */
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
+		break;
+	case 5: /* 6x86MX/M II */
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
+		break;
+	}
+}
 
 static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
 {
@@ -416,6 +439,7 @@
 static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
 	.c_vendor	= "Cyrix",
 	.c_ident	= { "CyrixInstead" },
+	.c_early_init	= early_init_cyrix,
 	.c_init		= init_cyrix,
 	.c_identify	= cyrix_identify,
 };
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c
index e43ad4a..c901779 100644
--- a/arch/x86/kernel/cpu/feature_names.c
+++ b/arch/x86/kernel/cpu/feature_names.c
@@ -39,7 +39,8 @@
 	NULL, NULL, NULL, NULL,
 	"constant_tsc", "up", NULL, "arch_perfmon",
 	"pebs", "bts", NULL, NULL,
-	"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	"rep_good", NULL, NULL, NULL,
+	"nopl", NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 	/* Intel-defined (#2) */
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 9af8907..66e48aa 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -1203,7 +1203,7 @@
 	if (!p)
 		return -EINVAL;
 
-	if (!strcmp(p, "exactmap")) {
+	if (!strncmp(p, "exactmap", 8)) {
 #ifdef CONFIG_CRASH_DUMP
 		/*
 		 * If we are doing a crash dump, we still need to know
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 59fd3b6..73deaff 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -210,8 +210,8 @@
 	/* Calculate the min / max delta */
 	hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
 							   &hpet_clockevent);
-	hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
-							   &hpet_clockevent);
+	/* 5 usec minimum reprogramming delta. */
+	hpet_clockevent.min_delta_ns = 5000;
 
 	/*
 	 * Start hpet with the boot cpu mask and make it
@@ -270,15 +270,22 @@
 }
 
 static int hpet_legacy_next_event(unsigned long delta,
-			   struct clock_event_device *evt)
+				  struct clock_event_device *evt)
 {
-	unsigned long cnt;
+	u32 cnt;
 
 	cnt = hpet_readl(HPET_COUNTER);
-	cnt += delta;
+	cnt += (u32) delta;
 	hpet_writel(cnt, HPET_T0_CMP);
 
-	return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0;
+	/*
+	 * We need to read back the CMP register to make sure that
+	 * what we wrote hit the chip before we compare it to the
+	 * counter.
+	 */
+	WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt);
+
+	return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
 }
 
 /*
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
index 1c3a66a..720d260 100644
--- a/arch/x86/kernel/io_delay.c
+++ b/arch/x86/kernel/io_delay.c
@@ -92,6 +92,14 @@
 			DMI_MATCH(DMI_BOARD_NAME, "30BF")
 		}
 	},
+	{
+		.callback	= dmi_io_delay_0xed_port,
+		.ident		= "Presario F700",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30D3")
+		}
+	},
 	{ }
 };
 
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 346cae5..8f98e9d 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -267,8 +267,7 @@
 	 */
 	if (tsc_pit_min == ULONG_MAX) {
 		/* PIT gave no useful value */
-		printk(KERN_WARNING "TSC: PIT calibration failed due to "
-		       "SMI disturbance.\n");
+		printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n");
 
 		/* We don't have an alternative source, disable TSC */
 		if (!hpet && !pm1 && !pm2) {
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 9ff6e3c..a4e201b 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1324,7 +1324,7 @@
 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
 
 	.pte_val = xen_pte_val,
-	.pte_flags = native_pte_val,
+	.pte_flags = native_pte_flags,
 	.pgd_val = xen_pgd_val,
 
 	.make_pte = xen_make_pte,
diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c
index 85eaf7b..e8362c1 100644
--- a/crypto/async_tx/async_tx.c
+++ b/crypto/async_tx/async_tx.c
@@ -137,7 +137,8 @@
 		spin_lock_bh(&next->lock);
 		next->parent = NULL;
 		_next = next->next;
-		next->next = NULL;
+		if (_next && _next->chan == chan)
+			next->next = NULL;
 		spin_unlock_bh(&next->lock);
 
 		next->tx_submit(next);
diff --git a/crypto/camellia.c b/crypto/camellia.c
index b1cc4de..493fee7 100644
--- a/crypto/camellia.c
+++ b/crypto/camellia.c
@@ -35,8 +35,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/bitops.h>
-#include <asm/unaligned.h>
 
 static const u32 camellia_sp1110[256] = {
 	0x70707000,0x82828200,0x2c2c2c00,0xececec00,
@@ -337,6 +335,20 @@
 /*
  *  macros
  */
+#define GETU32(v, pt) \
+    do { \
+	/* latest breed of gcc is clever enough to use move */ \
+	memcpy(&(v), (pt), 4); \
+	(v) = be32_to_cpu(v); \
+    } while(0)
+
+/* rotation right shift 1byte */
+#define ROR8(x) (((x) >> 8) + ((x) << 24))
+/* rotation left shift 1bit */
+#define ROL1(x) (((x) << 1) + ((x) >> 31))
+/* rotation left shift 1byte */
+#define ROL8(x) (((x) << 8) + ((x) >> 24))
+
 #define ROLDQ(ll, lr, rl, rr, w0, w1, bits)		\
     do {						\
 	w0 = ll;					\
@@ -371,7 +383,7 @@
 	   ^ camellia_sp3033[(u8)(il >> 8)]			\
 	   ^ camellia_sp4404[(u8)(il     )];			\
 	yl ^= yr;						\
-	yr = ror32(yr, 8);					\
+	yr = ROR8(yr);						\
 	yr ^= yl;						\
     } while(0)
 
@@ -393,7 +405,7 @@
 	subL[7] ^= subL[1]; subR[7] ^= subR[1];
 	subL[1] ^= subR[1] & ~subR[9];
 	dw = subL[1] & subL[9],
-		subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
+		subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */
 	/* round 8 */
 	subL[11] ^= subL[1]; subR[11] ^= subR[1];
 	/* round 10 */
@@ -402,7 +414,7 @@
 	subL[15] ^= subL[1]; subR[15] ^= subR[1];
 	subL[1] ^= subR[1] & ~subR[17];
 	dw = subL[1] & subL[17],
-		subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
+		subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */
 	/* round 14 */
 	subL[19] ^= subL[1]; subR[19] ^= subR[1];
 	/* round 16 */
@@ -418,7 +430,7 @@
 	} else {
 		subL[1] ^= subR[1] & ~subR[25];
 		dw = subL[1] & subL[25],
-			subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
+			subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */
 		/* round 20 */
 		subL[27] ^= subL[1]; subR[27] ^= subR[1];
 		/* round 22 */
@@ -438,7 +450,7 @@
 		subL[26] ^= kw4l; subR[26] ^= kw4r;
 		kw4l ^= kw4r & ~subR[24];
 		dw = kw4l & subL[24],
-			kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
+			kw4r ^= ROL1(dw); /* modified for FL(kl5) */
 	}
 	/* round 17 */
 	subL[22] ^= kw4l; subR[22] ^= kw4r;
@@ -448,7 +460,7 @@
 	subL[18] ^= kw4l; subR[18] ^= kw4r;
 	kw4l ^= kw4r & ~subR[16];
 	dw = kw4l & subL[16],
-		kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
+		kw4r ^= ROL1(dw); /* modified for FL(kl3) */
 	/* round 11 */
 	subL[14] ^= kw4l; subR[14] ^= kw4r;
 	/* round 9 */
@@ -457,7 +469,7 @@
 	subL[10] ^= kw4l; subR[10] ^= kw4r;
 	kw4l ^= kw4r & ~subR[8];
 	dw = kw4l & subL[8],
-		kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
+		kw4r ^= ROL1(dw); /* modified for FL(kl1) */
 	/* round 5 */
 	subL[6] ^= kw4l; subR[6] ^= kw4r;
 	/* round 3 */
@@ -482,7 +494,7 @@
 	SUBKEY_R(6) = subR[5] ^ subR[7];
 	tl = subL[10] ^ (subR[10] & ~subR[8]);
 	dw = tl & subL[8],  /* FL(kl1) */
-		tr = subR[10] ^ rol32(dw, 1);
+		tr = subR[10] ^ ROL1(dw);
 	SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
 	SUBKEY_R(7) = subR[6] ^ tr;
 	SUBKEY_L(8) = subL[8];       /* FL(kl1) */
@@ -491,7 +503,7 @@
 	SUBKEY_R(9) = subR[9];
 	tl = subL[7] ^ (subR[7] & ~subR[9]);
 	dw = tl & subL[9],  /* FLinv(kl2) */
-		tr = subR[7] ^ rol32(dw, 1);
+		tr = subR[7] ^ ROL1(dw);
 	SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
 	SUBKEY_R(10) = tr ^ subR[11];
 	SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
@@ -504,7 +516,7 @@
 	SUBKEY_R(14) = subR[13] ^ subR[15];
 	tl = subL[18] ^ (subR[18] & ~subR[16]);
 	dw = tl & subL[16], /* FL(kl3) */
-		tr = subR[18] ^ rol32(dw, 1);
+		tr = subR[18] ^ ROL1(dw);
 	SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
 	SUBKEY_R(15) = subR[14] ^ tr;
 	SUBKEY_L(16) = subL[16];     /* FL(kl3) */
@@ -513,7 +525,7 @@
 	SUBKEY_R(17) = subR[17];
 	tl = subL[15] ^ (subR[15] & ~subR[17]);
 	dw = tl & subL[17], /* FLinv(kl4) */
-		tr = subR[15] ^ rol32(dw, 1);
+		tr = subR[15] ^ ROL1(dw);
 	SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
 	SUBKEY_R(18) = tr ^ subR[19];
 	SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
@@ -532,7 +544,7 @@
 	} else {
 		tl = subL[26] ^ (subR[26] & ~subR[24]);
 		dw = tl & subL[24], /* FL(kl5) */
-			tr = subR[26] ^ rol32(dw, 1);
+			tr = subR[26] ^ ROL1(dw);
 		SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
 		SUBKEY_R(23) = subR[22] ^ tr;
 		SUBKEY_L(24) = subL[24];     /* FL(kl5) */
@@ -541,7 +553,7 @@
 		SUBKEY_R(25) = subR[25];
 		tl = subL[23] ^ (subR[23] & ~subR[25]);
 		dw = tl & subL[25], /* FLinv(kl6) */
-			tr = subR[23] ^ rol32(dw, 1);
+			tr = subR[23] ^ ROL1(dw);
 		SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
 		SUBKEY_R(26) = tr ^ subR[27];
 		SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
@@ -561,17 +573,17 @@
 	/* apply the inverse of the last half of P-function */
 	i = 2;
 	do {
-		dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */
+		dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */
 		SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
-		dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */
+		dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */
 		SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
-		dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */
+		dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */
 		SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
-		dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */
+		dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */
 		SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
-		dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 9);/* round 5 */
+		dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */
 		SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
-		dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */
+		dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */
 		SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
 		i += 8;
 	} while (i < max);
@@ -587,10 +599,10 @@
 	/**
 	 *  k == kll || klr || krl || krr (|| is concatenation)
 	 */
-	kll = get_unaligned_be32(key);
-	klr = get_unaligned_be32(key + 4);
-	krl = get_unaligned_be32(key + 8);
-	krr = get_unaligned_be32(key + 12);
+	GETU32(kll, key     );
+	GETU32(klr, key +  4);
+	GETU32(krl, key +  8);
+	GETU32(krr, key + 12);
 
 	/* generate KL dependent subkeys */
 	/* kw1 */
@@ -695,14 +707,14 @@
 	 *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
 	 *  (|| is concatenation)
 	 */
-	kll = get_unaligned_be32(key);
-	klr = get_unaligned_be32(key + 4);
-	krl = get_unaligned_be32(key + 8);
-	krr = get_unaligned_be32(key + 12);
-	krll = get_unaligned_be32(key + 16);
-	krlr = get_unaligned_be32(key + 20);
-	krrl = get_unaligned_be32(key + 24);
-	krrr = get_unaligned_be32(key + 28);
+	GETU32(kll,  key     );
+	GETU32(klr,  key +  4);
+	GETU32(krl,  key +  8);
+	GETU32(krr,  key + 12);
+	GETU32(krll, key + 16);
+	GETU32(krlr, key + 20);
+	GETU32(krrl, key + 24);
+	GETU32(krrr, key + 28);
 
 	/* generate KL dependent subkeys */
 	/* kw1 */
@@ -858,13 +870,13 @@
 	t0 &= ll;							\
 	t2 |= rr;							\
 	rl ^= t2;							\
-	lr ^= rol32(t0, 1);						\
+	lr ^= ROL1(t0);							\
 	t3 = krl;							\
 	t1 = klr;							\
 	t3 &= rl;							\
 	t1 |= lr;							\
 	ll ^= t1;							\
-	rr ^= rol32(t3, 1);						\
+	rr ^= ROL1(t3);							\
     } while(0)
 
 #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)		\
@@ -880,7 +892,7 @@
 	il ^= kl;							\
 	ir ^= il ^ kr;							\
 	yl ^= ir;							\
-	yr ^= ror32(il, 8) ^ ir;						\
+	yr ^= ROR8(il) ^ ir;						\
     } while(0)
 
 /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 1022e38..0f28058 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -496,7 +496,7 @@
 			arg = arg->common.next;
 		}
 
-		ACPI_ERROR((AE_INFO,
+		ACPI_WARNING((AE_INFO,
 			    "Package List length (%X) larger than NumElements count (%X), truncated\n",
 			    i, element_count));
 	} else if (i < element_count) {
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 80e3209..80c251e 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -71,7 +71,7 @@
  *  1 -> ignore _PPC totally -> forced by user through boot param
  */
 static int ignore_ppc = -1;
-module_param(ignore_ppc, uint, 0644);
+module_param(ignore_ppc, int, 0644);
 MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
 		 "limited by BIOS, this should help");
 
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index bcf2c70..a4e3767 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -107,6 +107,13 @@
 	if (wait_event_timeout(hc->wait, smb_check_done(hc),
 			       msecs_to_jiffies(timeout)))
 		return 0;
+	/*
+	 * After the timeout happens, OS will try to check the status of SMbus.
+	 * If the status is what OS expected, it will be regarded as the bogus
+	 * timeout.
+	 */
+	if (smb_check_done(hc))
+		return 0;
 	else
 		return -ETIME;
 }
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index c341918..775c97a 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -300,6 +300,8 @@
 
 static int __init acpi_parse_apic_instance(char *str)
 {
+	if (!str)
+		return -EINVAL;
 
 	acpi_apic_instance = simple_strtoul(str, NULL, 0);
 
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ae84949..11c8c19 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -448,8 +448,10 @@
 	tristate "Marvell PATA support via legacy mode"
 	depends on PCI
 	help
-	  This option enables limited support for the Marvell 88SE6145 ATA
-	  controller.
+	  This option enables limited support for the Marvell 88SE61xx ATA
+	  controllers. If you wish to use only the SATA ports then select
+	  the AHCI driver alone. If you wish to the use the PATA port or
+	  both SATA and PATA include this driver.
 
 	  If unsure, say N.
 
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c729e69..2e1a7cb 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -420,7 +420,7 @@
 	/* board_ahci_mv */
 	{
 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
-				 AHCI_HFLAG_MV_PATA),
+				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
 		.pio_mask	= 0x1f, /* pio0-4 */
@@ -487,7 +487,9 @@
 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -610,6 +612,15 @@
 MODULE_PARM_DESC(ahci_em_messages,
 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
 
+#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+static int marvell_enable;
+#else
+static int marvell_enable = 1;
+#endif
+module_param(marvell_enable, int, 0644);
+MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
+
+
 static inline int ahci_nr_ports(u32 cap)
 {
 	return (cap & 0x1f) + 1;
@@ -732,6 +743,8 @@
 			   "MV_AHCI HACK: port_map %x -> %x\n",
 			   port_map,
 			   port_map & mv);
+		dev_printk(KERN_ERR, &pdev->dev,
+			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
 
 		port_map &= mv;
 	}
@@ -2533,6 +2546,12 @@
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* The AHCI driver can only drive the SATA ports, the PATA driver
+	   can drive them all so if both drivers are selected make sure
+	   AHCI stays out of the way */
+	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
+		return -ENODEV;
+
 	/* acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 304fdc6..2a4c516 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1315,11 +1315,6 @@
 		break;
 
 	case HSM_ST_ERR:
-		/* make sure qc->err_mask is available to
-		 * know what's wrong and recover
-		 */
-		WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)));
-
 		ap->hsm_task_state = HSM_ST_IDLE;
 
 		/* complete taskfile transaction */
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 24a011b..0d87eec 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -20,7 +20,42 @@
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_marvell"
-#define DRV_VERSION	"0.1.4"
+#define DRV_VERSION	"0.1.6"
+
+/**
+ *	marvell_pata_active	-	check if PATA is active
+ *	@pdev: PCI device
+ *
+ *	Returns 1 if the PATA port may be active. We know how to check this
+ *	for the 6145 but not the other devices
+ */
+
+static int marvell_pata_active(struct pci_dev *pdev)
+{
+	int i;
+	u32 devices;
+	void __iomem *barp;
+
+	/* We don't yet know how to do this for other devices */
+	if (pdev->device != 0x6145)
+		return 1;	
+
+	barp = pci_iomap(pdev, 5, 0x10);
+	if (barp == NULL)
+		return -ENOMEM;
+
+	printk("BAR5:");
+	for(i = 0; i <= 0x0F; i++)
+		printk("%02X:%02X ", i, ioread8(barp + i));
+	printk("\n");
+
+	devices = ioread32(barp + 0x0C);
+	pci_iounmap(pdev, barp);
+
+	if (devices & 0x10)
+		return 1;
+	return 0;
+}
 
 /**
  *	marvell_pre_reset	-	check for 40/80 pin
@@ -34,26 +69,10 @@
 {
 	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u32 devices;
-	void __iomem *barp;
-	int i;
 
-	/* Check if our port is enabled */
-
-	barp = pci_iomap(pdev, 5, 0x10);
-	if (barp == NULL)
-		return -ENOMEM;
-	printk("BAR5:");
-	for(i = 0; i <= 0x0F; i++)
-		printk("%02X:%02X ", i, ioread8(barp + i));
-	printk("\n");
-
-	devices = ioread32(barp + 0x0C);
-	pci_iounmap(pdev, barp);
-
-	if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
-	    (!(devices & 0x10)))	/* PATA enable ? */
-		return -ENOENT;
+	if (pdev->device == 0x6145 && ap->port_no == 0 &&
+		!marvell_pata_active(pdev))	/* PATA enable ? */
+			return -ENOENT;
 
 	return ata_sff_prereset(link, deadline);
 }
@@ -128,6 +147,12 @@
 	if (pdev->device == 0x6101)
 		ppi[1] = &ata_dummy_port_info;
 
+#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE)
+	if (!marvell_pata_active(pdev)) {
+		printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
+		return -ENODEV;
+	}
+#endif
 	return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
 }
 
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 720b864..e970b22 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -322,9 +322,6 @@
 	/* Try to acquire MMIO resources and fallback to PIO if
 	 * that fails
 	 */
-	rc = pcim_enable_device(pdev);
-	if (rc)
-		return rc;
 	rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
 	if (rc)
 		goto use_ioports;
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 13c1d2a..c815f8e 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -667,7 +667,8 @@
 	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
 	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
 	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
-	/* RocketRAID 1740/174x have different identifiers */
+	/* RocketRAID 1720/174x have different identifiers */
+	{ PCI_VDEVICE(TTI, 0x1720), chip_6042 },
 	{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
 	{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
 
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 858f706..1e1f3f3 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -309,8 +309,6 @@
 static void nv_nf2_thaw(struct ata_port *ap);
 static void nv_ck804_freeze(struct ata_port *ap);
 static void nv_ck804_thaw(struct ata_port *ap);
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
-			unsigned long deadline);
 static int nv_adma_slave_config(struct scsi_device *sdev);
 static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
@@ -407,7 +405,7 @@
 
 static struct ata_port_operations nv_generic_ops = {
 	.inherits		= &ata_bmdma_port_ops,
-	.hardreset		= nv_hardreset,
+	.hardreset		= ATA_OP_NULL,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 };
@@ -1588,21 +1586,6 @@
 	ata_sff_thaw(ap);
 }
 
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
-			unsigned long deadline)
-{
-	int rc;
-
-	/* SATA hardreset fails to retrieve proper device signature on
-	 * some controllers.  Request follow up SRST.  For more info,
-	 * see http://bugzilla.kernel.org/show_bug.cgi?id=3352
-	 */
-	rc = sata_sff_hardreset(link, class, deadline);
-	if (rc)
-		return rc;
-	return -EAGAIN;
-}
-
 static void nv_adma_error_handler(struct ata_port *ap)
 {
 	struct nv_adma_port_priv *pp = ap->private_data;
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5ca1d80..4eee533 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 /*
@@ -151,13 +152,13 @@
  */
 static int verify_pmtmr_rate(void)
 {
-	u32 value1, value2;
+	cycle_t value1, value2;
 	unsigned long count, delta;
 
 	mach_prepare_counter();
-	value1 = read_pmtmr();
+	value1 = clocksource_acpi_pm.read();
 	mach_countup(&count);
-	value2 = read_pmtmr();
+	value2 = clocksource_acpi_pm.read();
 	delta = (value2 - value1) & ACPI_PM_MASK;
 
 	/* Check that the PMTMR delta is within 5% of what we expect */
@@ -175,10 +176,13 @@
 #define verify_pmtmr_rate() (0)
 #endif
 
+/* Number of monotonicity checks to perform during initialization */
+#define ACPI_PM_MONOTONICITY_CHECKS 10
+
 static int __init init_acpi_pm_clocksource(void)
 {
-	u32 value1, value2;
-	unsigned int i;
+	cycle_t value1, value2;
+	unsigned int i, j, good = 0;
 
 	if (!pmtmr_ioport)
 		return -ENODEV;
@@ -187,24 +191,32 @@
 						clocksource_acpi_pm.shift);
 
 	/* "verify" this timing source: */
-	value1 = read_pmtmr();
-	for (i = 0; i < 10000; i++) {
-		value2 = read_pmtmr();
-		if (value2 == value1)
-			continue;
-		if (value2 > value1)
-			goto pm_good;
-		if ((value2 < value1) && ((value2) < 0xFFF))
-			goto pm_good;
-		printk(KERN_INFO "PM-Timer had inconsistent results:"
-			" 0x%#x, 0x%#x - aborting.\n", value1, value2);
-		return -EINVAL;
+	for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
+		value1 = clocksource_acpi_pm.read();
+		for (i = 0; i < 10000; i++) {
+			value2 = clocksource_acpi_pm.read();
+			if (value2 == value1)
+				continue;
+			if (value2 > value1)
+				good++;
+				break;
+			if ((value2 < value1) && ((value2) < 0xFFF))
+				good++;
+				break;
+			printk(KERN_INFO "PM-Timer had inconsistent results:"
+			       " 0x%#llx, 0x%#llx - aborting.\n",
+			       value1, value2);
+			return -EINVAL;
+		}
+		udelay(300 * i);
 	}
-	printk(KERN_INFO "PM-Timer had no reasonable result:"
-			" 0x%#x - aborting.\n", value1);
-	return -ENODEV;
 
-pm_good:
+	if (good != ACPI_PM_MONOTONICITY_CHECKS) {
+		printk(KERN_INFO "PM-Timer failed consistency check "
+		       " (0x%#llx) - aborting.\n", value1);
+		return -ENODEV;
+	}
+
 	if (verify_pmtmr_rate() != 0)
 		return -ENODEV;
 
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 840e634f..640cbb2 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -31,13 +31,84 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+/* Transmit operation:                                                      */
+/*                                                                          */
+/* 0 byte transmit                                                          */
+/* BUS:     S     A8     ACK   P                                            */
+/* IRQ:       DTE   WAIT                                                    */
+/* ICIC:                                                                    */
+/* ICCR: 0x94 0x90                                                          */
+/* ICDR:      A8                                                            */
+/*                                                                          */
+/* 1 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT         WAIT                                       */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94       0x90                                                    */
+/* ICDR:      A8    D8(1)                                                   */
+/*                                                                          */
+/* 2 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT         WAIT          WAIT                         */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94                    0x90                                       */
+/* ICDR:      A8    D8(1)        D8(2)                                      */
+/*                                                                          */
+/* 3 bytes or more, +---------+ gets repeated                               */
+/*                                                                          */
+/*                                                                          */
+/* Receive operation:                                                       */
+/*                                                                          */
+/* 0 byte receive - not supported since slave may hold SDA low              */
+/*                                                                          */
+/* 1 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT     |   WAIT     DTE                               */
+/* ICIC:      -DTE           |   +DTE                                       */
+/* ICCR: 0x94       0x81     |   0xc0                                       */
+/* ICDR:      A8             |            D8(1)                             */
+/*                                                                          */
+/* 2 byte receive        [TX]| [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT     DTE                 */
+/* ICIC:      -DTE           |                 +DTE                         */
+/* ICCR: 0x94       0x81     |                 0xc0                         */
+/* ICDR:      A8             |                 D8(1)    D8(2)               */
+/*                                                                          */
+/* 3 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   D8(3)   ACK    P */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT         WAIT      DTE   */
+/* ICIC:      -DTE           |                              +DTE            */
+/* ICCR: 0x94       0x81     |                              0xc0            */
+/* ICDR:      A8             |                 D8(1)        D8(2)     D8(3) */
+/*                                                                          */
+/* 4 bytes or more, this part is repeated    +---------+                    */
+/*                                                                          */
+/*                                                                          */
+/* Interrupt order and BUSY flag                                            */
+/*     ___                                                 _                */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/                 */
+/* SCL      \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/                   */
+/*                                                                          */
+/*        S   D7  D6  D5  D4  D3  D2  D1  D0              P                 */
+/*                                           ___                            */
+/* WAIT IRQ ________________________________/   \___________                */
+/* TACK IRQ ____________________________________/   \_______                */
+/* DTE  IRQ __________________________________________/   \_                */
+/* AL   IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                */
+/*         _______________________________________________                  */
+/* BUSY __/                                               \_                */
+/*                                                                          */
+
 enum sh_mobile_i2c_op {
 	OP_START = 0,
-	OP_TX_ONLY,
+	OP_TX_FIRST,
+	OP_TX,
 	OP_TX_STOP,
 	OP_TX_TO_RX,
-	OP_RX_ONLY,
+	OP_RX,
 	OP_RX_STOP,
+	OP_RX_STOP_DATA,
 };
 
 struct sh_mobile_i2c_data {
@@ -127,25 +198,34 @@
 	spin_lock_irqsave(&pd->lock, flags);
 
 	switch (op) {
-	case OP_START:
+	case OP_START: /* issue start and trigger DTE interrupt */
 		iowrite8(0x94, ICCR(pd));
 		break;
-	case OP_TX_ONLY:
+	case OP_TX_FIRST: /* disable DTE interrupt and write data */
+		iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd));
 		iowrite8(data, ICDR(pd));
 		break;
-	case OP_TX_STOP:
+	case OP_TX: /* write data */
+		iowrite8(data, ICDR(pd));
+		break;
+	case OP_TX_STOP: /* write data and issue a stop afterwards */
 		iowrite8(data, ICDR(pd));
 		iowrite8(0x90, ICCR(pd));
-		iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
 		break;
-	case OP_TX_TO_RX:
-		iowrite8(data, ICDR(pd));
+	case OP_TX_TO_RX: /* select read mode */
 		iowrite8(0x81, ICCR(pd));
 		break;
-	case OP_RX_ONLY:
+	case OP_RX: /* just read data */
 		ret = ioread8(ICDR(pd));
 		break;
-	case OP_RX_STOP:
+	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+		iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+			 ICIC(pd));
+		iowrite8(0xc0, ICCR(pd));
+		break;
+	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+		iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+			 ICIC(pd));
 		ret = ioread8(ICDR(pd));
 		iowrite8(0xc0, ICCR(pd));
 		break;
@@ -157,58 +237,120 @@
 	return ret;
 }
 
+static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+	if (pd->pos == -1)
+		return 1;
+
+	return 0;
+}
+
+static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
+{
+	if (pd->pos == (pd->msg->len - 1))
+		return 1;
+
+	return 0;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+				   unsigned char *buf)
+{
+	switch (pd->pos) {
+	case -1:
+		*buf = (pd->msg->addr & 0x7f) << 1;
+		*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+		break;
+	default:
+		*buf = pd->msg->buf[pd->pos];
+	}
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+	unsigned char data;
+
+	if (pd->pos == pd->msg->len)
+		return 1;
+
+	sh_mobile_i2c_get_data(pd, &data);
+
+	if (sh_mobile_i2c_is_last_byte(pd))
+		i2c_op(pd, OP_TX_STOP, data);
+	else if (sh_mobile_i2c_is_first_byte(pd))
+		i2c_op(pd, OP_TX_FIRST, data);
+	else
+		i2c_op(pd, OP_TX, data);
+
+	pd->pos++;
+	return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+	unsigned char data;
+	int real_pos;
+
+	do {
+		if (pd->pos <= -1) {
+			sh_mobile_i2c_get_data(pd, &data);
+
+			if (sh_mobile_i2c_is_first_byte(pd))
+				i2c_op(pd, OP_TX_FIRST, data);
+			else
+				i2c_op(pd, OP_TX, data);
+			break;
+		}
+
+		if (pd->pos == 0) {
+			i2c_op(pd, OP_TX_TO_RX, 0);
+			break;
+		}
+
+		real_pos = pd->pos - 2;
+
+		if (pd->pos == pd->msg->len) {
+			if (real_pos < 0) {
+				i2c_op(pd, OP_RX_STOP, 0);
+				break;
+			}
+			data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+		} else
+			data = i2c_op(pd, OP_RX, 0);
+
+		pd->msg->buf[real_pos] = data;
+	} while (0);
+
+	pd->pos++;
+	return pd->pos == (pd->msg->len + 2);
+}
+
 static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
 {
 	struct platform_device *dev = dev_id;
 	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
-	struct i2c_msg *msg = pd->msg;
-	unsigned char data, sr;
-	int wakeup = 0;
+	unsigned char sr;
+	int wakeup;
 
 	sr = ioread8(ICSR(pd));
-	pd->sr |= sr;
+	pd->sr |= sr; /* remember state */
 
 	dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
-	       (msg->flags & I2C_M_RD) ? "read" : "write",
-	       pd->pos, msg->len);
+	       (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+	       pd->pos, pd->msg->len);
 
 	if (sr & (ICSR_AL | ICSR_TACK)) {
-		iowrite8(0, ICIC(pd)); /* disable interrupts */
-		wakeup = 1;
-		goto do_wakeup;
-	}
+		/* don't interrupt transaction - continue to issue stop */
+		iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd));
+		wakeup = 0;
+	} else if (pd->msg->flags & I2C_M_RD)
+		wakeup = sh_mobile_i2c_isr_rx(pd);
+	else
+		wakeup = sh_mobile_i2c_isr_tx(pd);
 
-	if (pd->pos == msg->len) {
-		i2c_op(pd, OP_RX_ONLY, 0);
-		wakeup = 1;
-		goto do_wakeup;
-	}
+	if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+		iowrite8(sr & ~ICSR_WAIT, ICSR(pd));
 
-	if (pd->pos == -1) {
-		data = (msg->addr & 0x7f) << 1;
-		data |= (msg->flags & I2C_M_RD) ? 1 : 0;
-	} else
-		data = msg->buf[pd->pos];
-
-	if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
-		if (msg->flags & I2C_M_RD)
-			i2c_op(pd, OP_TX_TO_RX, data);
-		else if (pd->pos == (msg->len - 1)) {
-			i2c_op(pd, OP_TX_STOP, data);
-			wakeup = 1;
-		} else
-			i2c_op(pd, OP_TX_ONLY, data);
-	} else {
-		if (pd->pos == (msg->len - 1))
-			data = i2c_op(pd, OP_RX_STOP, 0);
-		else
-			data = i2c_op(pd, OP_RX_ONLY, 0);
-
-		msg->buf[pd->pos] = data;
-	}
-	pd->pos++;
-
- do_wakeup:
 	if (wakeup) {
 		pd->sr |= SW_DONE;
 		wake_up(&pd->wait);
@@ -219,6 +361,11 @@
 
 static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
 {
+	if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
+		dev_err(pd->dev, "Unsupported zero length i2c read\n");
+		return -EIO;
+	}
+
 	/* Initialize channel registers */
 	iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
 
@@ -233,9 +380,8 @@
 	pd->pos = -1;
 	pd->sr = 0;
 
-	/* Enable all interrupts except wait */
-	iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE,
-		 ICIC(pd));
+	/* Enable all interrupts to begin with */
+	iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd));
 	return 0;
 }
 
@@ -268,25 +414,18 @@
 		if (!k)
 			dev_err(pd->dev, "Transfer request timed out\n");
 
-		retry_count = 10;
+		retry_count = 1000;
 again:
 		val = ioread8(ICSR(pd));
 
 		dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
 
-		if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
-			err = -EIO;
-			break;
-		}
-
 		/* the interrupt handler may wake us up before the
 		 * transfer is finished, so poll the hardware
 		 * until we're done.
 		 */
-
-		if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) &&
-		      (val & ICSR_SDAM))) {
-			msleep(1);
+		if (val & ICSR_BUSY) {
+			udelay(10);
 			if (retry_count--)
 				goto again;
 
@@ -294,6 +433,12 @@
 			dev_err(pd->dev, "Polling timed out\n");
 			break;
 		}
+
+		/* handle missing acknowledge and arbitration lost */
+		if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+			err = -EIO;
+			break;
+		}
 	}
 
 	deactivate_ch(pd);
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2ec921b..18f4d7f 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -63,7 +63,7 @@
 }
 
 /* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
 	/* MacbookAir1.1 */
 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -105,7 +105,7 @@
 
 /* trackpad finger structure */
 struct tp_finger {
-	__le16 origin;		/* left/right origin? */
+	__le16 origin;		/* zero when switching track finger */
 	__le16 abs_x;		/* absolute x coodinate */
 	__le16 abs_y;		/* absolute y coodinate */
 	__le16 rel_x;		/* relative x coodinate */
@@ -159,6 +159,7 @@
 	struct bt_data *bt_data;	/* button transferred data */
 	struct urb *tp_urb;		/* trackpad usb request block */
 	struct tp_data *tp_data;	/* trackpad transferred data */
+	int fingers;			/* number of fingers on trackpad */
 };
 
 /* logical dimensions */
@@ -172,6 +173,10 @@
 #define SN_WIDTH	100		/* width signal-to-noise ratio */
 #define SN_COORD	250		/* coordinate signal-to-noise ratio */
 
+/* pressure thresholds */
+#define PRESSURE_LOW	(2 * DIM_PRESSURE / SN_PRESSURE)
+#define PRESSURE_HIGH	(3 * PRESSURE_LOW)
+
 /* device constants */
 static const struct bcm5974_config bcm5974_config_table[] = {
 	{
@@ -248,6 +253,7 @@
 				0, cfg->y.dim, cfg->y.fuzz, 0);
 
 	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 	__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
 	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
@@ -273,32 +279,66 @@
 	const struct tp_finger *f = dev->tp_data->finger;
 	struct input_dev *input = dev->input;
 	const int fingers = (size - 26) / 28;
-	int p = 0, w, x, y, n = 0;
+	int raw_p, raw_w, raw_x, raw_y;
+	int ptest = 0, origin = 0, nmin = 0, nmax = 0;
+	int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
 
 	if (size < 26 || (size - 26) % 28 != 0)
 		return -EIO;
 
+	/* always track the first finger; when detached, start over */
 	if (fingers) {
-		p = raw2int(f->force_major);
-		w = raw2int(f->size_major);
-		x = raw2int(f->abs_x);
-		y = raw2int(f->abs_y);
-		n = p > 0 ? fingers : 0;
+		raw_p = raw2int(f->force_major);
+		raw_w = raw2int(f->size_major);
+		raw_x = raw2int(f->abs_x);
+		raw_y = raw2int(f->abs_y);
 
 		dprintk(9,
-			"bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
-			p, w, x, y, n);
+			"bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
+			raw_p, raw_w, raw_x, raw_y);
 
-		input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
-		input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
-		input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
+		ptest = int2bound(&c->p, raw_p);
+		origin = raw2int(f->origin);
 	}
 
-	input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+	/* while tracking finger still valid, count all fingers */
+	if (ptest > PRESSURE_LOW && origin) {
+		abs_p = ptest;
+		abs_w = int2bound(&c->w, raw_w);
+		abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+		abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+		for (; f != dev->tp_data->finger + fingers; f++) {
+			ptest = int2bound(&c->p, raw2int(f->force_major));
+			if (ptest > PRESSURE_LOW)
+				nmax++;
+			if (ptest > PRESSURE_HIGH)
+				nmin++;
+		}
+	}
 
-	input_report_key(input, BTN_TOOL_FINGER, n == 1);
-	input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
-	input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+	if (dev->fingers < nmin)
+		dev->fingers = nmin;
+	if (dev->fingers > nmax)
+		dev->fingers = nmax;
+
+	input_report_key(input, BTN_TOUCH, dev->fingers > 0);
+	input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
+	input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
+	input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
+
+	input_report_abs(input, ABS_PRESSURE, abs_p);
+	input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+
+	if (abs_p) {
+		input_report_abs(input, ABS_X, abs_x);
+		input_report_abs(input, ABS_Y, abs_y);
+
+		dprintk(8,
+			"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
+			"nmin: %d nmax: %d n: %d\n",
+			abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
+
+	}
 
 	input_sync(input);
 
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 3282b74..5aafe24 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -305,7 +305,7 @@
 		.ident = "Lenovo 3000 n100",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
 		},
 	},
 	{
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e8bc7ab..99be9e5 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1068,7 +1068,7 @@
 	{
 		v4l2_std_id *id = arg;
 		int found = 0;
-		int i, err;
+		int i;
 
 		DEB_EE(("VIDIOC_S_STD\n"));
 
@@ -1116,7 +1116,6 @@
 	case VIDIOC_OVERLAY:
 	{
 		int on = *(int *)arg;
-		int err = 0;
 
 		DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
 		if (on != 0) {
@@ -1192,7 +1191,6 @@
 	case VIDIOCGMBUF:
 	{
 		struct video_mbuf *mbuf = arg;
-		struct videobuf_queue *q;
 		int i;
 
 		/* fixme: number of capture buffers and sizes for v4l apps */
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c
index e254bcf..e8d3c48 100644
--- a/drivers/media/common/tuners/mt2131.c
+++ b/drivers/media/common/tuners/mt2131.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h
index cd8376f..6632de6 100644
--- a/drivers/media/common/tuners/mt2131.h
+++ b/drivers/media/common/tuners/mt2131.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
index e930759..4e05a67 100644
--- a/drivers/media/common/tuners/mt2131_priv.h
+++ b/drivers/media/common/tuners/mt2131_priv.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 0dc2bef..227642b 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -2,7 +2,7 @@
     MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
 
     Copyright (C) 2008 MaxLinear
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
       Functions:
 	mxl5005s_reset()
 	mxl5005s_writereg()
@@ -3837,7 +3837,7 @@
 /* ----------------------------------------------------------------
  * Begin: Everything after here is new code to adapt the
  * proprietary Realtek driver into a Linux API tuner.
- * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
  */
 static int mxl5005s_reset(struct dvb_frontend *fe)
 {
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
index 396db15..7ac6815 100644
--- a/drivers/media/common/tuners/mxl5005s.h
+++ b/drivers/media/common/tuners/mxl5005s.h
@@ -2,7 +2,7 @@
     MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
 
     Copyright (C) 2008 MaxLinear
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 597e47f..aa773a6 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -253,7 +253,7 @@
 
 static int simple_config_lookup(struct dvb_frontend *fe,
 				struct tuner_params *t_params,
-				int *frequency, u8 *config, u8 *cb)
+				unsigned *frequency, u8 *config, u8 *cb)
 {
 	struct tuner_simple_priv *priv = fe->tuner_priv;
 	int i;
@@ -587,45 +587,45 @@
 	priv->last_div = div;
 	if (t_params->has_tda9887) {
 		struct v4l2_priv_tun_config tda9887_cfg;
-		int config = 0;
+		int tda_config = 0;
 		int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
 						 V4L2_STD_SECAM_LC)) &&
 			!(params->std & ~(V4L2_STD_SECAM_L |
 					  V4L2_STD_SECAM_LC));
 
 		tda9887_cfg.tuner = TUNER_TDA9887;
-		tda9887_cfg.priv  = &config;
+		tda9887_cfg.priv  = &tda_config;
 
 		if (params->std == V4L2_STD_SECAM_LC) {
 			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
-				config |= TDA9887_PORT1_ACTIVE;
+				tda_config |= TDA9887_PORT1_ACTIVE;
 			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
-				config |= TDA9887_PORT2_ACTIVE;
+				tda_config |= TDA9887_PORT2_ACTIVE;
 		} else {
 			if (t_params->port1_active)
-				config |= TDA9887_PORT1_ACTIVE;
+				tda_config |= TDA9887_PORT1_ACTIVE;
 			if (t_params->port2_active)
-				config |= TDA9887_PORT2_ACTIVE;
+				tda_config |= TDA9887_PORT2_ACTIVE;
 		}
 		if (t_params->intercarrier_mode)
-			config |= TDA9887_INTERCARRIER;
+			tda_config |= TDA9887_INTERCARRIER;
 		if (is_secam_l) {
 			if (i == 0 && t_params->default_top_secam_low)
-				config |= TDA9887_TOP(t_params->default_top_secam_low);
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
 			else if (i == 1 && t_params->default_top_secam_mid)
-				config |= TDA9887_TOP(t_params->default_top_secam_mid);
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
 			else if (t_params->default_top_secam_high)
-				config |= TDA9887_TOP(t_params->default_top_secam_high);
+				tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
 		} else {
 			if (i == 0 && t_params->default_top_low)
-				config |= TDA9887_TOP(t_params->default_top_low);
+				tda_config |= TDA9887_TOP(t_params->default_top_low);
 			else if (i == 1 && t_params->default_top_mid)
-				config |= TDA9887_TOP(t_params->default_top_mid);
+				tda_config |= TDA9887_TOP(t_params->default_top_mid);
 			else if (t_params->default_top_high)
-				config |= TDA9887_TOP(t_params->default_top_high);
+				tda_config |= TDA9887_TOP(t_params->default_top_high);
 		}
 		if (t_params->default_pll_gating_18)
-			config |= TDA9887_GATING_18;
+			tda_config |= TDA9887_GATING_18;
 		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
 				    &tda9887_cfg);
 	}
@@ -813,7 +813,8 @@
 	static struct tuner_params *t_params;
 	u8 config, cb;
 	u32 div;
-	int ret, frequency = params->frequency / 62500;
+	int ret;
+	unsigned frequency = params->frequency / 62500;
 
 	t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
 	ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 5f99de0..dcddfa8 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -2,7 +2,7 @@
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
  *  Copyright (c) 2007 Xceive Corporation
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index c910715..5389f74 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index a72a988..b2a0074 100644
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index f9d0876..4eed783 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -137,7 +137,8 @@
 			flexcop_diseqc_send_byte(fe, 0xff);
 		else {
 			flexcop_set_tone(fe, SEC_TONE_ON);
-			udelay(12500);
+			mdelay(12);
+			udelay(500);
 			flexcop_set_tone(fe, SEC_TONE_OFF);
 		}
 		msleep(20);
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 55973ea..43a112e 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -221,12 +221,12 @@
 	fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
 	fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
 
-	strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
-		"B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
-	strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
-		"B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
-	strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
-		"B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+	strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+		sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+	strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+		sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+	strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+		sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
 
 	i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
 	i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index a763756..aa3db57 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1244,7 +1244,7 @@
 		goto error;
 	}
 	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		udelay(3000);
+		mdelay(3);
 	if (read_dst(state, &reply, GET_ACK)) {
 		dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
 		if ((dst_error_recovery(state)) < 0) {
@@ -1260,7 +1260,7 @@
 	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
 		goto error;
 	if (state->type_flags & DST_TYPE_HAS_FW_1)
-		udelay(3000);
+		mdelay(3);
 	else
 		udelay(2000);
 	if (!dst_wait_dst_ready(state, NO_DELAY))
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 1cf9fcb..069d847 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -641,7 +641,6 @@
 		struct timespec timeout = { 0 };
 		struct dmx_pes_filter_params *para = &filter->params.pes;
 		dmx_output_t otype;
-		int ret;
 		int ts_type;
 		enum dmx_ts_pes ts_pes;
 		struct dmx_ts_feed **tsfeed = &filter->feed.ts;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 8e5dd7b..98ee167 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1032,7 +1032,7 @@
 					/* we need this extra check for annoying interfaces like the budget-av */
 					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
 					    (ca->pub->poll_slot_status)) {
-						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
 						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
 							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
 							dvb_ca_en50221_thread_update_delay(ca);
@@ -1089,7 +1089,7 @@
 					/* we need this extra check for annoying interfaces like the budget-av */
 					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
 					    (ca->pub->poll_slot_status)) {
-						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						status = ca->pub->poll_slot_status(ca->pub, slot, 0);
 						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
 							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
 							dvb_ca_en50221_thread_update_delay(ca);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 8cbdb21..3526e3e 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -889,13 +889,13 @@
 			 * initialization, so parg is 8 bits and does not
 			 * include the initialization or start bit
 			 */
-			unsigned long cmd = ((unsigned long) parg) << 1;
+			unsigned long swcmd = ((unsigned long) parg) << 1;
 			struct timeval nexttime;
 			struct timeval tv[10];
 			int i;
 			u8 last = 1;
 			if (dvb_frontend_debug)
-				printk("%s switch command: 0x%04lx\n", __func__, cmd);
+				printk("%s switch command: 0x%04lx\n", __func__, swcmd);
 			do_gettimeofday(&nexttime);
 			if (dvb_frontend_debug)
 				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -908,12 +908,12 @@
 			for (i = 0; i < 9; i++) {
 				if (dvb_frontend_debug)
 					do_gettimeofday(&tv[i + 1]);
-				if ((cmd & 0x01) != last) {
+				if ((swcmd & 0x01) != last) {
 					/* set voltage to (last ? 13V : 18V) */
 					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
 					last = (last) ? 0 : 1;
 				}
-				cmd = cmd >> 1;
+				swcmd = swcmd >> 1;
 				if (i != 8)
 					dvb_frontend_sleep_until(&nexttime, 8000);
 			}
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index aaa0b6f..5634002 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -210,7 +210,7 @@
 	if (d->state == DVB_USB_STATE_INIT &&
 	    usb_set_interface(d->udev, 0, 0) < 0)
 		err("set interface failed");
-	do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+	do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
 		   !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
 		   !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
 	if (!ret) {
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 3dd20bf..6c0e5c5 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1117,7 +1117,8 @@
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
 	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_CINERGY_T_XXS) },
 	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
-	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
 	{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1373,7 +1374,7 @@
 			}
 		},
 
-		.num_device_descs = 3,
+		.num_device_descs = 4,
 		.devices = {
 			{   "DiBcom STK7070PD reference design",
 				{ &dib0700_usb_id_table[17], NULL },
@@ -1386,6 +1387,10 @@
 			{   "Hauppauge Nova-TD Stick (52009)",
 				{ &dib0700_usb_id_table[35], NULL },
 				{ NULL },
+			},
+			{   "Hauppauge Nova-TD-500 (84xxx)",
+				{ &dib0700_usb_id_table[36], NULL },
+				{ NULL },
 			}
 		}
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 029b437..03dfb9f 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -129,6 +129,7 @@
 #define USB_PID_WINTV_NOVA_T_USB2_WARM			0x9301
 #define USB_PID_HAUPPAUGE_NOVA_T_500			0x9941
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3			0x8400
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index f7b7165..0b82cc2 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -1,7 +1,7 @@
 /*
     Auvitek AU8522 QAM/8VSB demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -304,6 +304,43 @@
 	return ret;
 }
 
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	u8 r0b5, r0b6, r0b7;
+	char *ifmhz;
+
+	switch (if_freq) {
+	case AU8522_IF_3_25MHZ:
+		ifmhz = "3.25";
+		r0b5 = 0x00;
+		r0b6 = 0x3d;
+		r0b7 = 0xa0;
+		break;
+	case AU8522_IF_4MHZ:
+		ifmhz = "4.00";
+		r0b5 = 0x00;
+		r0b6 = 0x4b;
+		r0b7 = 0xd9;
+		break;
+	case AU8522_IF_6MHZ:
+		ifmhz = "6.00";
+		r0b5 = 0xfb;
+		r0b6 = 0x8e;
+		r0b7 = 0x39;
+		break;
+	default:
+		dprintk("%s() IF Frequency not supported\n", __func__);
+		return -EINVAL;
+	}
+	dprintk("%s() %s MHz\n", __func__, ifmhz);
+	au8522_writereg(state, 0x80b5, r0b5);
+	au8522_writereg(state, 0x80b6, r0b6);
+	au8522_writereg(state, 0x80b7, r0b7);
+
+	return 0;
+}
+
 /* VSB Modulation table */
 static struct {
 	u16 reg;
@@ -334,9 +371,6 @@
 	{ 0x80af, 0x66 },
 	{ 0x821b, 0xcc },
 	{ 0x821d, 0x80 },
-	{ 0x80b5, 0xfb },
-	{ 0x80b6, 0x8e },
-	{ 0x80b7, 0x39 },
 	{ 0x80a4, 0xe8 },
 	{ 0x8231, 0x13 },
 };
@@ -350,9 +384,6 @@
 	{ 0x80a4, 0x00 },
 	{ 0x8081, 0xc4 },
 	{ 0x80a5, 0x40 },
-	{ 0x80b5, 0xfb },
-	{ 0x80b6, 0x8e },
-	{ 0x80b7, 0x39 },
 	{ 0x80aa, 0x77 },
 	{ 0x80ad, 0x77 },
 	{ 0x80a6, 0x67 },
@@ -438,6 +469,7 @@
 			au8522_writereg(state,
 				VSB_mod_tab[i].reg,
 				VSB_mod_tab[i].data);
+		au8522_set_if(fe, state->config->vsb_if);
 		break;
 	case QAM_64:
 	case QAM_256:
@@ -446,6 +478,7 @@
 			au8522_writereg(state,
 				QAM_mod_tab[i].reg,
 				QAM_mod_tab[i].data);
+		au8522_set_if(fe, state->config->qam_if);
 		break;
 	default:
 		dprintk("%s() Invalid modulation\n", __func__);
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
index d7affa3..595915a 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -1,7 +1,7 @@
 /*
     Auvitek AU8522 QAM/8VSB demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -24,6 +24,12 @@
 
 #include <linux/dvb/frontend.h>
 
+enum au8522_if_freq {
+	AU8522_IF_6MHZ = 0,
+	AU8522_IF_4MHZ,
+	AU8522_IF_3_25MHZ,
+};
+
 struct au8522_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
@@ -32,6 +38,9 @@
 #define AU8522_TUNERLOCKING 0
 #define AU8522_DEMODLOCKING 1
 	u8 status_mode;
+
+	enum au8522_if_freq vsb_if;
+	enum au8522_if_freq qam_if;
 };
 
 #if defined(CONFIG_DVB_AU8522) || 				\
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index cc1db4e..9430e03 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -7,7 +7,7 @@
     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
 	  Holger Waechtler <holger@convergence.de>
 
-    Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 8af766a..b1e465c 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -7,7 +7,7 @@
     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
 	  Holger Waechtler <holger@convergence.de>
 
-    Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 7f68d78..7156157 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,7 +1,7 @@
 /*
  *   Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
  *
- *   Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ *   Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
  *
  *   Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
  *
@@ -1072,8 +1072,8 @@
     if (config->dont_use_pll)
 	cx24123_repeater_mode(state, 1, 0);
 
-	strncpy(state->tuner_i2c_adapter.name,
-		"CX24123 tuner I2C bus", I2C_NAME_SIZE);
+	strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+		sizeof(state->tuner_i2c_adapter.name));
 	state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
 	state->tuner_i2c_adapter.algo      = &cx24123_tuner_i2c_algo;
 	state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 81ebc3d..cc6b411 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -1,7 +1,7 @@
 /*
     Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
 
-    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 5ddb2dc..7500a1c 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1409 VSB/QAM demodulator driver
 
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -404,6 +404,7 @@
 		break;
 	case QAM_64:
 	case QAM_256:
+	case QAM_AUTO:
 		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
 		if (state->if_freq != S5H1409_QAM_IF_FREQ)
 			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 59f4335..d1a1d2e 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1409 VSB/QAM demodulator driver
 
-    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index cff360c..2da1a37 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1411 VSB/QAM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -488,6 +488,7 @@
 		break;
 	case QAM_64:
 	case QAM_256:
+	case QAM_AUTO:
 		dprintk("%s() QAM_AUTO (64/256)\n", __func__);
 		s5h1411_set_if_freq(fe, state->config->qam_if);
 		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
index 1855f64..7d542bc 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -1,7 +1,7 @@
 /*
     Samsung S5H1411 VSB/QAM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 720ed9f..747d3fa 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -915,7 +915,8 @@
 	state->frontend.demodulator_priv = state;
 
 	/* create tuner i2c adapter */
-	strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+	strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+		sizeof(state->tuner_i2c_adapter.name));
 	state->tuner_i2c_adapter.class     = I2C_CLASS_TV_DIGITAL,
 	state->tuner_i2c_adapter.algo      = &s5h1420_tuner_i2c_algo;
 	state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 0ab8d86b..04e7f1c 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -303,7 +303,7 @@
 
 	if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
 		printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
-		return -EIO;
+		ret = -EIO;
 	} else {
 		printk(KERN_INFO "%s: firmware uploading\n", __func__);
 
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
index 2b5c78e..0457b24 100644
--- a/drivers/media/dvb/frontends/tda10048.h
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index e7a8ac0..cc5efb6 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -4,7 +4,7 @@
  *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 83b39bc..c8f3da6 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -4,7 +4,7 @@
  *  Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index c5f45fe..6576fbb 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -8,7 +8,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index c1f8f1d..8d973f7 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 229274a..8d490e1 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index c10b184..87a3c24 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -6,7 +6,7 @@
  *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 3 as
+ *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation;
  *
  *  Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 39bd0a2..aa5ed4e 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -116,7 +116,8 @@
 			DiseqcSendByte(budget, 0xff);
 		else {
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-			udelay(12500);
+			mdelay(12);
+			udelay(500);
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 		}
 		msleep(20);
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 2293d80..f006899 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -108,7 +108,8 @@
 			DiseqcSendByte(budget, 0xff);
 		else {
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
-			udelay(12500);
+			mdelay(12);
+			udelay(500);
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 		}
 		msleep(20);
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index a30159f..7ca71ab 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -2,8 +2,6 @@
 # Makefile for the kernel character device drivers.
 #
 
-miropcm20-objs	:= miropcm20-rds-core.o miropcm20-radio.o
-
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -14,8 +12,6 @@
 obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
-obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
-obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 1ed88f3..70c65a7 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -493,7 +493,7 @@
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->curfreq = FREQ_MIN*FREQ_MUL;
 	video_set_drvdata(radio->videodev, radio);
-	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
 		warn("Could not register video device");
 		video_device_release(radio->videodev);
 		kfree(radio->transfer_buffer);
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
deleted file mode 100644
index 7fd7ee2..0000000
--- a/drivers/media/radio/miropcm20-radio.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Miro PCM20 radio driver for Linux radio support
- * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Thanks to Norberto Pellici for the ACI device interface specification
- * The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/aci.c)
- * Look there for further info...
- */
-
-/* Revision history:
- *
- *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
- *        removed unfinished volume control (maybe adding it later again)
- *        use OSS-mixer; added stereo control
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-struct pcm20_device {
-	unsigned long freq;
-	int muted;
-	int stereo;
-};
-
-
-static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
-{
-	dev->muted = mute;
-	return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
-}
-
-static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
-{
-	dev->stereo = stereo;
-	return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
-}
-
-static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
-{
-	unsigned char freql;
-	unsigned char freqh;
-
-	dev->freq=freq;
-
-	freq /= 160;
-	if (!(aci_version==0x07 || aci_version>=0xb0))
-		freq /= 10;  /* I don't know exactly which version
-			      * needs this hack */
-	freql = freq & 0xff;
-	freqh = freq >> 8;
-
-	aci_rds_cmd(RDS_RESET, NULL, 0);
-	pcm20_stereo(dev, 1);
-
-	return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
-}
-
-static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
-{
-	/* okay, check for signal, stereo and rds here... */
-	int i;
-	unsigned char buf;
-
-	if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
-		return i;
-	pr_debug("check_sig: 0x%x\n", i);
-	if (i & 0x80) {
-		/* no signal from tuner */
-		*flags=0;
-		*signal=0;
-		return 0;
-	} else
-		*signal=0xffff;
-
-	if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
-		return i;
-	if (i & 0x40) {
-		*flags=0;
-	} else {
-		/* stereo */
-		*flags=VIDEO_TUNER_STEREO_ON;
-		/* I can't see stereo, when forced to mono */
-		dev->stereo=1;
-	}
-
-	if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
-		return i;
-	if (buf & 1)
-		/* RDS available */
-		*flags|=VIDEO_TUNER_RDS_ON;
-	else
-		return 0;
-
-	if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
-		return i;
-	pr_debug("rds-signal: %d\n", buf);
-	if (buf > 15) {
-		printk("miropcm20-radio: RX strengths unexpected high...\n");
-		buf=15;
-	}
-	/* refine signal */
-	if ((*signal=SCALE(15, 0xffff, buf))==0)
-		*signal = 1;
-
-	return 0;
-}
-
-static int pcm20_do_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, void *arg)
-{
-	struct video_device *dev = video_devdata(file);
-	struct pcm20_device *pcm20 = dev->priv;
-	int i;
-
-	switch(cmd)
-	{
-		case VIDIOCGCAP:
-		{
-			struct video_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			strcpy(v->name, "Miro PCM20");
-			v->channels=1;
-			v->audios=1;
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
-				return -EINVAL;
-			v->rangelow=87*16000;
-			v->rangehigh=108*16000;
-			pcm20_getflags(pcm20, &v->flags, &v->signal);
-			v->flags|=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			strcpy(v->name, "FM");
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
-				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
-			return 0;
-		}
-		case VIDIOCGFREQ:
-		{
-			unsigned long *freq = arg;
-			*freq = pcm20->freq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			pcm20->freq = *freq;
-			i=pcm20_setfreq(pcm20, pcm20->freq);
-			pr_debug("First view (setfreq): 0x%x\n", i);
-			return i;
-		}
-		case VIDIOCGAUDIO:
-		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags=VIDEO_AUDIO_MUTABLE;
-			if (pcm20->muted)
-				v->flags|=VIDEO_AUDIO_MUTE;
-			v->mode=VIDEO_SOUND_STEREO;
-			if (pcm20->stereo)
-				v->mode|=VIDEO_SOUND_MONO;
-			/* v->step=2048; */
-			strcpy(v->name, "Radio");
-			return 0;
-		}
-		case VIDIOCSAUDIO:
-		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-
-			pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
-			if(v->flags&VIDEO_SOUND_MONO)
-				pcm20_stereo(pcm20, 0);
-			if(v->flags&VIDEO_SOUND_STEREO)
-				pcm20_stereo(pcm20, 1);
-
-			return 0;
-		}
-		default:
-			return -ENOIOCTLCMD;
-	}
-}
-
-static int pcm20_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl);
-}
-
-static struct pcm20_device pcm20_unit = {
-	.freq   = 87*16000,
-	.muted  = 1,
-};
-
-static const struct file_operations pcm20_fops = {
-	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
-	.ioctl		= pcm20_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= v4l_compat_ioctl32,
-#endif
-	.llseek         = no_llseek,
-};
-
-static struct video_device pcm20_radio = {
-	.name		= "Miro PCM 20 radio",
-	.fops           = &pcm20_fops,
-	.priv		= &pcm20_unit
-};
-
-static int __init pcm20_init(void)
-{
-	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-		goto video_register_device;
-
-	if(attach_aci_rds()<0)
-		goto attach_aci_rds;
-
-	printk(KERN_INFO "Miro PCM20 radio card driver.\n");
-
-	return 0;
-
- attach_aci_rds:
-	video_unregister_device(&pcm20_radio);
- video_register_device:
-	return -EINVAL;
-}
-
-MODULE_AUTHOR("Ruurd Reitsma");
-MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
-MODULE_LICENSE("GPL");
-
-static void __exit pcm20_cleanup(void)
-{
-	unload_aci_rds();
-	video_unregister_device(&pcm20_radio);
-}
-
-module_init(pcm20_init);
-module_exit(pcm20_cleanup);
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
deleted file mode 100644
index 9428d8b..0000000
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- *  Many thanks to Fred Seidel <seidel@metabox.de>, the
- *  designer of the RDS decoder hardware. With his help
- *  I was able to code this driver.
- *  Thanks also to Norberto Pellicci, Dominic Mounteney
- *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
- *  for good hints on finding Fred. It was somewhat hard
- *  to locate him here in Germany... [:
- *
- * Revision history:
- *
- *   2000-08-09  Robert Siemer <Robert.Siemer@gmx.de>
- *        RDS support for MiroSound PCM20 radio
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-#define DEBUG 0
-
-static struct mutex aci_rds_mutex;
-
-#define RDS_DATASHIFT          2   /* Bit 2 */
-#define RDS_DATAMASK        (1 << RDS_DATASHIFT)
-#define RDS_BUSYMASK        0x10   /* Bit 4 */
-#define RDS_CLOCKMASK       0x08   /* Bit 3 */
-
-#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
-
-
-#if DEBUG
-static void print_matrix(char array[], unsigned int length)
-{
-	int i, j;
-
-	for (i=0; i<length; i++) {
-		printk(KERN_DEBUG "aci-rds: ");
-		for (j=7; j>=0; j--) {
-			printk("%d", (array[i] >> j) & 0x1);
-		}
-		if (i%8 == 0)
-			printk(" byte-border\n");
-		else
-			printk("\n");
-	}
-}
-#endif /* DEBUG */
-
-static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
-{
-	int i;
-
-	if (size != 8)
-		return -1;
-	for (i = 7; i >= 0; i--)
-		sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
-	sendbuffer[0] |= RDS_CLOCKMASK;
-
-	return 0;
-}
-
-static int rds_waitread(void)
-{
-	unsigned char byte;
-	int i=2000;
-
-	do {
-		byte=inb(RDS_REGISTER);
-		i--;
-	}
-	while ((byte & RDS_BUSYMASK) && i);
-
-	if (i) {
-		#if DEBUG
-		printk(KERN_DEBUG "rds_waitread()");
-		print_matrix(&byte, 1);
-		#endif
-		return (byte);
-	} else {
-		printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
-		return -1;
-	}
-}
-
-/* don't use any ..._nowait() function if you are not sure what you do... */
-
-static inline void rds_rawwrite_nowait(unsigned char byte)
-{
-	#if DEBUG
-	printk(KERN_DEBUG "rds_rawwrite()");
-	print_matrix(&byte, 1);
-	#endif
-	outb(byte, RDS_REGISTER);
-}
-
-static int rds_rawwrite(unsigned char byte)
-{
-	if (rds_waitread() >= 0) {
-		rds_rawwrite_nowait(byte);
-		return 0;
-	} else
-		return -1;
-}
-
-static int rds_write(unsigned char cmd)
-{
-	unsigned char sendbuffer[8];
-	int i;
-
-	if (byte2trans(cmd, sendbuffer, 8) != 0){
-		return -1;
-	} else {
-		for (i=0; i<8; i++) {
-			rds_rawwrite(sendbuffer[i]);
-		}
-	}
-	return 0;
-}
-
-static int rds_readcycle_nowait(void)
-{
-	rds_rawwrite_nowait(0);
-	return rds_waitread();
-}
-
-static int rds_readcycle(void)
-{
-	if (rds_rawwrite(0) < 0)
-		return -1;
-	return rds_waitread();
-}
-
-static int rds_read(unsigned char databuffer[], int datasize)
-{
-	#define READSIZE (8*datasize)
-
-	int i,j;
-
-	if (datasize < 1)  /* nothing to read */
-		return 0;
-
-	/* to be able to use rds_readcycle_nowait()
-	   I have to waitread() here */
-	if (rds_waitread() < 0)
-		return -1;
-
-	memset(databuffer, 0, datasize);
-
-	for (i=0; i< READSIZE; i++)
-		if((j=rds_readcycle_nowait()) < 0) {
-			return -1;
-		} else {
-			databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
-		}
-
-	return 0;
-}
-
-static int rds_ack(void)
-{
-	int i=rds_readcycle();
-
-	if (i < 0)
-		return -1;
-	if (i & RDS_DATAMASK) {
-		return 0;  /* ACK  */
-	} else {
-		printk(KERN_DEBUG "aci-rds: NACK\n");
-		return 1;  /* NACK */
-	}
-}
-
-int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
-{
-	int ret;
-
-	if (mutex_lock_interruptible(&aci_rds_mutex))
-		return -EINTR;
-
-	rds_write(cmd);
-
-	/* RDS_RESET doesn't need further processing */
-	if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
-		ret = -1;
-	else
-		ret = 0;
-
-	mutex_unlock(&aci_rds_mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(aci_rds_cmd);
-
-int __init attach_aci_rds(void)
-{
-	mutex_init(&aci_rds_mutex);
-	return 0;
-}
-
-void __exit unload_aci_rds(void)
-{
-}
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/miropcm20-rds-core.h b/drivers/media/radio/miropcm20-rds-core.h
deleted file mode 100644
index aeb5761..0000000
--- a/drivers/media/radio/miropcm20-rds-core.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _MIROPCM20_RDS_CORE_H_
-#define _MIROPCM20_RDS_CORE_H_
-
-extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
-
-#define RDS_STATUS      0x01
-#define RDS_STATIONNAME 0x02
-#define RDS_TEXT        0x03
-#define RDS_ALTFREQ     0x04
-#define RDS_TIMEDATE    0x05
-#define RDS_PI_CODE     0x06
-#define RDS_PTYTATP     0x07
-#define RDS_RESET       0x08
-#define RDS_RXVALUE     0x09
-
-extern void __exit unload_aci_rds(void);
-extern int __init attach_aci_rds(void);
-
-#endif /* _MIROPCM20_RDS_CORE_H_ */
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
deleted file mode 100644
index 3e840f7..0000000
--- a/drivers/media/radio/miropcm20-rds.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* MiroSOUND PCM20 radio rds interface driver
- * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
- * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information.
- */
-
-/* Revision history:
- *
- *   2001-04-18  Robert Siemer <Robert.Siemer@gmx.de>
- *        separate file for user interface driver
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include "miropcm20-rds-core.h"
-
-static char * text_buffer;
-static int rds_users;
-
-
-static int rds_f_open(struct inode *in, struct file *fi)
-{
-	if (rds_users)
-		return -EBUSY;
-
-	lock_kernel();
-	rds_users++;
-	if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) {
-		rds_users--;
-		printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n");
-		unlock_kernel();
-		return -ENOMEM;
-	}
-
-	unlock_kernel();
-	return 0;
-}
-
-static int rds_f_release(struct inode *in, struct file *fi)
-{
-	kfree(text_buffer);
-
-	rds_users--;
-	return 0;
-}
-
-static void print_matrix(char *ch, char out[])
-{
-	int j;
-
-	for (j=7; j>=0; j--) {
-		 out[7-j] = ((*ch >> j) & 0x1) + '0';
-	}
-}
-
-static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
-{
-//	i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset);
-
-	char c;
-	char bits[8];
-
-	msleep(2000);
-	aci_rds_cmd(RDS_STATUS, &c, 1);
-	print_matrix(&c, bits);
-	if (copy_to_user(buffer, bits, 8))
-		return -EFAULT;
-
-/*	if ((c >> 3) & 1) {
-		aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8);
-		text_buffer[0]  = ' ' ;
-		text_buffer[9]  = '\n';
-		return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18;
-	}
-*/
-/*	if ((c >> 6) & 1) {
-		aci_rds_cmd(RDS_PTYTATP, &c, 1);
-		if ( c & 1)
-			sprintf(text_buffer, " M");
-		else
-			sprintf(text_buffer, " S");
-		if ((c >> 1) & 1)
-			sprintf(text_buffer+2, " TA");
-		else
-			sprintf(text_buffer+2, " --");
-		if ((c >> 7) & 1)
-			sprintf(text_buffer+5, " TP");
-		else
-			sprintf(text_buffer+5, " --");
-		sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f);
-		return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20;
-	}
-*/
-
-	if ((c >> 4) & 1) {
-		aci_rds_cmd(RDS_TEXT, text_buffer, 65);
-		text_buffer[0]  = ' ' ;
-		text_buffer[65] = '\n';
-		return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8;
-	} else {
-		put_user('\n', buffer+8);
-		return 9;
-	}
-}
-
-static const struct file_operations rds_fops = {
-	.owner		= THIS_MODULE,
-	.read		= rds_f_read,
-	.open		= rds_f_open,
-	.release	= rds_f_release
-};
-
-static struct miscdevice rds_miscdev = {
-	.minor		= MISC_DYNAMIC_MINOR,
-	.name		= "radiotext",
-	.fops		= &rds_fops,
-};
-
-static int __init miropcm20_rds_init(void)
-{
-	return misc_register(&rds_miscdev);
-}
-
-static void __exit miropcm20_rds_cleanup(void)
-{
-	misc_deregister(&rds_miscdev);
-}
-
-module_init(miropcm20_rds_init);
-module_exit(miropcm20_rds_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index eba9209..1f064f4 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -426,8 +426,7 @@
 
 	rtrack_radio.priv=&rtrack_unit;
 
-	if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 3fe5504..628c689 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -394,8 +394,7 @@
 	mutex_init(&lock);
 	aztech_radio.priv=&aztech_unit;
 
-	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io,2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 6166e72..04c3698 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -682,7 +682,7 @@
 	}
 	if (!request_region(io,2,"cadet"))
 		goto fail;
-	if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
+	if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io,2);
 		goto fail;
 	}
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 36e754e..5cd7f03 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -425,7 +425,7 @@
 	}
 	*devradio = vdev_template;
 
-	if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
+	if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) {
 		kfree( devradio );
 		goto err_video;
 	}
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 2b1a622..0a0f956 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -612,8 +612,7 @@
 
 	gemtek_radio.priv = &gemtek_unit;
 
-	if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
-		radio_nr) == -1) {
+	if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 1);
 		return -EBUSY;
 	}
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 0ada1c6..9ef0a76 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -409,8 +409,7 @@
 	video_set_drvdata(maestro_radio_inst, radio_unit);
 	pci_set_drvdata(pdev, maestro_radio_inst);
 
-	retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO,
-		radio_nr);
+	retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr);
 	if (retval) {
 		printk(KERN_ERR "can't register video device!\n");
 		goto errfr1;
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 43c7549..0cc6fcb 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -156,28 +156,28 @@
 {
 	unsigned long int si;
 	int bl;
-	int data = FREQ2BITS(freq);
+	int val = FREQ2BITS(freq);
 
 	/* TEA5757 shift register bits (see pdf) */
 
-	outbit(0,io); // 24  search
-	outbit(1,io); // 23  search up/down
+	outbit(0, io); /* 24  search */
+	outbit(1, io); /* 23  search up/down */
 
-	outbit(0,io); // 22  stereo/mono
+	outbit(0, io); /* 22  stereo/mono */
 
-	outbit(0,io); // 21  band
-	outbit(0,io); // 20  band (only 00=FM works I think)
+	outbit(0, io); /* 21  band */
+	outbit(0, io); /* 20  band (only 00=FM works I think) */
 
-	outbit(0,io); // 19  port ?
-	outbit(0,io); // 18  port ?
+	outbit(0, io); /* 19  port ? */
+	outbit(0, io); /* 18  port ? */
 
-	outbit(0,io); // 17  search level
-	outbit(0,io); // 16  search level
+	outbit(0, io); /* 17  search level */
+	outbit(0, io); /* 16  search level */
 
 	si = 0x8000;
-	for (bl = 1; bl <= 16 ; bl++) {
-		outbit(data & si,io);
-		si >>=1;
+	for (bl = 1; bl <= 16; bl++) {
+		outbit(val & si, io);
+		si >>= 1;
 	}
 
 	dprintk(1, "Radio freq set to %d.%02d MHz\n",
@@ -410,7 +410,7 @@
 	mutex_init(&radio_unit.lock);
 	maxiradio_radio.priv = &radio_unit;
 
-	if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
+	if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		printk("radio-maxiradio: can't register device!");
 		goto err_out_free_region;
 	}
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index e2dde08..6d820e2 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -332,8 +332,7 @@
 	rtrack2_radio.priv=&rtrack2_unit;
 
 	spin_lock_init(&lock);
-	if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 4);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index bb5d92f..0d478f5 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -377,7 +377,7 @@
 
 	mutex_init(&lock);
 
-	if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
+	if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index a4984ff..16c7ef2 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -1694,8 +1694,8 @@
 	INIT_DELAYED_WORK(&radio->work, si470x_work);
 
 	/* register video device */
-	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
-		retval = -EIO;
+	retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+	if (retval) {
 		printk(KERN_WARNING DRIVER_NAME
 				": Could not register video device\n");
 		goto err_all;
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index cefa44f..0876fec 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -405,8 +405,7 @@
 
 	spin_lock_init(&lock);
 
-	if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io,2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index d70172d..1931619 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -378,8 +378,7 @@
 		printk(KERN_ERR "trust: port 0x%x already in use\n", io);
 		return -EBUSY;
 	}
-	if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 9f17a33..51d57ed 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -446,8 +446,7 @@
 		return -EBUSY;
 	}
 
-	if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1)
-	{
+	if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index bbc6f8b..ef7c8d3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -20,6 +20,8 @@
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
@@ -85,8 +87,6 @@
 obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
 obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index ed9a50f..018f72b 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -7,6 +7,7 @@
 	select DVB_AU8522 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
+	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
 	---help---
 	  This is a video4linux driver for Auvitek's USB device.
 
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 443e590..ed48908 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -38,6 +38,9 @@
 	[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
 		.name	= "DViCO FusionHDTV USB",
 	},
+	[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+		.name = "Hauppauge Woodbury",
+	},
 };
 
 /* Tuner callback function for au0828 boards. Currently only needed
@@ -115,6 +118,7 @@
 	case AU0828_BOARD_HAUPPAUGE_HVR850:
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
 		if (dev->i2c_rc == 0)
 			hauppauge_eeprom(dev, eeprom+0xa0);
 		break;
@@ -134,6 +138,7 @@
 	case AU0828_BOARD_HAUPPAUGE_HVR850:
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
 		/* GPIO's
 		 * 4 - CS5340
 		 * 5 - AU8522 Demodulator
@@ -205,6 +210,8 @@
 		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
 	{ USB_DEVICE(0x2040, 0x7281),
 		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+	{ USB_DEVICE(0x2040, 0x8200),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
 	{ },
 };
 
diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h
index c37f5fd..48a1882 100644
--- a/drivers/media/video/au0828/au0828-cards.h
+++ b/drivers/media/video/au0828/au0828-cards.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,3 +24,4 @@
 #define AU0828_BOARD_HAUPPAUGE_HVR850 	2
 #define AU0828_BOARD_DVICO_FUSIONHDTV7	3
 #define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL	4
+#define AU0828_BOARD_HAUPPAUGE_WOODBURY	5
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
index 54bfc0f..d856de9 100644
--- a/drivers/media/video/au0828/au0828-core.c
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -252,5 +252,5 @@
 module_exit(au0828_exit);
 
 MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 584a83a..ba94be7 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
 #include "au8522.h"
 #include "xc5000.h"
 #include "mxl5007t.h"
+#include "tda18271.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -38,6 +39,15 @@
 static struct au8522_config hauppauge_hvr950q_config = {
 	.demod_address = 0x8e >> 1,
 	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_6MHZ,
+	.vsb_if        = AU8522_IF_6MHZ,
+};
+
+static struct au8522_config hauppauge_woodbury_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+	.qam_if        = AU8522_IF_4MHZ,
+	.vsb_if        = AU8522_IF_3_25MHZ,
 };
 
 static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
@@ -51,6 +61,10 @@
 	.if_freq_hz = MxL_IF_6_MHZ,
 };
 
+static struct tda18271_config hauppauge_woodbury_tunerconfig = {
+	.gate    = TDA18271_GATE_DIGITAL,
+};
+
 /*-------------------------------------------------------------------*/
 static void urb_completion(struct urb *purb)
 {
@@ -357,6 +371,15 @@
 				   &dev->i2c_adap, 0x60,
 				   &mxl5007t_hvr950q_config);
 		break;
+	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_woodbury_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			dvb_attach(tda18271_attach, dvb->frontend,
+				   0x60, &dev->i2c_adap,
+				   &hauppauge_woodbury_tunerconfig);
+		break;
 	default:
 		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
 		       "isn't supported yet\n");
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 741a493..d618fba 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek AU0828 USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
index 3982755..1e87fa0c6 100644
--- a/drivers/media/video/au0828/au0828-reg.h
+++ b/drivers/media/video/au0828/au0828-reg.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 7beb571..4f10ff3 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Auvitek AU0828 USB bridge
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 1c56ae9..6081edc 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3144,8 +3144,9 @@
 
 static void flyvideo_gpio(struct bttv *btv)
 {
-	int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-	int tuner=UNSET,ttype;
+	int gpio, has_remote, has_radio, is_capture_only;
+	int is_lr90, has_tda9820_tda9821;
+	int tuner_type = UNSET, ttype;
 
 	gpio_inout(0xffffff, 0);
 	udelay(8);  /* without this we would see the 0x1800 mask */
@@ -3163,20 +3164,26 @@
 	 * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
 	 * Note: Some bits are Audio_Mask !
 	 */
-	ttype=(gpio&0x0f0000)>>16;
-	switch(ttype) {
-	case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
+	ttype = (gpio & 0x0f0000) >> 16;
+	switch (ttype) {
+	case 0x0:
+		tuner_type = 2;  /* NTSC, e.g. TPI8NSR11P */
 		break;
-	case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+	case 0x2:
+		tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */
 		break;
-	case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+	case 0x4:
+		tuner_type = 5;  /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
 		break;
-	case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
+	case 0x6:
+		tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */
 		break;
-		case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+	case 0xC:
+		tuner_type = 3;  /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
 		break;
 	default:
 		printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+		break;
 	}
 
 	has_remote          =   gpio & 0x800000;
@@ -3189,23 +3196,26 @@
 	/*
 	 * gpio & 0x001000    output bit for audio routing */
 
-	if(is_capture_only)
-		tuner = TUNER_ABSENT; /* No tuner present */
+	if (is_capture_only)
+		tuner_type = TUNER_ABSENT; /* No tuner present */
 
 	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
-	       btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
+		btv->c.nr, has_radio ? "yes" : "no ",
+		has_remote ? "yes" : "no ", tuner_type, gpio);
 	printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
-		btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
-		is_capture_only?"yes":"no ");
+		btv->c.nr, is_lr90 ? "yes" : "no ",
+		has_tda9820_tda9821 ? "yes" : "no ",
+		is_capture_only ? "yes" : "no ");
 
-	if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
-		btv->tuner_type = tuner;
+	if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
+		btv->tuner_type = tuner_type;
 	btv->has_radio = has_radio;
 
 	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
 	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
 	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-	if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+	if (has_tda9820_tda9821)
+		btv->audio_mode_gpio = lt9415_audio;
 	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
 }
 
@@ -3962,7 +3972,7 @@
 
 static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-	int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+	int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
 
 	tuner_make      = (eeprom_data[0x41] & 0x7);
 	tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
@@ -3970,24 +3980,24 @@
 	btv->has_remote = (eeprom_data[0x42] & 0x01);
 
 	if (tuner_make == 0 || tuner_make == 2)
-		if(tuner_format <=0x0a)
-			tuner = tuner_0_table[tuner_format];
+		if (tuner_format <= 0x0a)
+			tuner_type = tuner_0_table[tuner_format];
 	if (tuner_make == 1)
-		if(tuner_format <=9)
-			tuner = tuner_1_table[tuner_format];
+		if (tuner_format <= 9)
+			tuner_type = tuner_1_table[tuner_format];
 
 	if (tuner_make == 4)
-		if(tuner_format == 0x09)
-			tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+		if (tuner_format == 0x09)
+			tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
 
 	printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
-		btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
-	if(tuner) {
-		btv->tuner_type=tuner;
-		printk("%d",tuner);
+		btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
+	if (tuner_type) {
+		btv->tuner_type = tuner_type;
+		printk(KERN_CONT "%d", tuner_type);
 	} else
-		printk("Unknown type");
-	printk(" radio:%s remote control:%s\n",
+		printk(KERN_CONT "Unknown type");
+	printk(KERN_CONT " radio:%s remote control:%s\n",
 	       tuner_tv_fm     ? "yes" : "no",
 	       btv->has_remote ? "yes" : "no");
 }
@@ -4029,7 +4039,8 @@
 
 	gpio_inout(mask,mask);
 	gpio_bits(mask,0);
-	udelay(2500);
+	mdelay(2);
+	udelay(500);
 	gpio_bits(mask,mask);
 
 	if (bttv_gpio)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 85bf31a..6ae4cc8 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -96,7 +96,6 @@
 static unsigned int uv_ratio    = 50;
 static unsigned int full_luma_range;
 static unsigned int coring;
-extern int no_overlay;
 
 /* API features (turn on/off stuff for testing) */
 static unsigned int v4l2        = 1;
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index 649682a..5b1b8e4 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -244,7 +244,8 @@
 		  const struct bttv_format *fmt, struct bttv_overlay *ov,
 		  int skip_even, int skip_odd)
 {
-	int dwords,rc,line,maxy,start,end,skip,nskips;
+	int dwords, rc, line, maxy, start, end;
+	unsigned skip, nskips;
 	struct btcx_skiplist *skips;
 	__le32 *rp;
 	u32 ri,ra;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 08ef54a..b4d940b 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -267,6 +267,11 @@
 int bttv_sub_del_devices(struct bttv_core *core);
 
 /* ---------------------------------------------------------- */
+/* bttv-cards.c                                               */
+
+extern int no_overlay;
+
+/* ---------------------------------------------------------- */
 /* bttv-driver.c                                              */
 
 /* insmod options */
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index f42701f..3324ab3 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -184,12 +184,12 @@
 }
 
 void
-btcx_calc_skips(int line, int width, unsigned int *maxy,
+btcx_calc_skips(int line, int width, int *maxy,
 		struct btcx_skiplist *skips, unsigned int *nskips,
 		const struct v4l2_clip *clips, unsigned int nclips)
 {
 	unsigned int clip,skip;
-	int end,maxline;
+	int end, maxline;
 
 	skip=0;
 	maxline = 9999;
diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h
index 861bc81..f8bc6e8 100644
--- a/drivers/media/video/btcx-risc.h
+++ b/drivers/media/video/btcx-risc.h
@@ -23,7 +23,7 @@
 int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
 	       unsigned int n, int mask);
 void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, unsigned int *maxy,
+void btcx_calc_skips(int line, int width, int *maxy,
 		     struct btcx_skiplist *skips, unsigned int *nskips,
 		     const struct v4l2_clip *clips, unsigned int nclips);
 
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index d3b3268..6e39e25 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -946,8 +946,7 @@
 
 	printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
 
-	if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
-	{
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
 		return -ENODEV;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index fe9379b..7f6c6b4 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -787,8 +787,7 @@
 
 	parport_release(qcam->pdev);
 
-	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
-	{
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
 		       qcam->pport->name);
 		parport_unregister_device(qcam->pdev);
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index dc8cc61..a661800 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3955,7 +3955,7 @@
 	camera->lowlevel_data = lowlevel;
 
 	/* register v4l device */
-	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		kfree(camera);
 		printk(KERN_DEBUG "video_register_device failed\n");
 		return NULL;
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 515c8b5..eb9f15c 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1024,7 +1024,6 @@
 		if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
 		   cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
 			// Maximum 15fps
-			int i;
 			for(i=0; i<c->maximum; ++i) {
 				if(framerate_controls[i].value ==
 				   CPIA2_VP_FRAMERATE_15) {
@@ -1959,8 +1958,7 @@
 	reset_camera_struct_v4l(cam);
 
 	/* register v4l device */
-	if (video_register_device
-	    (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+	if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		ERR("video_register_device failed\n");
 		video_device_release(cam->vdev);
 		return -ENODEV;
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index 834b924..e996a4e 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -32,7 +32,7 @@
 	u32 v;
 	const u8 *ptr;
 	int i;
-	int retries = 0;
+	int retries1 = 0;
 
 	if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
 		CX18_ERR("unable to open firmware %s\n", FWFILE);
@@ -41,7 +41,7 @@
 
 	/* The firmware load often has byte errors, so allow for several
 	   retries, both at byte level and at the firmware load level. */
-	while (retries < 5) {
+	while (retries1 < 5) {
 		cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
 		cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
 
@@ -57,9 +57,9 @@
 		for (i = 0; i < size; i++) {
 			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
 			u32 value = 0;
-			int retries;
+			int retries2;
 
-			for (retries = 0; retries < 5; retries++) {
+			for (retries2 = 0; retries2 < 5; retries2++) {
 				cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
 				udelay(10);
 				value = cx18_av_read4(cx, CXADEC_DL_CTL);
@@ -69,18 +69,18 @@
 				   the address.  We can only write the lower
 				   address byte of the address. */
 				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
-					retries = 5;
+					retries2 = 5;
 					break;
 				}
 			}
-			if (retries >= 5)
+			if (retries2 >= 5)
 				break;
 		}
 		if (i == size)
 			break;
-		retries++;
+		retries1++;
 	}
-	if (retries >= 5) {
+	if (retries1 >= 5) {
 		CX18_ERR("unable to load firmware %s\n", FWFILE);
 		release_firmware(fw);
 		return -EIO;
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 22434aa..bd18afe 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -74,9 +74,9 @@
 				     -1, -1, -1, -1, -1, -1, -1, -1,
 				     -1, -1, -1, -1, -1, -1, -1, -1 };
 
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index cae3898..1e420a8 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -1,7 +1,7 @@
 /*
  *  cx18 functions for DVB support
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
index d6a6ccd..bf8d8f6 100644
--- a/drivers/media/video/cx18/cx18-dvb.h
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -1,7 +1,7 @@
 /*
  *  cx18 functions for DVB support
  *
- *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index 25114a5..ab21831 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -61,7 +61,7 @@
 		CX18_WARN("Ack struct = %d for %s\n",
 			mb->args[2], s->name);
 	id = read_enc(off);
-	buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+	buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
 	CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
 	if (buf) {
 		cx18_buf_sync_for_cpu(s, buf);
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 6990b77..dbe792a 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -78,12 +78,13 @@
 	return buf;
 }
 
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
 	u32 bytesused)
 {
 	struct cx18 *cx = s->cx;
 	struct list_head *p;
 
+	spin_lock(&s->qlock);
 	list_for_each(p, &s->q_free.list) {
 		struct cx18_buffer *buf =
 			list_entry(p, struct cx18_buffer, list);
@@ -92,114 +93,48 @@
 			continue;
 		buf->bytesused = bytesused;
 		/* the transport buffers are handled differently,
-		   so there is no need to move them to the full queue */
-		if (s->type == CX18_ENC_STREAM_TYPE_TS)
-			return buf;
-		s->q_free.buffers--;
-		s->q_free.length -= s->buf_size;
-		s->q_full.buffers++;
-		s->q_full.length += s->buf_size;
-		s->q_full.bytesused += buf->bytesused;
-		list_move_tail(&buf->list, &s->q_full.list);
+		   they are not moved to the full queue */
+		if (s->type != CX18_ENC_STREAM_TYPE_TS) {
+			s->q_free.buffers--;
+			s->q_free.length -= s->buf_size;
+			s->q_full.buffers++;
+			s->q_full.length += s->buf_size;
+			s->q_full.bytesused += buf->bytesused;
+			list_move_tail(&buf->list, &s->q_full.list);
+		}
+		spin_unlock(&s->qlock);
 		return buf;
 	}
+	spin_unlock(&s->qlock);
 	CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
 	return NULL;
 }
 
-static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
-		struct cx18_queue *to, int clear, int full)
-{
-	struct cx18_buffer *buf =
-		list_entry(from->list.next, struct cx18_buffer, list);
-
-	list_move_tail(from->list.next, &to->list);
-	from->buffers--;
-	from->length -= s->buf_size;
-	from->bytesused -= buf->bytesused - buf->readpos;
-	/* special handling for q_free */
-	if (clear)
-		buf->bytesused = buf->readpos = buf->b_flags = 0;
-	else if (full) {
-		/* special handling for stolen buffers, assume
-		   all bytes are used. */
-		buf->bytesused = s->buf_size;
-		buf->readpos = buf->b_flags = 0;
-	}
-	to->buffers++;
-	to->length += s->buf_size;
-	to->bytesused += buf->bytesused - buf->readpos;
-}
-
-/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
-   If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
-   If 'steal' != NULL, then buffers may also taken from that queue if
-   needed.
-
-   The buffer is automatically cleared if it goes to the free queue. It is
-   also cleared if buffers need to be taken from the 'steal' queue and
-   the 'from' queue is the free queue.
-
-   When 'from' is q_free, then needed_bytes is compared to the total
-   available buffer length, otherwise needed_bytes is compared to the
-   bytesused value. For the 'steal' queue the total available buffer
-   length is always used.
-
-   -ENOMEM is returned if the buffers could not be obtained, 0 if all
-   buffers where obtained from the 'from' list and if non-zero then
-   the number of stolen buffers is returned. */
-static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
-			   struct cx18_queue *steal, struct cx18_queue *to,
-			   int needed_bytes)
+/* Move all buffers of a queue to q_free, while flushing the buffers */
+static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
 {
 	unsigned long flags;
-	int rc = 0;
-	int from_free = from == &s->q_free;
-	int to_free = to == &s->q_free;
-	int bytes_available;
+	struct cx18_buffer *buf;
+
+	if (q == &s->q_free)
+		return;
 
 	spin_lock_irqsave(&s->qlock, flags);
-	if (needed_bytes == 0) {
-		from_free = 1;
-		needed_bytes = from->length;
+	while (!list_empty(&q->list)) {
+		buf = list_entry(q->list.next, struct cx18_buffer, list);
+		list_move_tail(q->list.next, &s->q_free.list);
+		buf->bytesused = buf->readpos = buf->b_flags = 0;
+		s->q_free.buffers++;
+		s->q_free.length += s->buf_size;
 	}
-
-	bytes_available = from_free ? from->length : from->bytesused;
-	bytes_available += steal ? steal->length : 0;
-
-	if (bytes_available < needed_bytes) {
-		spin_unlock_irqrestore(&s->qlock, flags);
-		return -ENOMEM;
-	}
-	if (from_free) {
-		u32 old_length = to->length;
-
-		while (to->length - old_length < needed_bytes) {
-			if (list_empty(&from->list))
-				from = steal;
-			if (from == steal)
-				rc++; 	/* keep track of 'stolen' buffers */
-			cx18_queue_move_buf(s, from, to, 1, 0);
-		}
-	} else {
-		u32 old_bytesused = to->bytesused;
-
-		while (to->bytesused - old_bytesused < needed_bytes) {
-			if (list_empty(&from->list))
-				from = steal;
-			if (from == steal)
-				rc++; 	/* keep track of 'stolen' buffers */
-			cx18_queue_move_buf(s, from, to, to_free, rc);
-		}
-	}
+	cx18_queue_init(q);
 	spin_unlock_irqrestore(&s->qlock, flags);
-	return rc;
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
 {
-	cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
-	cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+	cx18_queue_flush(s, &s->q_io);
+	cx18_queue_flush(s, &s->q_full);
 }
 
 int cx18_stream_alloc(struct cx18_stream *s)
@@ -214,10 +149,10 @@
 		s->name, s->buffers, s->buf_size,
 		s->buffers * s->buf_size / 1024);
 
-	if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
-				(char *)cx->scb) > SCB_RESERVED_SIZE) {
-		unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
-					((char *)cx->scb->cpu_mdl));
+	if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+				(char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
+		unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
+					((char __iomem *)cx->scb->cpu_mdl));
 
 		CX18_ERR("Too many buffers, cannot fit in SCB area\n");
 		CX18_ERR("Max buffers = %zd\n",
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 91423b9..7f93bb1 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -46,7 +46,7 @@
 void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
 	struct cx18_queue *q);
 struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
 	u32 bytesused);
 void cx18_flush_queues(struct cx18_stream *s);
 
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 8118091..7b0e8c0 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -4,7 +4,7 @@
  *
  *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
- *    (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *    (c) 2008 Steven Toth <stoth@linuxtv.org>
  *      - CX23885/7/8 support
  *
  *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index a19de85..c36d3f6 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 6286a9c..25fb099 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@
 #include "cx23885.h"
 
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
 static unsigned int debug;
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 0a2e655..291b9d0 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index c6bb0a0..f98e476 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
index bdd11bc..20b68a2 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
index e36e3fc..35e61cd 100644
--- a/drivers/media/video/cx23885/cx23885-vbi.c
+++ b/drivers/media/video/cx23885/cx23885-vbi.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index ad2235d..6047c78 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@
 #endif
 
 MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
 /* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 00dfdc8..e23d97c0 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for the Conexant CX23885 PCIe bridge
  *
- *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 209d3bc..4da8cd7 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -13,7 +13,7 @@
  * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
  * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
  *
- * CX23885 support by Steven Toth <stoth@hauppauge.com>.
+ * CX23885 support by Steven Toth <stoth@linuxtv.org>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 2d170d1..8db2a05 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2588,6 +2588,7 @@
 	cam->v4ldev->fops = &et61x251_fops;
 	cam->v4ldev->minor = video_nr[dev_nr];
 	cam->v4ldev->release = video_device_release;
+	cam->v4ldev->parent = &udev->dev;
 	video_set_drvdata(cam->v4ldev, cam);
 
 	init_completion(&cam->probe);
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index cd3a3f5..4d9f4cc 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -124,7 +124,7 @@
 	struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-	if (len > sizeof gspca_dev->usb_buf) {
+	if (len > USB_BUF_SZ) {
 		err("reg_r: buffer overflow");
 		return;
 	}
@@ -164,7 +164,7 @@
 	struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-	if (len > sizeof gspca_dev->usb_buf) {
+	if (len > USB_BUF_SZ) {
 		err("reg_w: buffer overflow");
 		return;
 	}
@@ -731,13 +731,13 @@
 	reg_w_val(gspca_dev, 0x0000, 0x00);
 	/* wait for completion */
 	retry = 50;
-	while (retry--) {
+	do {
 		reg_r(gspca_dev, 0x0002, 1);
 							/* 0x07 until 0x00 */
 		if (gspca_dev->usb_buf[0] == 0x00)
 			break;
 		reg_w_val(gspca_dev, 0x0053, 0x00);
-	}
+	} while (--retry);
 	if (retry == 0)
 		PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
 	/* send the qtable now */
@@ -826,8 +826,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	cx11646_init1(gspca_dev);
 	cx11646_initsize(gspca_dev);
@@ -845,10 +845,6 @@
 	cx11646_jpeg(gspca_dev);
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
 	int retry = 50;
@@ -871,10 +867,6 @@
 	reg_w_val(gspca_dev, 0x00fc, 0xe0);
 }
 
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -998,11 +990,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
-	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -1026,6 +1016,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index 1dbe92d..4ff0e38 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -81,6 +81,7 @@
 	 .set = sd_setcontrast,
 	 .get = sd_getcontrast,
 	 },
+#define COLOR_IDX 2
 	{
 	 {
 	  .id = V4L2_CID_SATURATION,
@@ -234,7 +235,7 @@
 	struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-	if (len > sizeof gspca_dev->usb_buf) {
+	if (len > USB_BUF_SZ) {
 		err("reg_r: buffer overflow");
 		return;
 	}
@@ -272,7 +273,7 @@
 	struct usb_device *dev = gspca_dev->dev;
 
 #ifdef GSPCA_DEBUG
-	if (len > sizeof gspca_dev->usb_buf) {
+	if (len > USB_BUF_SZ) {
 		err("reg_w: buffer overflow");
 		return;
 	}
@@ -665,6 +666,7 @@
 	} else {
 		cam->cam_mode = vga_mode;
 		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+		gspca_dev->ctrl_dis = (1 << COLOR_IDX);
 	}
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
@@ -674,8 +676,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -709,14 +711,6 @@
 	et_video(gspca_dev, 0);		/* video off */
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -893,21 +887,19 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_ET61X251
 	{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#endif
+#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
 	{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
+#endif
 	{}
 };
 
@@ -926,6 +918,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 15d302b..7be6928 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -114,7 +114,10 @@
 	cam_pkt_op pkt_scan;
 
 	if (urb->status != 0) {
-		PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+#ifdef CONFIG_PM
+		if (!gspca_dev->frozen)
+#endif
+			PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
 		return;		/* disconnection ? */
 	}
 	pkt_scan = gspca_dev->sd_desc->pkt_scan;
@@ -555,10 +558,12 @@
 	gspca_dev->streaming = 0;
 	atomic_set(&gspca_dev->nevent, 0);
 	if (gspca_dev->present) {
-		gspca_dev->sd_desc->stopN(gspca_dev);
+		if (gspca_dev->sd_desc->stopN)
+			gspca_dev->sd_desc->stopN(gspca_dev);
 		destroy_urbs(gspca_dev);
 		gspca_set_alt0(gspca_dev);
-		gspca_dev->sd_desc->stop0(gspca_dev);
+		if (gspca_dev->sd_desc->stop0)
+			gspca_dev->sd_desc->stop0(gspca_dev);
 		PDEBUG(D_STREAM, "stream off OK");
 	}
 }
@@ -767,19 +772,7 @@
 		goto out;
 	}
 
-	/* if not done yet, initialize the sensor */
-	if (gspca_dev->users == 0) {
-		if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
-			ret = -ERESTARTSYS;
-			goto out;
-		}
-		ret = gspca_dev->sd_desc->open(gspca_dev);
-		mutex_unlock(&gspca_dev->usb_lock);
-		if (ret != 0) {
-			PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
-			goto out;
-		}
-	} else if (gspca_dev->users > 4) {	/* (arbitrary value) */
+	if (gspca_dev->users > 4) {	/* (arbitrary value) */
 		ret = -EBUSY;
 		goto out;
 	}
@@ -792,6 +785,7 @@
 	else
 		gspca_dev->vdev.debug &= ~3;
 #endif
+	ret = 0;
 out:
 	mutex_unlock(&gspca_dev->queue_lock);
 	if (ret != 0)
@@ -812,11 +806,11 @@
 
 	/* if the file did the capture, free the streaming resources */
 	if (gspca_dev->capt_file == file) {
-		mutex_lock(&gspca_dev->usb_lock);
-		if (gspca_dev->streaming)
+		if (gspca_dev->streaming) {
+			mutex_lock(&gspca_dev->usb_lock);
 			gspca_stream_off(gspca_dev);
-		gspca_dev->sd_desc->close(gspca_dev);
-		mutex_unlock(&gspca_dev->usb_lock);
+			mutex_unlock(&gspca_dev->usb_lock);
+		}
 		frame_free(gspca_dev);
 		gspca_dev->capt_file = NULL;
 		gspca_dev->memory = GSPCA_MEMORY_NO;
@@ -853,42 +847,44 @@
 	return 0;
 }
 
-/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
 static int vidioc_queryctrl(struct file *file, void *priv,
 			   struct v4l2_queryctrl *q_ctrl)
 {
 	struct gspca_dev *gspca_dev = priv;
-	int i;
+	int i, ix;
 	u32 id;
 
+	ix = -1;
 	id = q_ctrl->id;
 	if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
 		id &= V4L2_CTRL_ID_MASK;
 		id++;
 		for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-			if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-				memcpy(q_ctrl,
-					&gspca_dev->sd_desc->ctrls[i].qctrl,
-					sizeof *q_ctrl);
-				return 0;
+			if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+				continue;
+			if (ix < 0) {
+				ix = i;
+				continue;
 			}
+			if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+				    > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
+				continue;
+			ix = i;
 		}
-		return -EINVAL;
 	}
 	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
 		if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-			memcpy(q_ctrl,
-				&gspca_dev->sd_desc->ctrls[i].qctrl,
-				sizeof *q_ctrl);
-			return 0;
+			ix = i;
+			break;
 		}
 	}
-	if (id >= V4L2_CID_BASE
-	    && id <= V4L2_CID_LASTP1) {
+	if (ix < 0)
+		return -EINVAL;
+	memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
+		sizeof *q_ctrl);
+	if (gspca_dev->ctrl_dis & (1 << ix))
 		q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-		return 0;
-	}
-	return -EINVAL;
+	return 0;
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
@@ -903,6 +899,8 @@
 	     i++, ctrls++) {
 		if (ctrl->id != ctrls->qctrl.id)
 			continue;
+		if (gspca_dev->ctrl_dis & (1 << i))
+			return -EINVAL;
 		if (ctrl->value < ctrls->qctrl.minimum
 		    || ctrl->value > ctrls->qctrl.maximum)
 			return -ERANGE;
@@ -929,6 +927,8 @@
 	     i++, ctrls++) {
 		if (ctrl->id != ctrls->qctrl.id)
 			continue;
+		if (gspca_dev->ctrl_dis & (1 << i))
+			return -EINVAL;
 		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
 			return -ERESTARTSYS;
 		ret = ctrls->get(gspca_dev, &ctrl->value);
@@ -1403,7 +1403,7 @@
 	i = ret;				/* frame index */
 	frame = &gspca_dev->frame[i];
 	if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
-		if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+		if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
 				 frame->data,
 				 frame->v4l2_buf.bytesused)) {
 			PDEBUG(D_ERR|D_STREAM,
@@ -1731,6 +1731,12 @@
 		err("couldn't kzalloc gspca struct");
 		return -EIO;
 	}
+	gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
+	if (!gspca_dev->usb_buf) {
+		err("out of memory");
+		ret = -EIO;
+		goto out;
+	}
 	gspca_dev->dev = dev;
 	gspca_dev->iface = interface->bInterfaceNumber;
 	gspca_dev->nbalt = intf->num_altsetting;
@@ -1738,10 +1744,13 @@
 /*	gspca_dev->users = 0;			(done by kzalloc) */
 	gspca_dev->nbufread = 2;
 
-	/* configure the subdriver */
+	/* configure the subdriver and initialize the USB device */
 	ret = gspca_dev->sd_desc->config(gspca_dev, id);
 	if (ret < 0)
 		goto out;
+	ret = gspca_dev->sd_desc->init(gspca_dev);
+	if (ret < 0)
+		goto out;
 	ret = gspca_set_alt0(gspca_dev);
 	if (ret < 0)
 		goto out;
@@ -1771,6 +1780,7 @@
 	PDEBUG(D_PROBE, "probe ok");
 	return 0;
 out:
+	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 	return ret;
 }
@@ -1803,11 +1813,42 @@
 /* We don't want people trying to open up the device */
 	video_unregister_device(&gspca_dev->vdev);
 /* Free the memory */
+	kfree(gspca_dev->usb_buf);
 	kfree(gspca_dev);
 	PDEBUG(D_PROBE, "disconnect complete");
 }
 EXPORT_SYMBOL(gspca_disconnect);
 
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+	if (!gspca_dev->streaming)
+		return 0;
+	gspca_dev->frozen = 1;		/* avoid urb error messages */
+	if (gspca_dev->sd_desc->stopN)
+		gspca_dev->sd_desc->stopN(gspca_dev);
+	destroy_urbs(gspca_dev);
+	gspca_set_alt0(gspca_dev);
+	if (gspca_dev->sd_desc->stop0)
+		gspca_dev->sd_desc->stop0(gspca_dev);
+	return 0;
+}
+EXPORT_SYMBOL(gspca_suspend);
+
+int gspca_resume(struct usb_interface *intf)
+{
+	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+	gspca_dev->frozen = 0;
+	gspca_dev->sd_desc->init(gspca_dev);
+	if (gspca_dev->streaming)
+		return gspca_init_transfer(gspca_dev);
+	return 0;
+}
+EXPORT_SYMBOL(gspca_resume);
+#endif
 /* -- cam driver utility functions -- */
 
 /* auto gain and exposure algorithm based on the knee algorithm described here:
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 67e4489..c17625c 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -56,7 +56,6 @@
 
 /* device information - set at probe time */
 struct cam {
-	char *dev_name;
 	struct v4l2_pix_format *cam_mode;	/* size nmodes */
 	char nmodes;
 	__u8 epaddr;
@@ -91,15 +90,14 @@
 /* controls */
 	const struct ctrl *ctrls;
 	int nctrls;
-/* operations */
+/* mandatory operations */
 	cam_cf_op config;	/* called on probe */
-	cam_op open;		/* called on open */
+	cam_op init;		/* called on probe and resume */
 	cam_v_op start;		/* called on stream on */
-	cam_v_op stopN;		/* called on stream off - main alt */
-	cam_v_op stop0;		/* called on stream off - alt 0 */
-	cam_v_op close;		/* called on close */
 	cam_pkt_op pkt_scan;
 /* optional operations */
+	cam_v_op stopN;		/* called on stream off - main alt */
+	cam_v_op stop0;		/* called on stream off - alt 0 */
 	cam_v_op dq_callback;	/* called when a frame has been dequeued */
 	cam_jpg_op get_jcomp;
 	cam_jpg_op set_jcomp;
@@ -127,8 +125,10 @@
 
 	struct cam cam;				/* device information */
 	const struct sd_desc *sd_desc;		/* subdriver description */
+	unsigned ctrl_dis;		/* disabled controls (bit map) */
 
-	__u8 usb_buf[8];			/* buffer for USB exchanges */
+#define USB_BUF_SZ 64
+	__u8 *usb_buf;				/* buffer for USB exchanges */
 	struct urb *urb[MAX_NURBS];
 
 	__u8 *frbuf;				/* buffer for nframes */
@@ -155,6 +155,9 @@
 	struct mutex queue_lock;	/* ISOC queue protection */
 	__u32 sequence;			/* frame sequence number */
 	char streaming;
+#ifdef CONFIG_PM
+	char frozen;			/* suspend - resume */
+#endif
 	char users;			/* number of opens */
 	char present;			/* device connected */
 	char nbufread;			/* number of buffers for read() */
@@ -174,6 +177,10 @@
 				    struct gspca_frame *frame,
 				    const __u8 *data,
 				    int len);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message);
+int gspca_resume(struct usb_interface *intf);
+#endif
 int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
 	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
 #endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 21c4ee5..4d5db47 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -100,22 +100,6 @@
 	return rc;
 }
 
-static int reg_w_buf(struct gspca_dev *gspca_dev,
-			__u16 index, __u8 *buf, int len)
-{
-	int rc;
-
-	rc = usb_control_msg(gspca_dev->dev,
-			 usb_sndbulkpipe(gspca_dev->dev, 4),
-			 0x12,
-			 0xc8,		/* ?? */
-			 0,		/* value */
-			 index, buf, len, 500);
-	if (rc < 0)
-		PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
-	return rc;
-}
-
 static void bulk_w(struct gspca_dev *gspca_dev,
 		   __u16 *pch,
 		   __u16 Address)
@@ -144,8 +128,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	return 0;
 }
@@ -175,7 +159,6 @@
 	/*
 	   Initialize the MR97113 chip register
 	 */
-	data = kmalloc(16, GFP_KERNEL);
 	data[0] = 0x00;		/* address */
 	data[1] = 0x0c | 0x01;	/* reg 0 */
 	data[2] = 0x01;		/* reg 1 */
@@ -195,12 +178,10 @@
 	data[10] = 0x5d;	/* reg 9, I2C device address
 				 *	[for PAS5101 (0x40)] [for MI (0x5d)] */
 
-	err_code = reg_w_buf(gspca_dev, data[0], data, 11);
-	kfree(data);
+	err_code = reg_w(gspca_dev, data[0], 11);
 	if (err_code < 0)
 		return;
 
-	data = gspca_dev->usb_buf;
 	data[0] = 0x23;		/* address */
 	data[1] = 0x09;		/* reg 35, append frame header */
 
@@ -358,14 +339,6 @@
 		PDEBUG(D_ERR, "Camera Stop failed");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -411,11 +384,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -439,6 +410,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index b4f00ec..4df4eec 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -63,11 +63,10 @@
 #define SEN_OV6630 2
 #define SEN_OV7610 3
 #define SEN_OV7620 4
-#define SEN_OV7630 5
-#define SEN_OV7640 6
-#define SEN_OV7670 7
-#define SEN_OV76BE 8
-#define SEN_OV8610 9
+#define SEN_OV7640 5
+#define SEN_OV7670 6
+#define SEN_OV76BE 7
+#define SEN_OV8610 8
 
 };
 
@@ -127,6 +126,7 @@
 	    .get = sd_getcolors,
 	},
 /* next controls work with ov7670 only */
+#define HFLIP_IDX 3
 	{
 	    {
 		.id      = V4L2_CID_HFLIP,
@@ -141,6 +141,7 @@
 	    .set = sd_sethflip,
 	    .get = sd_gethflip,
 	},
+#define VFLIP_IDX 4
 	{
 	    {
 		.id      = V4L2_CID_VFLIP,
@@ -293,6 +294,541 @@
 #define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
 #define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
 
+struct ov_regvals {
+	__u8 reg;
+	__u8 val;
+};
+struct ov_i2c_regvals {
+	__u8 reg;
+	__u8 val;
+};
+
+static const struct ov_i2c_regvals norm_6x20[] = {
+	{ 0x12, 0x80 }, /* reset */
+	{ 0x11, 0x01 },
+	{ 0x03, 0x60 },
+	{ 0x05, 0x7f }, /* For when autoadjust is off */
+	{ 0x07, 0xa8 },
+	/* The ratio of 0x0c and 0x0d  controls the white point */
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+	{ 0x0f, 0x15 }, /* COMS */
+	{ 0x10, 0x75 }, /* AEC Exposure time */
+	{ 0x12, 0x24 }, /* Enable AGC */
+	{ 0x14, 0x04 },
+	/* 0x16: 0x06 helps frame stability with moving objects */
+	{ 0x16, 0x06 },
+/*	{ 0x20, 0x30 },  * Aperture correction enable */
+	{ 0x26, 0xb2 }, /* BLC enable */
+	/* 0x28: 0x05 Selects RGB format if RGB on */
+	{ 0x28, 0x05 },
+	{ 0x2a, 0x04 }, /* Disable framerate adjust */
+/*	{ 0x2b, 0xac },  * Framerate; Set 2a[7] first */
+	{ 0x2d, 0x99 },
+	{ 0x33, 0xa0 }, /* Color Processing Parameter */
+	{ 0x34, 0xd2 }, /* Max A/D range */
+	{ 0x38, 0x8b },
+	{ 0x39, 0x40 },
+
+	{ 0x3c, 0x39 }, /* Enable AEC mode changing */
+	{ 0x3c, 0x3c }, /* Change AEC mode */
+	{ 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+	{ 0x3d, 0x80 },
+	/* These next two registers (0x4a, 0x4b) are undocumented.
+	 * They control the color balance */
+	{ 0x4a, 0x80 },
+	{ 0x4b, 0x80 },
+	{ 0x4d, 0xd2 }, /* This reduces noise a bit */
+	{ 0x4e, 0xc1 },
+	{ 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+};
+
+static const struct ov_i2c_regvals norm_6x30[] = {
+	{ 0x12, 0x80 }, /* Reset */
+	{ 0x00, 0x1f }, /* Gain */
+	{ 0x01, 0x99 }, /* Blue gain */
+	{ 0x02, 0x7c }, /* Red gain */
+	{ 0x03, 0xc0 }, /* Saturation */
+	{ 0x05, 0x0a }, /* Contrast */
+	{ 0x06, 0x95 }, /* Brightness */
+	{ 0x07, 0x2d }, /* Sharpness */
+	{ 0x0c, 0x20 },
+	{ 0x0d, 0x20 },
+	{ 0x0e, 0x20 },
+	{ 0x0f, 0x05 },
+	{ 0x10, 0x9a },
+	{ 0x11, 0x00 }, /* Pixel clock = fastest */
+	{ 0x12, 0x24 }, /* Enable AGC and AWB */
+	{ 0x13, 0x21 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x03 },
+	{ 0x17, 0x38 },
+	{ 0x18, 0xea },
+	{ 0x19, 0x04 },
+	{ 0x1a, 0x93 },
+	{ 0x1b, 0x00 },
+	{ 0x1e, 0xc4 },
+	{ 0x1f, 0x04 },
+	{ 0x20, 0x20 },
+	{ 0x21, 0x10 },
+	{ 0x22, 0x88 },
+	{ 0x23, 0xc0 }, /* Crystal circuit power level */
+	{ 0x25, 0x9a }, /* Increase AEC black ratio */
+	{ 0x26, 0xb2 }, /* BLC enable */
+	{ 0x27, 0xa2 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x84 }, /* 60 Hz power */
+	{ 0x2b, 0xa8 }, /* 60 Hz power */
+	{ 0x2c, 0xa0 },
+	{ 0x2d, 0x95 }, /* Enable auto-brightness */
+	{ 0x2e, 0x88 },
+	{ 0x33, 0x26 },
+	{ 0x34, 0x03 },
+	{ 0x36, 0x8f },
+	{ 0x37, 0x80 },
+	{ 0x38, 0x83 },
+	{ 0x39, 0x80 },
+	{ 0x3a, 0x0f },
+	{ 0x3b, 0x3c },
+	{ 0x3c, 0x1a },
+	{ 0x3d, 0x80 },
+	{ 0x3e, 0x80 },
+	{ 0x3f, 0x0e },
+	{ 0x40, 0x00 }, /* White bal */
+	{ 0x41, 0x00 }, /* White bal */
+	{ 0x42, 0x80 },
+	{ 0x43, 0x3f }, /* White bal */
+	{ 0x44, 0x80 },
+	{ 0x45, 0x20 },
+	{ 0x46, 0x20 },
+	{ 0x47, 0x80 },
+	{ 0x48, 0x7f },
+	{ 0x49, 0x00 },
+	{ 0x4a, 0x00 },
+	{ 0x4b, 0x80 },
+	{ 0x4c, 0xd0 },
+	{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+	{ 0x4e, 0x40 },
+	{ 0x4f, 0x07 }, /* UV avg., col. killer: max */
+	{ 0x50, 0xff },
+	{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
+	{ 0x55, 0xff },
+	{ 0x56, 0x12 },
+	{ 0x57, 0x81 },
+	{ 0x58, 0x75 },
+	{ 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+	{ 0x5a, 0x2c },
+	{ 0x5b, 0x0f }, /* AWB chrominance levels */
+	{ 0x5c, 0x10 },
+	{ 0x3d, 0x80 },
+	{ 0x27, 0xa6 },
+	{ 0x12, 0x20 }, /* Toggle AWB */
+	{ 0x12, 0x24 },
+};
+
+/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ *	shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ *	contrast
+ */
+static const struct ov_i2c_regvals norm_7610[] = {
+	{ 0x10, 0xff },
+	{ 0x16, 0x06 },
+	{ 0x28, 0x24 },
+	{ 0x2b, 0xac },
+	{ 0x12, 0x00 },
+	{ 0x38, 0x81 },
+	{ 0x28, 0x24 },	/* 0c */
+	{ 0x0f, 0x85 },	/* lg's setting */
+	{ 0x15, 0x01 },
+	{ 0x20, 0x1c },
+	{ 0x23, 0x2a },
+	{ 0x24, 0x10 },
+	{ 0x25, 0x8a },
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xc2 },
+	{ 0x2a, 0x04 },
+	{ 0x2c, 0xfe },
+	{ 0x2d, 0x93 },
+	{ 0x30, 0x71 },
+	{ 0x31, 0x60 },
+	{ 0x32, 0x26 },
+	{ 0x33, 0x20 },
+	{ 0x34, 0x48 },
+	{ 0x12, 0x24 },
+	{ 0x11, 0x01 },
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+};
+
+static const struct ov_i2c_regvals norm_7620[] = {
+	{ 0x00, 0x00 },		/* gain */
+	{ 0x01, 0x80 },		/* blue gain */
+	{ 0x02, 0x80 },		/* red gain */
+	{ 0x03, 0xc0 },		/* OV7670_REG_VREF */
+	{ 0x06, 0x60 },
+	{ 0x07, 0x00 },
+	{ 0x0c, 0x24 },
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+	{ 0x11, 0x01 },
+	{ 0x12, 0x24 },
+	{ 0x13, 0x01 },
+	{ 0x14, 0x84 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x03 },
+	{ 0x17, 0x2f },
+	{ 0x18, 0xcf },
+	{ 0x19, 0x06 },
+	{ 0x1a, 0xf5 },
+	{ 0x1b, 0x00 },
+	{ 0x20, 0x18 },
+	{ 0x21, 0x80 },
+	{ 0x22, 0x80 },
+	{ 0x23, 0x00 },
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xea },
+	{ 0x28, 0x20 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x10 },
+	{ 0x2b, 0x00 },
+	{ 0x2c, 0x88 },
+	{ 0x2d, 0x91 },
+	{ 0x2e, 0x80 },
+	{ 0x2f, 0x44 },
+	{ 0x60, 0x27 },
+	{ 0x61, 0x02 },
+	{ 0x62, 0x5f },
+	{ 0x63, 0xd5 },
+	{ 0x64, 0x57 },
+	{ 0x65, 0x83 },
+	{ 0x66, 0x55 },
+	{ 0x67, 0x92 },
+	{ 0x68, 0xcf },
+	{ 0x69, 0x76 },
+	{ 0x6a, 0x22 },
+	{ 0x6b, 0x00 },
+	{ 0x6c, 0x02 },
+	{ 0x6d, 0x44 },
+	{ 0x6e, 0x80 },
+	{ 0x6f, 0x1d },
+	{ 0x70, 0x8b },
+	{ 0x71, 0x00 },
+	{ 0x72, 0x14 },
+	{ 0x73, 0x54 },
+	{ 0x74, 0x00 },
+	{ 0x75, 0x8e },
+	{ 0x76, 0x00 },
+	{ 0x77, 0xff },
+	{ 0x78, 0x80 },
+	{ 0x79, 0x80 },
+	{ 0x7a, 0x80 },
+	{ 0x7b, 0xe2 },
+	{ 0x7c, 0x00 },
+};
+
+/* 7640 and 7648. The defaults should be OK for most registers. */
+static const struct ov_i2c_regvals norm_7640[] = {
+	{ 0x12, 0x80 },
+	{ 0x12, 0x14 },
+};
+
+/* 7670. Defaults taken from OmniVision provided data,
+*  as provided by Jonathan Corbet of OLPC		*/
+static const struct ov_i2c_regvals norm_7670[] = {
+	{ OV7670_REG_COM7, OV7670_COM7_RESET },
+	{ OV7670_REG_TSLB, 0x04 },		/* OV */
+	{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+	{ OV7670_REG_CLKRC, 0x01 },
+/*
+ * Set the hardware window.  These values from OV don't entirely
+ * make sense - hstop is less than hstart.  But they work...
+ */
+	{ OV7670_REG_HSTART, 0x13 },
+	{ OV7670_REG_HSTOP, 0x01 },
+	{ OV7670_REG_HREF, 0xb6 },
+	{ OV7670_REG_VSTART, 0x02 },
+	{ OV7670_REG_VSTOP, 0x7a },
+	{ OV7670_REG_VREF, 0x0a },
+
+	{ OV7670_REG_COM3, 0 },
+	{ OV7670_REG_COM14, 0 },
+/* Mystery scaling numbers */
+	{ 0x70, 0x3a },
+	{ 0x71, 0x35 },
+	{ 0x72, 0x11 },
+	{ 0x73, 0xf0 },
+	{ 0xa2, 0x02 },
+/*	{ OV7670_REG_COM10, 0x0 }, */
+
+/* Gamma curve values */
+	{ 0x7a, 0x20 },
+	{ 0x7b, 0x10 },
+	{ 0x7c, 0x1e },
+	{ 0x7d, 0x35 },
+	{ 0x7e, 0x5a },
+	{ 0x7f, 0x69 },
+	{ 0x80, 0x76 },
+	{ 0x81, 0x80 },
+	{ 0x82, 0x88 },
+	{ 0x83, 0x8f },
+	{ 0x84, 0x96 },
+	{ 0x85, 0xa3 },
+	{ 0x86, 0xaf },
+	{ 0x87, 0xc4 },
+	{ 0x88, 0xd7 },
+	{ 0x89, 0xe8 },
+
+/* AGC and AEC parameters.  Note we start by disabling those features,
+   then turn them only after tweaking the values. */
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			 | OV7670_COM8_AECSTEP
+			 | OV7670_COM8_BFILT },
+	{ OV7670_REG_GAIN, 0 },
+	{ OV7670_REG_AECH, 0 },
+	{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+	{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+	{ OV7670_REG_BD50MAX, 0x05 },
+	{ OV7670_REG_BD60MAX, 0x07 },
+	{ OV7670_REG_AEW, 0x95 },
+	{ OV7670_REG_AEB, 0x33 },
+	{ OV7670_REG_VPT, 0xe3 },
+	{ OV7670_REG_HAECC1, 0x78 },
+	{ OV7670_REG_HAECC2, 0x68 },
+	{ 0xa1, 0x03 }, /* magic */
+	{ OV7670_REG_HAECC3, 0xd8 },
+	{ OV7670_REG_HAECC4, 0xd8 },
+	{ OV7670_REG_HAECC5, 0xf0 },
+	{ OV7670_REG_HAECC6, 0x90 },
+	{ OV7670_REG_HAECC7, 0x94 },
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			| OV7670_COM8_AECSTEP
+			| OV7670_COM8_BFILT
+			| OV7670_COM8_AGC
+			| OV7670_COM8_AEC },
+
+/* Almost all of these are magic "reserved" values.  */
+	{ OV7670_REG_COM5, 0x61 },
+	{ OV7670_REG_COM6, 0x4b },
+	{ 0x16, 0x02 },
+	{ OV7670_REG_MVFP, 0x07 },
+	{ 0x21, 0x02 },
+	{ 0x22, 0x91 },
+	{ 0x29, 0x07 },
+	{ 0x33, 0x0b },
+	{ 0x35, 0x0b },
+	{ 0x37, 0x1d },
+	{ 0x38, 0x71 },
+	{ 0x39, 0x2a },
+	{ OV7670_REG_COM12, 0x78 },
+	{ 0x4d, 0x40 },
+	{ 0x4e, 0x20 },
+	{ OV7670_REG_GFIX, 0 },
+	{ 0x6b, 0x4a },
+	{ 0x74, 0x10 },
+	{ 0x8d, 0x4f },
+	{ 0x8e, 0 },
+	{ 0x8f, 0 },
+	{ 0x90, 0 },
+	{ 0x91, 0 },
+	{ 0x96, 0 },
+	{ 0x9a, 0 },
+	{ 0xb0, 0x84 },
+	{ 0xb1, 0x0c },
+	{ 0xb2, 0x0e },
+	{ 0xb3, 0x82 },
+	{ 0xb8, 0x0a },
+
+/* More reserved magic, some of which tweaks white balance */
+	{ 0x43, 0x0a },
+	{ 0x44, 0xf0 },
+	{ 0x45, 0x34 },
+	{ 0x46, 0x58 },
+	{ 0x47, 0x28 },
+	{ 0x48, 0x3a },
+	{ 0x59, 0x88 },
+	{ 0x5a, 0x88 },
+	{ 0x5b, 0x44 },
+	{ 0x5c, 0x67 },
+	{ 0x5d, 0x49 },
+	{ 0x5e, 0x0e },
+	{ 0x6c, 0x0a },
+	{ 0x6d, 0x55 },
+	{ 0x6e, 0x11 },
+	{ 0x6f, 0x9f },
+					/* "9e for advance AWB" */
+	{ 0x6a, 0x40 },
+	{ OV7670_REG_BLUE, 0x40 },
+	{ OV7670_REG_RED, 0x60 },
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			| OV7670_COM8_AECSTEP
+			| OV7670_COM8_BFILT
+			| OV7670_COM8_AGC
+			| OV7670_COM8_AEC
+			| OV7670_COM8_AWB },
+
+/* Matrix coefficients */
+	{ 0x4f, 0x80 },
+	{ 0x50, 0x80 },
+	{ 0x51, 0 },
+	{ 0x52, 0x22 },
+	{ 0x53, 0x5e },
+	{ 0x54, 0x80 },
+	{ 0x58, 0x9e },
+
+	{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+	{ OV7670_REG_EDGE, 0 },
+	{ 0x75, 0x05 },
+	{ 0x76, 0xe1 },
+	{ 0x4c, 0 },
+	{ 0x77, 0x01 },
+	{ OV7670_REG_COM13, OV7670_COM13_GAMMA
+			  | OV7670_COM13_UVSAT
+			  | 2},		/* was 3 */
+	{ 0x4b, 0x09 },
+	{ 0xc9, 0x60 },
+	{ OV7670_REG_COM16, 0x38 },
+	{ 0x56, 0x40 },
+
+	{ 0x34, 0x11 },
+	{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+	{ 0xa4, 0x88 },
+	{ 0x96, 0 },
+	{ 0x97, 0x30 },
+	{ 0x98, 0x20 },
+	{ 0x99, 0x30 },
+	{ 0x9a, 0x84 },
+	{ 0x9b, 0x29 },
+	{ 0x9c, 0x03 },
+	{ 0x9d, 0x4c },
+	{ 0x9e, 0x3f },
+	{ 0x78, 0x04 },
+
+/* Extra-weird stuff.  Some sort of multiplexor register */
+	{ 0x79, 0x01 },
+	{ 0xc8, 0xf0 },
+	{ 0x79, 0x0f },
+	{ 0xc8, 0x00 },
+	{ 0x79, 0x10 },
+	{ 0xc8, 0x7e },
+	{ 0x79, 0x0a },
+	{ 0xc8, 0x80 },
+	{ 0x79, 0x0b },
+	{ 0xc8, 0x01 },
+	{ 0x79, 0x0c },
+	{ 0xc8, 0x0f },
+	{ 0x79, 0x0d },
+	{ 0xc8, 0x20 },
+	{ 0x79, 0x09 },
+	{ 0xc8, 0x80 },
+	{ 0x79, 0x02 },
+	{ 0xc8, 0xc0 },
+	{ 0x79, 0x03 },
+	{ 0xc8, 0x40 },
+	{ 0x79, 0x05 },
+	{ 0xc8, 0x30 },
+	{ 0x79, 0x26 },
+};
+
+static const struct ov_i2c_regvals norm_8610[] = {
+	{ 0x12, 0x80 },
+	{ 0x00, 0x00 },
+	{ 0x01, 0x80 },
+	{ 0x02, 0x80 },
+	{ 0x03, 0xc0 },
+	{ 0x04, 0x30 },
+	{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+	{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+	{ 0x0a, 0x86 },
+	{ 0x0b, 0xb0 },
+	{ 0x0c, 0x20 },
+	{ 0x0d, 0x20 },
+	{ 0x11, 0x01 },
+	{ 0x12, 0x25 },
+	{ 0x13, 0x01 },
+	{ 0x14, 0x04 },
+	{ 0x15, 0x01 }, /* Lin and Win think different about UV order */
+	{ 0x16, 0x03 },
+	{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+	{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+	{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+	{ 0x1a, 0xf5 },
+	{ 0x1b, 0x00 },
+	{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+	{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+	{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+	{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xea },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x80 },
+	{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+	{ 0x2c, 0xac },
+	{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+	{ 0x2e, 0x80 },
+	{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+	{ 0x4c, 0x00 },
+	{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+	{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+	{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+	{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+	{ 0x63, 0xff },
+	{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+			 * maybe thats wrong */
+	{ 0x65, 0x00 },
+	{ 0x66, 0x55 },
+	{ 0x67, 0xb0 },
+	{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+	{ 0x69, 0x02 },
+	{ 0x6a, 0x22 },
+	{ 0x6b, 0x00 },
+	{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+			 * deleting bit7 colors the first images red */
+	{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+	{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+	{ 0x6f, 0x01 },
+	{ 0x70, 0x8b },
+	{ 0x71, 0x00 },
+	{ 0x72, 0x14 },
+	{ 0x73, 0x54 },
+	{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+	{ 0x75, 0x0e },
+	{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+	{ 0x77, 0xff },
+	{ 0x78, 0x80 },
+	{ 0x79, 0x80 },
+	{ 0x7a, 0x80 },
+	{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+	{ 0x7c, 0x00 },
+	{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+	{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+	{ 0x7f, 0xfb },
+	{ 0x80, 0x28 },
+	{ 0x81, 0x00 },
+	{ 0x82, 0x23 },
+	{ 0x83, 0x0b },
+	{ 0x84, 0x00 },
+	{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+	{ 0x86, 0xc9 },
+	{ 0x87, 0x00 },
+	{ 0x88, 0x00 },
+	{ 0x89, 0x01 },
+	{ 0x12, 0x20 },
+	{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+};
+
 static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
 	if (v > 127)
@@ -537,18 +1073,10 @@
 	rc = reg_w(sd, R51x_I2C_W_SID, slave);
 	if (rc < 0)
 		return rc;
+	sd->primary_i2c_slave = slave;
 	return reg_w(sd, R51x_I2C_R_SID, slave + 1);
 }
 
-struct ov_regvals {
-	__u8 reg;
-	__u8 val;
-};
-struct ov_i2c_regvals {
-	__u8 reg;
-	__u8 val;
-};
-
 static int write_regvals(struct sd *sd,
 			 const struct ov_regvals *regvals,
 			 int n)
@@ -591,101 +1119,9 @@
 static int ov8xx0_configure(struct sd *sd)
 {
 	int rc;
-	static const struct ov_i2c_regvals norm_8610[] = {
-		{ 0x12, 0x80 },
-		{ 0x00, 0x00 },
-		{ 0x01, 0x80 },
-		{ 0x02, 0x80 },
-		{ 0x03, 0xc0 },
-		{ 0x04, 0x30 },
-		{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
-		{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
-		{ 0x0a, 0x86 },
-		{ 0x0b, 0xb0 },
-		{ 0x0c, 0x20 },
-		{ 0x0d, 0x20 },
-		{ 0x11, 0x01 },
-		{ 0x12, 0x25 },
-		{ 0x13, 0x01 },
-		{ 0x14, 0x04 },
-		{ 0x15, 0x01 }, /* Lin and Win think different about UV order */
-		{ 0x16, 0x03 },
-		{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
-		{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
-		{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
-		{ 0x1a, 0xf5 },
-		{ 0x1b, 0x00 },
-		{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
-		{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
-		{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
-		{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xea },
-		{ 0x28, 0x00 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x80 },
-		{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
-		{ 0x2c, 0xac },
-		{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
-		{ 0x2e, 0x80 },
-		{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
-		{ 0x4c, 0x00 },
-		{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
-		{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
-		{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
-		{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
-		{ 0x63, 0xff },
-		{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,
-				 * maybe thats wrong */
-		{ 0x65, 0x00 },
-		{ 0x66, 0x55 },
-		{ 0x67, 0xb0 },
-		{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
-		{ 0x69, 0x02 },
-		{ 0x6a, 0x22 },
-		{ 0x6b, 0x00 },
-		{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
-				   deleting bit7 colors the first images red */
-		{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
-		{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
-		{ 0x6f, 0x01 },
-		{ 0x70, 0x8b },
-		{ 0x71, 0x00 },
-		{ 0x72, 0x14 },
-		{ 0x73, 0x54 },
-		{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
-		{ 0x75, 0x0e },
-		{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
-		{ 0x77, 0xff },
-		{ 0x78, 0x80 },
-		{ 0x79, 0x80 },
-		{ 0x7a, 0x80 },
-		{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
-		{ 0x7c, 0x00 },
-		{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
-		{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
-		{ 0x7f, 0xfb },
-		{ 0x80, 0x28 },
-		{ 0x81, 0x00 },
-		{ 0x82, 0x23 },
-		{ 0x83, 0x0b },
-		{ 0x84, 0x00 },
-		{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
-		{ 0x86, 0xc9 },
-		{ 0x87, 0x00 },
-		{ 0x88, 0x00 },
-		{ 0x89, 0x01 },
-		{ 0x12, 0x20 },
-		{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
-	};
 
 	PDEBUG(D_PROBE, "starting ov8xx0 configuration");
 
-	if (init_ov_sensor(sd) < 0)
-		PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
-	else
-		PDEBUG(D_PROBE, "OV86x0 initialized");
-
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
 	if (rc < 0) {
@@ -698,9 +1134,6 @@
 		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
 		return -1;
 	}
-	PDEBUG(D_PROBE, "Writing 8610 registers");
-	if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
-		return -1;
 
 	/* Set sensor-specific vars */
 /*	sd->sif = 0;		already done */
@@ -714,252 +1147,6 @@
 {
 	int rc, high, low;
 
-	/* Lawrence Glaister <lg@jfm.bc.ca> reports:
-	 *
-	 * Register 0x0f in the 7610 has the following effects:
-	 *
-	 * 0x85 (AEC method 1): Best overall, good contrast range
-	 * 0x45 (AEC method 2): Very overexposed
-	 * 0xa5 (spec sheet default): Ok, but the black level is
-	 *	shifted resulting in loss of contrast
-	 * 0x05 (old driver setting): very overexposed, too much
-	 *	contrast
-	 */
-	static const struct ov_i2c_regvals norm_7610[] = {
-		{ 0x10, 0xff },
-		{ 0x16, 0x06 },
-		{ 0x28, 0x24 },
-		{ 0x2b, 0xac },
-		{ 0x12, 0x00 },
-		{ 0x38, 0x81 },
-		{ 0x28, 0x24 },	/* 0c */
-		{ 0x0f, 0x85 },	/* lg's setting */
-		{ 0x15, 0x01 },
-		{ 0x20, 0x1c },
-		{ 0x23, 0x2a },
-		{ 0x24, 0x10 },
-		{ 0x25, 0x8a },
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xc2 },
-		{ 0x2a, 0x04 },
-		{ 0x2c, 0xfe },
-		{ 0x2d, 0x93 },
-		{ 0x30, 0x71 },
-		{ 0x31, 0x60 },
-		{ 0x32, 0x26 },
-		{ 0x33, 0x20 },
-		{ 0x34, 0x48 },
-		{ 0x12, 0x24 },
-		{ 0x11, 0x01 },
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-	};
-
-	static const struct ov_i2c_regvals norm_7620[] = {
-		{ 0x00, 0x00 },		/* gain */
-		{ 0x01, 0x80 },		/* blue gain */
-		{ 0x02, 0x80 },		/* red gain */
-		{ 0x03, 0xc0 },		/* OV7670_REG_VREF */
-		{ 0x06, 0x60 },
-		{ 0x07, 0x00 },
-		{ 0x0c, 0x24 },
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-		{ 0x11, 0x01 },
-		{ 0x12, 0x24 },
-		{ 0x13, 0x01 },
-		{ 0x14, 0x84 },
-		{ 0x15, 0x01 },
-		{ 0x16, 0x03 },
-		{ 0x17, 0x2f },
-		{ 0x18, 0xcf },
-		{ 0x19, 0x06 },
-		{ 0x1a, 0xf5 },
-		{ 0x1b, 0x00 },
-		{ 0x20, 0x18 },
-		{ 0x21, 0x80 },
-		{ 0x22, 0x80 },
-		{ 0x23, 0x00 },
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xea },
-		{ 0x28, 0x20 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x10 },
-		{ 0x2b, 0x00 },
-		{ 0x2c, 0x88 },
-		{ 0x2d, 0x91 },
-		{ 0x2e, 0x80 },
-		{ 0x2f, 0x44 },
-		{ 0x60, 0x27 },
-		{ 0x61, 0x02 },
-		{ 0x62, 0x5f },
-		{ 0x63, 0xd5 },
-		{ 0x64, 0x57 },
-		{ 0x65, 0x83 },
-		{ 0x66, 0x55 },
-		{ 0x67, 0x92 },
-		{ 0x68, 0xcf },
-		{ 0x69, 0x76 },
-		{ 0x6a, 0x22 },
-		{ 0x6b, 0x00 },
-		{ 0x6c, 0x02 },
-		{ 0x6d, 0x44 },
-		{ 0x6e, 0x80 },
-		{ 0x6f, 0x1d },
-		{ 0x70, 0x8b },
-		{ 0x71, 0x00 },
-		{ 0x72, 0x14 },
-		{ 0x73, 0x54 },
-		{ 0x74, 0x00 },
-		{ 0x75, 0x8e },
-		{ 0x76, 0x00 },
-		{ 0x77, 0xff },
-		{ 0x78, 0x80 },
-		{ 0x79, 0x80 },
-		{ 0x7a, 0x80 },
-		{ 0x7b, 0xe2 },
-		{ 0x7c, 0x00 },
-	};
-
-	/* 7640 and 7648. The defaults should be OK for most registers. */
-	static const struct ov_i2c_regvals norm_7640[] = {
-		{ 0x12, 0x80 },
-		{ 0x12, 0x14 },
-	};
-
-	/* 7670. Defaults taken from OmniVision provided data,
-	*  as provided by Jonathan Corbet of OLPC		*/
-	static const struct ov_i2c_regvals norm_7670[] = {
-		{ OV7670_REG_COM7, OV7670_COM7_RESET },
-		{ OV7670_REG_TSLB, 0x04 },		/* OV */
-		{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
-		{ OV7670_REG_CLKRC, 0x01 },
-	/*
-	 * Set the hardware window.  These values from OV don't entirely
-	 * make sense - hstop is less than hstart.  But they work...
-	 */
-		{ OV7670_REG_HSTART, 0x13 },	{ OV7670_REG_HSTOP, 0x01 },
-		{ OV7670_REG_HREF, 0xb6 },	{ OV7670_REG_VSTART, 0x02 },
-		{ OV7670_REG_VSTOP, 0x7a },	{ OV7670_REG_VREF, 0x0a },
-
-		{ OV7670_REG_COM3, 0 },	{ OV7670_REG_COM14, 0 },
-	/* Mystery scaling numbers */
-		{ 0x70, 0x3a },		{ 0x71, 0x35 },
-		{ 0x72, 0x11 },		{ 0x73, 0xf0 },
-		{ 0xa2, 0x02 },
-/*		{ OV7670_REG_COM10, 0x0 }, */
-
-	/* Gamma curve values */
-		{ 0x7a, 0x20 },
-		{ 0x7b, 0x10 },
-		{ 0x7c, 0x1e },
-		{ 0x7d, 0x35 },
-		{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
-		{ 0x80, 0x76 },		{ 0x81, 0x80 },
-		{ 0x82, 0x88 },		{ 0x83, 0x8f },
-		{ 0x84, 0x96 },		{ 0x85, 0xa3 },
-		{ 0x86, 0xaf },		{ 0x87, 0xc4 },
-		{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
-
-	/* AGC and AEC parameters.  Note we start by disabling those features,
-	   then turn them only after tweaking the values. */
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				 | OV7670_COM8_AECSTEP
-				 | OV7670_COM8_BFILT },
-		{ OV7670_REG_GAIN, 0 },	{ OV7670_REG_AECH, 0 },
-		{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
-		{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
-		{ OV7670_REG_BD50MAX, 0x05 },	{ OV7670_REG_BD60MAX, 0x07 },
-		{ OV7670_REG_AEW, 0x95 },	{ OV7670_REG_AEB, 0x33 },
-		{ OV7670_REG_VPT, 0xe3 },	{ OV7670_REG_HAECC1, 0x78 },
-		{ OV7670_REG_HAECC2, 0x68 },
-		{ 0xa1, 0x03 }, /* magic */
-		{ OV7670_REG_HAECC3, 0xd8 },	{ OV7670_REG_HAECC4, 0xd8 },
-		{ OV7670_REG_HAECC5, 0xf0 },	{ OV7670_REG_HAECC6, 0x90 },
-		{ OV7670_REG_HAECC7, 0x94 },
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				| OV7670_COM8_AECSTEP
-				| OV7670_COM8_BFILT
-				| OV7670_COM8_AGC
-				| OV7670_COM8_AEC },
-
-	/* Almost all of these are magic "reserved" values.  */
-		{ OV7670_REG_COM5, 0x61 },	{ OV7670_REG_COM6, 0x4b },
-		{ 0x16, 0x02 },
-		{ OV7670_REG_MVFP, 0x07 },
-		{ 0x21, 0x02 },		{ 0x22, 0x91 },
-		{ 0x29, 0x07 },		{ 0x33, 0x0b },
-		{ 0x35, 0x0b },		{ 0x37, 0x1d },
-		{ 0x38, 0x71 },		{ 0x39, 0x2a },
-		{ OV7670_REG_COM12, 0x78 },	{ 0x4d, 0x40 },
-		{ 0x4e, 0x20 },		{ OV7670_REG_GFIX, 0 },
-		{ 0x6b, 0x4a },		{ 0x74, 0x10 },
-		{ 0x8d, 0x4f },		{ 0x8e, 0 },
-		{ 0x8f, 0 },		{ 0x90, 0 },
-		{ 0x91, 0 },		{ 0x96, 0 },
-		{ 0x9a, 0 },		{ 0xb0, 0x84 },
-		{ 0xb1, 0x0c },		{ 0xb2, 0x0e },
-		{ 0xb3, 0x82 },		{ 0xb8, 0x0a },
-
-	/* More reserved magic, some of which tweaks white balance */
-		{ 0x43, 0x0a },		{ 0x44, 0xf0 },
-		{ 0x45, 0x34 },		{ 0x46, 0x58 },
-		{ 0x47, 0x28 },		{ 0x48, 0x3a },
-		{ 0x59, 0x88 },		{ 0x5a, 0x88 },
-		{ 0x5b, 0x44 },		{ 0x5c, 0x67 },
-		{ 0x5d, 0x49 },		{ 0x5e, 0x0e },
-		{ 0x6c, 0x0a },		{ 0x6d, 0x55 },
-		{ 0x6e, 0x11 },		{ 0x6f, 0x9f },
-						/* "9e for advance AWB" */
-		{ 0x6a, 0x40 },		{ OV7670_REG_BLUE, 0x40 },
-		{ OV7670_REG_RED, 0x60 },
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				| OV7670_COM8_AECSTEP
-				| OV7670_COM8_BFILT
-				| OV7670_COM8_AGC
-				| OV7670_COM8_AEC
-				| OV7670_COM8_AWB },
-
-	/* Matrix coefficients */
-		{ 0x4f, 0x80 },		{ 0x50, 0x80 },
-		{ 0x51, 0 },		{ 0x52, 0x22 },
-		{ 0x53, 0x5e },		{ 0x54, 0x80 },
-		{ 0x58, 0x9e },
-
-		{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
-		{ OV7670_REG_EDGE, 0 },
-		{ 0x75, 0x05 },		{ 0x76, 0xe1 },
-		{ 0x4c, 0 },		{ 0x77, 0x01 },
-		{ OV7670_REG_COM13, OV7670_COM13_GAMMA
-				  | OV7670_COM13_UVSAT
-				  | 2},		/* was 3 */
-		{ 0x4b, 0x09 },
-		{ 0xc9, 0x60 },		{ OV7670_REG_COM16, 0x38 },
-		{ 0x56, 0x40 },
-
-		{ 0x34, 0x11 },
-		{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
-		{ 0xa4, 0x88 },		{ 0x96, 0 },
-		{ 0x97, 0x30 },		{ 0x98, 0x20 },
-		{ 0x99, 0x30 },		{ 0x9a, 0x84 },
-		{ 0x9b, 0x29 },		{ 0x9c, 0x03 },
-		{ 0x9d, 0x4c },		{ 0x9e, 0x3f },
-		{ 0x78, 0x04 },
-
-	/* Extra-weird stuff.  Some sort of multiplexor register */
-		{ 0x79, 0x01 },		{ 0xc8, 0xf0 },
-		{ 0x79, 0x0f },		{ 0xc8, 0x00 },
-		{ 0x79, 0x10 },		{ 0xc8, 0x7e },
-		{ 0x79, 0x0a },		{ 0xc8, 0x80 },
-		{ 0x79, 0x0b },		{ 0xc8, 0x01 },
-		{ 0x79, 0x0c },		{ 0xc8, 0x0f },
-		{ 0x79, 0x0d },		{ 0xc8, 0x20 },
-		{ 0x79, 0x09 },		{ 0xc8, 0x80 },
-		{ 0x79, 0x02 },		{ 0xc8, 0xc0 },
-		{ 0x79, 0x03 },		{ 0xc8, 0x40 },
-		{ 0x79, 0x05 },		{ 0xc8, 0x30 },
-		{ 0x79, 0x26 },
-	};
 
 	PDEBUG(D_PROBE, "starting OV7xx0 configuration");
 
@@ -1011,8 +1198,9 @@
 			switch (low) {
 			case 0x30:
 				PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
-				sd->sensor = SEN_OV7630;
-				break;
+				PDEBUG(D_ERR,
+				      "7630 is not supported by this driver");
+				return -1;
 			case 0x40:
 				PDEBUG(D_PROBE, "Sensor is an OV7645");
 				sd->sensor = SEN_OV7640; /* FIXME */
@@ -1038,32 +1226,6 @@
 		return -1;
 	}
 
-	switch (sd->sensor) {
-	case SEN_OV7620:
-		PDEBUG(D_PROBE, "Writing 7620 registers");
-		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
-			return -1;
-		break;
-	case SEN_OV7630:
-		PDEBUG(D_ERR, "7630 is not supported by this driver version");
-		return -1;
-	case SEN_OV7640:
-		PDEBUG(D_PROBE, "Writing 7640 registers");
-		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
-			return -1;
-		break;
-	case SEN_OV7670:
-		PDEBUG(D_PROBE, "Writing 7670 registers");
-		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
-			return -1;
-		break;
-	default:
-		PDEBUG(D_PROBE, "Writing 7610 registers");
-		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
-			return -1;
-		break;
-	}
-
 	/* Set sensor-specific vars */
 /*	sd->sif = 0;		already done */
 	return 0;
@@ -1073,141 +1235,7 @@
 static int ov6xx0_configure(struct sd *sd)
 {
 	int rc;
-	static const struct ov_i2c_regvals norm_6x20[] = {
-		{ 0x12, 0x80 }, /* reset */
-		{ 0x11, 0x01 },
-		{ 0x03, 0x60 },
-		{ 0x05, 0x7f }, /* For when autoadjust is off */
-		{ 0x07, 0xa8 },
-		/* The ratio of 0x0c and 0x0d  controls the white point */
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-		{ 0x0f, 0x15 }, /* COMS */
-		{ 0x10, 0x75 }, /* AEC Exposure time */
-		{ 0x12, 0x24 }, /* Enable AGC */
-		{ 0x14, 0x04 },
-		/* 0x16: 0x06 helps frame stability with moving objects */
-		{ 0x16, 0x06 },
-/*		{ 0x20, 0x30 },  * Aperture correction enable */
-		{ 0x26, 0xb2 }, /* BLC enable */
-		/* 0x28: 0x05 Selects RGB format if RGB on */
-		{ 0x28, 0x05 },
-		{ 0x2a, 0x04 }, /* Disable framerate adjust */
-/*		{ 0x2b, 0xac },  * Framerate; Set 2a[7] first */
-		{ 0x2d, 0x99 },
-		{ 0x33, 0xa0 }, /* Color Processing Parameter */
-		{ 0x34, 0xd2 }, /* Max A/D range */
-		{ 0x38, 0x8b },
-		{ 0x39, 0x40 },
-
-		{ 0x3c, 0x39 }, /* Enable AEC mode changing */
-		{ 0x3c, 0x3c }, /* Change AEC mode */
-		{ 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-		{ 0x3d, 0x80 },
-		/* These next two registers (0x4a, 0x4b) are undocumented.
-		 * They control the color balance */
-		{ 0x4a, 0x80 },
-		{ 0x4b, 0x80 },
-		{ 0x4d, 0xd2 }, /* This reduces noise a bit */
-		{ 0x4e, 0xc1 },
-		{ 0x4f, 0x04 },
-/* Do 50-53 have any effect? */
-/* Toggle 0x12[2] off and on here? */
-	};
-
-	static const struct ov_i2c_regvals norm_6x30[] = {
-		{ 0x12, 0x80 }, /* Reset */
-		{ 0x00, 0x1f }, /* Gain */
-		{ 0x01, 0x99 }, /* Blue gain */
-		{ 0x02, 0x7c }, /* Red gain */
-		{ 0x03, 0xc0 }, /* Saturation */
-		{ 0x05, 0x0a }, /* Contrast */
-		{ 0x06, 0x95 }, /* Brightness */
-		{ 0x07, 0x2d }, /* Sharpness */
-		{ 0x0c, 0x20 },
-		{ 0x0d, 0x20 },
-		{ 0x0e, 0x20 },
-		{ 0x0f, 0x05 },
-		{ 0x10, 0x9a },
-		{ 0x11, 0x00 }, /* Pixel clock = fastest */
-		{ 0x12, 0x24 }, /* Enable AGC and AWB */
-		{ 0x13, 0x21 },
-		{ 0x14, 0x80 },
-		{ 0x15, 0x01 },
-		{ 0x16, 0x03 },
-		{ 0x17, 0x38 },
-		{ 0x18, 0xea },
-		{ 0x19, 0x04 },
-		{ 0x1a, 0x93 },
-		{ 0x1b, 0x00 },
-		{ 0x1e, 0xc4 },
-		{ 0x1f, 0x04 },
-		{ 0x20, 0x20 },
-		{ 0x21, 0x10 },
-		{ 0x22, 0x88 },
-		{ 0x23, 0xc0 }, /* Crystal circuit power level */
-		{ 0x25, 0x9a }, /* Increase AEC black ratio */
-		{ 0x26, 0xb2 }, /* BLC enable */
-		{ 0x27, 0xa2 },
-		{ 0x28, 0x00 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x84 }, /* 60 Hz power */
-		{ 0x2b, 0xa8 }, /* 60 Hz power */
-		{ 0x2c, 0xa0 },
-		{ 0x2d, 0x95 }, /* Enable auto-brightness */
-		{ 0x2e, 0x88 },
-		{ 0x33, 0x26 },
-		{ 0x34, 0x03 },
-		{ 0x36, 0x8f },
-		{ 0x37, 0x80 },
-		{ 0x38, 0x83 },
-		{ 0x39, 0x80 },
-		{ 0x3a, 0x0f },
-		{ 0x3b, 0x3c },
-		{ 0x3c, 0x1a },
-		{ 0x3d, 0x80 },
-		{ 0x3e, 0x80 },
-		{ 0x3f, 0x0e },
-		{ 0x40, 0x00 }, /* White bal */
-		{ 0x41, 0x00 }, /* White bal */
-		{ 0x42, 0x80 },
-		{ 0x43, 0x3f }, /* White bal */
-		{ 0x44, 0x80 },
-		{ 0x45, 0x20 },
-		{ 0x46, 0x20 },
-		{ 0x47, 0x80 },
-		{ 0x48, 0x7f },
-		{ 0x49, 0x00 },
-		{ 0x4a, 0x00 },
-		{ 0x4b, 0x80 },
-		{ 0x4c, 0xd0 },
-		{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-		{ 0x4e, 0x40 },
-		{ 0x4f, 0x07 }, /* UV avg., col. killer: max */
-		{ 0x50, 0xff },
-		{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
-		{ 0x55, 0xff },
-		{ 0x56, 0x12 },
-		{ 0x57, 0x81 },
-		{ 0x58, 0x75 },
-		{ 0x59, 0x01 }, /* AGC dark current comp.: +1 */
-		{ 0x5a, 0x2c },
-		{ 0x5b, 0x0f }, /* AWB chrominance levels */
-		{ 0x5c, 0x10 },
-		{ 0x3d, 0x80 },
-		{ 0x27, 0xa6 },
-		{ 0x12, 0x20 }, /* Toggle AWB */
-		{ 0x12, 0x24 },
-	};
-
-	PDEBUG(D_PROBE, "starting sensor configuration");
-
-	if (init_ov_sensor(sd) < 0) {
-		PDEBUG(D_ERR, "Failed to read sensor ID.");
-		return -1;
-	}
-	PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+	PDEBUG(D_PROBE, "starting OV6xx0 configuration");
 
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
@@ -1251,15 +1279,6 @@
 	/* Set sensor-specific vars */
 	sd->sif = 1;
 
-	if (sd->sensor == SEN_OV6620) {
-		PDEBUG(D_PROBE, "Writing 6x20 registers");
-		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
-			return -1;
-	} else {
-		PDEBUG(D_PROBE, "Writing 6x30 registers");
-		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
-			return -1;
-	}
 	return 0;
 }
 
@@ -1298,22 +1317,31 @@
 	ov51x_led_control(sd, 0);	/* turn LED off */
 
 	/* Test for 76xx */
-	sd->primary_i2c_slave = OV7xx0_SID;
 	if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
 		goto error;
 
 	/* The OV519 must be more aggressive about sensor detection since
 	 * I2C write will never fail if the sensor is not present. We have
 	 * to try to initialize the sensor to detect its presence */
-	if (init_ov_sensor(sd) < 0) {
+	if (init_ov_sensor(sd) >= 0) {
+		if (ov7xx0_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure OV7xx0");
+			goto error;
+		}
+	} else {
+
 		/* Test for 6xx0 */
-		sd->primary_i2c_slave = OV6xx0_SID;
 		if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
 			goto error;
 
-		if (init_ov_sensor(sd) < 0) {
+		if (init_ov_sensor(sd) >= 0) {
+			if (ov6xx0_configure(sd) < 0) {
+				PDEBUG(D_ERR, "Failed to configure OV6xx0");
+				goto error;
+			}
+		} else {
+
 			/* Test for 8xx0 */
-			sd->primary_i2c_slave = OV8xx0_SID;
 			if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
 				goto error;
 
@@ -1321,24 +1349,13 @@
 				PDEBUG(D_ERR,
 					"Can't determine sensor slave IDs");
 				goto error;
-			} else {
-				if (ov8xx0_configure(sd) < 0) {
-					PDEBUG(D_ERR,
-					   "Failed to configure OV8xx0 sensor");
-					goto error;
-				}
 			}
-		} else {
-			if (ov6xx0_configure(sd) < 0) {
-				PDEBUG(D_ERR, "Failed to configure OV6xx0");
+			if (ov8xx0_configure(sd) < 0) {
+				PDEBUG(D_ERR,
+				   "Failed to configure OV8xx0 sensor");
 				goto error;
 			}
 		}
-	} else {
-		if (ov7xx0_configure(sd) < 0) {
-			PDEBUG(D_ERR, "Failed to configure OV7xx0");
-			goto error;
-		}
 	}
 
 	cam = &gspca_dev->cam;
@@ -1355,15 +1372,53 @@
 	sd->colors = COLOR_DEF;
 	sd->hflip = HFLIP_DEF;
 	sd->vflip = VFLIP_DEF;
+	if (sd->sensor != SEN_OV7670)
+		gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+					| (1 << VFLIP_IDX);
 	return 0;
 error:
 	PDEBUG(D_ERR, "OV519 Config failed");
 	return -EBUSY;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* initialize the sensor */
+	switch (sd->sensor) {
+	case SEN_OV6620:
+		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
+			return -EIO;
+		break;
+	case SEN_OV6630:
+		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
+			return -EIO;
+		break;
+	default:
+/*	case SEN_OV7610: */
+/*	case SEN_OV76BE: */
+		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
+			return -EIO;
+		break;
+	case SEN_OV7620:
+		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
+			return -EIO;
+		break;
+	case SEN_OV7640:
+		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
+			return -EIO;
+		break;
+	case SEN_OV7670:
+		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
+			return -EIO;
+		break;
+	case SEN_OV8610:
+		if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
+			return -EIO;
+		break;
+	}
 	return 0;
 }
 
@@ -1827,14 +1882,6 @@
 	ov51x_led_control((struct sd *) gspca_dev, 0);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -2091,11 +2138,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -2132,6 +2177,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 7ef18d5..83b5f74 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -56,12 +56,6 @@
 #define PAC207_GAIN_KNEE		20
 
 #define PAC207_AUTOGAIN_DEADZONE	30
-/* We calculating the autogain at the end of the transfer of a frame, at this
-   moment a frame with the old settings is being transmitted, and a frame is
-   being captured with the old settings. So if we adjust the autogain we must
-   ignore atleast the 2 next frames for the new settings to come into effect
-   before doing any other adjustments */
-#define PAC207_AUTOGAIN_IGNORE_FRAMES	3
 
 /* specific webcam descriptor */
 struct sd {
@@ -131,7 +125,8 @@
 		.minimum = 0,
 		.maximum = 1,
 		.step	= 1,
-		.default_value = 1,
+#define AUTOGAIN_DEF 1
+		.default_value = AUTOGAIN_DEF,
 		.flags = 0,
 	    },
 	    .set = sd_setautogain,
@@ -181,9 +176,6 @@
 			/* 48 reg_72 Rate Control end BalSize_4a =0x36 */
 static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
 
-static const unsigned char pac207_sof_marker[5] =
-		{ 0xff, 0xff, 0x00, 0xff, 0x96 };
-
 static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
 	const u8 *buffer, u16 length)
 {
@@ -259,6 +251,25 @@
 		return -ENODEV;
 	}
 
+	PDEBUG(D_PROBE,
+		"Pixart PAC207BCA Image Processor and Control Chip detected"
+		" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+
+	cam = &gspca_dev->cam;
+	cam->epaddr = 0x05;
+	cam->cam_mode = sif_mode;
+	cam->nmodes = ARRAY_SIZE(sif_mode);
+	sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
+	sd->exposure = PAC207_EXPOSURE_DEFAULT;
+	sd->gain = PAC207_GAIN_DEFAULT;
+	sd->autogain = AUTOGAIN_DEF;
+
+	return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
 	pac207_write_reg(gspca_dev, 0x41, 0x00);
 				/* Bit_0=Image Format,
 				 * Bit_1=LED,
@@ -266,28 +277,6 @@
 	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 	pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
 
-	PDEBUG(D_PROBE,
-		"Pixart PAC207BCA Image Processor and Control Chip detected"
-		" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
-
-	cam = &gspca_dev->cam;
-	cam->dev_name = (char *) id->driver_info;
-	cam->epaddr = 0x05;
-	cam->cam_mode = sif_mode;
-	cam->nmodes = ARRAY_SIZE(sif_mode);
-	sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
-	sd->exposure = PAC207_EXPOSURE_DEFAULT;
-	sd->gain = PAC207_GAIN_DEFAULT;
-
-	return 0;
-}
-
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	sd->autogain = 1;
 	return 0;
 }
 
@@ -343,14 +332,8 @@
 	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 {
@@ -365,33 +348,7 @@
 	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
 			100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
 			PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
-		sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
-}
-
-static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
-					unsigned char *m, int len)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-
-	/* Search for the SOF marker (fixed part) in the header */
-	for (i = 0; i < len; i++) {
-		if (m[i] == pac207_sof_marker[sd->sof_read]) {
-			sd->sof_read++;
-			if (sd->sof_read == sizeof(pac207_sof_marker)) {
-				PDEBUG(D_STREAM,
-					"SOF found, bytes to analyze: %u."
-					" Frame starts at byte #%u",
-					len, i + 1);
-				sd->sof_read = 0;
-				return m + i + 1;
-			}
-		} else {
-			sd->sof_read = 0;
-		}
-	}
-
-	return NULL;
+		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -402,14 +359,14 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned char *sof;
 
-	sof = pac207_find_sof(gspca_dev, data, len);
+	sof = pac_find_sof(gspca_dev, data, len);
 	if (sof) {
 		int n;
 
 		/* finish decoding current frame */
 		n = sof - data;
-		if (n > sizeof pac207_sof_marker)
-			n -= sizeof pac207_sof_marker;
+		if (n > sizeof pac_sof_marker)
+			n -= sizeof pac_sof_marker;
 		else
 			n = 0;
 		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -537,7 +494,7 @@
 		sd->gain = PAC207_GAIN_DEFAULT;
 		if (gspca_dev->streaming) {
 			sd->autogain_ignore_frames =
-				PAC207_AUTOGAIN_IGNORE_FRAMES;
+				PAC_AUTOGAIN_IGNORE_FRAMES;
 			setexposure(gspca_dev);
 			setgain(gspca_dev);
 		}
@@ -560,11 +517,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.dq_callback = pac207_do_auto_gain,
 	.pkt_scan = sd_pkt_scan,
 };
@@ -597,6 +552,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 815bea6..d4be518 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -19,6 +19,36 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+/* Some documentation about various registers as determined by trial and error.
+   When the register addresses differ between the 7202 and the 7311 the 2
+   different addresses are written as 7302addr/7311addr, when one of the 2
+   addresses is a - sign that register description is not valid for the
+   matching IC.
+
+   Register page 1:
+
+   Address	Description
+   -/0x08	Unknown compressor related, must always be 8 except when not
+		in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+   -/0x1b	Auto white balance related, bit 0 is AWB enable (inverted)
+		bits 345 seem to toggle per color gains on/off (inverted)
+   0x78		Global control, bit 6 controls the LED (inverted)
+   -/0x80	JPEG compression ratio ? Best not touched
+
+   Register page 3/4:
+
+   Address	Description
+   0x02		Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+		the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+   -/0x0f	Master gain 1-245, low value = high gain
+   0x10/-	Master gain 0-31
+   -/0x10	Another gain 0-15, limited influence (1-2x gain I guess)
+   0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+   -/0x27	Seems to toggle various gains on / off, Setting bit 7 seems to
+		completely disable the analog amplification block. Set to 0x68
+		for max gain, 0x14 for minimal gain.
+*/
+
 #define MODULE_NAME "pac7311"
 
 #include "gspca.h"
@@ -31,18 +61,23 @@
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
-	int lum_sum;
-	atomic_t avg_lum;
-	atomic_t do_gain;
-
 	unsigned char brightness;
 	unsigned char contrast;
 	unsigned char colors;
+	unsigned char gain;
+	unsigned char exposure;
 	unsigned char autogain;
+	__u8 hflip;
+	__u8 vflip;
 
-	char ffseq;
-	signed char ag_cnt;
-#define AG_CNT_START 13
+	__u8 sensor;
+#define SENSOR_PAC7302 0
+#define SENSOR_PAC7311 1
+
+	u8 sof_read;
+	u8 autogain_ignore_frames;
+
+	atomic_t avg_lum;
 };
 
 /* V4L2 controls supported by the driver */
@@ -54,8 +89,18 @@
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+#define BRIGHTNESS_IDX 0
 	{
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
@@ -71,13 +116,15 @@
 	    .set = sd_setbrightness,
 	    .get = sd_getbrightness,
 	},
+/* This control is for both the 7302 and the 7311 */
 	{
 	    {
 		.id      = V4L2_CID_CONTRAST,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Contrast",
 		.minimum = 0,
-		.maximum = 255,
+#define CONTRAST_MAX 255
+		.maximum = CONTRAST_MAX,
 		.step    = 1,
 #define CONTRAST_DEF 127
 		.default_value = CONTRAST_DEF,
@@ -85,13 +132,16 @@
 	    .set = sd_setcontrast,
 	    .get = sd_getcontrast,
 	},
+/* This control is pac7302 only */
+#define SATURATION_IDX 2
 	{
 	    {
 		.id      = V4L2_CID_SATURATION,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Color",
+		.name    = "Saturation",
 		.minimum = 0,
-		.maximum = 255,
+#define COLOR_MAX 255
+		.maximum = COLOR_MAX,
 		.step    = 1,
 #define COLOR_DEF 127
 		.default_value = COLOR_DEF,
@@ -99,6 +149,39 @@
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+/* All controls below are for both the 7302 and the 7311 */
+	{
+	    {
+		.id      = V4L2_CID_GAIN,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gain",
+		.minimum = 0,
+#define GAIN_MAX 255
+		.maximum = GAIN_MAX,
+		.step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+	{
+	    {
+		.id      = V4L2_CID_EXPOSURE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Exposure",
+		.minimum = 0,
+#define EXPOSURE_MAX 255
+		.maximum = EXPOSURE_MAX,
+		.step    = 1,
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+		.default_value = EXPOSURE_DEF,
+	    },
+	    .set = sd_setexposure,
+	    .get = sd_getexposure,
+	},
 	{
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -113,101 +196,207 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+	{
+	    {
+		.id      = V4L2_CID_HFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Mirror",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define HFLIP_DEF 0
+		.default_value = HFLIP_DEF,
+	    },
+	    .set = sd_sethflip,
+	    .get = sd_gethflip,
+	},
+	{
+	    {
+		.id      = V4L2_CID_VFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Vflip",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define VFLIP_DEF 0
+		.default_value = VFLIP_DEF,
+	    },
+	    .set = sd_setvflip,
+	    .get = sd_getvflip,
+	},
 };
 
 static struct v4l2_pix_format vga_mode[] = {
-	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	{160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
 		.sizeimage = 160 * 120 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 2},
-	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	{320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
 		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 1},
-	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+	{640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
 		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 0},
 };
 
-#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header)	/* (594) */
+/* pac 7302 */
+static const __u8 init_7302[] = {
+/*	index,value */
+	0xff, 0x01,		/* page 1 */
+	0x78, 0x00,		/* deactivate */
+	0xff, 0x01,
+	0x78, 0x40,		/* led off */
+};
+static const __u8 start_7302[] = {
+/*	index, len, [value]* */
+	0xff, 1,	0x00,		/* page 0 */
+	0x00, 12,	0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
+			0x00, 0x00, 0x00, 0x00,
+	0x0d, 24,	0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
+			0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
+			0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
+	0x26, 2,	0xaa, 0xaa,
+	0x2e, 1,	0x31,
+	0x38, 1,	0x01,
+	0x3a, 3,	0x14, 0xff, 0x5a,
+	0x43, 11,	0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
+			0x00, 0x54, 0x11,
+	0x55, 1,	0x00,
+	0x62, 4, 	0x10, 0x1e, 0x1e, 0x18,
+	0x6b, 1,	0x00,
+	0x6e, 3,	0x08, 0x06, 0x00,
+	0x72, 3,	0x00, 0xff, 0x00,
+	0x7d, 23,	0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
+			0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
+			0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
+	0xa2, 10,	0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
+			0xd2, 0xeb,
+	0xaf, 1,	0x02,
+	0xb5, 2,	0x08, 0x08,
+	0xb8, 2,	0x08, 0x88,
+	0xc4, 4,	0xae, 0x01, 0x04, 0x01,
+	0xcc, 1,	0x00,
+	0xd1, 11,	0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
+			0xc1, 0xd7, 0xec,
+	0xdc, 1,	0x01,
+	0xff, 1,	0x01,		/* page 1 */
+	0x12, 3,	0x02, 0x00, 0x01,
+	0x3e, 2,	0x00, 0x00,
+	0x76, 5,	0x01, 0x20, 0x40, 0x00, 0xf2,
+	0x7c, 1,	0x00,
+	0x7f, 10,	0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
+			0x02, 0x00,
+	0x96, 5,	0x01, 0x10, 0x04, 0x01, 0x04,
+	0xc8, 14,	0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+			0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
+	0xd8, 1,	0x01,
+	0xdb, 2,	0x00, 0x01,
+	0xde, 7,	0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
+	0xe6, 4,	0x00, 0x00, 0x00, 0x01,
+	0xeb, 1,	0x00,
+	0xff, 1,	0x02,		/* page 2 */
+	0x22, 1,	0x00,
+	0xff, 1,	0x03,		/* page 3 */
+	0x00, 255,			/* load the page 3 */
+	0x11, 1,	0x01,
+	0xff, 1,	0x02,		/* page 2 */
+	0x13, 1,	0x00,
+	0x22, 4,	0x1f, 0xa4, 0xf0, 0x96,
+	0x27, 2,	0x14, 0x0c,
+	0x2a, 5,	0xc8, 0x00, 0x18, 0x12, 0x22,
+	0x64, 8,	0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
+	0x6e, 1,	0x08,
+	0xff, 1,	0x01,		/* page 1 */
+	0x78, 1,	0x00,
+	0, 0				/* end of sequence */
+};
 
-static const __u8 pac7311_jpeg_header[] = {
-	0xff, 0xd8,
-	0xff, 0xe0, 0x00, 0x03, 0x20,
-	0xff, 0xc0, 0x00, 0x11, 0x08,
-		0x01, 0xe0,			/* 12: height */
-		0x02, 0x80,			/* 14: width */
-		0x03,				/* 16 */
-			0x01, 0x21, 0x00,
-			0x02, 0x11, 0x01,
-			0x03, 0x11, 0x01,
-	0xff, 0xdb, 0x00, 0x84,
-	0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
-	0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
-	0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
-	0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
-	0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
-	0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
-	0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
-	0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
-	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-	0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-	0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
-	0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-	0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
-	0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
-	0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
-	0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
-	0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
-	0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
-	0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
-	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
-	0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
-	0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
-	0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
-	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
-	0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
-	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-	0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
-	0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
-	0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
-	0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
-	0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
-	0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
-	0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
-	0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
-	0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
-	0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
-	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
-	0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
-	0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
-	0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
-	0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
-	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
-	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
-	0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
-	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-	0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
-	0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
-	0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
-	0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
-	0x11, 0x00, 0x3f, 0x00
+/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page3_7302[] = {
+	0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+	0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
+	0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
+	0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
+	0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
+	0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
+	0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+	0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
+	0x00
+};
+
+/* pac 7311 */
+static const __u8 init_7311[] = {
+	0x78, 0x40,	/* Bit_0=start stream, Bit_6=LED */
+	0x78, 0x40,	/* Bit_0=start stream, Bit_6=LED */
+	0x78, 0x44,	/* Bit_0=start stream, Bit_6=LED */
+	0xff, 0x04,
+	0x27, 0x80,
+	0x28, 0xca,
+	0x29, 0x53,
+	0x2a, 0x0e,
+	0xff, 0x01,
+	0x3e, 0x20,
+};
+
+static const __u8 start_7311[] = {
+/*	index, len, [value]* */
+	0xff, 1,	0x01,		/* page 1 */
+	0x02, 43,	0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
+			0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
+			0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
+			0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00,
+	0x3e, 42,	0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
+			0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
+			0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
+			0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
+			0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
+			0xd0, 0xff,
+	0x78, 6,	0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
+	0x7f, 18,	0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
+			0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
+			0x18, 0x20,
+	0x96, 3,	0x01, 0x08, 0x04,
+	0xa0, 4,	0x44, 0x44, 0x44, 0x04,
+	0xf0, 13,	0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
+			0x3f, 0x00, 0x0a, 0x01, 0x00,
+	0xff, 1,	0x04,		/* page 4 */
+	0x00, 254,			/* load the page 4 */
+	0x11, 1,	0x01,
+	0, 0				/* end of sequence */
+};
+
+/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page4_7311[] = {
+	0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
+	0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
+	0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
+	0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
+	0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
+	0x23, 0x28, 0x04, 0x11, 0x00, 0x00
 };
 
 static void reg_w_buf(struct gspca_dev *gspca_dev,
-		  __u16 index,
-		  const char *buffer, __u16 len)
+		  __u8 index,
+		  const char *buffer, int len)
 {
 	memcpy(gspca_dev->usb_buf, buffer, len);
 	usb_control_msg(gspca_dev->dev,
@@ -219,21 +408,9 @@
 			500);
 }
 
-static __u8 reg_r(struct gspca_dev *gspca_dev,
-			     __u16 index)
-{
-	usb_control_msg(gspca_dev->dev,
-			usb_rcvctrlpipe(gspca_dev->dev, 0),
-			0,			/* request */
-			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			0,			/* value */
-			index, gspca_dev->usb_buf, 1,
-			500);
-	return gspca_dev->usb_buf[0];
-}
 
 static void reg_w(struct gspca_dev *gspca_dev,
-		  __u16 index,
+		  __u8 index,
 		  __u8 value)
 {
 	gspca_dev->usb_buf[0] = value;
@@ -241,10 +418,78 @@
 			usb_sndctrlpipe(gspca_dev->dev, 0),
 			0,			/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, index, gspca_dev->usb_buf, 1,
+			0, index, gspca_dev->usb_buf, 1,
 			500);
 }
 
+static void reg_w_seq(struct gspca_dev *gspca_dev,
+		const __u8 *seq, int len)
+{
+	while (--len >= 0) {
+		reg_w(gspca_dev, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+/* load the beginning of a page */
+static void reg_w_page(struct gspca_dev *gspca_dev,
+			const __u8 *page, int len)
+{
+	int index;
+
+	for (index = 0; index < len; index++) {
+		if (page[index] == 0xaa)		/* skip this index */
+			continue;
+		gspca_dev->usb_buf[0] = page[index];
+		usb_control_msg(gspca_dev->dev,
+				usb_sndctrlpipe(gspca_dev->dev, 0),
+				0,			/* request */
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				0, index, gspca_dev->usb_buf, 1,
+				500);
+	}
+}
+
+/* output a variable sequence */
+static void reg_w_var(struct gspca_dev *gspca_dev,
+			const __u8 *seq)
+{
+	int index, len;
+
+	for (;;) {
+		index = *seq++;
+		len = *seq++;
+		switch (len) {
+		case 0:
+			return;
+		case 254:
+			reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
+			break;
+		case 255:
+			reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
+			break;
+		default:
+			if (len > 64) {
+				PDEBUG(D_ERR|D_STREAM,
+					"Incorrect variable sequence");
+				return;
+			}
+			while (len > 0) {
+				if (len < 8) {
+					reg_w_buf(gspca_dev, index, seq, len);
+					seq += len;
+					break;
+				}
+				reg_w_buf(gspca_dev, index, seq, 8);
+				seq += 8;
+				index += 8;
+				len -= 8;
+			}
+		}
+	}
+	/* not reached */
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 			const struct usb_device_id *id)
@@ -252,203 +497,245 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
 
-	PDEBUG(D_CONF, "Find Sensor PAC7311");
-	reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x27, 0x80);
-	reg_w(gspca_dev, 0x28, 0xca);
-	reg_w(gspca_dev, 0x29, 0x53);
-	reg_w(gspca_dev, 0x2a, 0x0e);
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x3e, 0x20);
-
 	cam = &gspca_dev->cam;
 	cam->epaddr = 0x05;
-	cam->cam_mode = vga_mode;
-	cam->nmodes = ARRAY_SIZE(vga_mode);
+
+	sd->sensor = id->driver_info;
+	if (sd->sensor == SENSOR_PAC7302) {
+		PDEBUG(D_CONF, "Find Sensor PAC7302");
+		cam->cam_mode = &vga_mode[2];	/* only 640x480 */
+		cam->nmodes = 1;
+	} else {
+		PDEBUG(D_CONF, "Find Sensor PAC7311");
+		cam->cam_mode = vga_mode;
+		cam->nmodes = ARRAY_SIZE(vga_mode);
+		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
+				| (1 << SATURATION_IDX);
+	}
 
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
 	sd->colors = COLOR_DEF;
+	sd->gain = GAIN_DEF;
+	sd->exposure = EXPOSURE_DEF;
 	sd->autogain = AUTOGAIN_DEF;
-	sd->ag_cnt = -1;
+	sd->hflip = HFLIP_DEF;
+	sd->vflip = VFLIP_DEF;
 	return 0;
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int brightness;
+	int i, v;
+	static const __u8 max[10] =
+		{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
+		 0xd4, 0xec};
+	static const __u8 delta[10] =
+		{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
+		 0x11, 0x0b};
 
-/*jfm: inverted?*/
-	brightness = BRIGHTNESS_MAX - sd->brightness;
-	reg_w(gspca_dev, 0xff, 0x04);
-/*	reg_w(gspca_dev, 0x0e, 0x00); */
-	reg_w(gspca_dev, 0x0f, brightness);
-	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
+	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	for (i = 0; i < 10; i++) {
+		v = max[i];
+		v += (sd->brightness - BRIGHTNESS_MAX)
+			* 150 / BRIGHTNESS_MAX;		/* 200 ? */
+		v -= delta[i] * sd->contrast / CONTRAST_MAX;
+		if (v < 0)
+			v = 0;
+		else if (v > 0xff)
+			v = 0xff;
+		reg_w(gspca_dev, 0xa2 + i, v);
+	}
+	reg_w(gspca_dev, 0xdc, 0x01);
 }
 
+/* This function is used by pac7311 only */
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x80, sd->contrast);
+	reg_w(gspca_dev, 0xff, 0x04);
+	reg_w(gspca_dev, 0x10, sd->contrast >> 4);
 	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
 }
 
+/* This function is used by pac7302 only */
 static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int i, v;
+	static const int a[9] =
+		{217, -212, 0, -101, 170, -67, -38, -315, 355};
+	static const int b[9] =
+		{19, 106, 0, 19, 106, 1, 19, 106, 1};
 
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x10, sd->colors);
-	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */
 	reg_w(gspca_dev, 0x11, 0x01);
+	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	for (i = 0; i < 9; i++) {
+		v = a[i] * sd->colors / COLOR_MAX + b[i];
+		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+	}
+	reg_w(gspca_dev, 0xdc, 0x01);
 	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->autogain) {
-		sd->lum_sum = 0;
-		sd->ag_cnt = AG_CNT_START;
+	if (sd->sensor == SENSOR_PAC7302) {
+		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+		reg_w(gspca_dev, 0x10, sd->gain >> 3);
 	} else {
-		sd->ag_cnt = -1;
+		int gain = GAIN_MAX - sd->gain;
+		if (gain < 1)
+			gain = 1;
+		else if (gain > 245)
+			gain = 245;
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+		reg_w(gspca_dev, 0x0e, 0x00);
+		reg_w(gspca_dev, 0x0f, gain);
 	}
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
 {
-	reg_w(gspca_dev, 0x78, 0x00);	/* Turn on LED */
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 reg;
+
+	/* register 2 of frame 3/4 contains the clock divider configuring the
+	   no fps according to the formula: 60 / reg. sd->exposure is the
+	   desired exposure time in ms. */
+	reg = 120 * sd->exposure / 1000;
+	if (reg < 2)
+		reg = 2;
+	else if (reg > 63)
+		reg = 63;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		/* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+		   the nearest multiple of 3, except when between 6 and 12? */
+		if (reg < 6 || reg > 12)
+			reg = ((reg + 1) / 3) * 3;
+		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+		reg_w(gspca_dev, 0x02, reg);
+	} else {
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+		reg_w(gspca_dev, 0x02, reg);
+		/* Page 1 register 8 must always be 0x08 except when not in
+		   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+		reg_w(gspca_dev, 0xff, 0x01);
+		if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+				reg <= 3)
+			reg_w(gspca_dev, 0x08, 0x09);
+		else
+			reg_w(gspca_dev, 0x08, 0x08);
+	}
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+}
+
+static void sethvflip(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+		data = (sd->hflip ? 0x08 : 0x00)
+			| (sd->vflip ? 0x04 : 0x00);
+	} else {
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+		data = (sd->hflip ? 0x04 : 0x00)
+			| (sd->vflip ? 0x08 : 0x00);
+	}
+	reg_w(gspca_dev, 0x21, data);
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAC7302)
+		reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
+	else
+		reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
+
 	return 0;
 }
 
 static void sd_start(struct gspca_dev *gspca_dev)
 {
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
-	reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
-	reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
-	reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
-	reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
-	reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
-	reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
-	reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
-	reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
-	reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
-	reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
-	reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
-	reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
-	reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
-	reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
-	reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
-	reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
-	reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
-	reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
-	reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x02, 0x04);
-	reg_w(gspca_dev, 0x03, 0x54);
-	reg_w(gspca_dev, 0x04, 0x07);
-	reg_w(gspca_dev, 0x05, 0x2b);
-	reg_w(gspca_dev, 0x06, 0x09);
-	reg_w(gspca_dev, 0x07, 0x0f);
-	reg_w(gspca_dev, 0x08, 0x09);
-	reg_w(gspca_dev, 0x09, 0x00);
-	reg_w(gspca_dev, 0x0c, 0x07);
-	reg_w(gspca_dev, 0x0d, 0x00);
-	reg_w(gspca_dev, 0x0e, 0x00);
-	reg_w(gspca_dev, 0x0f, 0x62);
-	reg_w(gspca_dev, 0x10, 0x08);
-	reg_w(gspca_dev, 0x12, 0x07);
-	reg_w(gspca_dev, 0x13, 0x00);
-	reg_w(gspca_dev, 0x14, 0x00);
-	reg_w(gspca_dev, 0x15, 0x00);
-	reg_w(gspca_dev, 0x16, 0x00);
-	reg_w(gspca_dev, 0x17, 0x00);
-	reg_w(gspca_dev, 0x18, 0x00);
-	reg_w(gspca_dev, 0x19, 0x00);
-	reg_w(gspca_dev, 0x1a, 0x00);
-	reg_w(gspca_dev, 0x1b, 0x03);
-	reg_w(gspca_dev, 0x1c, 0xa0);
-	reg_w(gspca_dev, 0x1d, 0x01);
-	reg_w(gspca_dev, 0x1e, 0xf4);
-	reg_w(gspca_dev, 0x21, 0x00);
-	reg_w(gspca_dev, 0x22, 0x08);
-	reg_w(gspca_dev, 0x24, 0x03);
-	reg_w(gspca_dev, 0x26, 0x00);
-	reg_w(gspca_dev, 0x27, 0x01);
-	reg_w(gspca_dev, 0x28, 0xca);
-	reg_w(gspca_dev, 0x29, 0x10);
-	reg_w(gspca_dev, 0x2a, 0x06);
-	reg_w(gspca_dev, 0x2b, 0x78);
-	reg_w(gspca_dev, 0x2c, 0x00);
-	reg_w(gspca_dev, 0x2d, 0x00);
-	reg_w(gspca_dev, 0x2e, 0x00);
-	reg_w(gspca_dev, 0x2f, 0x00);
-	reg_w(gspca_dev, 0x30, 0x23);
-	reg_w(gspca_dev, 0x31, 0x28);
-	reg_w(gspca_dev, 0x32, 0x04);
-	reg_w(gspca_dev, 0x33, 0x11);
-	reg_w(gspca_dev, 0x34, 0x00);
-	reg_w(gspca_dev, 0x35, 0x00);
-	reg_w(gspca_dev, 0x11, 0x01);
-	setcontrast(gspca_dev);
-	setbrightness(gspca_dev);
-	setcolors(gspca_dev);
-	setautogain(gspca_dev);
+	sd->sof_read = 0;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		reg_w_var(gspca_dev, start_7302);
+		setbrightcont(gspca_dev);
+		setcolors(gspca_dev);
+	} else {
+		reg_w_var(gspca_dev, start_7311);
+		setcontrast(gspca_dev);
+	}
+	setgain(gspca_dev);
+	setexposure(gspca_dev);
+	sethvflip(gspca_dev);
 
 	/* set correct resolution */
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
-	case 2:					/* 160x120 */
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x03);
+	case 2:					/* 160x120 pac7311 */
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x09);
 		reg_w(gspca_dev, 0x17, 0x20);
-		reg_w(gspca_dev, 0x1b, 0x00);
-/*		reg_w(gspca_dev, 0x80, 0x69); */
 		reg_w(gspca_dev, 0x87, 0x10);
 		break;
-	case 1:					/* 320x240 */
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x03);
+	case 1:					/* 320x240 pac7311 */
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x09);
 		reg_w(gspca_dev, 0x17, 0x30);
-/*		reg_w(gspca_dev, 0x80, 0x3f); */
 		reg_w(gspca_dev, 0x87, 0x11);
 		break;
 	case 0:					/* 640x480 */
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x03);
+		if (sd->sensor == SENSOR_PAC7302)
+			break;
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x08);
 		reg_w(gspca_dev, 0x17, 0x00);
-/*		reg_w(gspca_dev, 0x80, 0x1c); */
 		reg_w(gspca_dev, 0x87, 0x12);
 		break;
 	}
 
+	sd->sof_read = 0;
+	sd->autogain_ignore_frames = 0;
+	atomic_set(&sd->avg_lum, -1);
+
 	/* start stream */
 	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x78, 0x04);
-	reg_w(gspca_dev, 0x78, 0x05);
+	if (sd->sensor == SENSOR_PAC7302)
+		reg_w(gspca_dev, 0x78, 0x01);
+	else
+		reg_w(gspca_dev, 0x78, 0x05);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		reg_w(gspca_dev, 0xff, 0x01);
+		reg_w(gspca_dev, 0x78, 0x00);
+		reg_w(gspca_dev, 0x78, 0x00);
+		return;
+	}
 	reg_w(gspca_dev, 0xff, 0x04);
 	reg_w(gspca_dev, 0x27, 0x80);
 	reg_w(gspca_dev, 0x28, 0xca);
@@ -456,187 +743,147 @@
 	reg_w(gspca_dev, 0x2a, 0x0e);
 	reg_w(gspca_dev, 0xff, 0x01);
 	reg_w(gspca_dev, 0x3e, 0x20);
-	reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		reg_w(gspca_dev, 0xff, 0x01);
+		reg_w(gspca_dev, 0x78, 0x40);
+	}
 }
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x27, 0x80);
-	reg_w(gspca_dev, 0x28, 0xca);
-	reg_w(gspca_dev, 0x29, 0x53);
-	reg_w(gspca_dev, 0x2a, 0x0e);
-	reg_w(gspca_dev, 0xff, 0x01);
-	reg_w(gspca_dev, 0x3e, 0x20);
-	reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
-}
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int luma;
-	int luma_mean = 128;
-	int luma_delta = 20;
-	__u8 spring = 5;
-	int Gbright;
+	int avg_lum = atomic_read(&sd->avg_lum);
+	int desired_lum, deadzone;
 
-	if (!atomic_read(&sd->do_gain))
+	if (avg_lum == -1)
 		return;
-	atomic_set(&sd->do_gain, 0);
 
-	luma = atomic_read(&sd->avg_lum);
-	Gbright = reg_r(gspca_dev, 0x02);
-	PDEBUG(D_FRAM, "luma mean %d", luma);
-	if (luma < luma_mean - luma_delta ||
-	    luma > luma_mean + luma_delta) {
-		Gbright += (luma_mean - luma) >> spring;
-		if (Gbright > 0x1a)
-			Gbright = 0x1a;
-		else if (Gbright < 4)
-			Gbright = 4;
-		PDEBUG(D_FRAM, "gbright %d", Gbright);
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x0f, Gbright);
-		/* load registers to sensor (Bit 0, auto clear) */
-		reg_w(gspca_dev, 0x11, 0x01);
+	if (sd->sensor == SENSOR_PAC7302) {
+		desired_lum = 270 + sd->brightness * 4;
+		/* Hack hack, with the 7202 the first exposure step is
+		   pretty large, so if we're about to make the first
+		   exposure increase make the deadzone large to avoid
+		   oscilating */
+		if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
+				sd->exposure > EXPOSURE_DEF &&
+				sd->exposure < 42)
+			deadzone = 90;
+		else
+			deadzone = 30;
+	} else {
+		desired_lum = 200;
+		deadzone = 20;
 	}
+
+	if (sd->autogain_ignore_frames > 0)
+		sd->autogain_ignore_frames--;
+	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+			deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
+static const unsigned char pac7311_jpeg_header1[] = {
+  0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
+};
+
+static const unsigned char pac7311_jpeg_header2[] = {
+  0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
+  0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	unsigned char tmpbuf[4];
-	int i, p, ffseq;
+	unsigned char *sof;
 
-/*	if (len < 5) { */
-	if (len < 6) {
-/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
-		return;
-	}
+	sof = pac_find_sof(gspca_dev, data, len);
+	if (sof) {
+		unsigned char tmpbuf[4];
+		int n, lum_offset, footer_length;
 
-	ffseq = sd->ffseq;
+		if (sd->sensor == SENSOR_PAC7302) {
+		  /* 6 bytes after the FF D9 EOF marker a number of lumination
+		     bytes are send corresponding to different parts of the
+		     image, the 14th and 15th byte after the EOF seem to
+		     correspond to the center of the image */
+		  lum_offset = 61 + sizeof pac_sof_marker;
+		  footer_length = 74;
+		} else {
+		  lum_offset = 24 + sizeof pac_sof_marker;
+		  footer_length = 26;
+		}
 
-	for (p = 0; p < len - 6; p++) {
-		if ((data[0 + p] == 0xff)
-		    && (data[1 + p] == 0xff)
-		    && (data[2 + p] == 0x00)
-		    && (data[3 + p] == 0xff)
-		    && (data[4 + p] == 0x96)) {
-
-			/* start of frame */
-			if (sd->ag_cnt >= 0 && p > 28) {
-				sd->lum_sum += data[p - 23];
-				if (--sd->ag_cnt < 0) {
-					sd->ag_cnt = AG_CNT_START;
-					atomic_set(&sd->avg_lum,
-						sd->lum_sum / AG_CNT_START);
-					sd->lum_sum = 0;
-					atomic_set(&sd->do_gain, 1);
-				}
-			}
-
-			/* copy the end of data to the current frame */
+		/* Finish decoding current frame */
+		n = (sof - data) - (footer_length + sizeof pac_sof_marker);
+		if (n < 0) {
+			frame->data_end += n;
+			n = 0;
+		}
+		frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+					data, n);
+		if (gspca_dev->last_packet_type != DISCARD_PACKET &&
+				frame->data_end[-2] == 0xff &&
+				frame->data_end[-1] == 0xd9)
 			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-						data, p);
+						NULL, 0);
 
-			/* put the JPEG header in the new frame */
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-					(unsigned char *) pac7311_jpeg_header,
-					12);
+		n = sof - data;
+		len -= n;
+		data = sof;
+
+		/* Get average lumination */
+		if (gspca_dev->last_packet_type == LAST_PACKET &&
+				n >= lum_offset)
+			atomic_set(&sd->avg_lum, data[-lum_offset] +
+						data[-lum_offset + 1]);
+		else
+			atomic_set(&sd->avg_lum, -1);
+
+		/* Start the new frame with the jpeg header */
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
+		if (sd->sensor == SENSOR_PAC7302) {
+			/* The PAC7302 has the image rotated 90 degrees */
+			tmpbuf[0] = gspca_dev->width >> 8;
+			tmpbuf[1] = gspca_dev->width & 0xff;
+			tmpbuf[2] = gspca_dev->height >> 8;
+			tmpbuf[3] = gspca_dev->height & 0xff;
+		} else {
 			tmpbuf[0] = gspca_dev->height >> 8;
 			tmpbuf[1] = gspca_dev->height & 0xff;
 			tmpbuf[2] = gspca_dev->width >> 8;
 			tmpbuf[3] = gspca_dev->width & 0xff;
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-					tmpbuf, 4);
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-				(unsigned char *) &pac7311_jpeg_header[16],
-				PAC7311_JPEG_HEADER_SIZE - 16);
-
-			data += p + 7;
-			len -= p + 7;
-			ffseq = 0;
-			break;
 		}
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
 	}
-
-	/* remove the 'ff ff ff xx' sequences */
-	switch (ffseq) {
-	case 3:
-		data += 1;
-		len -= 1;
-		break;
-	case 2:
-		if (data[0] == 0xff) {
-			data += 2;
-			len -= 2;
-			frame->data_end -= 2;
-		}
-		break;
-	case 1:
-		if (data[0] == 0xff
-		    && data[1] == 0xff) {
-			data += 3;
-			len -= 3;
-			frame->data_end -= 1;
-		}
-		break;
-	}
-	for (i = 0; i < len - 4; i++) {
-		if (data[i] == 0xff
-		    && data[i + 1] == 0xff
-		    && data[i + 2] == 0xff) {
-			memmove(&data[i], &data[i + 4], len - i - 4);
-			len -= 4;
-		}
-	}
-	ffseq = 0;
-	if (data[len - 4] == 0xff) {
-		if (data[len - 3] == 0xff
-		    && data[len - 2] == 0xff) {
-			len -= 4;
-		}
-	} else if (data[len - 3] == 0xff) {
-		if (data[len - 2] == 0xff
-		    && data[len - 1] == 0xff)
-			ffseq = 3;
-	} else if (data[len - 2] == 0xff) {
-		if (data[len - 1] == 0xff)
-			ffseq = 2;
-	} else if (data[len - 1] == 0xff)
-		ffseq = 1;
-	sd->ffseq = ffseq;
 	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-/*	sd->brightness = reg_r(gspca_dev, 0x08);
-	return sd->brightness;	*/
-/*	PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
-}
-
-
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->brightness = val;
 	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
+		setbrightcont(gspca_dev);
 	return 0;
 }
 
@@ -644,7 +891,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	getbrightness(gspca_dev);
 	*val = sd->brightness;
 	return 0;
 }
@@ -654,8 +900,12 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->contrast = val;
-	if (gspca_dev->streaming)
-		setcontrast(gspca_dev);
+	if (gspca_dev->streaming) {
+		if (sd->sensor == SENSOR_PAC7302)
+			setbrightcont(gspca_dev);
+		else
+			setcontrast(gspca_dev);
+	}
 	return 0;
 }
 
@@ -663,7 +913,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-/*	getcontrast(gspca_dev); */
 	*val = sd->contrast;
 	return 0;
 }
@@ -682,18 +931,66 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-/*	getcolors(gspca_dev); */
 	*val = sd->colors;
 	return 0;
 }
 
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
-	if (gspca_dev->streaming)
-		setautogain(gspca_dev);
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->autogain) {
+		sd->exposure = EXPOSURE_DEF;
+		sd->gain = GAIN_DEF;
+		if (gspca_dev->streaming) {
+			sd->autogain_ignore_frames =
+				PAC_AUTOGAIN_IGNORE_FRAMES;
+			setexposure(gspca_dev);
+			setgain(gspca_dev);
+		}
+	}
+
 	return 0;
 }
 
@@ -705,30 +1002,67 @@
 	return 0;
 }
 
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hflip = val;
+	if (gspca_dev->streaming)
+		sethvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hflip;
+	return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->vflip = val;
+	if (gspca_dev->streaming)
+		sethvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->vflip;
+	return 0;
+}
+
 /* sub-driver description */
 static struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
-	{USB_DEVICE(0x093a, 0x2600)},
-	{USB_DEVICE(0x093a, 0x2601)},
-	{USB_DEVICE(0x093a, 0x2603)},
-	{USB_DEVICE(0x093a, 0x2608)},
-	{USB_DEVICE(0x093a, 0x260e)},
-	{USB_DEVICE(0x093a, 0x260f)},
-	{USB_DEVICE(0x093a, 0x2621)},
+	{USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+	{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+	{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
+	{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -746,6 +1080,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
new file mode 100644
index 0000000..34d4b14
--- /dev/null
+++ b/drivers/media/video/gspca/pac_common.h
@@ -0,0 +1,60 @@
+/*
+ * Pixart PAC207BCA / PAC73xx common functions
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ */
+
+/* We calculate the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define PAC_AUTOGAIN_IGNORE_FRAMES	3
+
+static const unsigned char pac_sof_marker[5] =
+		{ 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
+					unsigned char *m, int len)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+
+	/* Search for the SOF marker (fixed part) in the header */
+	for (i = 0; i < len; i++) {
+		if (m[i] == pac_sof_marker[sd->sof_read]) {
+			sd->sof_read++;
+			if (sd->sof_read == sizeof(pac_sof_marker)) {
+				PDEBUG(D_FRAM,
+					"SOF found, bytes to analyze: %u."
+					" Frame starts at byte #%u",
+					len, i + 1);
+				sd->sof_read = 0;
+				return m + i + 1;
+			}
+		} else {
+			sd->sof_read = 0;
+		}
+	}
+
+	return NULL;
+}
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 11210c7..5dd78c6 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -20,6 +20,26 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+/* Some documentation on known sonixb registers:
+
+Reg	Use
+0x10	high nibble red gain low nibble blue gain
+0x11	low nibble green gain
+0x12	hstart
+0x13	vstart
+0x15	hsize (hsize = register-value * 16)
+0x16	vsize (vsize = register-value * 16)
+0x17	bit 0 toggle compression quality (according to sn9c102 driver)
+0x18	bit 7 enables compression, bit 4-5 set image down scaling:
+	00 scale 1, 01 scale 1/2, 10, scale 1/4
+0x19	high-nibble is sensor clock divider, changes exposure on sensors which
+	use a clock generated by the bridge. Some sensors have their own clock.
+0x1c	auto_exposure area (for avg_lum) startx (startx = register-value * 32)
+0x1d	auto_exposure area (for avg_lum) starty (starty = register-value * 32)
+0x1e	auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32)
+0x1f	auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32)
+*/
+
 #define MODULE_NAME "sonixb"
 
 #include "gspca.h"
@@ -31,10 +51,8 @@
 /* specific webcam descriptor */
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
-
-	struct sd_desc sd_desc;		/* our nctrls differ dependend upon the
-					   sensor, so we use a per cam copy */
 	atomic_t avg_lum;
+	int prev_avg_lum;
 
 	unsigned char gain;
 	unsigned char exposure;
@@ -44,8 +62,12 @@
 	unsigned char frames_to_drop;
 	unsigned char freq;		/* light freq filter setting */
 
-	unsigned char fr_h_sz;		/* size of frame header */
-	char sensor;			/* Type of image sensor chip */
+	__u8 bridge;			/* Type of bridge */
+#define BRIDGE_101 0
+#define BRIDGE_102 0 /* We make no difference between 101 and 102 */
+#define BRIDGE_103 1
+
+	__u8 sensor;			/* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_OV6650 1
 #define SENSOR_OV7630 2
@@ -53,16 +75,35 @@
 #define SENSOR_PAS202 4
 #define SENSOR_TAS5110 5
 #define SENSOR_TAS5130CXX 6
-	char sensor_has_gain;
-	__u8 sensor_addr;
 	__u8 reg11;
 };
 
-/* flags used in the device id table */
+typedef const __u8 sensor_init_t[8];
+
+struct sensor_data {
+	const __u8 *bridge_init[2];
+	int bridge_init_size[2];
+	sensor_init_t *sensor_init;
+	int sensor_init_size;
+	sensor_init_t *sensor_bridge_init[2];
+	int sensor_bridge_init_size[2];
+	int flags;
+	unsigned ctrl_dis;
+	__u8 sensor_addr;
+};
+
+/* sensor_data flags */
 #define F_GAIN 0x01		/* has gain */
-#define F_AUTO 0x02		/* has autogain */
-#define F_SIF  0x04		/* sif or vga */
-#define F_H18  0x08		/* long (18 b) or short (12 b) frame header */
+#define F_SIF  0x02		/* sif or vga */
+
+/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
+#define MODE_RAW 0x10		/* raw bayer mode */
+#define MODE_REDUCED_SIF 0x20	/* vga mode (320x240 / 160x120) on sif cam */
+
+/* ctrl_dis helper macros */
+#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
+#define NO_FREQ (1 << FREQ_IDX)
+#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
 
 #define COMP2 0x8f
 #define COMP 0xc7		/* 0x87 //0x07 */
@@ -73,6 +114,18 @@
 
 #define SYS_CLK 0x04
 
+#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
+	sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+{ \
+	.bridge_init = { bridge_1, bridge_3 }, \
+	.bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+	.sensor_init = sensor, \
+	.sensor_init_size = sizeof(sensor), \
+	.sensor_bridge_init = { sensor_1, sensor_3,}, \
+	.sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
+	.flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
+}
+
 /* We calculate the autogain at the end of the transfer of a frame, at this
    moment a frame with the old settings is being transmitted, and a frame is
    being captured with the old settings. So if we adjust the autogain we must
@@ -95,6 +148,7 @@
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
 	{
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
@@ -109,6 +163,7 @@
 	    .set = sd_setbrightness,
 	    .get = sd_getbrightness,
 	},
+#define GAIN_IDX 1
 	{
 	    {
 		.id      = V4L2_CID_GAIN,
@@ -124,6 +179,7 @@
 	    .set = sd_setgain,
 	    .get = sd_getgain,
 	},
+#define EXPOSURE_IDX 2
 	{
 		{
 			.id = V4L2_CID_EXPOSURE,
@@ -140,6 +196,7 @@
 		.set = sd_setexposure,
 		.get = sd_getexposure,
 	},
+#define AUTOGAIN_IDX 3
 	{
 		{
 			.id = V4L2_CID_AUTOGAIN,
@@ -155,6 +212,7 @@
 		.set = sd_setautogain,
 		.get = sd_getautogain,
 	},
+#define FREQ_IDX 4
 	{
 		{
 			.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -172,31 +230,56 @@
 };
 
 static struct v4l2_pix_format vga_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 5 / 4,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2 | MODE_RAW},
 	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
 		.bytesperline = 160,
-		.sizeimage = 160 * 120,
+		.sizeimage = 160 * 120 * 5 / 4,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2},
 	{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
 		.bytesperline = 320,
-		.sizeimage = 320 * 240,
+		.sizeimage = 320 * 240 * 5 / 4,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
 	{640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
 		.bytesperline = 640,
-		.sizeimage = 640 * 480,
+		.sizeimage = 640 * 480 * 5 / 4,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
 };
 static struct v4l2_pix_format sif_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1 | MODE_RAW | MODE_REDUCED_SIF},
+	{160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120 * 5 / 4,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1 | MODE_REDUCED_SIF},
+	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144 * 5 / 4,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1 | MODE_RAW},
 	{176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
 		.bytesperline = 176,
-		.sizeimage = 176 * 144,
+		.sizeimage = 176 * 144 * 5 / 4,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
+	{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240 * 5 / 4,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0 | MODE_REDUCED_SIF},
 	{352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
 		.bytesperline = 352,
-		.sizeimage = 352 * 288,
+		.sizeimage = 352 * 288 * 5 / 4,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
 };
@@ -204,7 +287,7 @@
 static const __u8 initHv7131[] = {
 	0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
 	0x00, 0x00,
-	0x00, 0x00, 0x00, 0x03, 0x01, 0x00,	/* shift from 0x02 0x01 0x00 */
+	0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
 	0x28, 0x1e, 0x60, 0x8a, 0x20,
 	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
 };
@@ -218,8 +301,8 @@
 static const __u8 initOv6650[] = {
 	0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
-	0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+	0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
+	0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 static const __u8 ov6650_sensor_init[][8] =
 {
@@ -257,15 +340,15 @@
 static const __u8 initOv7630[] = {
 	0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,	/* r01 .. r08 */
 	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* r09 .. r10 */
-	0x00, 0x02, 0x01, 0x0a,				/* r11 .. r14 */
+	0x00, 0x01, 0x01, 0x0a,				/* r11 .. r14 */
 	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
-	0x68, COMP1, MCK_INIT1,				/* r17 .. r19 */
+	0x68, COMP2, MCK_INIT1,				/* r17 .. r19 */
 	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c		/* r1a .. r1f */
 };
 static const __u8 initOv7630_3[] = {
 	0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80,	/* r01 .. r08 */
 	0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,	/* r09 .. r10 */
-	0x00, 0x01, 0x01, 0x0a,				/* r11 .. r14 */
+	0x00, 0x02, 0x01, 0x0a,				/* r11 .. r14 */
 	0x28, 0x1e,			/* H & V sizes     r15 .. r16 */
 	0x68, 0x8f, MCK_INIT1,				/* r17 .. r19 */
 	0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00,	/* r1a .. r20 */
@@ -294,47 +377,65 @@
 	{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
 };
 
+static const __u8 ov7630_sensor_init_3[][8] = {
+	{0xa0, 0x21, 0x13, 0x80, 0x00,	0x00, 0x00, 0x10},
+};
+
 static const __u8 initPas106[] = {
 	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
 	0x00, 0x00,
-	0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
-	0x16, 0x12, 0x28, COMP1, MCK_INIT1,
-	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+	0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
+	0x16, 0x12, 0x24, COMP1, MCK_INIT1,
+	0x18, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 /* compression 0x86 mckinit1 0x2b */
-static const __u8 pas106_data[][2] = {
-	{0x02, 0x04},		/* Pixel Clock Divider 6 */
-	{0x03, 0x13},		/* Frame Time MSB */
-/*	{0x03, 0x12},		 * Frame Time MSB */
-	{0x04, 0x06},		/* Frame Time LSB */
-/*	{0x04, 0x05},		 * Frame Time LSB */
-	{0x05, 0x65},		/* Shutter Time Line Offset */
-/*	{0x05, 0x6d},		 * Shutter Time Line Offset */
-/*	{0x06, 0xb1},		 * Shutter Time Pixel Offset */
-	{0x06, 0xcd},		/* Shutter Time Pixel Offset */
-	{0x07, 0xc1},		/* Black Level Subtract Sign */
-/*	{0x07, 0x00},		 * Black Level Subtract Sign */
-	{0x08, 0x06},		/* Black Level Subtract Level */
-	{0x08, 0x06},		/* Black Level Subtract Level */
-/*	{0x08, 0x01},		 * Black Level Subtract Level */
-	{0x09, 0x05},		/* Color Gain B Pixel 5 a */
-	{0x0a, 0x04},		/* Color Gain G1 Pixel 1 5 */
-	{0x0b, 0x04},		/* Color Gain G2 Pixel 1 0 5 */
-	{0x0c, 0x05},		/* Color Gain R Pixel 3 1 */
-	{0x0d, 0x00},		/* Color GainH  Pixel */
-	{0x0e, 0x0e},		/* Global Gain */
-	{0x0f, 0x00},		/* Contrast */
-	{0x10, 0x06},		/* H&V synchro polarity */
-	{0x11, 0x06},		/* ?default */
-	{0x12, 0x06},		/* DAC scale */
-	{0x14, 0x02},		/* ?default */
-	{0x13, 0x01},		/* Validate Settings */
+static const __u8 pas106_sensor_init[][8] = {
+	/* Pixel Clock Divider 6 */
+	{ 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
+	/* Frame Time MSB (also seen as 0x12) */
+	{ 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
+	/* Frame Time LSB (also seen as 0x05) */
+	{ 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	/* Shutter Time Line Offset (also seen as 0x6d) */
+	{ 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
+	/* Shutter Time Pixel Offset (also seen as 0xb1) */
+	{ 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
+	/* Black Level Subtract Sign (also seen 0x00) */
+	{ 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
+	/* Black Level Subtract Level (also seen 0x01) */
+	{ 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	{ 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	/* Color Gain B Pixel 5 a */
+	{ 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
+	/* Color Gain G1 Pixel 1 5 */
+	{ 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
+	/* Color Gain G2 Pixel 1 0 5 */
+	{ 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
+	/* Color Gain R Pixel 3 1 */
+	{ 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
+	/* Color GainH  Pixel */
+	{ 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
+	/* Global Gain */
+	{ 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
+	/* Contrast */
+	{ 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
+	/* H&V synchro polarity */
+	{ 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	/* ?default */
+	{ 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	/* DAC scale */
+	{ 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
+	/* ?default */
+	{ 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
+	/* Validate Settings */
+	{ 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
 };
+
 static const __u8 initPas202[] = {
 	0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
 	0x00, 0x00,
-	0x00, 0x00, 0x00, 0x07, 0x03, 0x0a,	/* 6 */
-	0x28, 0x1e, 0x28, 0x89, 0x30,
+	0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
+	0x28, 0x1e, 0x28, 0x89, 0x20,
 	0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
 };
 static const __u8 pas202_sensor_init[][8] = {
@@ -364,7 +465,7 @@
 static const __u8 initTas5110[] = {
 	0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
 	0x00, 0x00,
-	0x00, 0x01, 0x00, 0x46, 0x09, 0x0a,	/* shift from 0x45 0x09 0x0a */
+	0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
 	0x16, 0x12, 0x60, 0x86, 0x2b,
 	0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
 };
@@ -377,7 +478,7 @@
 static const __u8 initTas5130[] = {
 	0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
 	0x00, 0x00,
-	0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+	0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
 	0x28, 0x1e, 0x60, COMP, MCK_INIT,
 	0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
 };
@@ -389,6 +490,21 @@
 	{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
 };
 
+struct sensor_data sensor_data[] = {
+SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
+	F_GAIN, 0, 0x21),
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+	0),
+SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
+	NO_EXPO|NO_FREQ, 0),
+SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
+	NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
+	0),
+};
+
 /* get one byte in gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
 		  __u16 value)
@@ -409,7 +525,7 @@
 		  int len)
 {
 #ifdef GSPCA_DEBUG
-	if (len > sizeof gspca_dev->usb_buf) {
+	if (len > USB_BUF_SZ) {
 		PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
 		return;
 	}
@@ -425,26 +541,6 @@
 			500);
 }
 
-static void reg_w_big(struct gspca_dev *gspca_dev,
-		  __u16 value,
-		  const __u8 *buffer,
-		  int len)
-{
-	__u8 *tmpbuf;
-
-	tmpbuf = kmalloc(len, GFP_KERNEL);
-	memcpy(tmpbuf, buffer, len);
-	usb_control_msg(gspca_dev->dev,
-			usb_sndctrlpipe(gspca_dev->dev, 0),
-			0x08,			/* request */
-			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-			value,
-			0,			/* index */
-			tmpbuf, len,
-			500);
-	kfree(tmpbuf);
-}
-
 static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
 {
 	int retry = 60;
@@ -487,7 +583,7 @@
 			{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
 
 		/* change reg 0x06 */
-		i2cOV[1] = sd->sensor_addr;
+		i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
 		i2cOV[3] = sd->brightness;
 		if (i2c_w(gspca_dev, i2cOV) < 0)
 			goto err;
@@ -545,9 +641,6 @@
 			goto err;
 		break;
 	    }
-	case SENSOR_TAS5110:
-		/* FIXME figure out howto control brightness on TAS5110 */
-		break;
 	}
 	return;
 err:
@@ -577,7 +670,7 @@
 	case SENSOR_OV7630: {
 		__u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
 
-		i2c[1] = sd->sensor_addr;
+		i2c[1] = sensor_data[sd->sensor].sensor_addr;
 		i2c[3] = gain >> 2;
 		if (i2c_w(gspca_dev, i2c) < 0)
 			goto err;
@@ -604,7 +697,7 @@
 	rgb_value = gain;
 	reg_w(gspca_dev, 0x11, &rgb_value, 1);
 
-	if (sd->sensor_has_gain)
+	if (sensor_data[sd->sensor].flags & F_GAIN)
 		setsensorgain(gspca_dev);
 }
 
@@ -665,6 +758,11 @@
 		else if (reg11 > 16)
 			reg11 = 16;
 
+		/* In 640x480, if the reg11 has less than 3, the image is
+		   unstable (not enough bandwidth). */
+		if (gspca_dev->width == 640 && reg11 < 3)
+			reg11 = 3;
+
 		/* frame exposure time in ms = 1000 * reg11 / 30    ->
 		reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
 		reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
@@ -678,13 +776,8 @@
 		else if (reg10 > reg10_max)
 			reg10 = reg10_max;
 
-		/* In 640x480, if the reg11 has less than 3, the image is
-		   unstable (not enough bandwidth). */
-		if (gspca_dev->width == 640 && reg11 < 3)
-			reg11 = 3;
-
 		/* Write reg 10 and reg11 low nibble */
-		i2c[1] = sd->sensor_addr;
+		i2c[1] = sensor_data[sd->sensor].sensor_addr;
 		i2c[3] = reg10;
 		i2c[4] |= reg11 - 1;
 
@@ -724,7 +817,7 @@
 					? 0x4f : 0x8a;
 			break;
 		}
-		i2c[1] = sd->sensor_addr;
+		i2c[1] = sensor_data[sd->sensor].sensor_addr;
 		if (i2c_w(gspca_dev, i2c) < 0)
 			PDEBUG(D_ERR, "i2c error setfreq");
 		break;
@@ -757,30 +850,19 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
-	int sif = 0;
 
-	/* nctrls depends upon the sensor, so we use a per cam copy */
-	memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
-	gspca_dev->sd_desc = &sd->sd_desc;
+	reg_r(gspca_dev, 0x00);
+	if (gspca_dev->usb_buf[0] != 0x10)
+		return -ENODEV;
 
 	/* copy the webcam info from the device id */
-	sd->sensor = (id->driver_info >> 24) & 0xff;
-	if (id->driver_info & (F_GAIN << 16))
-		sd->sensor_has_gain = 1;
-	if (id->driver_info & (F_AUTO << 16))
-		sd->sd_desc.dq_callback = do_autogain;
-	if (id->driver_info & (F_SIF << 16))
-		sif = 1;
-	if (id->driver_info & (F_H18 << 16))
-		sd->fr_h_sz = 18;		/* size of frame header */
-	else
-		sd->fr_h_sz = 12;
-	sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff;
-	sd->sensor_addr = id->driver_info & 0xff;
+	sd->sensor = id->driver_info >> 8;
+	sd->bridge = id->driver_info & 0xff;
+	gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
 
 	cam = &gspca_dev->cam;
 	cam->epaddr = 0x01;
-	if (!sif) {
+	if (!(sensor_data[sd->sensor].flags & F_SIF)) {
 		cam->cam_mode = vga_mode;
 		cam->nmodes = ARRAY_SIZE(vga_mode);
 	} else {
@@ -790,95 +872,61 @@
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->gain = GAIN_DEF;
 	sd->exposure = EXPOSURE_DEF;
-	sd->autogain = AUTOGAIN_DEF;
+	if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+		sd->autogain = 0; /* Disable do_autogain callback */
+	else
+		sd->autogain = AUTOGAIN_DEF;
 	sd->freq = FREQ_DEF;
 
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
-	reg_r(gspca_dev, 0x00);
-	if (gspca_dev->usb_buf[0] != 0x10)
-		return -ENODEV;
+	const __u8 stop = 0x09; /* Disable stream turn of LED */
+
+	reg_w(gspca_dev, 0x01, &stop, 1);
+
 	return 0;
 }
 
-static void pas106_i2cinit(struct gspca_dev *gspca_dev)
-{
-	int i;
-	const __u8 *data;
-	__u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
-
-	i = ARRAY_SIZE(pas106_data);
-	data = pas106_data[0];
-	while (--i >= 0) {
-		memcpy(&i2c1[2], data, 2);
-					/* copy 2 bytes from the template */
-		if (i2c_w(gspca_dev, i2c1) < 0)
-			PDEBUG(D_ERR, "i2c error pas106");
-		data += 2;
-	}
-}
-
 /* -- start the camera -- */
 static void sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int mode, l = 0x1f;
+	struct cam *cam = &gspca_dev->cam;
+	int mode, l;
 	const __u8 *sn9c10x;
-	__u8 reg17_19[3];
+	__u8 reg12_19[8];
 
-	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
+	sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
+	l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
+	memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
+	reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
+	/* Special cases where reg 17 and or 19 value depends on mode */
 	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		sn9c10x = initHv7131;
-		reg17_19[0] = 0x60;
-		reg17_19[1] = (mode << 4) | 0x8a;
-		reg17_19[2] = 0x20;
-		break;
-	case SENSOR_OV6650:
-		sn9c10x = initOv6650;
-		reg17_19[0] = 0x68;
-		reg17_19[1] = (mode << 4) | 0x8b;
-		reg17_19[2] = 0x20;
-		break;
-	case SENSOR_OV7630:
-		if (sd->fr_h_sz == 18) { /* SN9C103 */
-			sn9c10x = initOv7630_3;
-			l = sizeof initOv7630_3;
-		} else
-			sn9c10x = initOv7630;
-		reg17_19[0] = 0x68;
-		reg17_19[1] = (mode << 4) | COMP2;
-		reg17_19[2] = MCK_INIT1;
-		break;
-	case SENSOR_PAS106:
-		sn9c10x = initPas106;
-		reg17_19[0] = 0x24;		/* 0x28 */
-		reg17_19[1] = (mode << 4) | COMP1;
-		reg17_19[2] = MCK_INIT1;
-		break;
 	case SENSOR_PAS202:
-		sn9c10x = initPas202;
-		reg17_19[0] = mode ? 0x24 : 0x20;
-		reg17_19[1] = (mode << 4) | 0x89;
-		reg17_19[2] = 0x20;
+		reg12_19[5] = mode ? 0x24 : 0x20;
 		break;
-	case SENSOR_TAS5110:
-		sn9c10x = initTas5110;
-		reg17_19[0] = 0x60;
-		reg17_19[1] = (mode << 4) | 0x86;
-		reg17_19[2] = 0x2b;		/* 0xf3; */
+	case SENSOR_TAS5130CXX:
+		/* probably not mode specific at all most likely the upper
+		   nibble of 0x19 is exposure (clock divider) just as with
+		   the tas5110, we need someone to test this. */
+		reg12_19[7] = mode ? 0x23 : 0x43;
 		break;
-	default:
-/*	case SENSOR_TAS5130CXX: */
-		sn9c10x = initTas5130;
-		reg17_19[0] = 0x60;
-		reg17_19[1] = (mode << 4) | COMP;
-		reg17_19[2] = mode ? 0x23 : 0x43;
-		break;
+	}
+	/* Disable compression when the raw bayer format has been selected */
+	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
+		reg12_19[6] &= ~0x80;
+
+	/* Vga mode emulation on SIF sensor? */
+	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
+		reg12_19[0] += 16; /* 0x12: hstart adjust */
+		reg12_19[1] += 24; /* 0x13: vstart adjust */
+		reg12_19[3] = 320 / 16; /* 0x15: hsize */
+		reg12_19[4] = 240 / 16; /* 0x16: vsize */
 	}
 
 	/* reg 0x01 bit 2 video transfert on */
@@ -886,61 +934,36 @@
 	/* reg 0x17 SensorClk enable inv Clk 0x60 */
 	reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
 	/* Set the registers from the template */
-	reg_w_big(gspca_dev, 0x01, sn9c10x, l);
-	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		i2c_w_vector(gspca_dev, hv7131_sensor_init,
-				sizeof hv7131_sensor_init);
-		break;
-	case SENSOR_OV6650:
-		i2c_w_vector(gspca_dev, ov6650_sensor_init,
-				sizeof ov6650_sensor_init);
-		break;
-	case SENSOR_OV7630:
-		i2c_w_vector(gspca_dev, ov7630_sensor_init,
-				sizeof ov7630_sensor_init);
-		if (sd->fr_h_sz == 18) { /* SN9C103 */
-			const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
-						0x00, 0x00, 0x10 };
-			i2c_w(gspca_dev, i2c);
-		}
-		break;
-	case SENSOR_PAS106:
-		pas106_i2cinit(gspca_dev);
-		break;
-	case SENSOR_PAS202:
-		i2c_w_vector(gspca_dev, pas202_sensor_init,
-				sizeof pas202_sensor_init);
-		break;
-	case SENSOR_TAS5110:
-		i2c_w_vector(gspca_dev, tas5110_sensor_init,
-				sizeof tas5110_sensor_init);
-		break;
-	default:
-/*	case SENSOR_TAS5130CXX: */
-		i2c_w_vector(gspca_dev, tas5130_sensor_init,
-				sizeof tas5130_sensor_init);
-		break;
-	}
+	reg_w(gspca_dev, 0x01, sn9c10x, l);
+
+	/* Init the sensor */
+	i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
+			sensor_data[sd->sensor].sensor_init_size);
+	if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
+		i2c_w_vector(gspca_dev,
+			sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
+			sensor_data[sd->sensor].sensor_bridge_init_size[
+				sd->bridge]);
+
 	/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
-	reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
+	reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
 	/* compression register */
-	reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
+	reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
 	/* H_start */
-	reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
+	reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
 	/* V_START */
-	reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
+	reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
 	/* reset 0x17 SensorClk enable inv Clk 0x60 */
 				/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
-	reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
+	reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
 	/*MCKSIZE ->3 */	/*fixme: not ov7630*/
-	reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
+	reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
 	/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
 	reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
 	/* Enable video transfert */
 	reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
 	/* Compression */
-	reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
+	reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
 	msleep(20);
 
 	sd->reg11 = -1;
@@ -957,18 +980,7 @@
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	__u8 ByteSend;
-
-	ByteSend = 0x09;	/* 0X00 */
-	reg_w(gspca_dev, 0x01, &ByteSend, 1);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+	sd_init(gspca_dev);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -978,6 +990,7 @@
 {
 	int i;
 	struct sd *sd = (struct sd *) gspca_dev;
+	struct cam *cam = &gspca_dev->cam;
 
 	/* frames start with:
 	 *	ff ff 00 c4 c4 96	synchro
@@ -998,20 +1011,31 @@
 			    && data[5 + i] == 0x96) {	/* start of frame */
 				int lum = -1;
 				int pkt_type = LAST_PACKET;
+				int fr_h_sz = (sd->bridge == BRIDGE_103) ?
+					18 : 12;
 
-				if (len - i < sd->fr_h_sz) {
+				if (len - i < fr_h_sz) {
 					PDEBUG(D_STREAM, "packet too short to"
 						" get avg brightness");
-				} else if (sd->fr_h_sz == 12) {
-					lum = data[i + 8] + (data[i + 9] << 8);
-				} else {
+				} else if (sd->bridge == BRIDGE_103) {
 					lum = data[i + 9] +
 						(data[i + 10] << 8);
+				} else {
+					lum = data[i + 8] + (data[i + 9] << 8);
 				}
-				if (lum == 0) {
+				/* When exposure changes midway a frame we
+				   get a lum of 0 in this case drop 2 frames
+				   as the frames directly after an exposure
+				   change have an unstable image. Sometimes lum
+				   *really* is 0 (cam used in low light with
+				   low exposure setting), so do not drop frames
+				   if the previous lum was 0 too. */
+				if (lum == 0 && sd->prev_avg_lum != 0) {
 					lum = -1;
 					sd->frames_to_drop = 2;
-				}
+					sd->prev_avg_lum = 0;
+				} else
+					sd->prev_avg_lum = lum;
 				atomic_set(&sd->avg_lum, lum);
 
 				if (sd->frames_to_drop) {
@@ -1021,14 +1045,25 @@
 
 				frame = gspca_frame_add(gspca_dev, pkt_type,
 							frame, data, 0);
-				data += i + sd->fr_h_sz;
-				len -= i + sd->fr_h_sz;
+				data += i + fr_h_sz;
+				len -= i + fr_h_sz;
 				gspca_frame_add(gspca_dev, FIRST_PACKET,
 						frame, data, len);
 				return;
 			}
 		}
 	}
+
+	if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
+		/* In raw mode we sometimes get some garbage after the frame
+		   ignore this */
+		int used = frame->data_end - frame->data;
+		int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
+
+		if (used + len > size)
+			len = size - used;
+	}
+
 	gspca_frame_add(gspca_dev, INTER_PACKET,
 			frame, data, len);
 }
@@ -1162,58 +1197,45 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
+	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */
-#define SFCI(sensor, flags, nctrls, i2c_addr) \
-	.driver_info = (SENSOR_ ## sensor << 24) \
-			| ((flags) << 16) \
-			| ((nctrls) << 8) \
-			| (i2c_addr)
+#define SB(sensor, bridge) \
+	.driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
+
+
 static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
-	{USB_DEVICE(0x0c45, 0x6001),			/* SN9C102 */
-			SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-	{USB_DEVICE(0x0c45, 0x6005),			/* SN9C101 */
-			SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-	{USB_DEVICE(0x0c45, 0x6007),			/* SN9C101 */
-			SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
-	{USB_DEVICE(0x0c45, 0x6009),			/* SN9C101 */
-			SFCI(PAS106, F_SIF, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x600d),			/* SN9C101 */
-			SFCI(PAS106, F_SIF, 2, 0)},
+	{USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */
+	{USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+	{USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */
+	{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
+	{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
 #endif
-	{USB_DEVICE(0x0c45, 0x6011),		/* SN9C101 - SN9C101G */
-			SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)},
-#ifndef CONFIG_USB_SN9C102
-	{USB_DEVICE(0x0c45, 0x6019),			/* SN9C101 */
-			SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-	{USB_DEVICE(0x0c45, 0x6024),			/* SN9C102 */
-			SFCI(TAS5130CXX, 0, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x6025),			/* SN9C102 */
-			SFCI(TAS5130CXX, 0, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x6028),			/* SN9C102 */
-			SFCI(PAS202, 0, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x6029),			/* SN9C101 */
-			SFCI(PAS106, F_SIF, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x602c),			/* SN9C102 */
-			SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-	{USB_DEVICE(0x0c45, 0x602d),			/* SN9C102 */
-			SFCI(HV7131R, 0, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x602e),			/* SN9C102 */
-			SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
-	{USB_DEVICE(0x0c45, 0x60af),			/* SN9C103 */
-			SFCI(PAS202, F_H18, 2, 0)},
-	{USB_DEVICE(0x0c45, 0x60b0),			/* SN9C103 */
-			SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)},
+	{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+	{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+	{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
+	{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
+	{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
+	{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
+	{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
 #endif
+	{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+	{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
+#endif
+	{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+	{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
+#endif
+	{USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -1231,6 +1253,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 245a30e..d75b1d2 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -54,8 +54,10 @@
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MO4000 2
-#define SENSOR_OV7648 3
-#define SENSOR_OV7660 4
+#define SENSOR_OM6802 3
+#define SENSOR_OV7630 4
+#define SENSOR_OV7648 5
+#define SENSOR_OV7660 6
 	unsigned char i2c_base;
 };
 
@@ -76,7 +78,8 @@
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Brightness",
 		.minimum = 0,
-		.maximum = 0xffff,
+#define BRIGHTNESS_MAX 0xffff
+		.maximum = BRIGHTNESS_MAX,
 		.step    = 1,
 #define BRIGHTNESS_DEF 0x7fff
 		.default_value = BRIGHTNESS_DEF,
@@ -90,7 +93,8 @@
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Contrast",
 		.minimum = 0,
-		.maximum = 127,
+#define CONTRAST_MAX 127
+		.maximum = CONTRAST_MAX,
 		.step    = 1,
 #define CONTRAST_DEF 63
 		.default_value = CONTRAST_DEF,
@@ -104,14 +108,15 @@
 		.type    = V4L2_CTRL_TYPE_INTEGER,
 		.name    = "Color",
 		.minimum = 0,
-		.maximum = 255,
+		.maximum = 64,
 		.step    = 1,
-#define COLOR_DEF 127
+#define COLOR_DEF 32
 		.default_value = COLOR_DEF,
 	    },
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+#define AUTOGAIN_IDX 3
 	{
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -131,7 +136,7 @@
 static struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
-		.sizeimage = 160 * 120 * 3 / 8 + 590,
+		.sizeimage = 160 * 120 * 4 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 2},
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -180,6 +185,31 @@
 	0x08,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
 };
 
+static const __u8 sn_om6802[] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x23,	0x72,	0x00,	0x1a,	0x34,	0x27,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x80,	0x34,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x51,	0x01,	0x00,	0x28,	0x1e,	0x40,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x05,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	0x08,	0x22,	0x44,	0x63,	0x7d,	0x92,	0xa3,	0xaf,
+	0xbc,	0xc4,	0xcd,	0xd5,	0xdc,	0xe1,	0xe8,	0xef,
+	0xf7
+};
+
+static const __u8 sn_ov7630[] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x21,	0x40,	0x00,	0x1a,	0x20,	0x1f,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0xa1,	0x21,	0x76,	0x21,	0x00,	0x00,	0x00,	0x10,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x04,	0x01,	0x0a,	0x28,	0x1e,	0xc2,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x0b,	0x00,	0x00,	0x00,	0x00,	0x00
+};
+
 static const __u8 sn_ov7648[] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
 	0x00,	0x21,	0x62,	0x00,	0x1a,	0x20,	0x20,	0x20,
@@ -207,31 +237,22 @@
 	sn_hv7131,
 	sn_mi0360,
 	sn_mo4000,
+	sn_om6802,
+	sn_ov7630,
 	sn_ov7648,
 	sn_ov7660
 };
 
-static const __u8 regsn20[] = {
+static const __u8 gamma_def[] = {
 	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
 	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
-static const __u8 regsn20_sn9c325[] = {
-	0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
-	0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
-};
 
 static const __u8 reg84[] = {
 	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
 	0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-/*	0x00, 0x00, 0x00, 0x00, 0x00 */
-	0xf7, 0x0f, 0x0a, 0x00, 0x00
+	0xf7, 0x0f, 0x00, 0x00, 0x00
 };
-static const __u8 reg84_sn9c325[] = {
-	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
-	0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
-	0xf8, 0x0f, 0x00, 0x00, 0x00
-};
-
 static const __u8 hv7131r_sensor_init[][8] = {
 	{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
 	{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -340,6 +361,92 @@
 	{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
 	{}
 };
+static __u8 om6802_sensor_init[][8] = {
+	{0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
+/*	{0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
+	{0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
+					/* white balance & auto-exposure */
+/*	{0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
+							 * set color mode */
+/*	{0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
+						 * max AGC value in AE */
+/*	{0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10},
+							 * preset AGC */
+/*	{0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10},
+						 * preset brightness */
+/*	{0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10},
+							 * preset contrast */
+/*	{0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
+							 * preset gamma */
+	{0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
+					/* luminance mode (0x4f = AE) */
+	{0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
+							/* preset shutter */
+/*	{0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
+							 * auto frame rate */
+/*	{0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
+
+/*	{0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
+/*	{0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
+/*	{0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
+/*	{0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+	{}
+};
+static const __u8 ov7630_sensor_init[][8] = {
+	{0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/* win: i2c_r from 00 to 80 */
+	{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
+	{0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
+	{0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+	{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10},
+	{0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10},
+	{0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10},
+	{0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10},
+	{0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10},
+	{0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10},
+	{0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10},
+	{0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10},
+	{0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10},
+	{0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10},
+	{0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10},
+	{0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
+	{0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+	{0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+/* */
+	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/*fixme: + 0x12, 0x04*/
+	{0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
+/* */
+	{0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
+/* */
+	{0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
+/*	{0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
+	{}
+};
 static const __u8 ov7660_sensor_init[][8] = {
 	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
 /*		(delay 20ms) */
@@ -506,10 +613,16 @@
 	0x29, 0x29, 0x29, 0x29
 };
 
-/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
+/* read <len> bytes to gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
 		  __u16 value, int len)
 {
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		err("reg_r: buffer overflow");
+		return;
+	}
+#endif
 	usb_control_msg(gspca_dev->dev,
 			usb_rcvctrlpipe(gspca_dev->dev, 0),
 			0,
@@ -542,29 +655,20 @@
 {
 	PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
 		value, buffer[0], buffer[1]);
-	if (len <= sizeof gspca_dev->usb_buf) {
-		memcpy(gspca_dev->usb_buf, buffer, len);
-		usb_control_msg(gspca_dev->dev,
-				usb_sndctrlpipe(gspca_dev->dev, 0),
-				0x08,
-			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, 0,
-				gspca_dev->usb_buf, len,
-				500);
-	} else {
-		__u8 *tmpbuf;
-
-		tmpbuf = kmalloc(len, GFP_KERNEL);
-		memcpy(tmpbuf, buffer, len);
-		usb_control_msg(gspca_dev->dev,
-				usb_sndctrlpipe(gspca_dev->dev, 0),
-				0x08,
-			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, 0,
-				tmpbuf, len,
-				500);
-		kfree(tmpbuf);
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		err("reg_w: buffer overflow");
+		return;
 	}
+#endif
+	memcpy(gspca_dev->usb_buf, buffer, len);
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0x08,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			value, 0,
+			gspca_dev->usb_buf, len,
+			500);
 }
 
 /* I2C write 1 byte */
@@ -665,7 +769,7 @@
 	static const __u8 regd4[] = {0x60, 0x00, 0x00};
 
 	reg_w1(gspca_dev, 0xf1, 0x00);
-	reg_w1(gspca_dev, 0x01, 0x00);		/*jfm was sn9c1xx[1] in v1*/
+	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 
 	/* configure gpio */
 	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -685,21 +789,41 @@
 
 	reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
-	switch (sd->bridge) {
-	case BRIDGE_SN9C325:
+	switch (sd->sensor) {
+	case SENSOR_OM6802:
+		reg_w1(gspca_dev, 0x02, 0x71);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		reg_w1(gspca_dev, 0x17, 0x64);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		break;
+/*jfm: from win trace */
+	case SENSOR_OV7630:
+		reg_w1(gspca_dev, 0x01, 0x61);
+		reg_w1(gspca_dev, 0x17, 0xe2);
+		reg_w1(gspca_dev, 0x01, 0x60);
+		reg_w1(gspca_dev, 0x01, 0x40);
+		break;
+	case SENSOR_OV7648:
 		reg_w1(gspca_dev, 0x01, 0x43);
 		reg_w1(gspca_dev, 0x17, 0xae);
 		reg_w1(gspca_dev, 0x01, 0x42);
 		break;
+/*jfm: from win trace */
+	case SENSOR_OV7660:
+		reg_w1(gspca_dev, 0x01, 0x61);
+		reg_w1(gspca_dev, 0x17, 0x20);
+		reg_w1(gspca_dev, 0x01, 0x60);
+		reg_w1(gspca_dev, 0x01, 0x40);
+		break;
 	default:
 		reg_w1(gspca_dev, 0x01, 0x43);
 		reg_w1(gspca_dev, 0x17, 0x61);
 		reg_w1(gspca_dev, 0x01, 0x42);
-	}
-
-	if (sd->sensor == SENSOR_HV7131R) {
-		if (probesensor(gspca_dev) < 0)
-			return -ENODEV;
+		if (sd->sensor == SENSOR_HV7131R) {
+			if (probesensor(gspca_dev) < 0)
+				return -ENODEV;
+		}
+		break;
 	}
 	return 0;
 }
@@ -737,6 +861,40 @@
 	}
 }
 
+static void om6802_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	while (om6802_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, om6802_sensor_init[i]);
+		i++;
+	}
+}
+
+static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
+{
+	int i = 0;
+
+	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 76 01 */
+	i++;
+	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 (RGB+SRST) */
+	i++;
+	msleep(20);
+	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
+	i++;
+	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 c8 */
+	i++;
+	msleep(20);
+	i2c_w8(gspca_dev, ov7630_sensor_init[i]);	/* 12 48 */
+	i++;
+/*jfm:win i2c_r from 00 to 80*/
+
+	while (ov7630_sensor_init[i][0]) {
+		i2c_w8(gspca_dev, ov7630_sensor_init[i]);
+		i++;
+	}
+}
+
 static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
 {
 	int i = 0;
@@ -783,11 +941,19 @@
 	sd->autogain = AUTOGAIN_DEF;
 	sd->ag_cnt = -1;
 
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+	case SENSOR_OV7648:
+	case SENSOR_OV7660:
+		gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
+		break;
+	}
+
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 /*	const __u8 *sn9c1xx; */
@@ -891,16 +1057,53 @@
 			| ((expoMo10[3] & 0x30) >> 4));
 		break;
 	    }
+	case SENSOR_OM6802: {
+		__u8 gainOm[] =
+			{ 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+		if (expo > 0x03ff)
+			expo = 0x03ff;
+		 if (expo < 0x0001)
+			expo = 0x0001;
+		gainOm[3] = expo >> 2;
+		i2c_w8(gspca_dev, gainOm);
+		reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+		PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
+		break;
+	    }
 	}
 	return expo;
 }
 
+/* this function is used for sensors o76xx only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	unsigned val;
+	__u8 reg84_full[0x15];
+
+	memset(reg84_full, 0, sizeof reg84_full);
+	val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10;	/* 10..30 */
+	reg84_full[2] = val;
+	reg84_full[0] = (val + 1) / 2;
+	reg84_full[4] = (val + 1) / 5;
+	if (val > BRIGHTNESS_DEF)
+		val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+			/ BRIGHTNESS_MAX;
+	else
+		val = 0;
+	reg84_full[0x12] = val;			/* 00..1f */
+	reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
+}
+
+/* sensor != ov76xx */
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned int expo;
 	__u8 k2;
 
+	k2 = sd->brightness >> 10;
 	switch (sd->sensor) {
 	case SENSOR_HV7131R:
 		expo = sd->brightness << 4;
@@ -915,12 +1118,17 @@
 		expo = sd->brightness >> 4;
 		sd->exposure = setexposure(gspca_dev, expo);
 		break;
+	case SENSOR_OM6802:
+		expo = sd->brightness >> 6;
+		sd->exposure = setexposure(gspca_dev, expo);
+		k2 = sd->brightness >> 11;
+		break;
 	}
 
-	k2 = sd->brightness >> 10;
 	reg_w1(gspca_dev, 0x96, k2);
 }
 
+/* sensor != ov76xx */
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -937,31 +1145,30 @@
 static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 data;
-	int colour;
+	__u8 blue, red;
 
-	colour = sd->colors - 128;
-	if (colour > 0)
-		data = (colour + 32) & 0x7f;	/* blue */
-	else
-		data = (-colour + 32) & 0x7f;	/* red */
-	reg_w1(gspca_dev, 0x05, data);
+	if (sd->colors >= 32) {
+		red = 32 + (sd->colors - 32) / 2;
+		blue = 64 - sd->colors;
+	} else {
+		red = sd->colors;
+		blue = 32 + (32 - sd->colors) / 2;
+	}
+	reg_w1(gspca_dev, 0x05, red);
+/*	reg_w1(gspca_dev, 0x07, 32); */
+	reg_w1(gspca_dev, 0x06, blue);
 }
 
 static void setautogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-	case SENSOR_MO4000:
-	case SENSOR_MI0360:
-		if (sd->autogain)
-			sd->ag_cnt = AG_CNT_START;
-		else
-			sd->ag_cnt = -1;
-		break;
-	}
+	if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+		return;
+	if (sd->autogain)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
 }
 
 /* -- start the camera -- */
@@ -975,13 +1182,12 @@
 	static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
 	static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
 	static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
-	static const __u8 CE_sn9c325[] =
-			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7648 - SN9C325 */
+	static const __u8 CE_ov76xx[] =
+			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7630/48 */
 
 	sn9c1xx = sn_tb[(int) sd->sensor];
 	configure_gpio(gspca_dev, sn9c1xx);
 
-/*	reg_w1(gspca_dev, 0x01, 0x44);		jfm from win trace*/
 	reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
 	reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
 	reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
@@ -994,10 +1200,17 @@
 	reg_w1(gspca_dev, 0xc8, 0x50);
 	reg_w1(gspca_dev, 0xc9, 0x3c);
 	reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
-	switch (sd->bridge) {
-	case BRIDGE_SN9C325:
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+		reg17 = 0xe2;
+		break;
+	case SENSOR_OV7648:
 		reg17 = 0xae;
 		break;
+/*jfm: from win trace */
+	case SENSOR_OV7660:
+		reg17 = 0xa0;
+		break;
 	default:
 		reg17 = 0x60;
 		break;
@@ -1007,24 +1220,11 @@
 	reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
 	reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
 	reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
-	switch (sd->bridge) {
-	case BRIDGE_SN9C325:
-		reg_w(gspca_dev, 0x20, regsn20_sn9c325,
-				sizeof regsn20_sn9c325);
-		for (i = 0; i < 8; i++)
-			reg_w(gspca_dev, 0x84, reg84_sn9c325,
-					sizeof reg84_sn9c325);
-		reg_w1(gspca_dev, 0x9a, 0x0a);
-		reg_w1(gspca_dev, 0x99, 0x60);
-		break;
-	default:
-		reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
-		for (i = 0; i < 8; i++)
-			reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+	reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
+	for (i = 0; i < 8; i++)
+		reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
 		reg_w1(gspca_dev, 0x9a, 0x08);
 		reg_w1(gspca_dev, 0x99, 0x59);
-		break;
-	}
 
 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
 	if (mode)
@@ -1049,6 +1249,15 @@
 /*			reg1 = 0x06;	 * 640 clk 24Mz (done) */
 		}
 		break;
+	case SENSOR_OM6802:
+		om6802_InitSensor(gspca_dev);
+		reg17 = 0x64;		/* 640 MCKSIZE */
+		break;
+	case SENSOR_OV7630:
+		ov7630_InitSensor(gspca_dev);
+		reg17 = 0xe2;
+		reg1 = 0x44;
+		break;
 	case SENSOR_OV7648:
 		ov7648_InitSensor(gspca_dev);
 		reg17 = 0xa2;
@@ -1073,9 +1282,10 @@
 	}
 	reg_w(gspca_dev, 0xc0, C0, 6);
 	reg_w(gspca_dev, 0xca, CA, 4);
-	switch (sd->bridge) {
-	case BRIDGE_SN9C325:
-		reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+	case SENSOR_OV7648:
+		reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
 		break;
 	default:
 		reg_w(gspca_dev, 0xce, CE, 4);
@@ -1093,10 +1303,20 @@
 	reg_w1(gspca_dev, 0x18, reg18);
 
 	reg_w1(gspca_dev, 0x17, reg17);
-	reg_w1(gspca_dev, 0x01, reg1);
-	setbrightness(gspca_dev);
-	setcontrast(gspca_dev);
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+	case SENSOR_MI0360:
+	case SENSOR_MO4000:
+	case SENSOR_OM6802:
+		setbrightness(gspca_dev);
+		setcontrast(gspca_dev);
+		break;
+	default:			/* OV76xx */
+		setbrightcont(gspca_dev);
+		break;
+	}
 	setautogain(gspca_dev);
+	reg_w1(gspca_dev, 0x01, reg1);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1119,6 +1339,7 @@
 		i2c_w8(gspca_dev, stopmi0360);
 		data = 0x29;
 		break;
+	case SENSOR_OV7630:
 	case SENSOR_OV7648:
 		data = 0x29;
 		break;
@@ -1132,15 +1353,7 @@
 	reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
 	reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
 	reg_w1(gspca_dev, 0x01, data);
-	reg_w1(gspca_dev, 0xf1, 0x01);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+	reg_w1(gspca_dev, 0xf1, 0x00);
 }
 
 static void do_autogain(struct gspca_dev *gspca_dev)
@@ -1174,6 +1387,7 @@
 		default:
 /*		case SENSOR_MO4000: */
 /*		case SENSOR_MI0360: */
+/*		case SENSOR_OM6802: */
 			expotimes = sd->exposure;
 			expotimes += (luma_mean - delta) >> 6;
 			if (expotimes < 0)
@@ -1229,69 +1443,24 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static unsigned int getexposure(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 hexpo, mexpo, lexpo;
-
-	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		/* read sensor exposure */
-		i2c_r5(gspca_dev, 0x25);
-		return (gspca_dev->usb_buf[0] << 16)
-			| (gspca_dev->usb_buf[1] << 8)
-			| gspca_dev->usb_buf[2];
-	case SENSOR_MI0360:
-		/* read sensor exposure */
-		i2c_r5(gspca_dev, 0x09);
-		return (gspca_dev->usb_buf[0] << 8)
-			| gspca_dev->usb_buf[1];
-	case SENSOR_MO4000:
-		i2c_r5(gspca_dev, 0x0e);
-		hexpo = 0;		/* gspca_dev->usb_buf[1] & 0x07; */
-		mexpo = 0x40;		/* gspca_dev->usb_buf[2] & 0xff; */
-		lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
-		PDEBUG(D_CONF, "exposure %d",
-			(hexpo << 10) | (mexpo << 2) | lexpo);
-		return (hexpo << 10) | (mexpo << 2) | lexpo;
-	default:
-/*	case SENSOR_OV7648:		* jfm: is it ok for 7648? */
-/*	case SENSOR_OV7660: */
-		/* read sensor exposure */
-		i2c_r5(gspca_dev, 0x04);
-		hexpo = gspca_dev->usb_buf[3] & 0x2f;
-		lexpo = gspca_dev->usb_buf[0] & 0x02;
-		i2c_r5(gspca_dev, 0x08);
-		mexpo = gspca_dev->usb_buf[2];
-		return (hexpo << 10) | (mexpo << 2) | lexpo;
-	}
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	/* hardcoded registers seem not readable */
-	switch (sd->sensor) {
-	case SENSOR_HV7131R:
-		sd->brightness = getexposure(gspca_dev) >> 4;
-		break;
-	case SENSOR_MI0360:
-		sd->brightness = getexposure(gspca_dev) << 4;
-		break;
-	case SENSOR_MO4000:
-		sd->brightness = getexposure(gspca_dev) << 4;
-		break;
-	}
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->brightness = val;
-	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
+	if (gspca_dev->streaming) {
+		switch (sd->sensor) {
+		case SENSOR_HV7131R:
+		case SENSOR_MI0360:
+		case SENSOR_MO4000:
+		case SENSOR_OM6802:
+			setbrightness(gspca_dev);
+			break;
+		default:			/* OV76xx */
+			setbrightcont(gspca_dev);
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -1299,7 +1468,6 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	getbrightness(gspca_dev);
 	*val = sd->brightness;
 	return 0;
 }
@@ -1309,8 +1477,19 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->contrast = val;
-	if (gspca_dev->streaming)
-		setcontrast(gspca_dev);
+	if (gspca_dev->streaming) {
+		switch (sd->sensor) {
+		case SENSOR_HV7131R:
+		case SENSOR_MI0360:
+		case SENSOR_MO4000:
+		case SENSOR_OM6802:
+			setcontrast(gspca_dev);
+			break;
+		default:			/* OV76xx */
+			setbrightcont(gspca_dev);
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -1364,11 +1543,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 };
@@ -1379,7 +1556,7 @@
 			| (SENSOR_ ## sensor << 8) \
 			| (i2c_addr)
 static const __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
 	{USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
 	{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
 	{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
@@ -1406,15 +1583,17 @@
 /*	{USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
 /*	{USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*	{USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
-	{USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)},
-/* bw600.inf:
-	{USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */
+	{USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
+/*bw600.inf:*/
+	{USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/
 	{USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
-/*	{USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */
+	{USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
 /*	{USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
 	{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
+#endif
 	{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
 /*	{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */
 	{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
 	{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
@@ -1438,6 +1617,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 17fe2c2..6e73390 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -645,8 +645,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -880,14 +880,6 @@
 		gspca_dev->usb_buf[0]);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -1051,11 +1043,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -1093,6 +1083,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index 51a3c34..e9eb59b 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1953,8 +1953,8 @@
 	return -EINVAL;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
@@ -2023,11 +2023,6 @@
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
 	reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
 }
 
@@ -2120,11 +2115,10 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -2154,6 +2148,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index eda29d6..f601daf 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -655,8 +655,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret;
@@ -743,11 +743,6 @@
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
 	/* This maybe reset or power control */
 	reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
 	reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
@@ -825,11 +820,10 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -855,6 +849,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index f622fa7..195dce9 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -313,8 +313,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct usb_device *dev = gspca_dev->dev;
 
@@ -560,14 +560,6 @@
 	reg_w(dev, 0x03, 0x00, 0x0003);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -740,11 +732,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -772,6 +762,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 699340c..281ce02 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1521,8 +1521,8 @@
 	return 0;			/* success */
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 /*	write_vector(gspca_dev, spca508_open_data); */
 	return 0;
@@ -1554,15 +1554,6 @@
 	reg_write(gspca_dev->dev, 0x8112, 0x20);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -1633,11 +1624,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -1667,6 +1656,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 1073ac3..cfbc9eb 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -32,69 +32,48 @@
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	unsigned short contrast;
-	__u8 brightness;
+	__u16 contrast;			/* rev72a only */
+#define CONTRAST_MIN 0x0000
+#define CONTRAST_DEF 0x2000
+#define CONTRAST_MAX 0x3fff
+
+	__u16 exposure;			/* rev12a only */
+#define EXPOSURE_MIN 1
+#define EXPOSURE_DEF 200
+#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+
+	__u8 brightness;		/* rev72a only */
+#define BRIGHTNESS_MIN 0
+#define BRIGHTNESS_DEF 32
+#define BRIGHTNESS_MAX 63
+
+	__u8 white;			/* rev12a only */
+#define WHITE_MIN 1
+#define WHITE_DEF 0x40
+#define WHITE_MAX 0x7f
+
 	__u8 autogain;
+#define AUTOGAIN_MIN 0
+#define AUTOGAIN_DEF 1
+#define AUTOGAIN_MAX 1
+
+	__u8 gain;			/* rev12a only */
+#define GAIN_MIN 0x0
+#define GAIN_DEF 0x24
+#define GAIN_MAX 0x24
+
+#define EXPO12A_DEF 3
+	__u8 expo12a;		/* expo/gain? for rev 12a */
 
 	__u8 chip_revision;
+#define Rev012A 0
+#define Rev072A 1
+
 	signed char ag_cnt;
 #define AG_CNT_START 13
 };
 
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
-	{
-	 {
-	  .id = V4L2_CID_BRIGHTNESS,
-	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Brightness",
-	  .minimum = 0,
-	  .maximum = 63,
-	  .step = 1,
-	  .default_value = 32,
-	  },
-	 .set = sd_setbrightness,
-	 .get = sd_getbrightness,
-	 },
-#define SD_CONTRAST 1
-	{
-	 {
-	  .id = V4L2_CID_CONTRAST,
-	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Contrast",
-	  .minimum = 0,
-	  .maximum = 0x3fff,
-	  .step = 1,
-	  .default_value = 0x2000,
-	  },
-	 .set = sd_setcontrast,
-	 .get = sd_getcontrast,
-	 },
-#define SD_AUTOGAIN 2
-	{
-	 {
-	  .id = V4L2_CID_AUTOGAIN,
-	  .type = V4L2_CTRL_TYPE_BOOLEAN,
-	  .name = "Auto Gain",
-	  .minimum = 0,
-	  .maximum = 1,
-	  .step = 1,
-	  .default_value = 1,
-	  },
-	 .set = sd_setautogain,
-	 .get = sd_getautogain,
-	 },
-};
-
-static struct v4l2_pix_format sif_mode[] = {
+static struct v4l2_pix_format sif_012a_mode[] = {
 	{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
 		.bytesperline = 160,
 		.sizeimage = 160 * 120,
@@ -117,6 +96,29 @@
 		.priv = 0},
 };
 
+static struct v4l2_pix_format sif_072a_mode[] = {
+	{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 160,
+		.sizeimage = 160 * 120,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 3},
+	{176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 176,
+		.sizeimage = 176 * 144,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 2},
+	{320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 1},
+	{352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
 /*
  * Initialization data
  * I'm not very sure how to split initialization from open data
@@ -143,12 +145,8 @@
 #define SPCA561_INDEX_I2C_BASE 0x8800
 #define SPCA561_SNAPBIT 0x20
 #define SPCA561_SNAPCTRL 0x40
-enum {
-	Rev072A = 0,
-	Rev012A,
-};
 
-static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
 {
 	int ret;
 
@@ -198,12 +196,6 @@
 			index, gspca_dev->usb_buf, len, 500);
 }
 
-static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
-{
-	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
-	reg_w_val(gspca_dev->dev, mode, 0x8802);
-}
-
 static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
 {
 	int retry = 60;
@@ -212,9 +204,9 @@
 
 	DataLow = valeur;
 	DataHight = valeur >> 8;
-	reg_w_val(gspca_dev->dev, reg, 0x8801);
-	reg_w_val(gspca_dev->dev, DataLow, 0x8805);
-	reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+	reg_w_val(gspca_dev->dev, 0x8801, reg);
+	reg_w_val(gspca_dev->dev, 0x8805, DataLow);
+	reg_w_val(gspca_dev->dev, 0x8800, DataHight);
 	while (retry--) {
 		reg_r(gspca_dev, 0x8803, 1);
 		if (!gspca_dev->usb_buf[0])
@@ -228,14 +220,14 @@
 	__u8 value;
 	__u8 vallsb;
 
-	reg_w_val(gspca_dev->dev, 0x92, 0x8804);
-	reg_w_val(gspca_dev->dev, reg, 0x8801);
-	reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
-	while (retry--) {
+	reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+	reg_w_val(gspca_dev->dev, 0x8801, reg);
+	reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
+	do {
 		reg_r(gspca_dev, 0x8803, 1);
 		if (!gspca_dev->usb_buf)
 			break;
-	}
+	} while (--retry);
 	if (retry == 0)
 		return -1;
 	reg_r(gspca_dev, 0x8800, 1);
@@ -438,21 +430,10 @@
 	{0x0035, 0x8801},	/* 0x14 - set gain general */
 	{0x001f, 0x8805},	/* 0x14 */
 	{0x0000, 0x8800},
-	{0x0030, 0x8112},
+	{0x000e, 0x8112},	/* white balance - was 30 */
 	{}
 };
 
-static void sensor_reset(struct gspca_dev *gspca_dev)
-{
-	reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
-	reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
-	reg_w_val(gspca_dev->dev, 0x8112, 0x00);
-	reg_w_val(gspca_dev->dev, 0x8114, 0x00);
-	reg_w_val(gspca_dev->dev, 0x8118, 0x21);
-	i2c_init(gspca_dev, 0x14);
-	i2c_write(gspca_dev, 1, 0x0d);
-	i2c_write(gspca_dev, 0, 0x0d);
-}
 
 /******************** QC Express etch2 stuff ********************/
 static const __u16 Pb100_1map8300[][2] = {
@@ -462,9 +443,9 @@
 	{0x8303, 0x0125},	/* image area */
 	{0x8304, 0x0169},
 	{0x8328, 0x000b},
-	{0x833c, 0x0001},
+	{0x833c, 0x0001},		/*fixme: win:07*/
 
-	{0x832f, 0x0419},
+	{0x832f, 0x1904},		/*fixme: was 0419*/
 	{0x8307, 0x00aa},
 	{0x8301, 0x0003},
 	{0x8302, 0x000e},
@@ -478,9 +459,10 @@
 };
 
 static const __u16 spca561_161rev12A_data1[][2] = {
-	{0x21, 0x8118},
-	{0x01, 0x8114},
-	{0x00, 0x8112},
+	{0x29, 0x8118},		/* white balance - was 21 */
+	{0x08, 0x8114},		/* white balance - was 01 */
+	{0x0e, 0x8112},		/* white balance - was 00 */
+	{0x00, 0x8102},		/* white balance - new */
 	{0x92, 0x8804},
 	{0x04, 0x8802},		/* windows uses 08 */
 	{}
@@ -505,14 +487,16 @@
 	{0xb0, 0x8603},
 
 	/* sensor gains */
+	{0x07, 0x8601},		/* white balance - new */
+	{0x07, 0x8602},		/* white balance - new */
 	{0x00, 0x8610},		/* *red */
 	{0x00, 0x8611},		/* 3f   *green */
 	{0x00, 0x8612},		/* green *blue */
 	{0x00, 0x8613},		/* blue *green */
-	{0x35, 0x8614},		/* green *red */
-	{0x35, 0x8615},		/* 40   *green */
-	{0x35, 0x8616},		/* 7a   *blue */
-	{0x35, 0x8617},		/* 40   *green */
+	{0x43, 0x8614},		/* green *red - white balance - was 0x35 */
+	{0x40, 0x8615},		/* 40   *green - white balance - was 0x35 */
+	{0x71, 0x8616},		/* 7a   *blue - white balance - was 0x35 */
+	{0x40, 0x8617},		/* 40   *green - white balance - was 0x35 */
 
 	{0x0c, 0x8620},		/* 0c */
 	{0xc8, 0x8631},		/* c8 */
@@ -527,6 +511,7 @@
 	{0xdf, 0x863c},		/* df */
 	{0xf0, 0x8505},
 	{0x32, 0x850a},
+/*	{0x99, 0x8700},		 * - white balance - new (removed) */
 	{}
 };
 
@@ -545,9 +530,10 @@
 }
 static void init_161rev12A(struct gspca_dev *gspca_dev)
 {
-	sensor_reset(gspca_dev);
+/*	sensor_reset(gspca_dev);	(not in win) */
 	write_vector(gspca_dev, spca561_161rev12A_data1);
 	sensor_mapwrite(gspca_dev, Pb100_1map8300);
+/*fixme: should be in sd_start*/
 	write_vector(gspca_dev, spca561_161rev12A_data2);
 	sensor_mapwrite(gspca_dev, Pb100_2map8300);
 }
@@ -581,35 +567,38 @@
 	}
 
 	cam = &gspca_dev->cam;
-	cam->dev_name = (char *) id->driver_info;
 	cam->epaddr = 0x01;
 	gspca_dev->nbalt = 7 + 1;	/* choose alternate 7 first */
-	cam->cam_mode = sif_mode;
-	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
 
 	sd->chip_revision = id->driver_info;
-	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-	sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+	if (sd->chip_revision == Rev012A) {
+		cam->cam_mode = sif_012a_mode;
+		cam->nmodes = ARRAY_SIZE(sif_012a_mode);
+	} else {
+		cam->cam_mode = sif_072a_mode;
+		cam->nmodes = ARRAY_SIZE(sif_072a_mode);
+	}
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->white = WHITE_DEF;
+	sd->exposure = EXPOSURE_DEF;
+	sd->autogain = AUTOGAIN_DEF;
+	sd->gain = GAIN_DEF;
+	sd->expo12a = EXPO12A_DEF;
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init_12a(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
-	switch (sd->chip_revision) {
-	case Rev072A:
-		PDEBUG(D_STREAM, "Chip revision id: 072a");
-		write_vector(gspca_dev, spca561_init_data);
-		break;
-	default:
-/*	case Rev012A: */
-		PDEBUG(D_STREAM, "Chip revision id: 012a");
-		init_161rev12A(gspca_dev);
-		break;
-	}
+	PDEBUG(D_STREAM, "Chip revision: 012a");
+	init_161rev12A(gspca_dev);
+	return 0;
+}
+static int sd_init_72a(struct gspca_dev *gspca_dev)
+{
+	PDEBUG(D_STREAM, "Chip revision: 072a");
+	write_vector(gspca_dev, spca561_init_data);
 	return 0;
 }
 
@@ -618,25 +607,20 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
 	__u8 lowb;
-	int expotimes;
 
 	switch (sd->chip_revision) {
 	case Rev072A:
 		lowb = sd->contrast >> 8;
-		reg_w_val(dev, lowb, 0x8651);
-		reg_w_val(dev, lowb, 0x8652);
-		reg_w_val(dev, lowb, 0x8653);
-		reg_w_val(dev, lowb, 0x8654);
+		reg_w_val(dev, 0x8651, lowb);
+		reg_w_val(dev, 0x8652, lowb);
+		reg_w_val(dev, 0x8653, lowb);
+		reg_w_val(dev, 0x8654, lowb);
 		break;
-	case Rev012A: {
-		__u8 Reg8391[] =
-			{ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+	default: {
+/*	case Rev012A: { */
+		static const __u8 Reg8391[] =
+			{ 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
 
-		/* Write camera sensor settings */
-		expotimes = (sd->contrast >> 5) & 0x07ff;
-		Reg8391[0] = expotimes & 0xff;	/* exposure */
-		Reg8391[1] = 0x18 | (expotimes >> 8);
-		Reg8391[2] = sd->brightness;	/* gain */
 		reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
 		reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
 		break;
@@ -644,93 +628,151 @@
 	}
 }
 
+/* rev12a only */
+static void setwhite(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u16 white;
+	__u8 reg8614, reg8616;
+
+	white = sd->white;
+	/* try to emulate MS-win as possible */
+	reg8616 = 0x90 - white * 5 / 8;
+	reg_w_val(gspca_dev->dev, 0x8616, reg8616);
+	reg8614 = 0x20 + white * 3 / 8;
+	reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+}
+
+/* rev 12a only */
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int expo;
+	int clock_divider;
+	__u8 data[2];
+
+	/* Register 0x8309 controls exposure for the spca561,
+	   the basic exposure setting goes from 1-2047, where 1 is completely
+	   dark and 2047 is very bright. It not only influences exposure but
+	   also the framerate (to allow for longer exposure) from 1 - 300 it
+	   only raises the exposure time then from 300 - 600 it halves the
+	   framerate to be able to further raise the exposure time and for every
+	   300 more it halves the framerate again. This allows for a maximum
+	   exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
+	   Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
+	   configure a divider for the base framerate which us used at the
+	   exposure setting of 1-300. These bits configure the base framerate
+	   according to the following formula: fps = 60 / (value + 2) */
+	if (sd->exposure < 2048) {
+		expo = sd->exposure;
+		clock_divider = 0;
+	} else {
+		/* Add 900 to make the 0 setting of the second part of the
+		   exposure equal to the 2047 setting of the first part. */
+		expo = (sd->exposure - 2048) + 900;
+		clock_divider = 3;
+	}
+	expo |= clock_divider << 11;
+	data[0] = expo;
+	data[1] = expo >> 8;
+	reg_w_buf(gspca_dev, 0x8309, data, 2);
+}
+
+/* rev 12a only */
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data[2];
+
+	data[0] = sd->gain;
+	data[1] = 0;
+	reg_w_buf(gspca_dev, 0x8335, data, 2);
+}
+
 static void setautogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->chip_revision == Rev072A) {
-		if (sd->autogain)
-			sd->ag_cnt = AG_CNT_START;
-		else
-			sd->ag_cnt = -1;
-	}
+	if (sd->autogain)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static void sd_start_12a(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
-	int Clck;
+	int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
 	__u8 Reg8307[] = { 0xaa, 0x00 };
 	int mode;
 
 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
-	switch (sd->chip_revision) {
-	case Rev072A:
-		switch (mode) {
-		default:
-/*		case 0:
-		case 1: */
-			Clck = 0x25;
-			break;
-		case 2:
-			Clck = 0x22;
-			break;
-		case 3:
-			Clck = 0x21;
-			break;
-		}
-		reg_w_val(dev, 0x8500, mode);	/* mode */
-		reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
-		reg_w_val(dev, 0x8112, 0x10 | 0x20);
-		setautogain(gspca_dev);
-		break;
+	if (mode <= 1) {
+		/* Use compression on 320x240 and above */
+		reg_w_val(dev, 0x8500, 0x10 | mode);
+	} else {
+		/* I couldn't get the compression to work below 320x240
+		 * Fortunately at these resolutions the bandwidth
+		 * is sufficient to push raw frames at ~20fps */
+		reg_w_val(dev, 0x8500, mode);
+	}		/* -- qq@kuku.eu.org */
+	reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+	reg_w_val(gspca_dev->dev, 0x8700, Clck);
+					/* 0x8f 0x85 0x27 clock */
+	reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+	reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+	setcontrast(gspca_dev);
+	setwhite(gspca_dev);
+	setautogain(gspca_dev);
+	setexposure(gspca_dev);
+}
+static void sd_start_72a(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int Clck;
+	int mode;
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+	switch (mode) {
 	default:
-/*	case Rev012A: */
-		switch (mode) {
-		case 0:
-		case 1:
-			Clck = 0x8a;
-			break;
-		case 2:
-			Clck = 0x85;
-			break;
-		default:
-			Clck = 0x83;
-			break;
-		}
-		if (mode <= 1) {
-			/* Use compression on 320x240 and above */
-			reg_w_val(dev, 0x8500, 0x10 | mode);
-		} else {
-			/* I couldn't get the compression to work below 320x240
-			 * Fortunately at these resolutions the bandwidth
-			 * is sufficient to push raw frames at ~20fps */
-			reg_w_val(dev, 0x8500, mode);
-		}		/* -- qq@kuku.eu.org */
-		reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
-		reg_w_val(gspca_dev->dev, 0x8700, Clck);
-						/* 0x8f 0x85 0x27 clock */
-		reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
-		reg_w_val(gspca_dev->dev, 0x850b, 0x03);
-		setcontrast(gspca_dev);
+/*	case 0:
+	case 1: */
+		Clck = 0x25;
+		break;
+	case 2:
+		Clck = 0x22;
+		break;
+	case 3:
+		Clck = 0x21;
 		break;
 	}
+	reg_w_val(dev, 0x8500, mode);	/* mode */
+	reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
+	reg_w_val(dev, 0x8112, 0x10 | 0x20);
+	setautogain(gspca_dev);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->chip_revision == Rev012A) {
+		reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+	} else {
+		reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+/*		reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
+	}
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
+	struct sd *sd = (struct sd *) gspca_dev;
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-	reg_w_val(gspca_dev->dev, 0x8114, 0);
+	if (sd->chip_revision == Rev012A) {
+		reg_w_val(gspca_dev->dev, 0x8118, 0x29);
+		reg_w_val(gspca_dev->dev, 0x8114, 0x08);
+	}
+/*	reg_w_val(gspca_dev->dev, 0x8114, 0); */
 }
 
 static void do_autogain(struct gspca_dev *gspca_dev)
@@ -744,6 +786,7 @@
 	__u8 luma_mean = 110;
 	__u8 luma_delta = 20;
 	__u8 spring = 4;
+	__u8 reg8339[2];
 
 	if (sd->ag_cnt < 0)
 		return;
@@ -798,13 +841,16 @@
 		}
 		break;
 	case Rev012A:
-		/* sensor registers is access and memory mapped to 0x8300 */
-		/* readind all 0x83xx block the sensor */
-		/*
-		 * The data from the header seem wrong where is the luma
-		 * and chroma mean value
-		 * at the moment set exposure in contrast set
-		 */
+		reg_r(gspca_dev, 0x8330, 2);
+		if (gspca_dev->usb_buf[1] > 0x08) {
+			reg8339[0] = ++sd->expo12a;
+			reg8339[1] = 0;
+			reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+		} else if (gspca_dev->usb_buf[1] < 0x02) {
+			reg8339[0] = --sd->expo12a;
+			reg8339[1] = 0;
+			reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+		}
 		break;
 	}
 }
@@ -814,6 +860,8 @@
 			__u8 *data,		/* isoc packet */
 			int len)		/* iso packet length */
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
 	switch (data[0]) {
 	case 0:		/* start of frame */
 		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -826,8 +874,13 @@
 					frame, data, len);
 		} else {
 			/* raw bayer (with a header, which we skip) */
-			data += 20;
-			len -= 20;
+			if (sd->chip_revision == Rev012A) {
+				data += 20;
+				len -= 20;
+			} else {
+				data += 16;
+				len -= 16;
+			}
 			gspca_frame_add(gspca_dev, FIRST_PACKET,
 						frame, data, len);
 		}
@@ -841,24 +894,17 @@
 	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
+/* rev 72a only */
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	__u8 value;
 
-	switch (sd->chip_revision) {
-	case Rev072A:
-		value = sd->brightness;
-		reg_w_val(gspca_dev->dev, value, 0x8611);
-		reg_w_val(gspca_dev->dev, value, 0x8612);
-		reg_w_val(gspca_dev->dev, value, 0x8613);
-		reg_w_val(gspca_dev->dev, value, 0x8614);
-		break;
-	default:
-/*	case Rev012A: */
-		setcontrast(gspca_dev);
-		break;
-	}
+	value = sd->brightness;
+	reg_w_val(gspca_dev->dev, 0x8611, value);
+	reg_w_val(gspca_dev->dev, 0x8612, value);
+	reg_w_val(gspca_dev->dev, 0x8613, value);
+	reg_w_val(gspca_dev->dev, 0x8614, value);
 }
 
 static void getbrightness(struct gspca_dev *gspca_dev)
@@ -866,52 +912,38 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	__u16 tot;
 
-	switch (sd->chip_revision) {
-	case Rev072A:
-		tot = 0;
-		reg_r(gspca_dev, 0x8611, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8612, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8613, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8614, 1);
-		tot += gspca_dev->usb_buf[0];
-		sd->brightness = tot >> 2;
-		break;
-	default:
-/*	case Rev012A: */
-		/* no way to read sensor settings */
-		break;
-	}
+	tot = 0;
+	reg_r(gspca_dev, 0x8611, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8612, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8613, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8614, 1);
+	tot += gspca_dev->usb_buf[0];
+	sd->brightness = tot >> 2;
 }
 
+/* rev72a only */
 static void getcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	__u16 tot;
 
-	switch (sd->chip_revision) {
-	case Rev072A:
-		tot = 0;
-		reg_r(gspca_dev, 0x8651, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8652, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8653, 1);
-		tot += gspca_dev->usb_buf[0];
-		reg_r(gspca_dev, 0x8654, 1);
-		tot += gspca_dev->usb_buf[0];
-		sd->contrast = tot << 6;
-		break;
-	default:
-/*	case Rev012A: */
-		/* no way to read sensor settings */
-		break;
-	}
+	tot = 0;
+	reg_r(gspca_dev, 0x8651, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8652, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8653, 1);
+	tot += gspca_dev->usb_buf[0];
+	reg_r(gspca_dev, 0x8654, 1);
+	tot += gspca_dev->usb_buf[0];
+	sd->contrast = tot << 6;
 	PDEBUG(D_CONF, "get contrast %d", sd->contrast);
 }
 
+/* rev 72a only */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -931,6 +963,7 @@
 	return 0;
 }
 
+/* rev 72a only */
 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -968,20 +1001,190 @@
 	return 0;
 }
 
+/* rev12a only */
+static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->white = val;
+	if (gspca_dev->streaming)
+		setwhite(gspca_dev);
+	return 0;
+}
+
+static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->white;
+	return 0;
+}
+
+/* rev12a only */
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+/* rev12a only */
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+/* control tables */
+static struct ctrl sd_ctrls_12a[] = {
+	{
+	    {
+		.id = V4L2_CID_DO_WHITE_BALANCE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "While Balance",
+		.minimum = WHITE_MIN,
+		.maximum = WHITE_MAX,
+		.step = 1,
+		.default_value = WHITE_DEF,
+	    },
+	    .set = sd_setwhite,
+	    .get = sd_getwhite,
+	},
+	{
+	    {
+		.id = V4L2_CID_EXPOSURE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Exposure",
+		.minimum = EXPOSURE_MIN,
+		.maximum = EXPOSURE_MAX,
+		.step = 1,
+		.default_value = EXPOSURE_DEF,
+	    },
+	    .set = sd_setexposure,
+	    .get = sd_getexposure,
+	},
+	{
+	    {
+		.id = V4L2_CID_AUTOGAIN,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Auto Gain",
+		.minimum = AUTOGAIN_MIN,
+		.maximum = AUTOGAIN_MAX,
+		.step = 1,
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+	{
+	    {
+		.id = V4L2_CID_GAIN,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Gain",
+		.minimum = GAIN_MIN,
+		.maximum = GAIN_MAX,
+		.step = 1,
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+};
+
+static struct ctrl sd_ctrls_72a[] = {
+	{
+	   {
+		.id = V4L2_CID_BRIGHTNESS,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Brightness",
+		.minimum = BRIGHTNESS_MIN,
+		.maximum = BRIGHTNESS_MAX,
+		.step = 1,
+		.default_value = BRIGHTNESS_DEF,
+	    },
+	    .set = sd_setbrightness,
+	    .get = sd_getbrightness,
+	},
+	{
+	    {
+		.id = V4L2_CID_CONTRAST,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Contrast",
+		.minimum = CONTRAST_MIN,
+		.maximum = CONTRAST_MAX,
+		.step = 1,
+		.default_value = CONTRAST_DEF,
+	    },
+	    .set = sd_setcontrast,
+	    .get = sd_getcontrast,
+	},
+	{
+	    {
+		.id = V4L2_CID_AUTOGAIN,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Auto Gain",
+		.minimum = AUTOGAIN_MIN,
+		.maximum = AUTOGAIN_MAX,
+		.step = 1,
+		.default_value = AUTOGAIN_DEF,
+	    },
+	    .set = sd_setautogain,
+	    .get = sd_getautogain,
+	},
+};
+
 /* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_12a = {
 	.name = MODULE_NAME,
-	.ctrls = sd_ctrls,
-	.nctrls = ARRAY_SIZE(sd_ctrls),
+	.ctrls = sd_ctrls_12a,
+	.nctrls = ARRAY_SIZE(sd_ctrls_12a),
 	.config = sd_config,
-	.open = sd_open,
-	.start = sd_start,
+	.init = sd_init_12a,
+	.start = sd_start_12a,
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
+	.pkt_scan = sd_pkt_scan,
+/*	.dq_callback = do_autogain,	 * fixme */
+};
+static const struct sd_desc sd_desc_72a = {
+	.name = MODULE_NAME,
+	.ctrls = sd_ctrls_72a,
+	.nctrls = ARRAY_SIZE(sd_ctrls_72a),
+	.config = sd_config,
+	.init = sd_init_72a,
+	.start = sd_start_72a,
+	.stopN = sd_stopN,
+	.stop0 = sd_stop0,
 	.pkt_scan = sd_pkt_scan,
 	.dq_callback = do_autogain,
 };
+static const struct sd_desc *sd_desc[2] = {
+	&sd_desc_12a,
+	&sd_desc_72a
+};
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
@@ -1009,7 +1212,9 @@
 static int sd_probe(struct usb_interface *intf,
 		    const struct usb_device_id *id)
 {
-	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+	return gspca_dev_probe(intf, id,
+				sd_desc[id->driver_info],
+				sizeof(struct sd),
 			       THIS_MODULE);
 }
 
@@ -1018,6 +1223,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 16219cf..2f2de42 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -306,8 +306,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	int ret;
 
@@ -398,14 +398,6 @@
 	PDEBUG(D_STREAM, "camera stopped");
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -535,11 +527,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
 };
@@ -564,6 +554,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 54efa48..1cfcc6c 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -449,31 +449,47 @@
 	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
 };
 
-static void reg_r(struct usb_device *dev,
-			   __u16 req,
-			   __u16 index,
-			   __u8 *buffer, __u16 length)
+/* read <len> bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+		  __u16 req,
+		  __u16 index,
+		  __u16 len)
 {
-	usb_control_msg(dev,
-			usb_rcvctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		err("reg_r: buffer overflow");
+		return;
+	}
+#endif
+	usb_control_msg(gspca_dev->dev,
+			usb_rcvctrlpipe(gspca_dev->dev, 0),
 			req,
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			0,		/* value */
-			index, buffer, length,
+			index,
+			len ? gspca_dev->usb_buf : NULL, len,
 			500);
 }
 
-static void reg_w(struct usb_device *dev,
-			    __u16 req,
-			    __u16 value,
-			    __u16 index,
-			    __u8 *buffer, __u16 length)
+/* write <len> bytes from gspca_dev->usb_buf */
+static void reg_w(struct gspca_dev *gspca_dev,
+		   __u16 req,
+		   __u16 value,
+		   __u16 index,
+		   __u16 len)
 {
-	usb_control_msg(dev,
-			usb_sndctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+	if (len > USB_BUF_SZ) {
+		err("reg_w: buffer overflow");
+		return;
+	}
+#endif
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
 			req,
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, index, buffer, length,
+			value, index,
+			len ? gspca_dev->usb_buf : NULL, len,
 			500);
 }
 
@@ -634,7 +650,7 @@
 	int count = 10;
 
 	while (--count > 0) {
-		reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
+		reg_r(gspca_dev, 0x21, 0, 1);
 		if ((gspca_dev->usb_buf[0] & 0x01) == 0)
 			break;
 		msleep(10);
@@ -644,15 +660,14 @@
 
 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
 {
-	struct usb_device *dev = gspca_dev->dev;
 	int count = 50;
 
 	while (--count > 0) {
-		reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+		reg_r(gspca_dev, 0x21, 1, 1);
 		if (gspca_dev->usb_buf[0] != 0) {
 			gspca_dev->usb_buf[0] = 0;
-			reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
-			reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+			reg_w(gspca_dev, 0x21, 0, 1, 1);
+			reg_r(gspca_dev, 0x21, 1, 1);
 			spca504B_PollingDataReady(gspca_dev);
 			break;
 		}
@@ -662,16 +677,14 @@
 
 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
 {
-	struct usb_device *dev = gspca_dev->dev;
 	__u8 *data;
 
-	data = kmalloc(64, GFP_KERNEL);
-	reg_r(dev, 0x20, 0, data, 5);
+	data = gspca_dev->usb_buf;
+	reg_r(gspca_dev, 0x20, 0, 5);
 	PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
 		data[0], data[1], data[2], data[3], data[4]);
-	reg_r(dev, 0x23, 0, data, 64);
-	reg_r(dev, 0x23, 1, data, 64);
-	kfree(data);
+	reg_r(gspca_dev, 0x23, 0, 64);
+	reg_r(gspca_dev, 0x23, 1, 64);
 }
 
 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
@@ -686,21 +699,21 @@
 	Type = 0;
 	switch (sd->bridge) {
 	case BRIDGE_SPCA533:
-		reg_w(dev, 0x31, 0, 0, NULL, 0);
+		reg_w(gspca_dev, 0x31, 0, 0, 0);
 		spca504B_WaitCmdStatus(gspca_dev);
 		rc = spca504B_PollingDataReady(gspca_dev);
 		spca50x_GetFirmware(gspca_dev);
 		gspca_dev->usb_buf[0] = 2;			/* type */
-		reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
-		reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
+		reg_w(gspca_dev, 0x24, 0, 8, 1);
+		reg_r(gspca_dev, 0x24, 8, 1);
 
 		gspca_dev->usb_buf[0] = Size;
-		reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
-		reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);	/* size */
+		reg_w(gspca_dev, 0x25, 0, 4, 1);
+		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
 		rc = spca504B_PollingDataReady(gspca_dev);
 
 		/* Init the cam width height with some values get on init ? */
-		reg_w(dev, 0x31, 0, 4, NULL, 0);
+		reg_w(gspca_dev, 0x31, 0, 4, 0);
 		spca504B_WaitCmdStatus(gspca_dev);
 		rc = spca504B_PollingDataReady(gspca_dev);
 		break;
@@ -708,12 +721,12 @@
 /* case BRIDGE_SPCA504B: */
 /* case BRIDGE_SPCA536: */
 		gspca_dev->usb_buf[0] = Size;
-		reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
-		reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1);	/* size */
+		reg_w(gspca_dev, 0x25, 0, 4, 1);
+		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
 		Type = 6;
 		gspca_dev->usb_buf[0] = Type;
-		reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
-		reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1);	/* type */
+		reg_w(gspca_dev, 0x27, 0, 0, 1);
+		reg_r(gspca_dev, 0x27, 0, 1);			/* type */
 		rc = spca504B_PollingDataReady(gspca_dev);
 		break;
 	case BRIDGE_SPCA504:
@@ -752,18 +765,15 @@
 
 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
 {
-	struct usb_device *dev = gspca_dev->dev;
-
 	gspca_dev->usb_buf[0] = 3;
-	reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
-	reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
+	reg_w(gspca_dev, 0x26, 0, 0, 1);
+	reg_r(gspca_dev, 0x26, 0, 1);
 	spca504B_PollingDataReady(gspca_dev);
 }
 
 static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	struct usb_device *dev = gspca_dev->dev;
 	int pollreg = 1;
 
 	switch (sd->bridge) {
@@ -774,20 +784,20 @@
 	default:
 /*	case BRIDGE_SPCA533: */
 /*	case BRIDGE_SPCA504B: */
-		reg_w(dev, 0, 0, 0x21a7, NULL, 0);	/* brightness */
-		reg_w(dev, 0, 0x20, 0x21a8, NULL, 0);	/* contrast */
-		reg_w(dev, 0, 0, 0x21ad, NULL, 0);	/* hue */
-		reg_w(dev, 0, 1, 0x21ac, NULL, 0);	/* sat/hue */
-		reg_w(dev, 0, 0x20, 0x21ae, NULL, 0);	/* saturation */
-		reg_w(dev, 0, 0, 0x21a3, NULL, 0);	/* gamma */
+		reg_w(gspca_dev, 0, 0, 0x21a7, 0);	/* brightness */
+		reg_w(gspca_dev, 0, 0x20, 0x21a8, 0);	/* contrast */
+		reg_w(gspca_dev, 0, 0, 0x21ad, 0);	/* hue */
+		reg_w(gspca_dev, 0, 1, 0x21ac, 0);	/* sat/hue */
+		reg_w(gspca_dev, 0, 0x20, 0x21ae, 0);	/* saturation */
+		reg_w(gspca_dev, 0, 0, 0x21a3, 0);	/* gamma */
 		break;
 	case BRIDGE_SPCA536:
-		reg_w(dev, 0, 0, 0x20f0, NULL, 0);
-		reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
-		reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
-		reg_w(dev, 0, 1, 0x20f4, NULL, 0);
-		reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
-		reg_w(dev, 0, 0, 0x2089, NULL, 0);
+		reg_w(gspca_dev, 0, 0, 0x20f0, 0);
+		reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
+		reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
+		reg_w(gspca_dev, 0, 1, 0x20f4, 0);
+		reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
+		reg_w(gspca_dev, 0, 0, 0x2089, 0);
 		break;
 	}
 	if (pollreg)
@@ -799,7 +809,6 @@
 			const struct usb_device_id *id)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	struct usb_device *dev = gspca_dev->dev;
 	struct cam *cam;
 
 	cam = &gspca_dev->cam;
@@ -811,7 +820,7 @@
 	if (sd->subtype == AiptekMiniPenCam13) {
 /* try to get the firmware as some cam answer 2.0.1.2.2
  * and should be a spca504b then overwrite that setting */
-		reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
+		reg_r(gspca_dev, 0x20, 0, 1);
 		switch (gspca_dev->usb_buf[0]) {
 		case 1:
 			break;		/* (right bridge/subtype) */
@@ -848,8 +857,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct usb_device *dev = gspca_dev->dev;
@@ -860,12 +869,12 @@
 
 	switch (sd->bridge) {
 	case BRIDGE_SPCA504B:
-		reg_w(dev, 0x1d, 0, 0, NULL, 0);
-		reg_w(dev, 0, 1, 0x2306, NULL, 0);
-		reg_w(dev, 0, 0, 0x0d04, NULL, 0);
-		reg_w(dev, 0, 0, 0x2000, NULL, 0);
-		reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
-		reg_w(dev, 0, 0, 0x2306, NULL, 0);
+		reg_w(gspca_dev, 0x1d, 0, 0, 0);
+		reg_w(gspca_dev, 0, 1, 0x2306, 0);
+		reg_w(gspca_dev, 0, 0, 0x0d04, 0);
+		reg_w(gspca_dev, 0, 0, 0x2000, 0);
+		reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
+		reg_w(gspca_dev, 0, 0, 0x2306, 0);
 		/* fall thru */
 	case BRIDGE_SPCA533:
 		rc = spca504B_PollingDataReady(gspca_dev);
@@ -873,12 +882,12 @@
 		break;
 	case BRIDGE_SPCA536:
 		spca50x_GetFirmware(gspca_dev);
-		reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
+		reg_r(gspca_dev, 0x00, 0x5002, 1);
 		gspca_dev->usb_buf[0] = 0;
-		reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
-		reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
+		reg_w(gspca_dev, 0x24, 0, 0, 1);
+		reg_r(gspca_dev, 0x24, 0, 1);
 		rc = spca504B_PollingDataReady(gspca_dev);
-		reg_w(dev, 0x34, 0, 0, NULL, 0);
+		reg_w(gspca_dev, 0x34, 0, 0, 0);
 		spca504B_WaitCmdStatus(gspca_dev);
 		break;
 	case BRIDGE_SPCA504C:	/* pccam600 */
@@ -971,12 +980,12 @@
 /*	case BRIDGE_SPCA536: */
 		if (sd->subtype == MegapixV4 ||
 		    sd->subtype == LogitechClickSmart820) {
-			reg_w(dev, 0xf0, 0, 0, NULL, 0);
+			reg_w(gspca_dev, 0xf0, 0, 0, 0);
 			spca504B_WaitCmdStatus(gspca_dev);
-			reg_r(dev, 0xf0, 4, NULL, 0);
+			reg_r(gspca_dev, 0xf0, 4, 0);
 			spca504B_WaitCmdStatus(gspca_dev);
 		} else {
-			reg_w(dev, 0x31, 0, 4, NULL, 0);
+			reg_w(gspca_dev, 0x31, 0, 4, 0);
 			spca504B_WaitCmdStatus(gspca_dev);
 			rc = spca504B_PollingDataReady(gspca_dev);
 		}
@@ -1045,7 +1054,7 @@
 /*	case BRIDGE_SPCA533: */
 /*	case BRIDGE_SPCA536: */
 /*	case BRIDGE_SPCA504B: */
-		reg_w(dev, 0x31, 0, 0, NULL, 0);
+		reg_w(gspca_dev, 0x31, 0, 0, 0);
 		spca504B_WaitCmdStatus(gspca_dev);
 		spca504B_PollingDataReady(gspca_dev);
 		break;
@@ -1069,14 +1078,6 @@
 	}
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -1369,11 +1370,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -1456,6 +1455,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 91b555c..f034c74 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -30,7 +30,7 @@
 
 #define MAX_GAMMA 0x10		/* 0 to 15 */
 
-#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
 
 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
 MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
@@ -233,7 +233,7 @@
 static struct v4l2_pix_format vga_mode_t16[] = {
 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
-		.sizeimage = 160 * 120 * 3 / 8 + 590,
+		.sizeimage = 160 * 120 * 4 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 4},
 	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -391,7 +391,7 @@
 				NULL, 0, 500);
 		return;
 	}
-	if (len <= sizeof gspca_dev->usb_buf) {
+	if (len <= USB_BUF_SZ) {
 		memcpy(gspca_dev->usb_buf, buffer, len);
 		usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -552,6 +552,13 @@
 	return 0;
 }
 
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	init_default_parameters(gspca_dev);
+	return 0;
+}
+
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -893,18 +900,6 @@
 	setcolors(gspca_dev);
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -972,24 +967,14 @@
 	return -EINVAL;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
-{
-	init_default_parameters(gspca_dev);
-	return 0;
-}
-
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
-	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
 };
@@ -1014,6 +999,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 1ff8ba2..084af05 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -331,8 +331,8 @@
 	}
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
 	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
@@ -450,14 +450,6 @@
 	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
 }
 
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void tv8532_preprocess(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -611,11 +603,9 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
-	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 };
 
@@ -644,6 +634,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index f4a5295..bd4c226 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -69,6 +69,7 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+#define LIGHTFREQ_IDX 1
 	{
 	    {
 		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -87,12 +88,12 @@
 };
 
 static struct v4l2_pix_format vc0321_mode[] = {
-	{320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+	{320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
 		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
-	{640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+	{640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
 		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
@@ -1463,6 +1464,8 @@
 	sd->qindex = 7;
 	sd->autogain = AUTOGAIN_DEF;
 	sd->lightfreq = FREQ_DEF;
+	if (sd->sensor != SENSOR_OV7670)
+		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
 
 	if (sd->bridge == BRIDGE_VC0321) {
 		reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1474,8 +1477,8 @@
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	return 0;
 }
@@ -1637,19 +1640,6 @@
 	reg_w(dev, 0x89, 0xffff, 0xffff);
 }
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-/*	struct usb_device *dev = gspca_dev->dev;
-	__u8 buffread;
-
-	reg_w(dev, 0x89, 0xffff, 0xffff);
-	reg_w(dev, 0xa0, 0x01, 0xb301);
-	reg_w(dev, 0xa0, 0x09, 0xb303);
-	reg_w(dev, 0x89, 0xffff, 0xffff);
-*/
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -1738,11 +1728,10 @@
 	.ctrls = sd_ctrls,
 	.nctrls = ARRAY_SIZE(sd_ctrls),
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
 	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
 };
@@ -1774,6 +1763,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index bc7d0ee..8d7c27e 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -85,6 +85,7 @@
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
 #define SD_BRIGHTNESS 0
 	{
 	    {
@@ -141,6 +142,7 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+#define LIGHTFREQ_IDX 4
 #define SD_FREQ 4
 	{
 	    {
@@ -6964,8 +6966,13 @@
 	case SENSOR_MC501CB:
 		return -1;		/* don't probe */
 	case SENSOR_TAS5130C_VF0250:
-				/* may probe but with write in reg 0x0010 */
+			/* may probe but with no write in reg 0x0010 */
 		return -1;		/* don't probe */
+	case SENSOR_PAS106:
+		sensor =  sif_probe(gspca_dev);
+		if (sensor >= 0)
+			return sensor;
+		break;
 	}
 	sensor = vga_2wr_probe(gspca_dev);
 	if (sensor >= 0) {
@@ -6974,12 +6981,10 @@
 		/* next probe is needed for OmniVision ? */
 	}
 	sensor2 = vga_3wr_probe(gspca_dev);
-	if (sensor2 >= 0) {
-		if (sensor >= 0)
-			return sensor;
-		return sensor2;
-	}
-	return sif_probe(gspca_dev);
+	if (sensor2 >= 0
+	    && sensor >= 0)
+		return sensor;
+	return sensor2;
 }
 
 /* this function is called at probe time */
@@ -7147,13 +7152,27 @@
 	sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
 	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PO2030:
+		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+		break;
+	case SENSOR_HDCS2020:
+	case SENSOR_HV7131B:
+	case SENSOR_HV7131C:
+	case SENSOR_OV7630C:
+		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+		break;
+	}
+
 	/* switch the led off */
 	reg_w(gspca_dev->dev, 0x01, 0x0000);
 	return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	reg_w(gspca_dev->dev, 0x01, 0x0000);
 	return 0;
@@ -7314,10 +7333,6 @@
 	}
 }
 
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -7325,11 +7340,6 @@
 	send_unknown(gspca_dev->dev, sd->sensor);
 }
 
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,
 			__u8 *data,
@@ -7489,37 +7499,30 @@
 	.ctrls = sd_ctrls,
 	.nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
 	.config = sd_config,
-	.open = sd_open,
+	.init = sd_init,
 	.start = sd_start,
-	.stopN = sd_stopN,
 	.stop0 = sd_stop0,
-	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
 	.querymenu = sd_querymenu,
 };
 
 static const __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x041e, 0x041e)},
-#ifndef CONFIG_USB_ZC0301
 	{USB_DEVICE(0x041e, 0x4017)},
-	{USB_DEVICE(0x041e, 0x401c)},
+	{USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
 	{USB_DEVICE(0x041e, 0x401e)},
 	{USB_DEVICE(0x041e, 0x401f)},
-#endif
+	{USB_DEVICE(0x041e, 0x4022)},
 	{USB_DEVICE(0x041e, 0x4029)},
-#ifndef CONFIG_USB_ZC0301
-	{USB_DEVICE(0x041e, 0x4034)},
-	{USB_DEVICE(0x041e, 0x4035)},
+	{USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106},
+	{USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106},
 	{USB_DEVICE(0x041e, 0x4036)},
 	{USB_DEVICE(0x041e, 0x403a)},
-#endif
 	{USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
 	{USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
 	{USB_DEVICE(0x0458, 0x7007)},
 	{USB_DEVICE(0x0458, 0x700c)},
 	{USB_DEVICE(0x0458, 0x700f)},
-#endif
 	{USB_DEVICE(0x0461, 0x0a00)},
 	{USB_DEVICE(0x046d, 0x08a0)},
 	{USB_DEVICE(0x046d, 0x08a1)},
@@ -7531,7 +7534,7 @@
 	{USB_DEVICE(0x046d, 0x08aa)},
 	{USB_DEVICE(0x046d, 0x08ac)},
 	{USB_DEVICE(0x046d, 0x08ad)},
-#ifndef CONFIG_USB_ZC0301
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
 	{USB_DEVICE(0x046d, 0x08ae)},
 #endif
 	{USB_DEVICE(0x046d, 0x08af)},
@@ -7541,27 +7544,25 @@
 	{USB_DEVICE(0x046d, 0x08d8)},
 	{USB_DEVICE(0x046d, 0x08da)},
 	{USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
-	{USB_DEVICE(0x0471, 0x0325)},
-	{USB_DEVICE(0x0471, 0x0326)},
-	{USB_DEVICE(0x0471, 0x032d)},
-	{USB_DEVICE(0x0471, 0x032e)},
+	{USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106},
+	{USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106},
+	{USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106},
+	{USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106},
 	{USB_DEVICE(0x055f, 0xc005)},
-#ifndef CONFIG_USB_ZC0301
 	{USB_DEVICE(0x055f, 0xd003)},
 	{USB_DEVICE(0x055f, 0xd004)},
-#endif
 	{USB_DEVICE(0x0698, 0x2003)},
+	{USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
 	{USB_DEVICE(0x0ac8, 0x0302)},
-#ifndef CONFIG_USB_ZC0301
 	{USB_DEVICE(0x0ac8, 0x301b)},
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
 	{USB_DEVICE(0x0ac8, 0x303b)},
 #endif
 	{USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
 	{USB_DEVICE(0x0ac8, 0x307b)},
 	{USB_DEVICE(0x10fd, 0x0128)},
+	{USB_DEVICE(0x10fd, 0x804d)},
 	{USB_DEVICE(0x10fd, 0x8050)},
-#endif
 	{}			/* end of entry */
 };
 #undef DVNAME
@@ -7581,6 +7582,10 @@
 	.id_table = device_table,
 	.probe = sd_probe,
 	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+#endif
 };
 
 static int __init sd_mod_init(void)
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index aea1664..4afc7ea 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -688,7 +688,7 @@
 	spin_lock_init(&itv->lock);
 	spin_lock_init(&itv->dma_reg_lock);
 
-	itv->irq_work_queues = create_workqueue(itv->name);
+	itv->irq_work_queues = create_singlethread_workqueue(itv->name);
 	if (itv->irq_work_queues == NULL) {
 		IVTV_ERR("Could not create ivtv workqueue\n");
 		return -1;
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index ab287b4..2ceb522 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -251,6 +251,7 @@
 #define IVTV_F_I_DEC_PAUSED	   20 	/* the decoder is paused */
 #define IVTV_F_I_INITED		   21 	/* set after first open */
 #define IVTV_F_I_FAILED		   22 	/* set if first open failed */
+#define IVTV_F_I_WORK_INITED       23	/* worker thread was initialized */
 
 /* Event notifications */
 #define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fba150a..34f3ab8 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -76,6 +76,13 @@
 
 	DEFINE_WAIT(wait);
 
+	if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
+		struct sched_param param = { .sched_priority = 99 };
+
+		/* This thread must use the FIFO scheduler as it
+		   is realtime sensitive. */
+		sched_setscheduler(current, SCHED_FIFO, &param);
+	}
 	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
 		ivtv_pio_work_handler(itv);
 
@@ -678,34 +685,14 @@
 
 static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
 {
-	struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	struct ivtv_stream *s;
 
 	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
 	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 
-	/* If more than two VBI buffers are pending, then
-	   clear the old ones and start with this new one.
-	   This can happen during transition stages when MPEG capturing is
-	   started, but the first interrupts haven't arrived yet. During
-	   that period VBI requests can accumulate without being able to
-	   DMA the data. Since at most four VBI DMA buffers are available,
-	   we just drop the old requests when there are already three
-	   requests queued. */
-	if (s->sg_pending_size > 2) {
-		struct ivtv_buffer *buf;
-		list_for_each_entry(buf, &s->q_predma.list, list)
-			ivtv_buf_sync_for_cpu(s, buf);
-		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
-		s->sg_pending_size = 0;
-	}
-	/* if we can append the data, and the MPEG stream isn't capturing,
-	   then start a DMA request for just the VBI data. */
-	if (!stream_enc_dma_append(s, data) &&
-			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
+	if (!stream_enc_dma_append(s, data))
 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
-	}
 }
 
 static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
index 7cfc0c9..476556a 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -23,7 +23,7 @@
 #define IVTV_QUEUE_H
 
 #define IVTV_DMA_UNMAPPED	((u32) -1)
-#define SLICED_VBI_PIO 1
+#define SLICED_VBI_PIO 0
 
 /* ivtv_buffer utility functions */
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 54d2023..730e85d 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -363,7 +363,7 @@
 	/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
 	data[1] = 1;
 	/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
-	data[2] = raw ? 4 : 8;
+	data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
 	/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
 	   The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
 	   is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 71798f0..1ce9deb 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -293,6 +293,7 @@
 	u32 line_size = itv->vbi.sliced_decoder_line_size;
 	struct v4l2_decode_vbi_line vbi;
 	int i;
+	unsigned lines = 0;
 
 	/* find the first valid line */
 	for (i = 0; i < size; i++, buf++) {
@@ -313,7 +314,8 @@
 		}
 		vbi.p = p + 4;
 		itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
-		if (vbi.type) {
+		if (vbi.type && !(lines & (1 << vbi.line))) {
+			lines |= 1 << vbi.line;
 			itv->vbi.sliced_data[line].id = vbi.type;
 			itv->vbi.sliced_data[line].field = vbi.is_second_field;
 			itv->vbi.sliced_data[line].line = vbi.line;
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 442f43f..8cd753d 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -22,7 +22,7 @@
 
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 3
+#define IVTV_DRIVER_VERSION_MINOR 4
 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 4895540..2fd4b4a 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -679,26 +679,27 @@
 
 	case DECODER_ENABLE_OUTPUT:
 	{
+		int enable;
 
-		int *iarg = arg;
-		int enable = (*iarg != 0);
-			if (enable) {
-				dprintk("ks0127: command "
+		iarg = arg;
+		enable = (*iarg != 0);
+		if (enable) {
+			dprintk("ks0127: command "
 					"DECODER_ENABLE_OUTPUT on "
 					"(%d)\n", enable);
-				/* All output pins on */
-				ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
-				/* Obey the OEN pin */
-				ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
-			} else {
-				dprintk("ks0127: command "
+			/* All output pins on */
+			ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+			/* Obey the OEN pin */
+			ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+		} else {
+			dprintk("ks0127: command "
 					"DECODER_ENABLE_OUTPUT off "
 					"(%d)\n", enable);
-				/* Video output pins off */
-				ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
-				/* Ignore the OEN pin */
-				ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
-			}
+			/* Video output pins off */
+			ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+			/* Ignore the OEN pin */
+			ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+		}
 	}
 		break;
 
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 7c8ef6a..a9ef780 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1806,6 +1806,7 @@
 	memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
 	meye.video_dev->parent = &meye.mchip_dev->dev;
 
+	ret = -EIO;
 	if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
 		printk(KERN_ERR "meye: unable to power on the camera\n");
 		printk(KERN_ERR "meye: did you enable the camera in "
@@ -1813,7 +1814,6 @@
 		goto outsonypienable;
 	}
 
-	ret = -EIO;
 	if ((ret = pci_enable_device(meye.mchip_dev))) {
 		printk(KERN_ERR "meye: pci_enable_device failed\n");
 		goto outenabledev;
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index f68e91f..8ef578c 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -931,27 +931,29 @@
 	return 0;
 }
 
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
 {
-	struct mxb* mxb = (struct mxb*)dev->ext_priv;
+	struct mxb *mxb = (struct mxb *)dev->ext_priv;
 	int zero = 0;
 	int one = 1;
 
-	if(V4L2_STD_PAL_I == std->id ) {
+	if (V4L2_STD_PAL_I == standard->id) {
 		v4l2_std_id std = V4L2_STD_PAL_I;
+
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* unset the 7111 gpio register -- I don't know what this does exactly */
-		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
+		mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 	} else {
 		v4l2_std_id std = V4L2_STD_PAL_BG;
+
 		DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
 		/* set the 7146 gpio register -- I don't know what this does exactly */
 		saa7146_write(dev, GPIO_CTRL, 0x00404050);
 		/* set the 7111 gpio register -- I don't know what this does exactly */
-		mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
+		mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
 		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
 	}
 	return 0;
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 9edaca4..3d3c48d 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -626,9 +626,9 @@
 			break;
 
 		/* Retry until idle */
-		do
+		do {
 			rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0));
+		} while (rc > 0 && ((rc&1) == 0));
 		if (rc < 0)
 			break;
 
@@ -703,9 +703,9 @@
 			return rc;
 
 		/* Retry until idle */
-		do
-			 rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0));
+		do {
+			rc = reg_r(ov, R511_I2C_CTL);
+		} while (rc > 0 && ((rc & 1) == 0));
 		if (rc < 0)
 			return rc;
 
@@ -729,9 +729,9 @@
 			return rc;
 
 		/* Retry until idle */
-		do
+		do {
 			rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0));
+		} while (rc > 0 && ((rc&1) == 0));
 		if (rc < 0)
 			return rc;
 
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 00425d7..7c84f79 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -1019,10 +1019,23 @@
  *	Initialization and module stuff
  */
 
+#ifndef MODULE
+static int enable;
+module_param(enable, int, 0);
+#endif
+
 static int __init init_pms_cards(void)
 {
 	printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
 
+#ifndef MODULE
+	if (!enable) {
+		printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
+				 "probe\n");
+		return -ENODEV;
+	}
+#endif
+
 	data_port = io_port +1;
 
 	if(init_mediavision())
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 1cccd5c7..dbc5607 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1635,15 +1635,15 @@
 
 	case VIDIOCPWCGVIDCMD:
 	{
-		ARG_DEF(struct pwc_video_command, cmd);
+		ARG_DEF(struct pwc_video_command, vcmd);
 
-		ARGR(cmd).type = pdev->type;
-		ARGR(cmd).release = pdev->release;
-		ARGR(cmd).command_len = pdev->cmd_len;
-		memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
-		ARGR(cmd).bandlength = pdev->vbandlength;
-		ARGR(cmd).frame_size = pdev->frame_size;
-		ARG_OUT(cmd)
+		ARGR(vcmd).type = pdev->type;
+		ARGR(vcmd).release = pdev->release;
+		ARGR(vcmd).command_len = pdev->cmd_len;
+		memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+		ARGR(vcmd).bandlength = pdev->vbandlength;
+		ARGR(vcmd).frame_size = pdev->frame_size;
+		ARG_OUT(vcmd)
 		break;
 	}
 	/*
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index bcd1c8f..ad733ca 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1489,10 +1489,9 @@
 		 client->addr << 1, client->adapter->name);
 
 	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
-	i2c_set_clientdata(client, state);
-	if (state == NULL) {
+	if (state == NULL)
 		return -ENOMEM;
-	}
+	i2c_set_clientdata(client, state);
 	state->input = -1;
 	state->output = SAA7115_IPORT_ON;
 	state->enable = 1;
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index f481277..acceed5 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -1397,7 +1397,7 @@
 	mutex_init(&se401->lock);
 	wmb();
 
-	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		kfree(se401);
 		err("video_register_device failed");
 		return -EIO;
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 2340876..2da6938 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -3312,6 +3312,7 @@
 	cam->v4ldev->fops = &sn9c102_fops;
 	cam->v4ldev->minor = video_nr[dev_nr];
 	cam->v4ldev->release = video_device_release;
+	cam->v4ldev->parent = &udev->dev;
 
 	init_completion(&cam->probe);
 
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 6ff489b..90a401d 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -40,11 +40,14 @@
 
 static const struct usb_device_id sn9c102_id_table[] = {
 	/* SN9C101 and SN9C102 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+#endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
@@ -53,29 +56,33 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
 	/* SN9C103 */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+#endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+#endif
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
@@ -105,7 +112,7 @@
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
-	{ SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
+/*	{ SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 56dc3d6..dce9474 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -1462,7 +1462,7 @@
 	mutex_init (&stv680->lock);
 	wmb ();
 
-	if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+	if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
 		PDEBUG (0, "STV(e): video_register_device failed");
 		retval = -EIO;
 		goto error_vdev;
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index 59166b7..cc27efe 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -736,12 +736,12 @@
 		 * make black color and quit the horizontal scanning loop.
 		 */
 		if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-			const int j = i * V4L_BYTES_PER_PIXEL;
+			const int offset = i * V4L_BYTES_PER_PIXEL;
 #if USES_IBMCAM_PUTPIXEL
 			/* Refresh 'f' because we don't use it much with PUTPIXEL */
-			f = frame->data + (v4l_linesize * frame->curline) + j;
+			f = frame->data + (v4l_linesize * frame->curline) + offset;
 #endif
-			memset(f, 0, v4l_linesize - j);
+			memset(f, 0, v4l_linesize - offset);
 			break;
 		}
 
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index b779245..2eb4582 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -866,7 +866,7 @@
 	cam->udev = dev;
 	cam->bulkEndpoint = bulkEndpoint;
 
-	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
 		kfree(cam);
 		printk(KERN_WARNING "video_register_device failed\n");
 		return -EIO;
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 6f36006..155fdec 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -257,6 +257,9 @@
 	int ret;
 	char *name_base;
 
+	if (vfd == NULL)
+		return -EINVAL;
+
 	switch (type) {
 	case VFL_TYPE_GRABBER:
 		base = MINOR_VFL_TYPE_GRABBER_MIN;
@@ -281,7 +284,7 @@
 	default:
 		printk(KERN_ERR "%s called with unknown type: %d\n",
 		       __func__, type);
-		return -1;
+		return -EINVAL;
 	}
 
 	/* pick a minor number */
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index fdfe773..140ef92 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -499,7 +499,7 @@
 			p->timestamp.tv_sec / 3600,
 			(int)(p->timestamp.tv_sec / 60) % 60,
 			(int)(p->timestamp.tv_sec % 60),
-			p->timestamp.tv_usec,
+			(long)p->timestamp.tv_usec,
 			p->index,
 			prt_names(p->type, v4l2_type_names),
 			p->bytesused, p->flags,
@@ -674,7 +674,7 @@
 	 __video_do_ioctl will be called again, with one or more
 	 V4L2 ioctls.
 	 ********************************************************/
-	if (_IOC_TYPE(cmd) == 'v')
+	if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
 		return v4l_compat_translate_ioctl(inode, file, cmd, arg,
 						__video_do_ioctl);
 #endif
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3518af0..8ba8daa 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -1021,13 +1021,13 @@
 		dev = list_entry(list, struct vivi_dev, vivi_devlist);
 
 		if (-1 != dev->vfd->minor) {
+			printk(KERN_INFO "%s: unregistering /dev/video%d\n",
+				VIVI_MODULE_NAME, dev->vfd->minor);
 			video_unregister_device(dev->vfd);
-			printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
-				VIVI_MODULE_NAME, dev->vfd->minor);
 		} else {
-			video_device_release(dev->vfd);
-			printk(KERN_INFO "%s: /dev/video%d released.\n",
+			printk(KERN_INFO "%s: releasing /dev/video%d\n",
 				VIVI_MODULE_NAME, dev->vfd->minor);
+			video_device_release(dev->vfd);
 		}
 
 		kfree(dev);
@@ -1104,19 +1104,29 @@
 	Initialization and module stuff
    ------------------------------------------------------------------*/
 
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports. Since there are 64 minors for video grabbers, this is
+   currently the theoretical maximum limit. However, a further limit does
+   exist at videodev that forbids any driver to register more than 32 video
+   grabbers.
+ */
 static int __init vivi_init(void)
 {
 	int ret = -ENOMEM, i;
 	struct vivi_dev *dev;
 	struct video_device *vfd;
 
+	if (n_devs <= 0)
+		n_devs = 1;
+
 	for (i = 0; i < n_devs; i++) {
 		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-		if (NULL == dev)
+		if (!dev)
 			break;
 
-		list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
 		/* init video dma queues */
 		INIT_LIST_HEAD(&dev->vidq.active);
 		init_waitqueue_head(&dev->vidq.wq);
@@ -1126,14 +1136,27 @@
 		mutex_init(&dev->mutex);
 
 		vfd = video_device_alloc();
-		if (NULL == vfd)
+		if (!vfd) {
+			kfree(dev);
 			break;
+		}
 
 		*vfd = vivi_template;
 
 		ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-		if (ret < 0)
+		if (ret < 0) {
+			video_device_release(vfd);
+			kfree(dev);
+
+			/* If some registers succeeded, keep driver */
+			if (i)
+				ret = 0;
+
 			break;
+		}
+
+		/* Now that everything is fine, let's add it to device list */
+		list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
 		snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
 			 vivi_template.name, vfd->minor);
@@ -1149,11 +1172,16 @@
 	if (ret < 0) {
 		vivi_release();
 		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
-	} else
+	} else {
 		printk(KERN_INFO "Video Technology Magazine Virtual Video "
 			"Capture Board ver %u.%u.%u successfully loaded.\n",
 			(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
 			VIVI_VERSION & 0xFF);
+
+		/* n_devs will reflect the actual number of allocated devices */
+		n_devs = i;
+	}
+
 	return ret;
 }
 
@@ -1169,10 +1197,10 @@
 MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
 MODULE_LICENSE("Dual BSD/GPL");
 
-module_param(video_nr, int, 0);
+module_param(video_nr, uint, 0444);
 MODULE_PARM_DESC(video_nr, "video iminor start number");
 
-module_param(n_devs, int, 0);
+module_param(n_devs, uint, 0444);
 MODULE_PARM_DESC(n_devs, "number of video devices to create");
 
 module_param_named(debug, vivi_template.debug, int, 0444);
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 9402f40..2ff00bc 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -334,7 +334,7 @@
 	memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
 	cam->vdev.priv = cam;
 
-	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
 		return -1;
 
 	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 550ce7b..0c32877 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1988,6 +1988,7 @@
 	cam->v4ldev->fops = &zc0301_fops;
 	cam->v4ldev->minor = video_nr[dev_nr];
 	cam->v4ldev->release = video_device_release;
+	cam->v4ldev->parent = &udev->dev;
 	video_set_drvdata(cam->v4ldev, cam);
 
 	init_completion(&cam->probe);
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 70fe6fc..b0cd49c 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -60,27 +60,8 @@
 
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), },                         \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */            \
-	{ ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
-	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
-	{ ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */           \
 	{ }                                                                   \
 };
 
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 7a1ef6c..3e56203 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -463,6 +463,13 @@
 		     DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
 		     },
 	 .callback = dmi_check_cb_s6410},
+	{
+	 .ident = "FUJITSU LifeBook P8010",
+	 .matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
+		    },
+	 .callback = dmi_check_cb_s6410},
 	{}
 };
 
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index d3eb790..6b93007 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3086,7 +3086,6 @@
 	.read = wan_read,
 	.write = wan_write,
 	.exit = wan_exit,
-	.flags.experimental = 1,
 };
 
 /*************************************************************************
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 86dbb36..6986f39 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -103,8 +103,10 @@
 			check_disk_change(inode->i_bdev);
 		ret = 0;
 
-		if ((filp->f_mode & FMODE_WRITE) && md->read_only)
+		if ((filp->f_mode & FMODE_WRITE) && md->read_only) {
+			mmc_blk_put(md);
 			ret = -EROFS;
+		}
 	}
 
 	return ret;
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index cbab654..edb1e32 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -109,7 +109,7 @@
 
 	void __iomem *ccr;
 	void __iomem *fcr;
-	unsigned long fcr_phys;
+	unsigned long fcr_base;
 
 	unsigned int irq;
 
@@ -316,8 +316,8 @@
 	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
 
 	/* (10h)BaseAddress    0x1000 spba.spba2 */
-	tmio_iowrite16(tmio->fcr_phys, tmio->ccr + CCR_BASE);
-	tmio_iowrite16(tmio->fcr_phys >> 16, tmio->ccr + CCR_BASE + 16);
+	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
+	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
 
 	/* (04h)Command Register I/O spcmd */
 	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
@@ -395,7 +395,7 @@
 		goto err_iomap_ccr;
 	}
 
-	tmio->fcr_phys = (unsigned long)fcr->start;
+	tmio->fcr_base = fcr->start & 0xfffff;
 	tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1);
 	if (!tmio->fcr) {
 		retval = -EIO;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 331b86b..0b6ecef 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -5975,10 +5975,12 @@
 	if (netif_running(dev))
 		nv_close(dev);
 
-	pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
-	pci_enable_wake(pdev, PCI_D3cold, np->wolenabled);
 	pci_disable_device(pdev);
-	pci_set_power_state(pdev, PCI_D3hot);
+	if (system_state == SYSTEM_POWER_OFF) {
+		if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
+			pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+		pci_set_power_state(pdev, PCI_D3hot);
+	}
 }
 #else
 #define nv_suspend NULL
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 82634a2..1aad599 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -352,11 +352,12 @@
 				continue;
 			r_size = r->end - r->start + 1;
 			/* For bridges size != alignment */
-			align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+			align = resource_alignment(r);
 			order = __ffs(align) - 20;
 			if (order > 11) {
-				dev_warn(&dev->dev, "BAR %d too large: "
+				dev_warn(&dev->dev, "BAR %d bad alignment %llx: "
 				       "%#016llx-%#016llx\n", i,
+				       (unsigned long long)align,
 				       (unsigned long long)r->start,
 				       (unsigned long long)r->end);
 				r->flags = 0;
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index d7e9f21..95015cb 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -405,8 +405,6 @@
 
 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 		extended_irq = &res->data.extended_irq;
-		if (extended_irq->producer_consumer == ACPI_PRODUCER)
-			return AE_OK;
 
 		if (extended_irq->interrupt_count == 0)
 			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index db00b05..f1216cf 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -423,7 +423,7 @@
 	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
 	if (ret) {
 		device_unregister(&chp->dev);
-		goto out_free;
+		goto out;
 	}
 	mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
 	if (channel_subsystems[chpid.cssid]->cm_enabled) {
@@ -432,14 +432,15 @@
 			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
 			device_unregister(&chp->dev);
 			mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
-			goto out_free;
+			goto out;
 		}
 	}
 	channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
 	mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
-	return ret;
+	goto out;
 out_free:
 	kfree(chp);
+out:
 	return ret;
 }
 
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 33bff8f..5954b90 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -208,8 +208,10 @@
 	case 1:		/* status pending */
 	case 2:		/* busy */
 		return -EBUSY;
-	default:		/* device/path not operational */
+	case 3:		/* device/path not operational */
 		return cio_start_handle_notoper(sch, lpm);
+	default:
+		return ccode;
 	}
 }
 
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 51489ef..1261e1a 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -633,6 +633,11 @@
 
 	css = to_css(dev);
 	mutex_destroy(&css->mutex);
+	if (css->pseudo_subchannel) {
+		/* Implies that it has been generated but never registered. */
+		css_subchannel_release(&css->pseudo_subchannel->dev);
+		css->pseudo_subchannel = NULL;
+	}
 	kfree(css);
 }
 
@@ -785,11 +790,15 @@
 		}
 		channel_subsystems[i] = css;
 		ret = setup_css(i);
-		if (ret)
-			goto out_free;
+		if (ret) {
+			kfree(channel_subsystems[i]);
+			goto out_unregister;
+		}
 		ret = device_register(&css->device);
-		if (ret)
-			goto out_free_all;
+		if (ret) {
+			put_device(&css->device);
+			goto out_unregister;
+		}
 		if (css_chsc_characteristics.secm) {
 			ret = device_create_file(&css->device,
 						 &dev_attr_cm_enable);
@@ -802,7 +811,7 @@
 	}
 	ret = register_reboot_notifier(&css_reboot_notifier);
 	if (ret)
-		goto out_pseudo;
+		goto out_unregister;
 	css_init_done = 1;
 
 	/* Enable default isc for I/O subchannels. */
@@ -810,18 +819,12 @@
 
 	for_each_subchannel(__init_channel_subsystem, NULL);
 	return 0;
-out_pseudo:
-	device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
 out_file:
-	device_remove_file(&channel_subsystems[i]->device,
-			   &dev_attr_cm_enable);
+	if (css_chsc_characteristics.secm)
+		device_remove_file(&channel_subsystems[i]->device,
+				   &dev_attr_cm_enable);
 out_device:
 	device_unregister(&channel_subsystems[i]->device);
-out_free_all:
-	kfree(channel_subsystems[i]->pseudo_subchannel->lock);
-	kfree(channel_subsystems[i]->pseudo_subchannel);
-out_free:
-	kfree(channel_subsystems[i]);
 out_unregister:
 	while (i > 0) {
 		struct channel_subsystem *css;
@@ -829,6 +832,7 @@
 		i--;
 		css = channel_subsystems[i];
 		device_unregister(&css->pseudo_subchannel->dev);
+		css->pseudo_subchannel = NULL;
 		if (css_chsc_characteristics.secm)
 			device_remove_file(&css->device,
 					   &dev_attr_cm_enable);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 550508d..84cc9ea 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -658,6 +658,13 @@
 {
 	struct subchannel *sch;
 
+	/* Allow ccw_device_offline while disconnected. */
+	if (cdev->private->state == DEV_STATE_DISCONNECTED ||
+	    cdev->private->state == DEV_STATE_NOT_OPER) {
+		cdev->private->flags.donotify = 0;
+		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+		return 0;
+	}
 	if (ccw_device_is_orphan(cdev)) {
 		ccw_device_done(cdev, DEV_STATE_OFFLINE);
 		return 0;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 1eb64d0..95b3ec8 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -208,7 +208,7 @@
 	if (cpu_is_omap16xx())
 		ocpi_enable();
 
-#ifdef	CONFIG_ARCH_OMAP_OTG
+#ifdef	CONFIG_USB_OTG
 	if (need_transceiver) {
 		ohci->transceiver = otg_get_transceiver();
 		if (ohci->transceiver) {
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 7b74238..e980766 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -161,7 +161,7 @@
 		if (serial->type->set_termios) {
 			termios->c_cflag = cflag;
 			tty_termios_encode_baud_rate(termios, baud, baud);
-			serial->type->set_termios(NULL, port, &dummy);
+			serial->type->set_termios(tty, port, &dummy);
 
 			port->port.tty = NULL;
 			kfree(termios);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 9c59259..5a24c64 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -939,7 +939,7 @@
 	ret = register_framebuffer(info);
 	if (ret < 0) {
 		dev_err(dev, "failed to register framebuffer device: %d\n", ret);
-		goto free_cmap;
+		goto reset_drvdata;
 	}
 
 	/* add selected videomode to modelist */
@@ -955,7 +955,8 @@
 
 	return 0;
 
-
+reset_drvdata:
+	dev_set_drvdata(dev, NULL);
 free_cmap:
 	fb_dealloc_cmap(&info->cmap);
 unregister_irqs:
@@ -992,10 +993,11 @@
 {
 	struct device *dev = &pdev->dev;
 	struct fb_info *info = dev_get_drvdata(dev);
-	struct atmel_lcdfb_info *sinfo = info->par;
+	struct atmel_lcdfb_info *sinfo;
 
-	if (!sinfo)
+	if (!info || !info->par)
 		return 0;
+	sinfo = info->par;
 
 	cancel_work_sync(&sinfo->task);
 	exit_backlight(sinfo);
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index d4427cb..2e15da54 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -60,7 +60,7 @@
 
 #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
 
-#define BALLOON_CLASS_NAME "memory"
+#define BALLOON_CLASS_NAME "xen_memory"
 
 struct balloon_stats {
 	/* We aim for 'current allocation' == 'target allocation'. */
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 9abcd2b..e9b2017 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1279,6 +1279,12 @@
 		}
 	}
 
+	if (errors > 0) {
+		dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n",
+				errors, (errors == 1 ? "" : "s"));
+		if (!sloppy)
+			return 0;
+	}
 	return 1;
 
 out_nomem:
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 0d6eb33..71c9be5 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -337,65 +337,6 @@
 	return 0;
 }
 
-/*
- * Use precise platform statistics if available:
- */
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-static cputime_t task_utime(struct task_struct *p)
-{
-	return p->utime;
-}
-
-static cputime_t task_stime(struct task_struct *p)
-{
-	return p->stime;
-}
-#else
-static cputime_t task_utime(struct task_struct *p)
-{
-	clock_t utime = cputime_to_clock_t(p->utime),
-		total = utime + cputime_to_clock_t(p->stime);
-	u64 temp;
-
-	/*
-	 * Use CFS's precise accounting:
-	 */
-	temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
-
-	if (total) {
-		temp *= utime;
-		do_div(temp, total);
-	}
-	utime = (clock_t)temp;
-
-	p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));
-	return p->prev_utime;
-}
-
-static cputime_t task_stime(struct task_struct *p)
-{
-	clock_t stime;
-
-	/*
-	 * Use CFS's precise accounting. (we subtract utime from
-	 * the total, to make sure the total observed by userspace
-	 * grows monotonically - apps rely on that):
-	 */
-	stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
-			cputime_to_clock_t(task_utime(p));
-
-	if (stime >= 0)
-		p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime));
-
-	return p->prev_stime;
-}
-#endif
-
-static cputime_t task_gtime(struct task_struct *p)
-{
-	return p->gtime;
-}
-
 static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 			struct pid *pid, struct task_struct *task, int whole)
 {
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index 15409815..73db464 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -302,18 +302,6 @@
 	int subtract_lebs;
 	long long available;
 
-	/*
-	 * Force the amount available to the total size reported if the used
-	 * space is zero.
-	 */
-	if (c->lst.total_used <= UBIFS_INO_NODE_SZ &&
-	    c->budg_data_growth + c->budg_dd_growth == 0) {
-		/* Do the same calculation as for c->block_cnt */
-		available = c->main_lebs - 2;
-		available *= c->leb_size - c->dark_wm;
-		return available;
-	}
-
 	available = c->main_bytes - c->lst.total_used;
 
 	/*
@@ -714,34 +702,106 @@
 }
 
 /**
- * ubifs_budg_get_free_space - return amount of free space.
+ * ubifs_reported_space - calculate reported free space.
+ * @c: the UBIFS file-system description object
+ * @free: amount of free space
+ *
+ * This function calculates amount of free space which will be reported to
+ * user-space. User-space application tend to expect that if the file-system
+ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
+ * are able to write a file of size N. UBIFS attaches node headers to each data
+ * node and it has to write indexind nodes as well. This introduces additional
+ * overhead, and UBIFS it has to report sligtly less free space to meet the
+ * above expectetion.
+ *
+ * This function assumes free space is made up of uncompressed data nodes and
+ * full index nodes (one per data node, tripled because we always allow enough
+ * space to write the index thrice).
+ *
+ * Note, the calculation is pessimistic, which means that most of the time
+ * UBIFS reports less space than it actually has.
+ */
+long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free)
+{
+	int divisor, factor, f;
+
+	/*
+	 * Reported space size is @free * X, where X is UBIFS block size
+	 * divided by UBIFS block size + all overhead one data block
+	 * introduces. The overhead is the node header + indexing overhead.
+	 *
+	 * Indexing overhead calculations are based on the following formula:
+	 * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number
+	 * of data nodes, f - fanout. Because effective UBIFS fanout is twice
+	 * as less than maximum fanout, we assume that each data node
+	 * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
+	 * Note, the multiplier 3 is because UBIFS reseves thrice as more space
+	 * for the index.
+	 */
+	f = c->fanout > 3 ? c->fanout >> 1 : 2;
+	factor = UBIFS_BLOCK_SIZE;
+	divisor = UBIFS_MAX_DATA_NODE_SZ;
+	divisor += (c->max_idx_node_sz * 3) / (f - 1);
+	free *= factor;
+	do_div(free, divisor);
+	return free;
+}
+
+/**
+ * ubifs_get_free_space - return amount of free space.
  * @c: UBIFS file-system description object
  *
- * This function returns amount of free space on the file-system.
+ * This function calculates amount of free space to report to user-space.
+ *
+ * Because UBIFS may introduce substantial overhead (the index, node headers,
+ * alighment, wastage at the end of eraseblocks, etc), it cannot report real
+ * amount of free flash space it has (well, because not all dirty space is
+ * reclamable, UBIFS does not actually know the real amount). If UBIFS did so,
+ * it would bread user expectetion about what free space is. Users seem to
+ * accustomed to assume that if the file-system reports N bytes of free space,
+ * they would be able to fit a file of N bytes to the FS. This almost works for
+ * traditional file-systems, because they have way less overhead than UBIFS.
+ * So, to keep users happy, UBIFS tries to take the overhead into account.
  */
-long long ubifs_budg_get_free_space(struct ubifs_info *c)
+long long ubifs_get_free_space(struct ubifs_info *c)
 {
-	int min_idx_lebs, rsvd_idx_lebs;
+	int min_idx_lebs, rsvd_idx_lebs, lebs;
 	long long available, outstanding, free;
 
-	/* Do exactly the same calculations as in 'do_budget_space()' */
 	spin_lock(&c->space_lock);
 	min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+	outstanding = c->budg_data_growth + c->budg_dd_growth;
 
+	/*
+	 * Force the amount available to the total size reported if the used
+	 * space is zero.
+	 */
+	if (c->lst.total_used <= UBIFS_INO_NODE_SZ && !outstanding) {
+		spin_unlock(&c->space_lock);
+		return (long long)c->block_cnt << UBIFS_BLOCK_SHIFT;
+	}
+
+	available = ubifs_calc_available(c, min_idx_lebs);
+
+	/*
+	 * When reporting free space to user-space, UBIFS guarantees that it is
+	 * possible to write a file of free space size. This means that for
+	 * empty LEBs we may use more precise calculations than
+	 * 'ubifs_calc_available()' is using. Namely, we know that in empty
+	 * LEBs we would waste only @c->leb_overhead bytes, not @c->dark_wm.
+	 * Thus, amend the available space.
+	 *
+	 * Note, the calculations below are similar to what we have in
+	 * 'do_budget_space()', so refer there for comments.
+	 */
 	if (min_idx_lebs > c->lst.idx_lebs)
 		rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
 	else
 		rsvd_idx_lebs = 0;
-
-	if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt
-				- c->lst.taken_empty_lebs) {
-		spin_unlock(&c->space_lock);
-		return 0;
-	}
-
-	available = ubifs_calc_available(c, min_idx_lebs);
-	outstanding = c->budg_data_growth + c->budg_dd_growth;
-	c->min_idx_lebs = min_idx_lebs;
+	lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+	       c->lst.taken_empty_lebs;
+	lebs -= rsvd_idx_lebs;
+	available += lebs * (c->dark_wm - c->leb_overhead);
 	spin_unlock(&c->space_lock);
 
 	if (available > outstanding)
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 5c96f1f..2b267c9 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -587,7 +587,6 @@
 	if (err) {
 		if (err != -ENOSPC)
 			return err;
-		err = 0;
 		budgeted = 0;
 	}
 
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 4071d1c..3d698e2 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -793,7 +793,7 @@
 	int err;
 	struct ubifs_budget_req req;
 	loff_t old_size = inode->i_size, new_size = attr->ia_size;
-	int offset = new_size & (UBIFS_BLOCK_SIZE - 1);
+	int offset = new_size & (UBIFS_BLOCK_SIZE - 1), budgeted = 1;
 	struct ubifs_inode *ui = ubifs_inode(inode);
 
 	dbg_gen("ino %lu, size %lld -> %lld", inode->i_ino, old_size, new_size);
@@ -811,8 +811,15 @@
 	/* A funny way to budget for truncation node */
 	req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ;
 	err = ubifs_budget_space(c, &req);
-	if (err)
-		return err;
+	if (err) {
+		/*
+		 * Treat truncations to zero as deletion and always allow them,
+		 * just like we do for '->unlink()'.
+		 */
+		if (new_size || err != -ENOSPC)
+			return err;
+		budgeted = 0;
+	}
 
 	err = vmtruncate(inode, new_size);
 	if (err)
@@ -869,7 +876,12 @@
 	err = ubifs_jnl_truncate(c, inode, old_size, new_size);
 	mutex_unlock(&ui->ui_mutex);
 out_budg:
-	ubifs_release_budget(c, &req);
+	if (budgeted)
+		ubifs_release_budget(c, &req);
+	else {
+		c->nospace = c->nospace_rp = 0;
+		smp_wmb();
+	}
 	return err;
 }
 
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
index adee7b5..e045c8b 100644
--- a/fs/ubifs/find.c
+++ b/fs/ubifs/find.c
@@ -211,14 +211,8 @@
  * dirty index heap, and it falls-back to LPT scanning if the heaps are empty
  * or do not have an LEB which satisfies the @min_space criteria.
  *
- * Note:
- *   o LEBs which have less than dead watermark of dirty space are never picked
- *   by this function;
- *
- * Returns zero and the LEB properties of
- * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a
- * negative error code in case of other failures. The returned LEB is marked as
- * "taken".
+ * Note, LEBs which have less than dead watermark of free + dirty space are
+ * never picked by this function.
  *
  * The additional @pick_free argument controls if this function has to return a
  * free or freeable LEB if one is present. For example, GC must to set it to %1,
@@ -231,6 +225,10 @@
  *
  * In addition @pick_free is set to %2 by the recovery process in order to
  * recover gc_lnum in which case an index LEB must not be returned.
+ *
+ * This function returns zero and the LEB properties of found dirty LEB in case
+ * of success, %-ENOSPC if no dirty LEB was found and a negative error code in
+ * case of other failures. The returned LEB is marked as "taken".
  */
 int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
 			 int min_space, int pick_free)
@@ -245,7 +243,7 @@
 		int lebs, rsvd_idx_lebs = 0;
 
 		spin_lock(&c->space_lock);
-		lebs = c->lst.empty_lebs;
+		lebs = c->lst.empty_lebs + c->idx_gc_cnt;
 		lebs += c->freeable_cnt - c->lst.taken_empty_lebs;
 
 		/*
@@ -317,7 +315,7 @@
 		lp = idx_lp;
 
 	if (lp) {
-		ubifs_assert(lp->dirty >= c->dead_wm);
+		ubifs_assert(lp->free + lp->dirty >= c->dead_wm);
 		goto found;
 	}
 
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index d0f3dac..13f1019 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -344,6 +344,12 @@
 		if (err)
 			goto out;
 
+		/* Allow for races with TNC */
+		c->gced_lnum = lnum;
+		smp_wmb();
+		c->gc_seq += 1;
+		smp_wmb();
+
 		if (c->gc_lnum == -1) {
 			c->gc_lnum = lnum;
 			err = LEB_RETAINED;
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index 87dabf9..4c12a92 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -284,38 +284,6 @@
 }
 
 /**
- * ubifs_reported_space - calculate reported free space.
- * @c: the UBIFS file-system description object
- * @free: amount of free space
- *
- * This function calculates amount of free space which will be reported to
- * user-space. User-space application tend to expect that if the file-system
- * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
- * are able to write a file of size N. UBIFS attaches node headers to each data
- * node and it has to write indexind nodes as well. This introduces additional
- * overhead, and UBIFS it has to report sligtly less free space to meet the
- * above expectetion.
- *
- * This function assumes free space is made up of uncompressed data nodes and
- * full index nodes (one per data node, doubled because we always allow enough
- * space to write the index twice).
- *
- * Note, the calculation is pessimistic, which means that most of the time
- * UBIFS reports less space than it actually has.
- */
-static inline long long ubifs_reported_space(const struct ubifs_info *c,
-					     uint64_t free)
-{
-	int divisor, factor;
-
-	divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz * 3);
-	factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ;
-	do_div(free, divisor);
-
-	return free * factor;
-}
-
-/**
  * ubifs_current_time - round current time to time granularity.
  * @inode: inode
  */
@@ -325,4 +293,21 @@
 		current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
 }
 
+/**
+ * ubifs_tnc_lookup - look up a file-system node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure.
+ */
+static inline int ubifs_tnc_lookup(struct ubifs_info *c,
+				   const union ubifs_key *key, void *node)
+{
+	return ubifs_tnc_locate(c, key, node, NULL, NULL);
+}
+
 #endif /* __UBIFS_MISC_H__ */
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index f71e6b8..7562464 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -370,8 +370,9 @@
 {
 	struct ubifs_info *c = dentry->d_sb->s_fs_info;
 	unsigned long long free;
+	__le32 *uuid = (__le32 *)c->uuid;
 
-	free = ubifs_budg_get_free_space(c);
+	free = ubifs_get_free_space(c);
 	dbg_gen("free space %lld bytes (%lld blocks)",
 		free, free >> UBIFS_BLOCK_SHIFT);
 
@@ -386,7 +387,8 @@
 	buf->f_files = 0;
 	buf->f_ffree = 0;
 	buf->f_namelen = UBIFS_MAX_NLEN;
-
+	buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]);
+	buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]);
 	return 0;
 }
 
@@ -530,6 +532,12 @@
 	c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
 	c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
 
+	/*
+	 * Calculate how many bytes would be wasted at the end of LEB if it was
+	 * fully filled with data nodes of maximum size. This is used in
+	 * calculations when reporting free space.
+	 */
+	c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
 	return 0;
 }
 
@@ -647,13 +655,11 @@
 	 * internally because it does not make much sense for UBIFS, but it is
 	 * necessary to report something for the 'statfs()' call.
 	 *
-	 * Subtract the LEB reserved for GC and the LEB which is reserved for
-	 * deletions.
-	 *
-	 * Review 'ubifs_calc_available()' if changing this calculation.
+	 * Subtract the LEB reserved for GC, the LEB which is reserved for
+	 * deletions, and assume only one journal head is available.
 	 */
-	tmp64 = c->main_lebs - 2;
-	tmp64 *= (uint64_t)c->leb_size - c->dark_wm;
+	tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1;
+	tmp64 *= (uint64_t)c->leb_size - c->leb_overhead;
 	tmp64 = ubifs_reported_space(c, tmp64);
 	c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
 
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index e909f4a..7da209a 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -506,7 +506,7 @@
 		if (keys_cmp(c, key, &node_key) != 0)
 			ret = 0;
 	}
-	if (ret == 0)
+	if (ret == 0 && c->replaying)
 		dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
 			zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
 	return ret;
@@ -1382,50 +1382,39 @@
 }
 
 /**
- * ubifs_tnc_lookup - look up a file-system node.
+ * maybe_leb_gced - determine if a LEB may have been garbage collected.
  * @c: UBIFS file-system description object
- * @key: node key to lookup
- * @node: the node is returned here
+ * @lnum: LEB number
+ * @gc_seq1: garbage collection sequence number
  *
- * This function look up and reads node with key @key. The caller has to make
- * sure the @node buffer is large enough to fit the node. Returns zero in case
- * of success, %-ENOENT if the node was not found, and a negative error code in
- * case of failure.
+ * This function determines if @lnum may have been garbage collected since
+ * sequence number @gc_seq1. If it may have been then %1 is returned, otherwise
+ * %0 is returned.
  */
-int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
-		     void *node)
+static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
 {
-	int found, n, err;
-	struct ubifs_znode *znode;
-	struct ubifs_zbranch zbr, *zt;
+	int gc_seq2, gced_lnum;
 
-	mutex_lock(&c->tnc_mutex);
-	found = ubifs_lookup_level0(c, key, &znode, &n);
-	if (!found) {
-		err = -ENOENT;
-		goto out;
-	} else if (found < 0) {
-		err = found;
-		goto out;
-	}
-	zt = &znode->zbranch[n];
-	if (is_hash_key(c, key)) {
-		/*
-		 * In this case the leaf node cache gets used, so we pass the
-		 * address of the zbranch and keep the mutex locked
-		 */
-		err = tnc_read_node_nm(c, zt, node);
-		goto out;
-	}
-	zbr = znode->zbranch[n];
-	mutex_unlock(&c->tnc_mutex);
-
-	err = ubifs_tnc_read_node(c, &zbr, node);
-	return err;
-
-out:
-	mutex_unlock(&c->tnc_mutex);
-	return err;
+	gced_lnum = c->gced_lnum;
+	smp_rmb();
+	gc_seq2 = c->gc_seq;
+	/* Same seq means no GC */
+	if (gc_seq1 == gc_seq2)
+		return 0;
+	/* Different by more than 1 means we don't know */
+	if (gc_seq1 + 1 != gc_seq2)
+		return 1;
+	/*
+	 * We have seen the sequence number has increased by 1. Now we need to
+	 * be sure we read the right LEB number, so read it again.
+	 */
+	smp_rmb();
+	if (gced_lnum != c->gced_lnum)
+		return 1;
+	/* Finally we can check lnum */
+	if (gced_lnum == lnum)
+		return 1;
+	return 0;
 }
 
 /**
@@ -1436,16 +1425,19 @@
  * @lnum: LEB number is returned here
  * @offs: offset is returned here
  *
- * This function is the same as 'ubifs_tnc_lookup()' but it returns the node
- * location also. See 'ubifs_tnc_lookup()'.
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure. The node location can be returned in @lnum and @offs.
  */
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
 		     void *node, int *lnum, int *offs)
 {
-	int found, n, err;
+	int found, n, err, safely = 0, gc_seq1;
 	struct ubifs_znode *znode;
 	struct ubifs_zbranch zbr, *zt;
 
+again:
 	mutex_lock(&c->tnc_mutex);
 	found = ubifs_lookup_level0(c, key, &znode, &n);
 	if (!found) {
@@ -1456,24 +1448,43 @@
 		goto out;
 	}
 	zt = &znode->zbranch[n];
+	if (lnum) {
+		*lnum = zt->lnum;
+		*offs = zt->offs;
+	}
 	if (is_hash_key(c, key)) {
 		/*
 		 * In this case the leaf node cache gets used, so we pass the
 		 * address of the zbranch and keep the mutex locked
 		 */
-		*lnum = zt->lnum;
-		*offs = zt->offs;
 		err = tnc_read_node_nm(c, zt, node);
 		goto out;
 	}
+	if (safely) {
+		err = ubifs_tnc_read_node(c, zt, node);
+		goto out;
+	}
+	/* Drop the TNC mutex prematurely and race with garbage collection */
 	zbr = znode->zbranch[n];
+	gc_seq1 = c->gc_seq;
 	mutex_unlock(&c->tnc_mutex);
 
-	*lnum = zbr.lnum;
-	*offs = zbr.offs;
+	if (ubifs_get_wbuf(c, zbr.lnum)) {
+		/* We do not GC journal heads */
+		err = ubifs_tnc_read_node(c, &zbr, node);
+		return err;
+	}
 
-	err = ubifs_tnc_read_node(c, &zbr, node);
-	return err;
+	err = fallible_read_node(c, key, &zbr, node);
+	if (maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
+		/*
+		 * The node may have been GC'ed out from under us so try again
+		 * while keeping the TNC mutex locked.
+		 */
+		safely = 1;
+		goto again;
+	}
+	return 0;
 
 out:
 	mutex_unlock(&c->tnc_mutex);
@@ -1498,7 +1509,6 @@
 {
 	int found, n, err;
 	struct ubifs_znode *znode;
-	struct ubifs_zbranch zbr;
 
 	dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
 	mutex_lock(&c->tnc_mutex);
@@ -1522,11 +1532,7 @@
 		goto out_unlock;
 	}
 
-	zbr = znode->zbranch[n];
-	mutex_unlock(&c->tnc_mutex);
-
-	err = tnc_read_node_nm(c, &zbr, node);
-	return err;
+	err = tnc_read_node_nm(c, &znode->zbranch[n], node);
 
 out_unlock:
 	mutex_unlock(&c->tnc_mutex);
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index bd2121f..a9ecbd9 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -87,7 +87,7 @@
 #define UBIFS_SK_LEN 8
 
 /* Minimum index tree fanout */
-#define UBIFS_MIN_FANOUT 2
+#define UBIFS_MIN_FANOUT 3
 
 /* Maximum number of levels in UBIFS indexing B-tree */
 #define UBIFS_MAX_LEVELS 512
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d7f706f..17c620b 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -995,6 +995,9 @@
  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
  * @max_inode_sz: maximum possible inode size in bytes
  * @max_znode_sz: size of znode in bytes
+ *
+ * @leb_overhead: how many bytes are wasted in an LEB when it is filled with
+ *                data nodes of maximum size - used in free space reporting
  * @dead_wm: LEB dead space watermark
  * @dark_wm: LEB dark space watermark
  * @block_cnt: count of 4KiB blocks on the FS
@@ -1028,6 +1031,8 @@
  * @sbuf: a buffer of LEB size used by GC and replay for scanning
  * @idx_gc: list of index LEBs that have been garbage collected
  * @idx_gc_cnt: number of elements on the idx_gc list
+ * @gc_seq: incremented for every non-index LEB garbage collected
+ * @gced_lnum: last non-index LEB that was garbage collected
  *
  * @infos_list: links all 'ubifs_info' objects
  * @umount_mutex: serializes shrinker and un-mount
@@ -1224,6 +1229,8 @@
 	int max_idx_node_sz;
 	long long max_inode_sz;
 	int max_znode_sz;
+
+	int leb_overhead;
 	int dead_wm;
 	int dark_wm;
 	int block_cnt;
@@ -1257,6 +1264,8 @@
 	void *sbuf;
 	struct list_head idx_gc;
 	int idx_gc_cnt;
+	volatile int gc_seq;
+	volatile int gced_lnum;
 
 	struct list_head infos_list;
 	struct mutex umount_mutex;
@@ -1434,9 +1443,10 @@
 				struct ubifs_budget_req *req);
 void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
 			 struct ubifs_budget_req *req);
-long long ubifs_budg_get_free_space(struct ubifs_info *c);
+long long ubifs_get_free_space(struct ubifs_info *c);
 int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
 void ubifs_convert_page_budget(struct ubifs_info *c);
+long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free);
 long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
 
 /* find.c */
@@ -1451,8 +1461,6 @@
 /* tnc.c */
 int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
 			struct ubifs_znode **zn, int *n);
-int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
-		     void *node);
 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
 			void *node, const struct qstr *nm);
 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm
index 1170dc6..1870d5e 100644
--- a/include/asm-generic/Kbuild.asm
+++ b/include/asm-generic/Kbuild.asm
@@ -1,8 +1,10 @@
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \
+      		  $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
 header-y  += kvm.h
 endif
 
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
+      		  $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += auxvec.h
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 8feeae1..79a7ff9 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -14,4 +14,10 @@
 extern char __initdata_begin[], __initdata_end[];
 extern char __start_rodata[], __end_rodata[];
 
+/* function descriptor handling (if any).  Override
+ * in asm/sections.h */
+#ifndef dereference_function_descriptor
+#define dereference_function_descriptor(p) (p)
+#endif
+
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h
index abcf34c..ea8087b 100644
--- a/include/asm-generic/syscall.h
+++ b/include/asm-generic/syscall.h
@@ -126,7 +126,7 @@
  * @args:	array of argument values to store
  *
  * Changes @n arguments to the system call starting with the @i'th argument.
- * @n'th argument to @val.  Argument @i gets value @args[0], and so on.
+ * Argument @i gets value @args[0], and so on.
  * An arch inline version is probably optimal when @i and @n are constants.
  *
  * It's only valid to call this when @task is stopped for tracing on
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
index d5c0f2f..03b1d69 100644
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -63,6 +63,7 @@
 }
 
 extern void (*flush_icache_range)(unsigned long start, unsigned long end);
+extern void (*local_flush_icache_range)(unsigned long start, unsigned long end);
 
 extern void (*__flush_cache_vmap)(void);
 
diff --git a/include/asm-parisc/sections.h b/include/asm-parisc/sections.h
index fdd43ec..9d13c35 100644
--- a/include/asm-parisc/sections.h
+++ b/include/asm-parisc/sections.h
@@ -4,4 +4,9 @@
 /* nothing to see, move along */
 #include <asm-generic/sections.h>
 
+#ifdef CONFIG_64BIT
+#undef dereference_function_descriptor
+void *dereference_function_descriptor(void *);
+#endif
+
 #endif
diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h
index 762f6a6..9489283 100644
--- a/include/asm-x86/cpufeature.h
+++ b/include/asm-x86/cpufeature.h
@@ -72,14 +72,15 @@
 #define X86_FEATURE_UP		(3*32+ 9) /* smp kernel running on up */
 #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
 #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
-#define X86_FEATURE_PEBS	(3*32+12)  /* Precise-Event Based Sampling */
-#define X86_FEATURE_BTS		(3*32+13)  /* Branch Trace Store */
-#define X86_FEATURE_SYSCALL32	(3*32+14)  /* syscall in ia32 userspace */
-#define X86_FEATURE_SYSENTER32	(3*32+15)  /* sysenter in ia32 userspace */
+#define X86_FEATURE_PEBS	(3*32+12) /* Precise-Event Based Sampling */
+#define X86_FEATURE_BTS		(3*32+13) /* Branch Trace Store */
+#define X86_FEATURE_SYSCALL32	(3*32+14) /* syscall in ia32 userspace */
+#define X86_FEATURE_SYSENTER32	(3*32+15) /* sysenter in ia32 userspace */
 #define X86_FEATURE_REP_GOOD	(3*32+16) /* rep microcode works well on this CPU */
 #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
 #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
-#define X86_FEATURE_11AP	(3*32+19)  /* Bad local APIC aka 11AP */
+#define X86_FEATURE_11AP	(3*32+19) /* Bad local APIC aka 11AP */
+#define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
diff --git a/include/asm-x86/required-features.h b/include/asm-x86/required-features.h
index adec887..5c2ff4b 100644
--- a/include/asm-x86/required-features.h
+++ b/include/asm-x86/required-features.h
@@ -41,6 +41,12 @@
 # define NEED_3DNOW	0
 #endif
 
+#if defined(CONFIG_X86_P6_NOP) || defined(CONFIG_X86_64)
+# define NEED_NOPL	(1<<(X86_FEATURE_NOPL & 31))
+#else
+# define NEED_NOPL	0
+#endif
+
 #ifdef CONFIG_X86_64
 #define NEED_PSE	0
 #define NEED_MSR	(1<<(X86_FEATURE_MSR & 31))
@@ -67,7 +73,7 @@
 #define REQUIRED_MASK1	(NEED_LM|NEED_3DNOW)
 
 #define REQUIRED_MASK2	0
-#define REQUIRED_MASK3	0
+#define REQUIRED_MASK3	(NEED_NOPL)
 #define REQUIRED_MASK4	0
 #define REQUIRED_MASK5	0
 #define REQUIRED_MASK6	0
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 5939125..b68ec09 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -167,7 +167,8 @@
 unifdef-y += adb.h
 unifdef-y += adfs_fs.h
 unifdef-y += agpgart.h
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/a.out.h \
+      		  $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += apm_bios.h
@@ -258,7 +259,8 @@
 unifdef-y += kernelcapi.h
 unifdef-y += kernel.h
 unifdef-y += keyboard.h
-ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h \
+      		  $(srctree)/include/asm-$(SRCARCH)/kvm.h),)
 unifdef-y += kvm.h
 endif
 unifdef-y += llc.h
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index c33b0dc..ed3a5d4 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -127,6 +127,8 @@
 extern int clockevents_program_event(struct clock_event_device *dev,
 				     ktime_t expires, ktime_t now);
 
+extern void clockevents_handle_noop(struct clock_event_device *dev);
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
 #else
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index e8f450c..2691926 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -160,7 +160,7 @@
 
 static inline void rebuild_sched_domains(void)
 {
-	partition_sched_domains(0, NULL, NULL);
+	partition_sched_domains(1, NULL, NULL);
 }
 
 #endif /* !CONFIG_CPUSETS */
diff --git a/include/linux/list.h b/include/linux/list.h
index db35ef0..969f6e9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -619,6 +619,19 @@
 		next->next->pprev  = &next->next;
 }
 
+/*
+ * Move a list from one list head to another. Fixup the pprev
+ * reference of the first entry if it exists.
+ */
+static inline void hlist_move_list(struct hlist_head *old,
+				   struct hlist_head *new)
+{
+	new->first = old->first;
+	if (new->first)
+		new->first->pprev = &new->first;
+	old->first = NULL;
+}
+
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index fdeadd9..271c1c2 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -166,7 +166,7 @@
 	int ret = -EBUSY;
 
 	spin_lock_irqsave(&cnt->lock, flags);
-	if (cnt->usage < limit) {
+	if (cnt->usage <= limit) {
 		cnt->limit = limit;
 		ret = 0;
 	}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index cfb0d87..3d9120c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1475,6 +1475,10 @@
 		__put_task_struct(t);
 }
 
+extern cputime_t task_utime(struct task_struct *p);
+extern cputime_t task_stime(struct task_struct *p);
+extern cputime_t task_gtime(struct task_struct *p);
+
 /*
  * Per process flags
  */
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index b48d819..6186a78 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -272,7 +272,7 @@
  * tracehook_report_clone_complete().  This must prevent the child from
  * self-reaping if tracehook_report_clone_complete() uses the @child
  * pointer; otherwise it might have died and been released by the time
- * tracehook_report_report_clone_complete() is called.
+ * tracehook_report_clone_complete() is called.
  *
  * Called with no locks held, but the child cannot run until this returns.
  */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index e65a6bed..303d93f 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -334,6 +334,8 @@
 #define V4L2_PIX_FMT_SPCA508  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
 #define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16  YVU 4:2:2     */
 
 /*
  *	F O R M A T   E N U M E R A T I O N
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index cbf7510..46a43b7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -325,7 +325,8 @@
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type);
+int hci_conn_check_link_mode(struct hci_conn *conn);
 int hci_conn_auth(struct hci_conn *conn);
 int hci_conn_encrypt(struct hci_conn *conn);
 int hci_conn_change_link_key(struct hci_conn *conn);
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 95c660c..9132490 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -208,6 +208,9 @@
 extern void inet_twsk_deschedule(struct inet_timewait_sock *tw,
 				 struct inet_timewait_death_row *twdr);
 
+extern void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
+			    struct inet_timewait_death_row *twdr, int family);
+
 static inline
 struct net *twsk_net(const struct inet_timewait_sock *twsk)
 {
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index d5ab79c..f227bc1 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -14,6 +14,8 @@
  *  2003-10-22 Updates by Stephen Hemminger.
  *  2004 May-July Rework by Paul Jackson.
  *  2006 Rework by Paul Menage to use generic cgroups
+ *  2008 Rework of the scheduler domains and CPU hotplug handling
+ *       by Max Krasnyansky
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of the Linux
@@ -236,9 +238,11 @@
 
 static DEFINE_MUTEX(callback_mutex);
 
-/* This is ugly, but preserves the userspace API for existing cpuset
+/*
+ * This is ugly, but preserves the userspace API for existing cpuset
  * users. If someone tries to mount the "cpuset" filesystem, we
- * silently switch it to mount "cgroup" instead */
+ * silently switch it to mount "cgroup" instead
+ */
 static int cpuset_get_sb(struct file_system_type *fs_type,
 			 int flags, const char *unused_dev_name,
 			 void *data, struct vfsmount *mnt)
@@ -473,10 +477,9 @@
 }
 
 /*
- * Helper routine for rebuild_sched_domains().
+ * Helper routine for generate_sched_domains().
  * Do cpusets a, b have overlapping cpus_allowed masks?
  */
-
 static int cpusets_overlap(struct cpuset *a, struct cpuset *b)
 {
 	return cpus_intersects(a->cpus_allowed, b->cpus_allowed);
@@ -518,26 +521,15 @@
 }
 
 /*
- * rebuild_sched_domains()
+ * generate_sched_domains()
  *
- * This routine will be called to rebuild the scheduler's dynamic
- * sched domains:
- * - if the flag 'sched_load_balance' of any cpuset with non-empty
- *   'cpus' changes,
- * - or if the 'cpus' allowed changes in any cpuset which has that
- *   flag enabled,
- * - or if the 'sched_relax_domain_level' of any cpuset which has
- *   that flag enabled and with non-empty 'cpus' changes,
- * - or if any cpuset with non-empty 'cpus' is removed,
- * - or if a cpu gets offlined.
- *
- * This routine builds a partial partition of the systems CPUs
- * (the set of non-overlappping cpumask_t's in the array 'part'
- * below), and passes that partial partition to the kernel/sched.c
- * partition_sched_domains() routine, which will rebuild the
- * schedulers load balancing domains (sched domains) as specified
- * by that partial partition.  A 'partial partition' is a set of
- * non-overlapping subsets whose union is a subset of that set.
+ * This function builds a partial partition of the systems CPUs
+ * A 'partial partition' is a set of non-overlapping subsets whose
+ * union is a subset of that set.
+ * The output of this function needs to be passed to kernel/sched.c
+ * partition_sched_domains() routine, which will rebuild the scheduler's
+ * load balancing domains (sched domains) as specified by that partial
+ * partition.
  *
  * See "What is sched_load_balance" in Documentation/cpusets.txt
  * for a background explanation of this.
@@ -547,13 +539,7 @@
  * domains when operating in the severe memory shortage situations
  * that could cause allocation failures below.
  *
- * Call with cgroup_mutex held.  May take callback_mutex during
- * call due to the kfifo_alloc() and kmalloc() calls.  May nest
- * a call to the get_online_cpus()/put_online_cpus() pair.
- * Must not be called holding callback_mutex, because we must not
- * call get_online_cpus() while holding callback_mutex.  Elsewhere
- * the kernel nests callback_mutex inside get_online_cpus() calls.
- * So the reverse nesting would risk an ABBA deadlock.
+ * Must be called with cgroup_lock held.
  *
  * The three key local variables below are:
  *    q  - a linked-list queue of cpuset pointers, used to implement a
@@ -588,10 +574,10 @@
  *	element of the partition (one sched domain) to be passed to
  *	partition_sched_domains().
  */
-
-void rebuild_sched_domains(void)
+static int generate_sched_domains(cpumask_t **domains,
+			struct sched_domain_attr **attributes)
 {
-	LIST_HEAD(q);		/* queue of cpusets to be scanned*/
+	LIST_HEAD(q);		/* queue of cpusets to be scanned */
 	struct cpuset *cp;	/* scans q */
 	struct cpuset **csa;	/* array of all cpuset ptrs */
 	int csn;		/* how many cpuset ptrs in csa so far */
@@ -601,23 +587,26 @@
 	int ndoms;		/* number of sched domains in result */
 	int nslot;		/* next empty doms[] cpumask_t slot */
 
-	csa = NULL;
+	ndoms = 0;
 	doms = NULL;
 	dattr = NULL;
+	csa = NULL;
 
 	/* Special case for the 99% of systems with one, full, sched domain */
 	if (is_sched_load_balance(&top_cpuset)) {
-		ndoms = 1;
 		doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL);
 		if (!doms)
-			goto rebuild;
+			goto done;
+
 		dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL);
 		if (dattr) {
 			*dattr = SD_ATTR_INIT;
 			update_domain_attr_tree(dattr, &top_cpuset);
 		}
 		*doms = top_cpuset.cpus_allowed;
-		goto rebuild;
+
+		ndoms = 1;
+		goto done;
 	}
 
 	csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL);
@@ -680,61 +669,141 @@
 		}
 	}
 
-	/* Convert <csn, csa> to <ndoms, doms> */
+	/*
+	 * Now we know how many domains to create.
+	 * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
+	 */
 	doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL);
-	if (!doms)
-		goto rebuild;
+	if (!doms) {
+		ndoms = 0;
+		goto done;
+	}
+
+	/*
+	 * The rest of the code, including the scheduler, can deal with
+	 * dattr==NULL case. No need to abort if alloc fails.
+	 */
 	dattr = kmalloc(ndoms * sizeof(struct sched_domain_attr), GFP_KERNEL);
 
 	for (nslot = 0, i = 0; i < csn; i++) {
 		struct cpuset *a = csa[i];
+		cpumask_t *dp;
 		int apn = a->pn;
 
-		if (apn >= 0) {
-			cpumask_t *dp = doms + nslot;
-
-			if (nslot == ndoms) {
-				static int warnings = 10;
-				if (warnings) {
-					printk(KERN_WARNING
-					 "rebuild_sched_domains confused:"
-					  " nslot %d, ndoms %d, csn %d, i %d,"
-					  " apn %d\n",
-					  nslot, ndoms, csn, i, apn);
-					warnings--;
-				}
-				continue;
-			}
-
-			cpus_clear(*dp);
-			if (dattr)
-				*(dattr + nslot) = SD_ATTR_INIT;
-			for (j = i; j < csn; j++) {
-				struct cpuset *b = csa[j];
-
-				if (apn == b->pn) {
-					cpus_or(*dp, *dp, b->cpus_allowed);
-					b->pn = -1;
-					if (dattr)
-						update_domain_attr_tree(dattr
-								   + nslot, b);
-				}
-			}
-			nslot++;
+		if (apn < 0) {
+			/* Skip completed partitions */
+			continue;
 		}
+
+		dp = doms + nslot;
+
+		if (nslot == ndoms) {
+			static int warnings = 10;
+			if (warnings) {
+				printk(KERN_WARNING
+				 "rebuild_sched_domains confused:"
+				  " nslot %d, ndoms %d, csn %d, i %d,"
+				  " apn %d\n",
+				  nslot, ndoms, csn, i, apn);
+				warnings--;
+			}
+			continue;
+		}
+
+		cpus_clear(*dp);
+		if (dattr)
+			*(dattr + nslot) = SD_ATTR_INIT;
+		for (j = i; j < csn; j++) {
+			struct cpuset *b = csa[j];
+
+			if (apn == b->pn) {
+				cpus_or(*dp, *dp, b->cpus_allowed);
+				if (dattr)
+					update_domain_attr_tree(dattr + nslot, b);
+
+				/* Done with this partition */
+				b->pn = -1;
+			}
+		}
+		nslot++;
 	}
 	BUG_ON(nslot != ndoms);
 
-rebuild:
-	/* Have scheduler rebuild sched domains */
-	get_online_cpus();
-	partition_sched_domains(ndoms, doms, dattr);
-	put_online_cpus();
-
 done:
 	kfree(csa);
-	/* Don't kfree(doms) -- partition_sched_domains() does that. */
-	/* Don't kfree(dattr) -- partition_sched_domains() does that. */
+
+	*domains    = doms;
+	*attributes = dattr;
+	return ndoms;
+}
+
+/*
+ * Rebuild scheduler domains.
+ *
+ * Call with neither cgroup_mutex held nor within get_online_cpus().
+ * Takes both cgroup_mutex and get_online_cpus().
+ *
+ * Cannot be directly called from cpuset code handling changes
+ * to the cpuset pseudo-filesystem, because it cannot be called
+ * from code that already holds cgroup_mutex.
+ */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+	struct sched_domain_attr *attr;
+	cpumask_t *doms;
+	int ndoms;
+
+	get_online_cpus();
+
+	/* Generate domain masks and attrs */
+	cgroup_lock();
+	ndoms = generate_sched_domains(&doms, &attr);
+	cgroup_unlock();
+
+	/* Have scheduler rebuild the domains */
+	partition_sched_domains(ndoms, doms, attr);
+
+	put_online_cpus();
+}
+
+static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
+
+/*
+ * Rebuild scheduler domains, asynchronously via workqueue.
+ *
+ * If the flag 'sched_load_balance' of any cpuset with non-empty
+ * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
+ * which has that flag enabled, or if any cpuset with a non-empty
+ * 'cpus' is removed, then call this routine to rebuild the
+ * scheduler's dynamic sched domains.
+ *
+ * The rebuild_sched_domains() and partition_sched_domains()
+ * routines must nest cgroup_lock() inside get_online_cpus(),
+ * but such cpuset changes as these must nest that locking the
+ * other way, holding cgroup_lock() for much of the code.
+ *
+ * So in order to avoid an ABBA deadlock, the cpuset code handling
+ * these user changes delegates the actual sched domain rebuilding
+ * to a separate workqueue thread, which ends up processing the
+ * above do_rebuild_sched_domains() function.
+ */
+static void async_rebuild_sched_domains(void)
+{
+	schedule_work(&rebuild_sched_domains_work);
+}
+
+/*
+ * Accomplishes the same scheduler domain rebuild as the above
+ * async_rebuild_sched_domains(), however it directly calls the
+ * rebuild routine synchronously rather than calling it via an
+ * asynchronous work thread.
+ *
+ * This can only be called from code that is not holding
+ * cgroup_mutex (not nested in a cgroup_lock() call.)
+ */
+void rebuild_sched_domains(void)
+{
+	do_rebuild_sched_domains(NULL);
 }
 
 /**
@@ -863,7 +932,7 @@
 		return retval;
 
 	if (is_load_balanced)
-		rebuild_sched_domains();
+		async_rebuild_sched_domains();
 	return 0;
 }
 
@@ -1090,7 +1159,7 @@
 	if (val != cs->relax_domain_level) {
 		cs->relax_domain_level = val;
 		if (!cpus_empty(cs->cpus_allowed) && is_sched_load_balance(cs))
-			rebuild_sched_domains();
+			async_rebuild_sched_domains();
 	}
 
 	return 0;
@@ -1131,7 +1200,7 @@
 	mutex_unlock(&callback_mutex);
 
 	if (cpus_nonempty && balance_flag_changed)
-		rebuild_sched_domains();
+		async_rebuild_sched_domains();
 
 	return 0;
 }
@@ -1492,6 +1561,9 @@
 	default:
 		BUG();
 	}
+
+	/* Unreachable but makes gcc happy */
+	return 0;
 }
 
 static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
@@ -1504,6 +1576,9 @@
 	default:
 		BUG();
 	}
+
+	/* Unrechable but makes gcc happy */
+	return 0;
 }
 
 
@@ -1692,15 +1767,9 @@
 }
 
 /*
- * Locking note on the strange update_flag() call below:
- *
  * If the cpuset being removed has its flag 'sched_load_balance'
  * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains().  The get_online_cpus()
- * call in rebuild_sched_domains() must not be made while holding
- * callback_mutex.  Elsewhere the kernel nests callback_mutex inside
- * get_online_cpus() calls.  So the reverse nesting would risk an
- * ABBA deadlock.
+ * will call async_rebuild_sched_domains().
  */
 
 static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
@@ -1719,7 +1788,7 @@
 struct cgroup_subsys cpuset_subsys = {
 	.name = "cpuset",
 	.create = cpuset_create,
-	.destroy  = cpuset_destroy,
+	.destroy = cpuset_destroy,
 	.can_attach = cpuset_can_attach,
 	.attach = cpuset_attach,
 	.populate = cpuset_populate,
@@ -1811,7 +1880,7 @@
 }
 
 /*
- * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
+ * If CPU and/or memory hotplug handlers, below, unplug any CPUs
  * or memory nodes, we need to walk over the cpuset hierarchy,
  * removing that CPU or node from all cpusets.  If this removes the
  * last CPU or node from a cpuset, then move the tasks in the empty
@@ -1903,35 +1972,6 @@
 }
 
 /*
- * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
- * cpu_online_map and node_states[N_HIGH_MEMORY].  Force the top cpuset to
- * track what's online after any CPU or memory node hotplug or unplug event.
- *
- * Since there are two callers of this routine, one for CPU hotplug
- * events and one for memory node hotplug events, we could have coded
- * two separate routines here.  We code it as a single common routine
- * in order to minimize text size.
- */
-
-static void common_cpu_mem_hotplug_unplug(int rebuild_sd)
-{
-	cgroup_lock();
-
-	top_cpuset.cpus_allowed = cpu_online_map;
-	top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-	scan_for_empty_cpusets(&top_cpuset);
-
-	/*
-	 * Scheduler destroys domains on hotplug events.
-	 * Rebuild them based on the current settings.
-	 */
-	if (rebuild_sd)
-		rebuild_sched_domains();
-
-	cgroup_unlock();
-}
-
-/*
  * The top_cpuset tracks what CPUs and Memory Nodes are online,
  * period.  This is necessary in order to make cpusets transparent
  * (of no affect) on systems that are actively using CPU hotplug
@@ -1939,40 +1979,52 @@
  *
  * This routine ensures that top_cpuset.cpus_allowed tracks
  * cpu_online_map on each CPU hotplug (cpuhp) event.
+ *
+ * Called within get_online_cpus().  Needs to call cgroup_lock()
+ * before calling generate_sched_domains().
  */
-
-static int cpuset_handle_cpuhp(struct notifier_block *unused_nb,
+static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
 				unsigned long phase, void *unused_cpu)
 {
+	struct sched_domain_attr *attr;
+	cpumask_t *doms;
+	int ndoms;
+
 	switch (phase) {
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-	case CPU_DOWN_FAILED:
-	case CPU_DOWN_FAILED_FROZEN:
 	case CPU_ONLINE:
 	case CPU_ONLINE_FROZEN:
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
-		common_cpu_mem_hotplug_unplug(1);
 		break;
+
 	default:
 		return NOTIFY_DONE;
 	}
 
+	cgroup_lock();
+	top_cpuset.cpus_allowed = cpu_online_map;
+	scan_for_empty_cpusets(&top_cpuset);
+	ndoms = generate_sched_domains(&doms, &attr);
+	cgroup_unlock();
+
+	/* Have scheduler rebuild the domains */
+	partition_sched_domains(ndoms, doms, attr);
+
 	return NOTIFY_OK;
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY].
- * Call this routine anytime after you change
- * node_states[N_HIGH_MEMORY].
- * See also the previous routine cpuset_handle_cpuhp().
+ * Call this routine anytime after node_states[N_HIGH_MEMORY] changes.
+ * See also the previous routine cpuset_track_online_cpus().
  */
-
 void cpuset_track_online_nodes(void)
 {
-	common_cpu_mem_hotplug_unplug(0);
+	cgroup_lock();
+	top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+	scan_for_empty_cpusets(&top_cpuset);
+	cgroup_unlock();
 }
 #endif
 
@@ -1987,7 +2039,7 @@
 	top_cpuset.cpus_allowed = cpu_online_map;
 	top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
-	hotcpu_notifier(cpuset_handle_cpuhp, 0);
+	hotcpu_notifier(cpuset_track_online_cpus, 0);
 }
 
 /**
diff --git a/kernel/exit.c b/kernel/exit.c
index 25ed2ad..1639564 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -112,9 +112,9 @@
 		 * We won't ever get here for the group leader, since it
 		 * will have been the last reference on the signal_struct.
 		 */
-		sig->utime = cputime_add(sig->utime, tsk->utime);
-		sig->stime = cputime_add(sig->stime, tsk->stime);
-		sig->gtime = cputime_add(sig->gtime, tsk->gtime);
+		sig->utime = cputime_add(sig->utime, task_utime(tsk));
+		sig->stime = cputime_add(sig->stime, task_stime(tsk));
+		sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));
 		sig->min_flt += tsk->min_flt;
 		sig->maj_flt += tsk->maj_flt;
 		sig->nvcsw += tsk->nvcsw;
diff --git a/kernel/sched.c b/kernel/sched.c
index 9a1ddb8..cc1f81b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4179,6 +4179,65 @@
 }
 
 /*
+ * Use precise platform statistics if available:
+ */
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+cputime_t task_utime(struct task_struct *p)
+{
+	return p->utime;
+}
+
+cputime_t task_stime(struct task_struct *p)
+{
+	return p->stime;
+}
+#else
+cputime_t task_utime(struct task_struct *p)
+{
+	clock_t utime = cputime_to_clock_t(p->utime),
+		total = utime + cputime_to_clock_t(p->stime);
+	u64 temp;
+
+	/*
+	 * Use CFS's precise accounting:
+	 */
+	temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);
+
+	if (total) {
+		temp *= utime;
+		do_div(temp, total);
+	}
+	utime = (clock_t)temp;
+
+	p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));
+	return p->prev_utime;
+}
+
+cputime_t task_stime(struct task_struct *p)
+{
+	clock_t stime;
+
+	/*
+	 * Use CFS's precise accounting. (we subtract utime from
+	 * the total, to make sure the total observed by userspace
+	 * grows monotonically - apps rely on that):
+	 */
+	stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
+			cputime_to_clock_t(task_utime(p));
+
+	if (stime >= 0)
+		p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime));
+
+	return p->prev_stime;
+}
+#endif
+
+inline cputime_t task_gtime(struct task_struct *p)
+{
+	return p->gtime;
+}
+
+/*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
  *
@@ -7637,24 +7696,27 @@
  * and partition_sched_domains() will fallback to the single partition
  * 'fallback_doms', it also forces the domains to be rebuilt.
  *
+ * If doms_new==NULL it will be replaced with cpu_online_map.
+ * ndoms_new==0 is a special case for destroying existing domains.
+ * It will not create the default domain.
+ *
  * Call with hotplug lock held
  */
 void partition_sched_domains(int ndoms_new, cpumask_t *doms_new,
 			     struct sched_domain_attr *dattr_new)
 {
-	int i, j;
+	int i, j, n;
 
 	mutex_lock(&sched_domains_mutex);
 
 	/* always unregister in case we don't destroy any domains */
 	unregister_sched_domain_sysctl();
 
-	if (doms_new == NULL)
-		ndoms_new = 0;
+	n = doms_new ? ndoms_new : 0;
 
 	/* Destroy deleted domains */
 	for (i = 0; i < ndoms_cur; i++) {
-		for (j = 0; j < ndoms_new; j++) {
+		for (j = 0; j < n; j++) {
 			if (cpus_equal(doms_cur[i], doms_new[j])
 			    && dattrs_equal(dattr_cur, i, dattr_new, j))
 				goto match1;
@@ -7667,7 +7729,6 @@
 
 	if (doms_new == NULL) {
 		ndoms_cur = 0;
-		ndoms_new = 1;
 		doms_new = &fallback_doms;
 		cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map);
 		dattr_new = NULL;
@@ -7704,8 +7765,13 @@
 int arch_reinit_sched_domains(void)
 {
 	get_online_cpus();
+
+	/* Destroy domains first to force the rebuild */
+	partition_sched_domains(0, NULL, NULL);
+
 	rebuild_sched_domains();
 	put_online_cpus();
+
 	return 0;
 }
 
@@ -7789,7 +7855,7 @@
 	case CPU_ONLINE_FROZEN:
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
-		partition_sched_domains(0, NULL, NULL);
+		partition_sched_domains(1, NULL, NULL);
 		return NOTIFY_OK;
 
 	default:
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index fe47133..50ec088 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -159,6 +159,7 @@
 static struct ctl_table root_table[];
 static struct ctl_table_root sysctl_table_root;
 static struct ctl_table_header root_table_header = {
+	.count = 1,
 	.ctl_table = root_table,
 	.ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
 	.root = &sysctl_table_root,
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 3d1e3e1..1876b52 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -177,7 +177,7 @@
 /*
  * Noop handler when we shut down an event device
  */
-static void clockevents_handle_noop(struct clock_event_device *dev)
+void clockevents_handle_noop(struct clock_event_device *dev)
 {
 }
 
@@ -199,7 +199,6 @@
 	 * released list and do a notify add later.
 	 */
 	if (old) {
-		old->event_handler = clockevents_handle_noop;
 		clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
 		list_del(&old->list);
 		list_add(&old->list, &clockevents_released);
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 5125ddd..1ad46f3 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -245,7 +245,7 @@
 	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
 		fail = update_persistent_clock(now);
 
-	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
+	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
 	if (next.tv_nsec <= 0)
 		next.tv_nsec += NSEC_PER_SEC;
 
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 31463d3..2f5a382 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -175,6 +175,8 @@
  */
 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
+	ktime_t next;
+
 	tick_do_periodic_broadcast();
 
 	/*
@@ -185,10 +187,13 @@
 
 	/*
 	 * Setup the next period for devices, which do not have
-	 * periodic mode:
+	 * periodic mode. We read dev->next_event first and add to it
+	 * when the event alrady expired. clockevents_program_event()
+	 * sets dev->next_event only when the event is really
+	 * programmed to the device.
 	 */
-	for (;;) {
-		ktime_t next = ktime_add(dev->next_event, tick_period);
+	for (next = dev->next_event; ;) {
+		next = ktime_add(next, tick_period);
 
 		if (!clockevents_program_event(dev, next, ktime_get()))
 			return;
@@ -205,7 +210,7 @@
 	struct clock_event_device *bc, *dev;
 	struct tick_device *td;
 	unsigned long flags, *reason = why;
-	int cpu;
+	int cpu, bc_stopped;
 
 	spin_lock_irqsave(&tick_broadcast_lock, flags);
 
@@ -223,6 +228,8 @@
 	if (!tick_device_is_functional(dev))
 		goto out;
 
+	bc_stopped = cpus_empty(tick_broadcast_mask);
+
 	switch (*reason) {
 	case CLOCK_EVT_NOTIFY_BROADCAST_ON:
 	case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
@@ -245,9 +252,10 @@
 		break;
 	}
 
-	if (cpus_empty(tick_broadcast_mask))
-		clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
-	else {
+	if (cpus_empty(tick_broadcast_mask)) {
+		if (!bc_stopped)
+			clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+	} else if (bc_stopped) {
 		if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
 			tick_broadcast_start_periodic(bc);
 		else
@@ -364,16 +372,8 @@
 static int tick_broadcast_set_event(ktime_t expires, int force)
 {
 	struct clock_event_device *bc = tick_broadcast_device.evtdev;
-	ktime_t now = ktime_get();
-	int res;
 
-	for(;;) {
-		res = clockevents_program_event(bc, expires, now);
-		if (!res || !force)
-			return res;
-		now = ktime_get();
-		expires = ktime_add(now, ktime_set(0, bc->min_delta_ns));
-	}
+	return tick_dev_program_event(bc, expires, force);
 }
 
 int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -491,14 +491,52 @@
 	cpu_clear(cpu, tick_broadcast_oneshot_mask);
 }
 
+static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires)
+{
+	struct tick_device *td;
+	int cpu;
+
+	for_each_cpu_mask_nr(cpu, *mask) {
+		td = &per_cpu(tick_cpu_device, cpu);
+		if (td->evtdev)
+			td->evtdev->next_event = expires;
+	}
+}
+
 /**
  * tick_broadcast_setup_oneshot - setup the broadcast device
  */
 void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
-	bc->event_handler = tick_handle_oneshot_broadcast;
-	clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
-	bc->next_event.tv64 = KTIME_MAX;
+	/* Set it up only once ! */
+	if (bc->event_handler != tick_handle_oneshot_broadcast) {
+		int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC;
+		int cpu = smp_processor_id();
+		cpumask_t mask;
+
+		bc->event_handler = tick_handle_oneshot_broadcast;
+		clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+
+		/* Take the do_timer update */
+		tick_do_timer_cpu = cpu;
+
+		/*
+		 * We must be careful here. There might be other CPUs
+		 * waiting for periodic broadcast. We need to set the
+		 * oneshot_mask bits for those and program the
+		 * broadcast device to fire.
+		 */
+		mask = tick_broadcast_mask;
+		cpu_clear(cpu, mask);
+		cpus_or(tick_broadcast_oneshot_mask,
+			tick_broadcast_oneshot_mask, mask);
+
+		if (was_periodic && !cpus_empty(mask)) {
+			tick_broadcast_init_next_event(&mask, tick_next_period);
+			tick_broadcast_set_event(tick_next_period, 1);
+		} else
+			bc->next_event.tv64 = KTIME_MAX;
+	}
 }
 
 /*
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 80c4336..c477719 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -161,6 +161,7 @@
 	} else {
 		handler = td->evtdev->event_handler;
 		next_event = td->evtdev->next_event;
+		td->evtdev->event_handler = clockevents_handle_noop;
 	}
 
 	td->evtdev = newdev;
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index f13f2b7..0ffc291 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -17,6 +17,8 @@
 extern void tick_setup_oneshot(struct clock_event_device *newdev,
 			       void (*handler)(struct clock_event_device *),
 			       ktime_t nextevt);
+extern int tick_dev_program_event(struct clock_event_device *dev,
+				  ktime_t expires, int force);
 extern int tick_program_event(ktime_t expires, int force);
 extern void tick_oneshot_notify(void);
 extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index 450c049..2e8de67 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -23,21 +23,53 @@
 #include "tick-internal.h"
 
 /**
+ * tick_program_event internal worker function
+ */
+int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
+			   int force)
+{
+	ktime_t now = ktime_get();
+	int i;
+
+	for (i = 0;;) {
+		int ret = clockevents_program_event(dev, expires, now);
+
+		if (!ret || !force)
+			return ret;
+
+		/*
+		 * We tried 2 times to program the device with the given
+		 * min_delta_ns. If that's not working then we double it
+		 * and emit a warning.
+		 */
+		if (++i > 2) {
+			/* Increase the min. delta and try again */
+			if (!dev->min_delta_ns)
+				dev->min_delta_ns = 5000;
+			else
+				dev->min_delta_ns += dev->min_delta_ns >> 1;
+
+			printk(KERN_WARNING
+			       "CE: %s increasing min_delta_ns to %lu nsec\n",
+			       dev->name ? dev->name : "?",
+			       dev->min_delta_ns << 1);
+
+			i = 0;
+		}
+
+		now = ktime_get();
+		expires = ktime_add_ns(now, dev->min_delta_ns);
+	}
+}
+
+/**
  * tick_program_event
  */
 int tick_program_event(ktime_t expires, int force)
 {
 	struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
-	ktime_t now = ktime_get();
 
-	while (1) {
-		int ret = clockevents_program_event(dev, expires, now);
-
-		if (!ret || !force)
-			return ret;
-		now = ktime_get();
-		expires = ktime_add(now, ktime_set(0, dev->min_delta_ns));
-	}
+	return tick_dev_program_event(dev, expires, force);
 }
 
 /**
@@ -61,7 +93,7 @@
 {
 	newdev->event_handler = handler;
 	clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
-	clockevents_program_event(newdev, next_event, ktime_get());
+	tick_dev_program_event(newdev, next_event, 1);
 }
 
 /**
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7a46bde..a87b046 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -162,6 +162,8 @@
 		ts->idle_lastupdate = now;
 		ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
 		ts->idle_active = 0;
+
+		sched_clock_idle_wakeup_event(0);
 	}
 }
 
@@ -177,6 +179,7 @@
 	}
 	ts->idle_entrytime = now;
 	ts->idle_active = 1;
+	sched_clock_idle_sleep_event();
 	return now;
 }
 
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index 45a6bde..e3ab374 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -112,6 +112,7 @@
 
 /*
  * Allocate a new object. If the pool is empty, switch off the debugger.
+ * Must be called with interrupts disabled.
  */
 static struct debug_obj *
 alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
@@ -148,17 +149,18 @@
 static void free_object(struct debug_obj *obj)
 {
 	unsigned long idx = (unsigned long)(obj - obj_static_pool);
+	unsigned long flags;
 
 	if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) {
-		spin_lock(&pool_lock);
+		spin_lock_irqsave(&pool_lock, flags);
 		hlist_add_head(&obj->node, &obj_pool);
 		obj_pool_free++;
 		obj_pool_used--;
-		spin_unlock(&pool_lock);
+		spin_unlock_irqrestore(&pool_lock, flags);
 	} else {
-		spin_lock(&pool_lock);
+		spin_lock_irqsave(&pool_lock, flags);
 		obj_pool_used--;
-		spin_unlock(&pool_lock);
+		spin_unlock_irqrestore(&pool_lock, flags);
 		kmem_cache_free(obj_cache, obj);
 	}
 }
@@ -171,6 +173,7 @@
 {
 	struct debug_bucket *db = obj_hash;
 	struct hlist_node *node, *tmp;
+	HLIST_HEAD(freelist);
 	struct debug_obj *obj;
 	unsigned long flags;
 	int i;
@@ -179,11 +182,14 @@
 
 	for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
 		spin_lock_irqsave(&db->lock, flags);
-		hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+		hlist_move_list(&db->list, &freelist);
+		spin_unlock_irqrestore(&db->lock, flags);
+
+		/* Now free them */
+		hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
 			hlist_del(&obj->node);
 			free_object(obj);
 		}
-		spin_unlock_irqrestore(&db->lock, flags);
 	}
 }
 
@@ -498,8 +504,9 @@
 		return;
 	default:
 		hlist_del(&obj->node);
+		spin_unlock_irqrestore(&db->lock, flags);
 		free_object(obj);
-		break;
+		return;
 	}
 out_unlock:
 	spin_unlock_irqrestore(&db->lock, flags);
@@ -510,6 +517,7 @@
 {
 	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
 	struct hlist_node *node, *tmp;
+	HLIST_HEAD(freelist);
 	struct debug_obj_descr *descr;
 	enum debug_obj_state state;
 	struct debug_bucket *db;
@@ -545,11 +553,18 @@
 				goto repeat;
 			default:
 				hlist_del(&obj->node);
-				free_object(obj);
+				hlist_add_head(&obj->node, &freelist);
 				break;
 			}
 		}
 		spin_unlock_irqrestore(&db->lock, flags);
+
+		/* Now free them */
+		hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
+			hlist_del(&obj->node);
+			free_object(obj);
+		}
+
 		if (cnt > debug_objects_maxchain)
 			debug_objects_maxchain = cnt;
 	}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index d8d1d11..c399bc1 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -27,6 +27,7 @@
 
 #include <asm/page.h>		/* for PAGE_SIZE */
 #include <asm/div64.h>
+#include <asm/sections.h>	/* for dereference_function_descriptor() */
 
 /* Works only for digits and letters, but small and fast */
 #define TOLOWER(x) ((x) | 0x20)
@@ -513,16 +514,6 @@
 	return buf;
 }
 
-static inline void *dereference_function_descriptor(void *ptr)
-{
-#if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
-	void *p;
-	if (!probe_kernel_address(ptr, p))
-		ptr = p;
-#endif
-	return ptr;
-}
-
 static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
 {
 	unsigned long value = (unsigned long) ptr;
diff --git a/mm/mmap.c b/mm/mmap.c
index 339cf5c..e7a5a68 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1030,6 +1030,10 @@
 	} else {
 		switch (flags & MAP_TYPE) {
 		case MAP_SHARED:
+			/*
+			 * Ignore pgoff.
+			 */
+			pgoff = 0;
 			vm_flags |= VM_SHARED | VM_MAYSHARE;
 			break;
 		case MAP_PRIVATE:
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 1edfdf4..f6348e0 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -49,7 +49,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.12"
+#define VERSION "2.13"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO	8
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ca8d052..b700242 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -330,7 +330,7 @@
 
 /* Create SCO or ACL connection.
  * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type)
 {
 	struct hci_conn *acl;
 	struct hci_conn *sco;
@@ -344,8 +344,10 @@
 
 	hci_conn_hold(acl);
 
-	if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
+	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
+		acl->auth_type = auth_type;
 		hci_acl_connect(acl);
+	}
 
 	if (type == ACL_LINK)
 		return acl;
@@ -374,6 +376,19 @@
 }
 EXPORT_SYMBOL(hci_connect);
 
+/* Check link security requirement */
+int hci_conn_check_link_mode(struct hci_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+
+	if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
+					!(conn->link_mode & HCI_LM_ENCRYPT))
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(hci_conn_check_link_mode);
+
 /* Authenticate remote device */
 int hci_conn_auth(struct hci_conn *conn)
 {
@@ -381,7 +396,7 @@
 
 	if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
 		if (!(conn->auth_type & 0x01)) {
-			conn->auth_type = HCI_AT_GENERAL_BONDING_MITM;
+			conn->auth_type |= 0x01;
 			conn->link_mode &= ~HCI_LM_AUTH;
 		}
 	}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0e3db28..ad7a553 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1605,14 +1605,11 @@
 
 		if (conn->state == BT_CONFIG) {
 			if (!ev->status && hdev->ssp_mode > 0 &&
-							conn->ssp_mode > 0) {
-				if (conn->out) {
-					struct hci_cp_auth_requested cp;
-					cp.handle = ev->handle;
-					hci_send_cmd(hdev,
-						HCI_OP_AUTH_REQUESTED,
+					conn->ssp_mode > 0 && conn->out) {
+				struct hci_cp_auth_requested cp;
+				cp.handle = ev->handle;
+				hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
-				}
 			} else {
 				conn->state = BT_CONNECTED;
 				hci_proto_connect_cfm(conn, ev->status);
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 3396d5b..9610a9c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,7 +55,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.10"
+#define VERSION "2.11"
 
 static u32 l2cap_feat_mask = 0x0000;
 
@@ -778,6 +778,7 @@
 	struct l2cap_conn *conn;
 	struct hci_conn *hcon;
 	struct hci_dev *hdev;
+	__u8 auth_type;
 	int err = 0;
 
 	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
@@ -789,7 +790,21 @@
 
 	err = -ENOMEM;
 
-	hcon = hci_connect(hdev, ACL_LINK, dst);
+	if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
+			l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
+				l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
+		if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+			auth_type = HCI_AT_NO_BONDING_MITM;
+		else
+			auth_type = HCI_AT_GENERAL_BONDING_MITM;
+	} else {
+		if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+			auth_type = HCI_AT_NO_BONDING;
+		else
+			auth_type = HCI_AT_GENERAL_BONDING;
+	}
+
+	hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
 	if (!hcon)
 		goto done;
 
@@ -1553,10 +1568,10 @@
 	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
 	struct l2cap_conn_rsp rsp;
 	struct sock *sk, *parent;
-	int result, status = 0;
+	int result, status = L2CAP_CS_NO_INFO;
 
 	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-	__le16 psm  = req->psm;
+	__le16 psm = req->psm;
 
 	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
@@ -1567,6 +1582,13 @@
 		goto sendresp;
 	}
 
+	/* Check if the ACL is secure enough (if not SDP) */
+	if (psm != cpu_to_le16(0x0001) &&
+				!hci_conn_check_link_mode(conn->hcon)) {
+		result = L2CAP_CR_SEC_BLOCK;
+		goto response;
+	}
+
 	result = L2CAP_CR_NO_MEM;
 
 	/* Check for backlog size */
@@ -2224,7 +2246,7 @@
 			rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
 			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 			rsp.result = cpu_to_le16(result);
-			rsp.status = cpu_to_le16(0);
+			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 		}
@@ -2296,7 +2318,7 @@
 			rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
 			rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 			rsp.result = cpu_to_le16(result);
-			rsp.status = cpu_to_le16(0);
+			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 					L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 		}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index a16011f..0cc91e6 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -200,7 +200,7 @@
 	else
 		type = SCO_LINK;
 
-	hcon = hci_connect(hdev, type, dst);
+	hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
 	if (!hcon)
 		goto done;
 
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index eeee218..5bbf073 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -188,15 +188,21 @@
 		return 0;
 
 	case BRCTL_SET_BRIDGE_HELLO_TIME:
+	{
+		unsigned long t = clock_t_to_jiffies(args[1]);
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
+		if (t < HZ)
+			return -EINVAL;
+
 		spin_lock_bh(&br->lock);
-		br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+		br->bridge_hello_time = t;
 		if (br_is_root_bridge(br))
 			br->hello_time = br->bridge_hello_time;
 		spin_unlock_bh(&br->lock);
 		return 0;
+	}
 
 	case BRCTL_SET_BRIDGE_MAX_AGE:
 		if (!capable(CAP_NET_ADMIN))
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 27d6a51..158dee8 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -29,11 +29,12 @@
  */
 static ssize_t store_bridge_parm(struct device *d,
 				 const char *buf, size_t len,
-				 void (*set)(struct net_bridge *, unsigned long))
+				 int (*set)(struct net_bridge *, unsigned long))
 {
 	struct net_bridge *br = to_bridge(d);
 	char *endp;
 	unsigned long val;
+	int err;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -43,9 +44,9 @@
 		return -EINVAL;
 
 	spin_lock_bh(&br->lock);
-	(*set)(br, val);
+	err = (*set)(br, val);
 	spin_unlock_bh(&br->lock);
-	return len;
+	return err ? err : len;
 }
 
 
@@ -56,12 +57,13 @@
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
 {
 	unsigned long delay = clock_t_to_jiffies(val);
 	br->forward_delay = delay;
 	if (br_is_root_bridge(br))
 		br->bridge_forward_delay = delay;
+	return 0;
 }
 
 static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +82,17 @@
 		       jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
 {
 	unsigned long t = clock_t_to_jiffies(val);
+
+	if (t < HZ)
+		return -EINVAL;
+
 	br->hello_time = t;
 	if (br_is_root_bridge(br))
 		br->bridge_hello_time = t;
+	return 0;
 }
 
 static ssize_t store_hello_time(struct device *d,
@@ -104,12 +111,13 @@
 		       jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
 {
 	unsigned long t = clock_t_to_jiffies(val);
 	br->max_age = t;
 	if (br_is_root_bridge(br))
 		br->bridge_max_age = t;
+	return 0;
 }
 
 static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +134,10 @@
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
 {
 	br->ageing_time = clock_t_to_jiffies(val);
+	return 0;
 }
 
 static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +189,10 @@
 		       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
 
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
 {
 	br_stp_set_bridge_priority(br, (u16) val);
+	return 0;
 }
 
 static ssize_t store_priority(struct device *d, struct device_attribute *attr,
diff --git a/net/core/dev.c b/net/core/dev.c
index 60c51f7..e719ed2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1991,8 +1991,13 @@
 				spin_unlock(root_lock);
 			} else {
 				if (!test_bit(__QDISC_STATE_DEACTIVATED,
-					      &q->state))
+					      &q->state)) {
 					__netif_reschedule(q);
+				} else {
+					smp_mb__before_clear_bit();
+					clear_bit(__QDISC_STATE_SCHED,
+						  &q->state);
+				}
 			}
 		}
 	}
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index d985bd6..743f011 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -409,3 +409,38 @@
 }
 
 EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick);
+
+void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
+		     struct inet_timewait_death_row *twdr, int family)
+{
+	struct inet_timewait_sock *tw;
+	struct sock *sk;
+	struct hlist_node *node;
+	int h;
+
+	local_bh_disable();
+	for (h = 0; h < (hashinfo->ehash_size); h++) {
+		struct inet_ehash_bucket *head =
+			inet_ehash_bucket(hashinfo, h);
+		rwlock_t *lock = inet_ehash_lockp(hashinfo, h);
+restart:
+		write_lock(lock);
+		sk_for_each(sk, node, &head->twchain) {
+
+			tw = inet_twsk(sk);
+			if (!net_eq(twsk_net(tw), net) ||
+			    tw->tw_family != family)
+				continue;
+
+			atomic_inc(&tw->tw_refcnt);
+			write_unlock(lock);
+			inet_twsk_deschedule(tw, twdr);
+			inet_twsk_put(tw);
+
+			goto restart;
+		}
+		write_unlock(lock);
+	}
+	local_bh_enable();
+}
+EXPORT_SYMBOL_GPL(inet_twsk_purge);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 44c1e93..1b4fee2 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2376,6 +2376,7 @@
 static void __net_exit tcp_sk_exit(struct net *net)
 {
 	inet_ctl_sock_destroy(net->ipv4.tcp_sock);
+	inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET);
 }
 
 static struct pernet_operations __net_initdata tcp_sk_ops = {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 0e844c2..3df2c44 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -943,39 +943,39 @@
 	}
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
-		/*
-		 * Here if the dst entry we've looked up
-		 * has a neighbour entry that is in the INCOMPLETE
-		 * state and the src address from the flow is
-		 * marked as OPTIMISTIC, we release the found
-		 * dst entry and replace it instead with the
-		 * dst entry of the nexthop router
-		 */
-		if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
-			struct inet6_ifaddr *ifp;
-			struct flowi fl_gw;
-			int redirect;
+	/*
+	 * Here if the dst entry we've looked up
+	 * has a neighbour entry that is in the INCOMPLETE
+	 * state and the src address from the flow is
+	 * marked as OPTIMISTIC, we release the found
+	 * dst entry and replace it instead with the
+	 * dst entry of the nexthop router
+	 */
+	if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
+		struct inet6_ifaddr *ifp;
+		struct flowi fl_gw;
+		int redirect;
 
-			ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
-					      (*dst)->dev, 1);
+		ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
+				      (*dst)->dev, 1);
 
-			redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
-			if (ifp)
-				in6_ifa_put(ifp);
+		redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
+		if (ifp)
+			in6_ifa_put(ifp);
 
-			if (redirect) {
-				/*
-				 * We need to get the dst entry for the
-				 * default router instead
-				 */
-				dst_release(*dst);
-				memcpy(&fl_gw, fl, sizeof(struct flowi));
-				memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
-				*dst = ip6_route_output(net, sk, &fl_gw);
-				if ((err = (*dst)->error))
-					goto out_err_release;
-			}
+		if (redirect) {
+			/*
+			 * We need to get the dst entry for the
+			 * default router instead
+			 */
+			dst_release(*dst);
+			memcpy(&fl_gw, fl, sizeof(struct flowi));
+			memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
+			*dst = ip6_route_output(net, sk, &fl_gw);
+			if ((err = (*dst)->error))
+				goto out_err_release;
 		}
+	}
 #endif
 
 	return 0;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5b90b36..b585c85 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2148,6 +2148,7 @@
 static void tcpv6_net_exit(struct net *net)
 {
 	inet_ctl_sock_destroy(net->ipv6.tcp_sk);
+	inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6);
 }
 
 static struct pernet_operations tcpv6_net_ops = {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9bb68c6..902cac1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -478,21 +478,51 @@
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
 					 struct ieee80211_if_sta *ifsta)
 {
+	char *buf;
+	size_t len;
+	int i;
 	union iwreq_data wrqu;
 
+	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+		return;
+
+	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
+				ifsta->assocresp_ies_len), GFP_KERNEL);
+	if (!buf)
+		return;
+
+	len = sprintf(buf, "ASSOCINFO(");
 	if (ifsta->assocreq_ies) {
-		memset(&wrqu, 0, sizeof(wrqu));
-		wrqu.data.length = ifsta->assocreq_ies_len;
-		wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
-				    ifsta->assocreq_ies);
+		len += sprintf(buf + len, "ReqIEs=");
+		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocreq_ies[i]);
+		}
+	}
+	if (ifsta->assocresp_ies) {
+		if (ifsta->assocreq_ies)
+			len += sprintf(buf + len, " ");
+		len += sprintf(buf + len, "RespIEs=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
+	}
+	len += sprintf(buf + len, ")");
+
+	if (len > IW_CUSTOM_MAX) {
+		len = sprintf(buf, "ASSOCRESPIE=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
 	}
 
-	if (ifsta->assocresp_ies) {
-		memset(&wrqu, 0, sizeof(wrqu));
-		wrqu.data.length = ifsta->assocresp_ies_len;
-		wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
-				    ifsta->assocresp_ies);
-	}
+	memset(&wrqu, 0, sizeof(wrqu));
+	wrqu.data.length = len;
+	wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+
+	kfree(buf);
 }
 
 
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 1b1226d..20633fd 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -68,11 +68,21 @@
 static int parse_dcc(char *data, const char *data_end, u_int32_t *ip,
 		     u_int16_t *port, char **ad_beg_p, char **ad_end_p)
 {
+	char *tmp;
+
 	/* at least 12: "AAAAAAAA P\1\n" */
 	while (*data++ != ' ')
 		if (data > data_end - 12)
 			return -1;
 
+	/* Make sure we have a newline character within the packet boundaries
+	 * because simple_strtoul parses until the first invalid character. */
+	for (tmp = data; tmp <= data_end; tmp++)
+		if (*tmp == '\n')
+			break;
+	if (tmp > data_end || *tmp != '\n')
+		return -1;
+
 	*ad_beg_p = data;
 	*ip = simple_strtoul(data, &data, 10);
 
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 654a4f7..9bd0396 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -45,12 +45,12 @@
 
 void nf_ct_gre_keymap_flush(void)
 {
-	struct list_head *pos, *n;
+	struct nf_ct_gre_keymap *km, *tmp;
 
 	write_lock_bh(&nf_ct_gre_lock);
-	list_for_each_safe(pos, n, &gre_keymap_list) {
-		list_del(pos);
-		kfree(pos);
+	list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) {
+		list_del(&km->list);
+		kfree(km);
 	}
 	write_unlock_bh(&nf_ct_gre_lock);
 }
@@ -97,10 +97,14 @@
 	kmp = &help->help.ct_pptp_info.keymap[dir];
 	if (*kmp) {
 		/* check whether it's a retransmission */
+		read_lock_bh(&nf_ct_gre_lock);
 		list_for_each_entry(km, &gre_keymap_list, list) {
-			if (gre_key_cmpfn(km, t) && km == *kmp)
+			if (gre_key_cmpfn(km, t) && km == *kmp) {
+				read_unlock_bh(&nf_ct_gre_lock);
 				return 0;
+			}
 		}
+		read_unlock_bh(&nf_ct_gre_lock);
 		pr_debug("trying to override keymap_%s for ct %p\n",
 			 dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
 		return -EEXIST;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 2f9bbc0..1fa306b 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1193,7 +1193,6 @@
 static int process_sip_response(struct sk_buff *skb,
 				const char **dptr, unsigned int *datalen)
 {
-	static const struct sip_handler *handler;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	unsigned int matchoff, matchlen;
@@ -1214,6 +1213,8 @@
 	dataoff = matchoff + matchlen + 1;
 
 	for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+		const struct sip_handler *handler;
+
 		handler = &sip_handlers[i];
 		if (handler->response == NULL)
 			continue;
@@ -1228,13 +1229,14 @@
 static int process_sip_request(struct sk_buff *skb,
 			       const char **dptr, unsigned int *datalen)
 {
-	static const struct sip_handler *handler;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	unsigned int matchoff, matchlen;
 	unsigned int cseq, i;
 
 	for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+		const struct sip_handler *handler;
+
 		handler = &sip_handlers[i];
 		if (handler->request == NULL)
 			continue;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 46914b7..b7754b1 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1077,6 +1077,7 @@
 	struct hlist_head *chain = policy_hash_bysel(&pol->selector,
 						     pol->family, dir);
 
+	list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]);
 	hlist_add_head(&pol->bydst, chain);
 	hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
 	xfrm_policy_count[dir]++;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 7bd62f6..0a8f09c 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -858,6 +858,7 @@
 
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
+			list_add_tail(&x->all, &xfrm_state_all);
 			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 			h = xfrm_src_hash(daddr, saddr, family);
 			hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1055,6 +1056,7 @@
 		xfrm_state_hold(x);
 		x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
 		add_timer(&x->timer);
+		list_add_tail(&x->all, &xfrm_state_all);
 		hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 		h = xfrm_src_hash(daddr, saddr, family);
 		hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
diff --git a/sound/Kconfig b/sound/Kconfig
index a37bee0..8ebf512 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -91,6 +91,9 @@
 
 endif # !M68K
 
+endif # SOUND
+
+# AC97_BUS is used from both sound and ucb1400
 config AC97_BUS
 	tristate
 	help
@@ -99,4 +102,3 @@
 	  sound although they're sharing the AC97 bus. Concerned drivers
 	  should "select" this.
 
-endif # SOUND