Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb:
  V4L/DVB (7751): ir-kbd-i2c: Save a temporary memory allocation in ir_probe
  V4L/DVB (7750): au0828/ cleanups and fixes
  V4L/DVB (7748): tuner-core: some adjustments at tuner logs, if debug enabled
  V4L/DVB (7746): pvrusb2: make signed one-bit bitfields unsigned
  V4L/DVB (7744): pvrusb2-dvb: add atsc/qam support for Hauppauge pvrusb2 model 751xx
  V4L/DVB (7742): cx88: Add support for the DViCO FusionHDTV_7_GOLD digital modes
  V4L/DVB (7741): s5h1411: Adding support for this ATSC/QAM demodulator
  V4L/DVB (7740): tuner-xc2028.c dubious !x & y
  V4L/DVB (7739): mt312.h: dubious one-bit signed bitfield
  V4L/DVB (7735): Fix compilation for au0828
  V4L/DVB (7734): em28xx: copy and paste error in em28xx_init_isoc
  V4L/DVB (7733): blackbird_find_mailbox negative return ignored in blackbird_initialize_codec()
  V4L/DVB (7732): vivi: fix a warning
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 68fab61..f5fceb3 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -307,6 +307,14 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+config DVB_S5H1411
+	tristate "Samsung S5H1411 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 comment "Tuners/PLL support"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 2f873fc0..9747c73 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -55,3 +55,4 @@
 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 96338f0..de796ea 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -33,7 +33,7 @@
 	u8 demod_address;
 
 	/* inverted voltage setting */
-	int voltage_inverted:1;
+	unsigned int voltage_inverted:1;
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
new file mode 100644
index 0000000..eb5bfc9
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -0,0 +1,888 @@
+/*
+    Samsung S5H1411 VSB/QAM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "s5h1411.h"
+
+struct s5h1411_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct s5h1411_config *config;
+
+	struct dvb_frontend frontend;
+
+	fe_modulation_t current_modulation;
+
+	u32 current_frequency;
+	int if_freq;
+
+	u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do {	\
+	if (debug)		\
+		printk(arg);	\
+	} while (0)
+
+/* Register values to initialise the demod, defaults to VSB */
+static struct init_tab {
+	u8	addr;
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
+	{ S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
+	{ S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, },
+	{ S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
+	{ S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
+	{ S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
+	{ S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
+	{ S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
+	{ S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
+	{ S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
+	{ S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
+	{ S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
+	{ S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
+	{ S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
+	{ S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
+	{ S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
+	{ S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
+	{ S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
+	{ S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
+	{ S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
+	{ S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
+	{ S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
+	{ S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
+	{ S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
+	{ S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
+	{ S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
+	{ S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
+	{ S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
+	{ S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
+	{ S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
+	{ S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
+	{ S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
+	{ S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
+	{ S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
+	{ S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
+	{ S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
+	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
+	{ S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
+	{ S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
+	{ S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
+	{ S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
+	{ S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
+	{ S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
+	{ S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
+	{ S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
+	{ S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
+	{ S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
+	{ S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
+	{ S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
+	{ S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
+	{ S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
+	{ S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
+	{ S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
+	{ S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+	u16	val;
+	u16	data;
+} vsb_snr_tab[] = {
+	{  0x39f, 300, },
+	{  0x39b, 295, },
+	{  0x397, 290, },
+	{  0x394, 285, },
+	{  0x38f, 280, },
+	{  0x38b, 275, },
+	{  0x387, 270, },
+	{  0x382, 265, },
+	{  0x37d, 260, },
+	{  0x377, 255, },
+	{  0x370, 250, },
+	{  0x36a, 245, },
+	{  0x364, 240, },
+	{  0x35b, 235, },
+	{  0x353, 230, },
+	{  0x349, 225, },
+	{  0x340, 320, },
+	{  0x337, 215, },
+	{  0x327, 210, },
+	{  0x31b, 205, },
+	{  0x310, 200, },
+	{  0x302, 195, },
+	{  0x2f3, 190, },
+	{  0x2e4, 185, },
+	{  0x2d7, 180, },
+	{  0x2cd, 175, },
+	{  0x2bb, 170, },
+	{  0x2a9, 165, },
+	{  0x29e, 160, },
+	{  0x284, 155, },
+	{  0x27a, 150, },
+	{  0x260, 145, },
+	{  0x23a, 140, },
+	{  0x224, 135, },
+	{  0x213, 130, },
+	{  0x204, 125, },
+	{  0x1fe, 120, },
+	{      0,   0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+	u16	val;
+	u16	data;
+} qam64_snr_tab[] = {
+	{  0x0001,   0, },
+	{  0x0af0, 300, },
+	{  0x0d80, 290, },
+	{  0x10a0, 280, },
+	{  0x14b5, 270, },
+	{  0x1590, 268, },
+	{  0x1680, 266, },
+	{  0x17b0, 264, },
+	{  0x18c0, 262, },
+	{  0x19b0, 260, },
+	{  0x1ad0, 258, },
+	{  0x1d00, 256, },
+	{  0x1da0, 254, },
+	{  0x1ef0, 252, },
+	{  0x2050, 250, },
+	{  0x20f0, 249, },
+	{  0x21d0, 248, },
+	{  0x22b0, 247, },
+	{  0x23a0, 246, },
+	{  0x2470, 245, },
+	{  0x24f0, 244, },
+	{  0x25a0, 243, },
+	{  0x26c0, 242, },
+	{  0x27b0, 241, },
+	{  0x28d0, 240, },
+	{  0x29b0, 239, },
+	{  0x2ad0, 238, },
+	{  0x2ba0, 237, },
+	{  0x2c80, 236, },
+	{  0x2d20, 235, },
+	{  0x2e00, 234, },
+	{  0x2f10, 233, },
+	{  0x3050, 232, },
+	{  0x3190, 231, },
+	{  0x3300, 230, },
+	{  0x3340, 229, },
+	{  0x3200, 228, },
+	{  0x3550, 227, },
+	{  0x3610, 226, },
+	{  0x3600, 225, },
+	{  0x3700, 224, },
+	{  0x3800, 223, },
+	{  0x3920, 222, },
+	{  0x3a20, 221, },
+	{  0x3b30, 220, },
+	{  0x3d00, 219, },
+	{  0x3e00, 218, },
+	{  0x4000, 217, },
+	{  0x4100, 216, },
+	{  0x4300, 215, },
+	{  0x4400, 214, },
+	{  0x4600, 213, },
+	{  0x4700, 212, },
+	{  0x4800, 211, },
+	{  0x4a00, 210, },
+	{  0x4b00, 209, },
+	{  0x4d00, 208, },
+	{  0x4f00, 207, },
+	{  0x5050, 206, },
+	{  0x5200, 205, },
+	{  0x53c0, 204, },
+	{  0x5450, 203, },
+	{  0x5650, 202, },
+	{  0x5820, 201, },
+	{  0x6000, 200, },
+	{  0xffff,   0, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+	u16	val;
+	u16	data;
+} qam256_snr_tab[] = {
+	{  0x0001,   0, },
+	{  0x0970, 400, },
+	{  0x0a90, 390, },
+	{  0x0b90, 380, },
+	{  0x0d90, 370, },
+	{  0x0ff0, 360, },
+	{  0x1240, 350, },
+	{  0x1345, 348, },
+	{  0x13c0, 346, },
+	{  0x14c0, 344, },
+	{  0x1500, 342, },
+	{  0x1610, 340, },
+	{  0x1700, 338, },
+	{  0x1800, 336, },
+	{  0x18b0, 334, },
+	{  0x1900, 332, },
+	{  0x1ab0, 330, },
+	{  0x1bc0, 328, },
+	{  0x1cb0, 326, },
+	{  0x1db0, 324, },
+	{  0x1eb0, 322, },
+	{  0x2030, 320, },
+	{  0x2200, 318, },
+	{  0x2280, 316, },
+	{  0x2410, 314, },
+	{  0x25b0, 312, },
+	{  0x27a0, 310, },
+	{  0x2840, 308, },
+	{  0x29d0, 306, },
+	{  0x2b10, 304, },
+	{  0x2d30, 302, },
+	{  0x2f20, 300, },
+	{  0x30c0, 298, },
+	{  0x3260, 297, },
+	{  0x32c0, 296, },
+	{  0x3300, 295, },
+	{  0x33b0, 294, },
+	{  0x34b0, 293, },
+	{  0x35a0, 292, },
+	{  0x3650, 291, },
+	{  0x3800, 290, },
+	{  0x3900, 289, },
+	{  0x3a50, 288, },
+	{  0x3b30, 287, },
+	{  0x3cb0, 286, },
+	{  0x3e20, 285, },
+	{  0x3fa0, 284, },
+	{  0x40a0, 283, },
+	{  0x41c0, 282, },
+	{  0x42f0, 281, },
+	{  0x44a0, 280, },
+	{  0x4600, 279, },
+	{  0x47b0, 278, },
+	{  0x4900, 277, },
+	{  0x4a00, 276, },
+	{  0x4ba0, 275, },
+	{  0x4d00, 274, },
+	{  0x4f00, 273, },
+	{  0x5000, 272, },
+	{  0x51f0, 272, },
+	{  0x53a0, 270, },
+	{  0x5520, 269, },
+	{  0x5700, 268, },
+	{  0x5800, 267, },
+	{  0x5a00, 266, },
+	{  0x5c00, 265, },
+	{  0x5d00, 264, },
+	{  0x5f00, 263, },
+	{  0x6000, 262, },
+	{  0x6200, 261, },
+	{  0x6400, 260, },
+	{  0xffff,   0, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1411_writereg(struct s5h1411_state *state,
+	u8 addr, u8 reg, u16 data)
+{
+	int ret;
+	u8 buf [] = { reg, data >> 8,  data & 0xff };
+
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+		       "ret == %i)\n", __func__, addr, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0, 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = addr, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+			__func__, ret);
+	return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1411_softreset(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
+	return 0;
+}
+
+static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d KHz)\n", __func__, KHz);
+
+	switch (KHz) {
+	case 3250:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
+		break;
+	case 3500:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
+		break;
+	case 4000:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
+		break;
+	default:
+		dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
+			__func__, KHz);
+		/* no break, need to continue */
+	case 5380:
+	case 44000:
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
+		break;
+	}
+
+	state->if_freq = KHz;
+
+	return 0;
+}
+
+static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, mode);
+
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
+	switch (mode) {
+	case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+		val |= 0x0000;
+		break;
+	case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+		dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
+		val |= 0x1000;
+		break;
+	case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+		val |= 0x2000;
+		break;
+	case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+		val |= 0x3000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Configure MPEG Signal Timing charactistics */
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
+}
+
+static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, inversion);
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
+
+	if (inversion == 1)
+		val |= 0x1000; /* Inverted */
+	else
+		val |= 0x0000;
+
+	state->inversion = inversion;
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
+}
+
+static int s5h1411_enable_modulation(struct dvb_frontend *fe,
+				     fe_modulation_t m)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		s5h1411_set_if_freq(fe, state->config->vsb_if);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
+		break;
+	case QAM_64:
+	case QAM_256:
+		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);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
+		s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+	s5h1411_softreset(fe);
+
+	return 0;
+}
+
+static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+	else
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
+}
+
+static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
+
+	if (enable)
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
+				val | 0x02);
+	else
+		return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
+}
+
+static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
+	else {
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
+		s5h1411_softreset(fe);
+	}
+
+	return 0;
+}
+
+static int s5h1411_register_reset(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1411_set_frontend(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *p)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+	s5h1411_softreset(fe);
+
+	state->current_frequency = p->frequency;
+
+	s5h1411_enable_modulation(fe, p->u.vsb.modulation);
+
+	/* Allow the demod to settle */
+	msleep(100);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+
+		fe->ops.tuner_ops.set_params(fe, p);
+
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int s5h1411_init(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s()\n", __func__);
+
+	s5h1411_sleep(fe, 0);
+	s5h1411_register_reset(fe);
+
+	for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+		s5h1411_writereg(state, init_tab[i].addr,
+			init_tab[i].reg,
+			init_tab[i].data);
+
+	/* The datasheet says that after initialisation, VSB is default */
+	state->current_modulation = VSB_8;
+
+	if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
+		/* Serial */
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101);
+	else
+		/* Parallel */
+		s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001);
+
+	s5h1411_set_spectralinversion(fe, state->config->inversion);
+	s5h1411_set_if_freq(fe, state->config->vsb_if);
+	s5h1411_set_gpio(fe, state->config->gpio);
+	s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
+	s5h1411_softreset(fe);
+
+	/* Note: Leaving the I2C gate closed. */
+	s5h1411_i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	/* Get the demodulator status */
+	reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15)
+		& 0x0001;
+	if (reg)
+		*status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+	switch (state->current_modulation) {
+	case QAM_64:
+	case QAM_256:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
+		if (reg & 0x100)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x10)
+			*status |= FE_HAS_SYNC;
+		break;
+	case VSB_8:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e);
+		if (reg & 0x0001)
+			*status |= FE_HAS_SYNC;
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
+		if (reg & 0x1000)
+			*status |= FE_HAS_VITERBI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (state->config->status_mode) {
+	case S5H1411_DEMODLOCKING:
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case S5H1411_TUNERLOCKING:
+		/* Get the tuner status */
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+		if (v < qam256_snr_tab[i].val) {
+			*snr = qam256_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+		if (v < qam64_snr_tab[i].val) {
+			*snr = qam64_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+		if (v > vsb_snr_tab[i].val) {
+			*snr = vsb_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	u16 reg;
+	dprintk("%s()\n", __func__);
+
+	switch (state->current_modulation) {
+	case QAM_64:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+		return s5h1411_qam64_lookup_snr(fe, snr, reg);
+	case QAM_256:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+		return s5h1411_qam256_lookup_snr(fe, snr, reg);
+	case VSB_8:
+		reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
+			0xf2) & 0x3ff;
+		return s5h1411_vsb_lookup_snr(fe, snr, reg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
+	u16 *signal_strength)
+{
+	return s5h1411_read_snr(fe, signal_strength);
+}
+
+static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	*ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
+
+	return 0;
+}
+
+static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return s5h1411_read_ucblocks(fe, ber);
+}
+
+static int s5h1411_get_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->u.vsb.modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void s5h1411_release(struct dvb_frontend *fe)
+{
+	struct s5h1411_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1411_ops;
+
+struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct s5h1411_state *state = NULL;
+	u16 reg;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = VSB_8;
+	state->inversion = state->config->inversion;
+
+	/* check if the demod exists */
+	reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
+	if (reg != 0x0066)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1411_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	state->frontend.demodulator_priv = state;
+
+	if (s5h1411_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(s5h1411_attach);
+
+static struct dvb_frontend_ops s5h1411_ops = {
+
+	.info = {
+		.name			= "Samsung S5H1411 QAM/8VSB Frontend",
+		.type			= FE_ATSC,
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = s5h1411_init,
+	.i2c_gate_ctrl        = s5h1411_i2c_gate_ctrl,
+	.set_frontend         = s5h1411_set_frontend,
+	.get_frontend         = s5h1411_get_frontend,
+	.get_tune_settings    = s5h1411_get_tune_settings,
+	.read_status          = s5h1411_read_status,
+	.read_ber             = s5h1411_read_ber,
+	.read_signal_strength = s5h1411_read_signal_strength,
+	.read_snr             = s5h1411_read_snr,
+	.read_ucblocks        = s5h1411_read_ucblocks,
+	.release              = s5h1411_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
new file mode 100644
index 0000000..1855f64
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -0,0 +1,90 @@
+/*
+    Samsung S5H1411 VSB/QAM demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1411_H__
+#define __S5H1411_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
+#define S5H1411_I2C_QAM_ADDR (0x34 >> 1)
+
+struct s5h1411_config {
+
+	/* serial/parallel output */
+#define S5H1411_PARALLEL_OUTPUT 0
+#define S5H1411_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1411_GPIO_OFF 0
+#define S5H1411_GPIO_ON  1
+	u8 gpio;
+
+	/* MPEG signal timing */
+#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
+
+	/* IF Freq for QAM and VSB in KHz */
+#define S5H1411_IF_2500  2500
+#define S5H1411_IF_3500  3500
+#define S5H1411_IF_4000  4000
+#define S5H1411_IF_5380  5380
+#define S5H1411_IF_44000 44000
+#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000
+#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000
+	u16 qam_if;
+	u16 vsb_if;
+
+	/* Spectral Inversion */
+#define S5H1411_INVERSION_OFF 0
+#define S5H1411_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1411_TUNERLOCKING 0
+#define S5H1411_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1411) || \
+	(defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+					   struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1411_attach(
+	const struct s5h1411_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_S5H1411 */
+
+#endif /* __S5H1411_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index c97c4bd..4170826 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -1,7 +1,7 @@
 
 config VIDEO_AU0828
 	tristate "Auvitek AU0828 support"
-	depends on VIDEO_DEV && I2C && INPUT
+       depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
 	select I2C_ALGOBIT
 	select DVB_AU8522 if !DVB_FE_CUSTOMIZE
 	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 8ca91f8..a2a6983 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -36,7 +36,6 @@
 		.name	= "DViCO FusionHDTV USB",
 	},
 };
-const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards);
 
 /* Tuner callback function for au0828 boards. Currently only needed
  * for HVR1500Q, which has an xc5000 tuner.
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
index e65d564..54bfc0f 100644
--- a/drivers/media/video/au0828/au0828-core.c
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -32,18 +32,10 @@
  * 4 = I2C related
  * 8 = Bridge related
  */
-unsigned int debug;
-module_param(debug, int, 0644);
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
-unsigned int usb_debug;
-module_param(usb_debug, int, 0644);
-MODULE_PARM_DESC(usb_debug, "enable usb debug messages");
-
-unsigned int bridge_debug;
-module_param(bridge_debug, int, 0644);
-MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages");
-
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 
@@ -229,24 +221,18 @@
 {
 	int ret;
 
-	if (debug)
+	if (au0828_debug & 1)
 		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
 
-	if (usb_debug) {
+	if (au0828_debug & 2)
 		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
-		debug |= 2;
-	}
 
-	if (i2c_debug) {
+	if (au0828_debug & 4)
 		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
-		debug |= 4;
-	}
 
-	if (bridge_debug) {
+	if (au0828_debug & 8)
 		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
 		       __func__);
-		debug |= 8;
-	}
 
 	printk(KERN_INFO "au0828 driver loaded\n");
 
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 85d0ae9..5040d7f 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -204,7 +204,7 @@
 	return ret;
 }
 
-int dvb_register(struct au0828_dev *dev)
+static int dvb_register(struct au0828_dev *dev)
 {
 	struct au0828_dvb *dvb = &dev->dvb;
 	int result;
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 94c8b74..741a493 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -29,11 +29,7 @@
 
 #include <media/v4l2-common.h>
 
-unsigned int i2c_debug;
-module_param(i2c_debug, int, 0444);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-
-unsigned int i2c_scan;
+static int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 0200b9f..7beb571 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -96,15 +96,12 @@
 /* au0828-core.c */
 extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
 extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
-extern unsigned int debug;
-extern unsigned int usb_debug;
-extern unsigned int bridge_debug;
+extern int au0828_debug;
 
 /* ----------------------------------------------------------- */
 /* au0828-cards.c */
 extern struct au0828_board au0828_boards[];
 extern struct usb_device_id au0828_usb_id_table[];
-extern const unsigned int au0828_bcount;
 extern void au0828_gpio_setup(struct au0828_dev *dev);
 extern int au0828_tuner_callback(void *priv, int command, int arg);
 extern void au0828_card_setup(struct au0828_dev *dev);
@@ -115,7 +112,6 @@
 extern int au0828_i2c_unregister(struct au0828_dev *dev);
 extern void au0828_call_i2c_clients(struct au0828_dev *dev,
 	unsigned int cmd, void *arg);
-extern unsigned int i2c_debug;
 
 /* ----------------------------------------------------------- */
 /* au0828-dvb.c */
@@ -123,6 +119,6 @@
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
 
 #define dprintk(level, fmt, arg...)\
-	do { if (debug & level)\
+	do { if (au0828_debug & level)\
 		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
 	} while (0)
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index bcf6d9b..27635cd 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -58,6 +58,7 @@
 	select DVB_CX24123 if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Conexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 61c4f72..6c0c94c 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -546,10 +546,12 @@
 		if (retval < 0)
 			return retval;
 
-		dev->mailbox = blackbird_find_mailbox(dev);
-		if (dev->mailbox < 0)
+		retval = blackbird_find_mailbox(dev);
+		if (retval < 0)
 			return -1;
 
+		dev->mailbox = retval;
+
 		retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
 		if (retval < 0) {
 			dprintk(0, "ERROR: Firmware ping failed!\n");
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 620159d..2b6b283 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1591,6 +1591,7 @@
 			.vmux   = 2,
 			.gpio0  = 0x16d9,
 		}},
+		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PROLINK_PV_8000GT] = {
 		.name           = "Prolink Pixelview MPEG 8000GT",
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index f1251b8..1c7fe68 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -47,6 +47,7 @@
 #include "isl6421.h"
 #include "tuner-simple.h"
 #include "tda9887.h"
+#include "s5h1411.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -463,6 +464,22 @@
        .no_tuner = 1,
 };
 
+static struct s5h1411_config dvico_fusionhdtv7_config = {
+	.output_mode   = S5H1411_SERIAL_OUTPUT,
+	.gpio          = S5H1411_GPIO_ON,
+	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+	.qam_if        = S5H1411_IF_44000,
+	.vsb_if        = S5H1411_IF_44000,
+	.inversion     = S5H1411_INVERSION_OFF,
+	.status_mode   = S5H1411_DEMODLOCKING
+};
+
+static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+	.i2c_address    = 0xc2 >> 1,
+	.if_khz         = 5380,
+	.tuner_callback = cx88_tuner_callback,
+};
+
 static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
 {
 	struct dvb_frontend *fe;
@@ -844,6 +861,21 @@
 		if (attach_xc3028(0x61, dev) < 0)
 			return -EINVAL;
 		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+		dev->dvb.frontend = dvb_attach(s5h1411_attach,
+					       &dvico_fusionhdtv7_config,
+					       &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			/* tuner_config.video_dev must point to
+			 * i2c_adap.algo_data
+			 */
+			dvico_fusionhdtv7_tuner_config.priv =
+						dev->core->i2c_adap.algo_data;
+			dvb_attach(xc5000_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap,
+				   &dvico_fusionhdtv7_tuner_config);
+		}
+		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index f8c41d8..5d837c1 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -650,7 +650,7 @@
 
 	dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
 					      GFP_KERNEL);
-	if (!dev->isoc_ctl.urb) {
+	if (!dev->isoc_ctl.transfer_buffer) {
 		em28xx_errdev("cannot allocate memory for usbtransfer\n");
 		kfree(dev->isoc_ctl.urb);
 		return -ENOMEM;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 11c5fde..7b65f5e 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -509,8 +509,11 @@
 	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
 	static const int probe_cx23885[] = { 0x6b, -1 };
 	const int *probe;
-	struct i2c_client *c;
-	unsigned char buf;
+	struct i2c_msg msg = {
+		.flags = I2C_M_RD,
+		.len = 0,
+		.buf = NULL,
+	};
 	int i, rc;
 
 	switch (adap->id) {
@@ -536,23 +539,17 @@
 		return 0;
 	}
 
-	c = kzalloc(sizeof(*c), GFP_KERNEL);
-	if (!c)
-		return -ENOMEM;
-
-	c->adapter = adap;
 	for (i = 0; -1 != probe[i]; i++) {
-		c->addr = probe[i];
-		rc = i2c_master_recv(c, &buf, 0);
+		msg.addr = probe[i];
+		rc = i2c_transfer(adap, &msg, 1);
 		dprintk(1,"probe 0x%02x @ %s: %s\n",
 			probe[i], adap->name,
-			(0 == rc) ? "yes" : "no");
-		if (0 == rc) {
+			(1 == rc) ? "yes" : "no");
+		if (1 == rc) {
 			ir_attach(adap, probe[i], 0, 0);
 			break;
 		}
 	}
-	kfree(c);
 	return 0;
 }
 
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index a8da90f..158b3d0 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -64,6 +64,7 @@
 	depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
 	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
 	select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 2dd06a9..3a141d9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -36,6 +36,7 @@
 #include "pvrusb2-hdw-internal.h"
 #include "lgdt330x.h"
 #include "s5h1409.h"
+#include "s5h1411.h"
 #include "tda10048.h"
 #include "tda18271.h"
 #include "tda8290.h"
@@ -368,6 +369,15 @@
 	.status_mode   = S5H1409_DEMODLOCKING,
 };
 
+static struct s5h1411_config pvr2_s5h1411_config = {
+	.output_mode   = S5H1411_PARALLEL_OUTPUT,
+	.gpio          = S5H1411_GPIO_OFF,
+	.vsb_if        = S5H1411_IF_44000,
+	.qam_if        = S5H1411_IF_4000,
+	.inversion     = S5H1411_INVERSION_ON,
+	.status_mode   = S5H1411_DEMODLOCKING,
+};
+
 static struct tda18271_std_map hauppauge_tda18271_std_map = {
 	.atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
 		      .if_lvl = 6, .rfagc_top = 0x37, },
@@ -390,6 +400,16 @@
 	return -EIO;
 }
 
+static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
+{
+	adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
+			      &adap->channel.hdw->i2c_adap);
+	if (adap->fe)
+		return 0;
+
+	return -EIO;
+}
+
 static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
 {
 	dvb_attach(tda829x_attach, adap->fe,
@@ -406,6 +426,11 @@
 	.frontend_attach = pvr2_s5h1409_attach,
 	.tuner_attach    = pvr2_tda18271_8295_attach,
 };
+
+struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+	.frontend_attach = pvr2_s5h1411_attach,
+	.tuner_attach    = pvr2_tda18271_8295_attach,
+};
 #endif
 
 static const char *pvr2_client_75xxx[] = {
@@ -454,6 +479,9 @@
 		.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
 		.default_std_mask = V4L2_STD_NTSC_M,
 		.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+		.dvb_props = &pvr2_751xx_dvb_props,
+#endif
 };
 
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index c2e2b06..d016f8b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -104,28 +104,28 @@
 	unsigned char digital_control_scheme;
 
 	/* If set, we don't bother trying to load cx23416 firmware. */
-	int flag_skip_cx23416_firmware:1;
+	unsigned int flag_skip_cx23416_firmware:1;
 
 	/* If set, the encoder must be healthy in order for digital mode to
 	   work (otherwise we assume that digital streaming will work even
 	   if we fail to locate firmware for the encoder).  If the device
 	   doesn't support digital streaming then this flag has no
 	   effect. */
-	int flag_digital_requires_cx23416:1;
+	unsigned int flag_digital_requires_cx23416:1;
 
 	/* Device has a hauppauge eeprom which we can interrogate. */
-	int flag_has_hauppauge_rom:1;
+	unsigned int flag_has_hauppauge_rom:1;
 
 	/* Device does not require a powerup command to be issued. */
-	int flag_no_powerup:1;
+	unsigned int flag_no_powerup:1;
 
 	/* Device has a cx25840 - this enables special additional logic to
 	   handle it. */
-	int flag_has_cx25840:1;
+	unsigned int flag_has_cx25840:1;
 
 	/* Device has a wm8775 - this enables special additional logic to
 	   ensure that it is found. */
-	int flag_has_wm8775:1;
+	unsigned int flag_has_wm8775:1;
 
 	/* Device has IR hardware that can be faked into looking like a
 	   normal Hauppauge i2c IR receiver.  This is currently very
@@ -135,15 +135,15 @@
 	   to virtualize the presence of the non-existant IR receiver chip and
 	   implement the virtual receiver in terms of appropriate FX2
 	   commands. */
-	int flag_has_hauppauge_custom_ir:1;
+	unsigned int flag_has_hauppauge_custom_ir:1;
 
 	/* These bits define which kinds of sources the device can handle.
 	   Note: Digital tuner presence is inferred by the
 	   digital_control_scheme enumeration. */
-	int flag_has_fmradio:1;       /* Has FM radio receiver */
-	int flag_has_analogtuner:1;   /* Has analog tuner */
-	int flag_has_composite:1;     /* Has composite input */
-	int flag_has_svideo:1;        /* Has s-video input */
+	unsigned int flag_has_fmradio:1;       /* Has FM radio receiver */
+	unsigned int flag_has_analogtuner:1;   /* Has analog tuner */
+	unsigned int flag_has_composite:1;     /* Has composite input */
+	unsigned int flag_has_svideo:1;        /* Has s-video input */
 };
 
 extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 529e009..2b72e10 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -369,19 +369,13 @@
 		break;
 	}
 	case TUNER_TEA5767:
-		if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+			goto attach_failed;
 		t->mode_mask = T_RADIO;
 		break;
 	case TUNER_TEA5761:
-		if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+			goto attach_failed;
 		t->mode_mask = T_RADIO;
 		break;
 	case TUNER_PHILIPS_FMD1216ME_MK3:
@@ -394,12 +388,9 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0x54;
 		i2c_master_send(c, buffer, 4);
-		if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
-					t->type) == NULL) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
+					t->type))
+			goto attach_failed;
 		break;
 	case TUNER_PHILIPS_TD1316:
 		buffer[0] = 0x0b;
@@ -407,12 +398,9 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0xa4;
 		i2c_master_send(c,buffer,4);
-		if (simple_tuner_attach(&t->fe, t->i2c->adapter,
-					t->i2c->addr, t->type) == NULL) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
+					t->i2c->addr, t->type))
+			goto attach_failed;
 		break;
 	case TUNER_XC2028:
 	{
@@ -421,40 +409,34 @@
 			.i2c_addr  = t->i2c->addr,
 			.callback  = t->tuner_callback,
 		};
-		if (!xc2028_attach(&t->fe, &cfg)) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!xc2028_attach(&t->fe, &cfg))
+			goto attach_failed;
 		break;
 	}
 	case TUNER_TDA9887:
 		tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
 		break;
 	case TUNER_XC5000:
+	{
+		struct dvb_tuner_ops *xc_tuner_ops;
+
 		xc5000_cfg.i2c_address	  = t->i2c->addr;
 		xc5000_cfg.if_khz	  = 5380;
 		xc5000_cfg.priv           = c->adapter->algo_data;
 		xc5000_cfg.tuner_callback = t->tuner_callback;
-		if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
-		{
-		struct dvb_tuner_ops *xc_tuner_ops;
+		if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg))
+			goto attach_failed;
+
 		xc_tuner_ops = &t->fe.ops.tuner_ops;
-		if(xc_tuner_ops->init != NULL)
+		if (xc_tuner_ops->init)
 			xc_tuner_ops->init(&t->fe);
-		}
 		break;
+	}
 	default:
-		if (simple_tuner_attach(&t->fe, t->i2c->adapter,
-					t->i2c->addr, t->type) == NULL) {
-			t->type = TUNER_ABSENT;
-			t->mode_mask = T_UNINITIALIZED;
-			return;
-		}
+		if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
+					t->i2c->addr, t->type))
+			goto attach_failed;
+
 		break;
 	}
 
@@ -476,11 +458,27 @@
 	if (t->mode_mask == T_UNINITIALIZED)
 		t->mode_mask = new_mode_mask;
 
-	set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
+	/* xc2028/3028 and xc5000 requires a firmware to be set-up later
+	   trying to set a frequency here will just fail
+	   FIXME: better to move set_freq to the tuner code. This is needed
+	   on analog tuners for PLL to properly work
+	 */
+	if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
+		set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
+			    t->radio_freq : t->tv_freq);
+
 	tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
 		  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
 		  t->mode_mask);
 	tuner_i2c_address_check(t);
+	return;
+
+attach_failed:
+	tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
+	t->type = TUNER_ABSENT;
+	t->mode_mask = T_UNINITIALIZED;
+
+	return;
 }
 
 /*
@@ -495,14 +493,16 @@
 {
 	struct tuner *t = i2c_get_clientdata(c);
 
-	tuner_dbg("set addr for type %i\n", t->type);
-
 	if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
 		(t->mode_mask & tun_setup->mode_mask))) ||
 		(tun_setup->addr == c->addr)) {
 			set_type(c, tun_setup->type, tun_setup->mode_mask,
 				 tun_setup->config, tun_setup->tuner_callback);
-	}
+	} else
+		tuner_dbg("set addr discarded for type %i, mask %x. "
+			  "Asked to change tuner at addr 0x%02x, with mask %x\n",
+			  t->type, t->mode_mask,
+			  tun_setup->addr, tun_setup->mode_mask);
 }
 
 static inline int check_mode(struct tuner *t, char *cmd)
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index cc3db7d..9e9003c 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -432,7 +432,7 @@
 
 	type &= type_mask;
 
-	if (!type & SCODE)
+	if (!(type & SCODE))
 		type_mask = ~0;
 
 	/* Seek for exact match */
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index b1e9592..845be18 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -888,7 +888,7 @@
 {
 	int minor = iminor(inode);
 	struct vivi_dev *dev;
-	struct vivi_fh *fh;
+	struct vivi_fh *fh = NULL;
 	int i;
 	int retval = 0;