Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
index 2dc260b..068070f 100644
--- a/Documentation/dvb/avermedia.txt
+++ b/Documentation/dvb/avermedia.txt
@@ -150,7 +150,8 @@
 
    The frontend module sp887x.o, requires an external   firmware.
    Please use  the  command "get_dvb_firmware sp887x" to download
-   it. Then copy it to /usr/lib/hotplug/firmware.
+   it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/
+   (depending on configuration of firmware hotplug).
 
 Receiving DVB-T in Australia
 
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index be6eb4c..75c28a1 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -23,7 +23,7 @@
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
 		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
-		"or51211", "or51132_qam", "or51132_vsb");
+		"or51211", "or51132_qam", "or51132_vsb", "bluebird");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -34,7 +34,11 @@
     if ($cid eq $components[$i]) {
 	$outfile = eval($cid);
 	die $@ if $@;
-	print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n";
+	print STDERR <<EOF;
+Firmware $outfile extracted successfully.
+Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
+(depending on configuration of firmware hotplug).
+EOF
 	exit(0);
     }
 }
@@ -243,7 +247,7 @@
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
     checkstandard();
-    
+
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
     verify("$tmpdir/SkyNETU.sys", $hash);
@@ -308,6 +312,19 @@
     $fwfile;
 }
 
+sub bluebird {
+	my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+	my $outfile = "dvb-usb-bluebird-01.fw";
+	my $hash = "658397cb9eba9101af9031302671f49d";
+
+	checkstandard();
+
+	wgetfile($outfile, $url);
+	verify($outfile,$hash);
+
+	$outfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
diff --git a/Documentation/dvb/ttusb-dec.txt b/Documentation/dvb/ttusb-dec.txt
index 5c1e984..b2f271c 100644
--- a/Documentation/dvb/ttusb-dec.txt
+++ b/Documentation/dvb/ttusb-dec.txt
@@ -41,4 +41,5 @@
 For 2.6 kernels the firmware is loaded at the point that the driver module is
 loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
-Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware or
+/lib/firmware directory (depending on configuration of firmware hotplug).
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index 330246a..74fb085 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -141,3 +141,4 @@
 140 -> Osprey 440                                          [0070:ff07]
 141 -> Asound Skyeye PCTV
 142 -> Sabrent TV-FM (bttv version)
+143 -> Hauppauge ImpactVCB (bt878)                         [0070:13eb]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index a1017d1..34b6e59 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -16,7 +16,7 @@
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
  16 -> KWorld LTV883RF
  17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
- 18 -> Hauppauge Nova-T DVB-T                              [0070:9002]
+ 18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
  21 -> DViCO FusionHDTV DVB-T Plus                         [18ac:db10]
@@ -35,3 +35,11 @@
  34 -> ATI HDTV Wonder                                     [1002:a101]
  35 -> WinFast DTV1000-T                                   [107d:665f]
  36 -> AVerTV 303 (M126)                                   [1461:000a]
+ 37 -> Hauppauge Nova-S-Plus DVB-S                         [0070:9201,0070:9202]
+ 38 -> Hauppauge Nova-SE2 DVB-S                            [0070:9200]
+ 39 -> KWorld DVB-S 100                                    [17de:08b2]
+ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
+ 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
+ 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
+ 43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
+ 44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index efb708e..cb3a59b 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -56,7 +56,7 @@
  55 -> LifeView FlyDVB-T DUO                    [5168:0502,5168:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370,1421:1370]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0351,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
  60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
@@ -81,4 +81,5 @@
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
  82 -> MSI TV@Anywhere plus                     [1462:6231]
-
+ 83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
+ 84 -> LifeView FlyDVB Trio                     [5168:0319]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 9d6544e..0bf3d5b 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -40,7 +40,7 @@
 tuner=39 - LG NTSC (newer TAPC series)
 tuner=40 - HITACHI V7-J180AT
 tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC daul in
+tuner=42 - Philips 1236D ATSC/NTSC dual in
 tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
 tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
 tuner=45 - Microtune 4049 FM5
@@ -50,7 +50,7 @@
 tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
 tuner=50 - TCL 2002N
 tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
-tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
 tuner=54 - tda8290+75
 tuner=55 - TCL 2002MB
@@ -58,7 +58,7 @@
 tuner=57 - Philips FQ1236A MK4
 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
 tuner=59 - Ymec TVision TVF-5533MF
-tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+tuner=60 - Thomson DTT 761X (ATSC/NTSC)
 tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
 tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 09ec964..b614612 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -253,7 +253,10 @@
 
 	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
 		DEB_S(("initializing vbi...\n"));
-		result = saa7146_vbi_uops.open(dev,file);
+		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+			result = saa7146_vbi_uops.open(dev,file);
+		if (dev->ext_vv_data->vbi_fops.open)
+			dev->ext_vv_data->vbi_fops.open(inode, file);
 	} else {
 		DEB_S(("initializing video...\n"));
 		result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@
 		return -ERESTARTSYS;
 
 	if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		saa7146_vbi_uops.release(dev,file);
+		if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+			saa7146_vbi_uops.release(dev,file);
+		if (dev->ext_vv_data->vbi_fops.release)
+			dev->ext_vv_data->vbi_fops.release(inode, file);
 	} else {
 		saa7146_video_uops.release(dev,file);
 	}
@@ -332,6 +338,7 @@
 		BUG();
 		return 0;
 	}
+
 	return videobuf_mmap_mapper(q,vma);
 }
 
@@ -381,7 +388,10 @@
 		}
 	case V4L2_BUF_TYPE_VBI_CAPTURE: {
 //		DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
-		return saa7146_vbi_uops.read(file,data,count,ppos);
+		if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+			return saa7146_vbi_uops.read(file,data,count,ppos);
+		else
+			return -EINVAL;
 		}
 		break;
 	default:
@@ -390,12 +400,31 @@
 	}
 }
 
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7146_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return -EINVAL;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (fh->dev->ext_vv_data->vbi_fops.write)
+			return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+		else
+			return -EINVAL;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+}
+
 static struct file_operations video_fops =
 {
 	.owner		= THIS_MODULE,
 	.open		= fops_open,
 	.release	= fops_release,
 	.read		= fops_read,
+	.write		= fops_write,
 	.poll		= fops_poll,
 	.mmap		= fops_mmap,
 	.ioctl		= fops_ioctl,
@@ -467,7 +496,8 @@
 	memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
 
 	saa7146_video_uops.init(dev,vv);
-	saa7146_vbi_uops.init(dev,vv);
+	if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+		saa7146_vbi_uops.init(dev,vv);
 
 	dev->vv_data = vv;
 	dev->vv_callback = &vv_callback;
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index ec52dff..33bec8a 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -562,19 +562,26 @@
 
 	int b_depth = vv->ov_fmt->depth;
 	int b_bpl = vv->ov_fb.fmt.bytesperline;
-	u32 base = (u32)vv->ov_fb.base;
+	/* The unsigned long cast is to remove a 64-bit compile warning since
+	   it looks like a 64-bit address is cast to a 32-bit value, even
+	   though the base pointer is really a 32-bit physical address that
+	   goes into a 32-bit DMA register.
+	   FIXME: might not work on some 64-bit platforms, but see the FIXME
+	   in struct v4l2_framebuffer (videodev2.h) for that.
+	 */
+	u32 base = (u32)(unsigned long)vv->ov_fb.base;
 
 	struct	saa7146_video_dma vdma1;
 
 	/* calculate memory offsets for picture, look if we shall top-down-flip */
 	vdma1.pitch	= 2*b_bpl;
 	if ( 0 == vv->vflip ) {
-		vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+		vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
 		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
 		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
 	}
 	else {
-		vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+		vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
 		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
 		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
 	}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 063986e..468d3c9 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -500,9 +500,9 @@
 }
 
 struct saa7146_use_ops saa7146_vbi_uops = {
-	.init 		= vbi_init,
-	.open 		= vbi_open,
+	.init		= vbi_init,
+	.open		= vbi_open,
 	.release	= vbi_close,
 	.irq_done	= vbi_irq_done,
-	.read 		= vbi_read,
+	.read		= vbi_read,
 };
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 1d96102..7ebac79 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -151,8 +151,8 @@
 
 	if (V4L2_FIELD_ANY == field) {
 		field = (win->w.height > maxh/2)
-		        ? V4L2_FIELD_INTERLACED
-		        : V4L2_FIELD_TOP;
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_TOP;
 		}
 	switch (field) {
 	case V4L2_FIELD_TOP:
@@ -1114,10 +1114,6 @@
 		return 0;
 	}
 	case VIDIOC_OVERLAY:
-
-
-
-
 	{
 		int on = *(int *)arg;
 		int err = 0;
@@ -1359,7 +1355,6 @@
 	saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
 }
 
-
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
 	struct file *file = q->priv_data;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 21a9045..0b940e1 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -298,7 +298,7 @@
 }
 
 static int lgdt3303_pll_set(struct dvb_frontend* fe,
-		            struct dvb_frontend_parameters* params)
+			    struct dvb_frontend_parameters* params)
 {
 	struct flexcop_device *fc = fe->dvb->priv;
 	u8 buf[4];
@@ -485,12 +485,16 @@
 /* try to figure out the frontend, each card/box can have on of the following list */
 int flexcop_frontend_init(struct flexcop_device *fc)
 {
+	struct dvb_frontend_ops *ops;
+
 	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
 	if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-		fc->fe->ops->set_voltage = flexcop_set_voltage;
+		ops = fc->fe->ops;
 
-		fc->fe_sleep             = fc->fe->ops->sleep;
-		fc->fe->ops->sleep       = flexcop_sleep;
+		ops->set_voltage = flexcop_set_voltage;
+
+		fc->fe_sleep             = ops->sleep;
+		ops->sleep               = flexcop_sleep;
 
 		fc->dev_type          = FC_SKY;
 		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
@@ -522,15 +526,17 @@
 	} else
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
 	if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-		fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-		fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-		fc->fe->ops->set_tone               = flexcop_set_tone;
-		fc->fe->ops->set_voltage            = flexcop_set_voltage;
+		ops = fc->fe->ops;
 
-		fc->fe_sleep                        = fc->fe->ops->sleep;
-		fc->fe->ops->sleep                  = flexcop_sleep;
+		ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+		ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+		ops->set_tone               = flexcop_set_tone;
+		ops->set_voltage            = flexcop_set_voltage;
 
-		fc->dev_type                        = FC_SKY_OLD;
+		fc->fe_sleep                = ops->sleep;
+		ops->sleep                  = flexcop_sleep;
+
+		fc->dev_type                = FC_SKY_OLD;
 		info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
 	}
 
@@ -540,8 +546,9 @@
 	} else {
 		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
 			err("frontend registration failed!");
-			if (fc->fe->ops->release != NULL)
-				fc->fe->ops->release(fc->fe);
+			ops = fc->fe->ops;
+			if (ops->release != NULL)
+				ops->release(fc->fe);
 			fc->fe = NULL;
 			return -EINVAL;
 		}
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 23cc643..3153f95 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -39,11 +39,13 @@
 /* FlexCop IBI Registers */
 #if defined(__LITTLE_ENDIAN)
 	#include "flexcop_ibi_value_le.h"
-#elif defined(__BIG_ENDIAN)
+#else
+#if defined(__BIG_ENDIAN)
 	#include "flexcop_ibi_value_be.h"
 #else
 	#error no endian defined
 #endif
+#endif
 
 #define fc_data_Tag_ID_DVB  0x3e
 #define fc_data_Tag_ID_ATSC 0x3f
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 8977c7a..3a2ff1c 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1341,30 +1341,40 @@
 	return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend* fe,
+			    struct dvb_frontend_parameters* p,
+			    unsigned int mode_flags,
+			    int *delay,
+			    fe_status_t *status)
 {
 	struct dst_state *state = fe->demodulator_priv;
 
-	dst_set_freq(state, p->frequency);
-	dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+	if (p != NULL) {
+		dst_set_freq(state, p->frequency);
+		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
 
-	if (state->dst_type == DST_TYPE_IS_SAT) {
-		if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
-			dst_set_inversion(state, p->inversion);
-		dst_set_fec(state, p->u.qpsk.fec_inner);
-		dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
-		dst_set_polarization(state);
-		dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+				dst_set_inversion(state, p->inversion);
+			dst_set_fec(state, p->u.qpsk.fec_inner);
+			dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+			dst_set_polarization(state);
+			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
 
-	} else if (state->dst_type == DST_TYPE_IS_TERR)
-		dst_set_bandwidth(state, p->u.ofdm.bandwidth);
-	else if (state->dst_type == DST_TYPE_IS_CABLE) {
-		dst_set_fec(state, p->u.qam.fec_inner);
-		dst_set_symbolrate(state, p->u.qam.symbol_rate);
-		dst_set_modulation(state, p->u.qam.modulation);
+		} else if (state->dst_type == DST_TYPE_IS_TERR)
+			dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+		else if (state->dst_type == DST_TYPE_IS_CABLE) {
+			dst_set_fec(state, p->u.qam.fec_inner);
+			dst_set_symbolrate(state, p->u.qam.symbol_rate);
+			dst_set_modulation(state, p->u.qam.modulation);
+		}
+		dst_write_tuna(fe);
 	}
-	dst_write_tuna(fe);
 
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		dst_read_status(fe, status);
+
+	*delay = HZ/10;
 	return 0;
 }
 
@@ -1445,7 +1455,7 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.set_frontend = dst_set_frontend,
+	.tune = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
@@ -1469,7 +1479,7 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.set_frontend = dst_set_frontend,
+	.tune = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
@@ -1496,7 +1506,7 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.set_frontend = dst_set_frontend,
+	.tune = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 2239651..c650b4b 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -283,16 +283,17 @@
 		hw_buffer->msg[4] = 0x03;
 		hw_buffer->msg[5] = length & 0xff;
 		hw_buffer->msg[6] = 0x00;
+
 		/*
 		 *	Need to compute length for EN50221 section 8.3.2, for the time being
 		 *	assuming 8.3.2 is not applicable
 		 */
 		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
 	}
+
 	return 0;
 }
 
-
 static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
 {
 	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 77977e9..01b4e0a 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -600,7 +600,6 @@
 	struct dst_state* state = NULL;
 
 	switch(type) {
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
 	case BTTV_BOARD_DVICO_DVBT_LITE:
 		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
 		if (card->fe != NULL) {
@@ -608,22 +607,15 @@
 			card->fe->ops->info.frequency_max = 862000000;
 		}
 		break;
-#endif
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
 	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
 		lgdt330x_reset(card);
 		card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
 		if (card->fe != NULL)
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
 		break;
-#endif
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-	case BTTV_BOARD_TWINHAN_VP3021:
-#else
 	case BTTV_BOARD_NEBULA_DIGITV:
-#endif
 		/*
 		 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
 		 * this would be a cleaner solution than trying each frontend in turn.
@@ -812,9 +804,7 @@
 		card->irq_err_ignore = 0;
 		break;
 
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
 	case BTTV_BOARD_DVICO_DVBT_LITE:
-#endif
 		card->gpio_mode = 0x0400C060;
 		card->op_sync_orin = 0;
 		card->irq_err_ignore = 0;
@@ -823,19 +813,13 @@
 		 * DA_APP(parallel) */
 		break;
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
 	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-#endif
 		card->gpio_mode = 0x0400c060;
 		card->op_sync_orin = BT878_RISC_SYNC_MASK;
 		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
 		break;
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-	case BTTV_BOARD_TWINHAN_VP3021:
-#else
 	case BTTV_BOARD_NEBULA_DIGITV:
-#endif
 	case BTTV_BOARD_AVDVBT_761:
 		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
 		card->op_sync_orin = 0;
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 7cf4c4a..6018fcd 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -21,35 +21,35 @@
 config DVB_CINERGYT2_STREAM_URB_COUNT
 	int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
 	depends on DVB_CINERGYT2_TUNING
-        default "32"
+	default "32"
 	help
 	  USB Request Blocks for Highspeed Stream transfers are scheduled in
 	  a queue for the Host Controller.
 
 	  Usually the default value is a safe choice.
 
-	  You may increase this number if you are using this device in a 
-	  Server Environment with many high-traffic USB Highspeed devices 
+	  You may increase this number if you are using this device in a
+	  Server Environment with many high-traffic USB Highspeed devices
 	  sharing the same USB bus.
 
 
 config DVB_CINERGYT2_STREAM_BUF_SIZE
 	int "Size of URB Stream Buffers for Highspeed Transfers"
 	depends on DVB_CINERGYT2_TUNING
-        default "512"
+	default "512"
 	help
 	  Should be a multiple of native buffer size of 512 bytes.
 	  Default value is a safe choice.
 
-	  You may increase this number if you are using this device in a 
-	  Server Environment with many high-traffic USB Highspeed devices 
+	  You may increase this number if you are using this device in a
+	  Server Environment with many high-traffic USB Highspeed devices
 	  sharing the same USB bus.
 
 
 config DVB_CINERGYT2_QUERY_INTERVAL
 	int "Status update interval [milliseconds]"
 	depends on DVB_CINERGYT2_TUNING
-        default "250"
+	default "250"
 	help
 	  This is the interval for status readouts from the demodulator.
 	  You may try lower values if you need more responsive signal quality
@@ -64,9 +64,9 @@
 config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
 	bool "Register the onboard IR Remote Control Receiver as Input Device"
 	depends on DVB_CINERGYT2_TUNING
-        default "yes"
+	default "yes"
 	help
-	  Enable this option if you want to use the onboard Infrared Remote 
+	  Enable this option if you want to use the onboard Infrared Remote
 	  Control Receiver as Linux-Input device.
 
 	  Right now only the keycode table for the default Remote Control
@@ -77,7 +77,7 @@
 config DVB_CINERGYT2_RC_QUERY_INTERVAL
 	int "Infrared Remote Controller update interval [milliseconds]"
 	depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-        default "50"
+	default "50"
 	help
 	  If you have a very fast-repeating remote control you can try lower
 	  values, for normal consumer receivers the default value should be
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 1d69bf0..c4b4c5b 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -131,6 +131,8 @@
 
 	wait_queue_head_t poll_wq;
 	int pending_fe_events;
+	int disconnect_pending;
+	atomic_t inuse;
 
 	void *streambuf;
 	dma_addr_t streambuf_dmahandle;
@@ -343,7 +345,7 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (cinergyt2->streaming == 0)
@@ -359,7 +361,7 @@
 	struct dvb_demux *demux = dvbdmxfeed->demux;
 	struct cinergyt2 *cinergyt2 = demux->priv;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (--cinergyt2->streaming == 0)
@@ -479,23 +481,37 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	int err;
+	int err = -ERESTARTSYS;
 
-	if ((err = dvb_generic_open(inode, file)))
-		return err;
-
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
+	if ((err = dvb_generic_open(inode, file))) {
+		up(&cinergyt2->sem);
+		return err;
+	}
+
+
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 		cinergyt2_sleep(cinergyt2, 0);
 		schedule_delayed_work(&cinergyt2->query_work, HZ/2);
 	}
 
+	atomic_inc(&cinergyt2->inuse);
+
 	up(&cinergyt2->sem);
 	return 0;
 }
 
+static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
+{
+	dvb_unregister_device(cinergyt2->fedev);
+	dvb_unregister_adapter(&cinergyt2->adapter);
+
+	cinergyt2_free_stream_urbs(cinergyt2);
+	kfree(cinergyt2);
+}
+
 static int cinergyt2_release (struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
@@ -504,7 +520,7 @@
 	if (down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+	if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
 		cancel_delayed_work(&cinergyt2->query_work);
 		flush_scheduled_work();
 		cinergyt2_sleep(cinergyt2, 1);
@@ -512,6 +528,11 @@
 
 	up(&cinergyt2->sem);
 
+	if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
+		warn("delayed unregister in release");
+		cinergyt2_unregister(cinergyt2);
+	}
+
 	return dvb_generic_release(inode, file);
 }
 
@@ -519,7 +540,14 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
+
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+		return -ERESTARTSYS;
+
 	poll_wait(file, &cinergyt2->poll_wq, wait);
+
+	up(&cinergyt2->sem);
+
 	return (POLLIN | POLLRDNORM | POLLPRI);
 }
 
@@ -564,10 +592,15 @@
 				(__u16 __user *) arg);
 
 	case FE_READ_UNCORRECTED_BLOCKS:
-		/* UNC are already converted to host byte order... */
-		return put_user(stat->uncorrected_block_count,
-				(__u32 __user *) arg);
+	{
+		uint32_t unc_count;
 
+		unc_count = stat->uncorrected_block_count;
+		stat->uncorrected_block_count = 0;
+
+		/* UNC are already converted to host byte order... */
+		return put_user(unc_count,(__u32 __user *) arg);
+	}
 	case FE_SET_FRONTEND:
 	{
 		struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -580,7 +613,7 @@
 		if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
 			return -EFAULT;
 
-		if (down_interruptible(&cinergyt2->sem))
+		if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 			return -ERESTARTSYS;
 
 		param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -691,7 +724,7 @@
 	struct cinergyt2_rc_event rc_events[12];
 	int n, len, i;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return;
 
 	len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -786,7 +819,6 @@
 static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
 {
 	cancel_delayed_work(&cinergyt2->rc_query_work);
-	flush_scheduled_work();
 	input_unregister_device(cinergyt2->rc_input_dev);
 }
 
@@ -817,7 +849,7 @@
 	uint8_t lock_bits;
 	uint32_t unc;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return;
 
 	unc = s->uncorrected_block_count;
@@ -917,28 +949,25 @@
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-	if (down_interruptible(&cinergyt2->sem))
-		return;
+	flush_scheduled_work();
 
 	cinergyt2_unregister_rc(cinergyt2);
 
-	cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-	dvb_net_release(&cinergyt2->dvbnet);
-	dvb_dmxdev_release(&cinergyt2->dmxdev);
-	dvb_dmx_release(&cinergyt2->demux);
-	dvb_unregister_device(cinergyt2->fedev);
-	dvb_unregister_adapter(&cinergyt2->adapter);
+	cancel_delayed_work(&cinergyt2->query_work);
+	wake_up_interruptible(&cinergyt2->poll_wq);
 
-	cinergyt2_free_stream_urbs(cinergyt2);
-	up(&cinergyt2->sem);
-	kfree(cinergyt2);
+	cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
+	cinergyt2->disconnect_pending = 1;
+
+	if (!atomic_read(&cinergyt2->inuse))
+		cinergyt2_unregister(cinergyt2);
 }
 
 static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (state.event > PM_EVENT_ON) {
@@ -961,7 +990,7 @@
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 	struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-	if (down_interruptible(&cinergyt2->sem))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	if (!cinergyt2->sleeping) {
@@ -1014,4 +1043,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
-
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
index a9a7b34..12ee912 100644
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ b/drivers/media/dvb/dvb-core/Kconfig
@@ -5,7 +5,7 @@
 	help
 	  DVB core utility functions for device handling, software fallbacks etc.
 	  Say Y when you have a DVB card and want to use it. Say Y if your want
-	  to build your drivers outside the kernel, but need the DVB core. All 
+	  to build your drivers outside the kernel, but need the DVB core. All
 	  in-kernel drivers will select this automatically if needed.
 	  If unsure say N.
 
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
index c6baac2..7adb50c 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb/dvb-core/Makefile
@@ -3,7 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-	        dvb_ca_en50221.o dvb_frontend.o \
+		dvb_ca_en50221.o dvb_frontend.o \
 		dvb_net.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 5956c35..4bb779a 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1745,9 +1745,7 @@
 
 	for (i = 0; i < ca->slot_count; i++) {
 		dvb_ca_en50221_slot_shutdown(ca, i);
-		if (ca->slot_info[i].rx_buffer.data != NULL) {
-			vfree(ca->slot_info[i].rx_buffer.data);
-		}
+		vfree(ca->slot_info[i].rx_buffer.data);
 	}
 	kfree(ca->slot_info);
 	dvb_unregister_device(ca->dvbdev);
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c
index c49fd0b..772003f 100644
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ b/drivers/media/dvb/dvb-core/dvb_filter.c
@@ -409,16 +409,16 @@
 
 	if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
 		if (buf[7] & PTS_ONLY)
-		        pts = buf+9;
+			pts = buf+9;
 		else pts = NULL;
 		buf = inbuf + 9 + inbuf[8];
 	} else {        /* mpeg1 */
 		for (buf = inbuf + 6; *buf == 0xff; buf++)
-		        if (buf == inbuf + 6 + 16) {
-		                break;
-		        }
+			if (buf == inbuf + 6 + 16) {
+				break;
+			}
 		if ((*buf & 0xc0) == 0x40)
-		        buf += 2;
+			buf += 2;
 		skip = mpeg1_skip_table [*buf >> 4];
 		if (skip == 5 || skip == 10) pts = buf;
 		else pts = NULL;
@@ -529,9 +529,9 @@
 	pic->picture_header = 0;
 	pic->sequence_header_data
 		= ( INIT_HORIZONTAL_SIZE << 20 )
-		        | ( INIT_VERTICAL_SIZE << 8 )
-		        | ( INIT_ASPECT_RATIO << 4 )
-		        | ( INIT_FRAME_RATE );
+			| ( INIT_VERTICAL_SIZE << 8 )
+			| ( INIT_ASPECT_RATIO << 4 )
+			| ( INIT_FRAME_RATE );
 	pic->mpeg1_flag = 0;
 	pic->vinfo.horizontal_size
 		= INIT_DISP_HORIZONTAL_SIZE;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 95ea509..4a08c4a 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -92,6 +92,7 @@
 
 struct dvb_frontend_private {
 
+	/* thread/frontend values */
 	struct dvb_device *dvbdev;
 	struct dvb_frontend_parameters parameters;
 	struct dvb_fe_events events;
@@ -100,20 +101,25 @@
 	wait_queue_head_t wait_queue;
 	pid_t thread_pid;
 	unsigned long release_jiffies;
-	int state;
-	int bending;
-	int lnb_drift;
-	int inversion;
-	int auto_step;
-	int auto_sub_step;
-	int started_auto_step;
-	int min_delay;
-	int max_drift;
-	int step_size;
-	int exit;
-	int wakeup;
+	unsigned int exit;
+	unsigned int wakeup;
 	fe_status_t status;
-	fe_sec_tone_mode_t tone;
+	unsigned long tune_mode_flags;
+	unsigned int delay;
+
+	/* swzigzag values */
+	unsigned int state;
+	unsigned int bending;
+	int lnb_drift;
+	unsigned int inversion;
+	unsigned int auto_step;
+	unsigned int auto_sub_step;
+	unsigned int started_auto_step;
+	unsigned int min_delay;
+	unsigned int max_drift;
+	unsigned int step_size;
+	int quality;
+	unsigned int check_wrapped;
 };
 
 
@@ -208,21 +214,21 @@
 		fe->ops->init(fe);
 }
 
-static void update_delay(int *quality, int *delay, int min_delay, int locked)
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
 {
-	    int q2;
+	int q2;
 
-	    dprintk ("%s\n", __FUNCTION__);
+	dprintk ("%s\n", __FUNCTION__);
 
-	    if (locked)
-		      (*quality) = (*quality * 220 + 36*256) / 256;
-	    else
-		      (*quality) = (*quality * 220 + 0) / 256;
+	if (locked)
+		(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+	else
+		(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
 
-	    q2 = *quality - 128;
-	    q2 *= q2;
+	q2 = fepriv->quality - 128;
+	q2 *= q2;
 
-	    *delay = min_delay + q2 * HZ / (128*128);
+	fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
 }
 
 /**
@@ -232,7 +238,7 @@
  * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
  * @returns Number of complete iterations that have been performed.
  */
-static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
 {
 	int autoinversion;
 	int ready = 0;
@@ -321,6 +327,129 @@
 	return 0;
 }
 
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+	fe_status_t s;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+	/* if we've got no parameters, just keep idling */
+	if (fepriv->state & FESTATE_IDLE) {
+		fepriv->delay = 3*HZ;
+		fepriv->quality = 0;
+		return;
+	}
+
+	/* in SCAN mode, we just set the frontend when asked and leave it alone */
+	if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
+		if (fepriv->state & FESTATE_RETUNE) {
+			if (fe->ops->set_frontend)
+				fe->ops->set_frontend(fe, &fepriv->parameters);
+			fepriv->state = FESTATE_TUNED;
+		}
+		fepriv->delay = 3*HZ;
+		fepriv->quality = 0;
+		return;
+	}
+
+	/* get the frontend status */
+	if (fepriv->state & FESTATE_RETUNE) {
+		s = 0;
+	} else {
+		if (fe->ops->read_status)
+			fe->ops->read_status(fe, &s);
+		if (s != fepriv->status) {
+			dvb_frontend_add_event(fe, s);
+			fepriv->status = s;
+		}
+	}
+
+	/* if we're not tuned, and we have a lock, move to the TUNED state */
+	if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		fepriv->state = FESTATE_TUNED;
+
+		/* if we're tuned, then we have determined the correct inversion */
+		if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+		    (fepriv->parameters.inversion == INVERSION_AUTO)) {
+			fepriv->parameters.inversion = fepriv->inversion;
+		}
+		return;
+	}
+
+	/* if we are tuned already, check we're still locked */
+	if (fepriv->state & FESTATE_TUNED) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+		/* we're tuned, and the lock is still good... */
+		if (s & FE_HAS_LOCK) {
+			return;
+		} else { /* if we _WERE_ tuned, but now don't have a lock */
+			fepriv->state = FESTATE_ZIGZAG_FAST;
+			fepriv->started_auto_step = fepriv->auto_step;
+			fepriv->check_wrapped = 0;
+		}
+	}
+
+	/* don't actually do anything if we're in the LOSTLOCK state,
+	 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+	if ((fepriv->state & FESTATE_LOSTLOCK) &&
+	    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		return;
+	}
+
+	/* don't do anything if we're in the DISEQC state, since this
+	 * might be someone with a motorized dish controlled by DISEQC.
+	 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
+	if (fepriv->state & FESTATE_DISEQC) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+		return;
+	}
+
+	/* if we're in the RETUNE state, set everything up for a brand
+	 * new scan, keeping the current inversion setting, as the next
+	 * tune is _very_ likely to require the same */
+	if (fepriv->state & FESTATE_RETUNE) {
+		fepriv->lnb_drift = 0;
+		fepriv->auto_step = 0;
+		fepriv->auto_sub_step = 0;
+		fepriv->started_auto_step = 0;
+		fepriv->check_wrapped = 0;
+	}
+
+	/* fast zigzag. */
+	if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+		fepriv->delay = fepriv->min_delay;
+
+		/* peform a tune */
+		if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
+			/* OK, if we've run out of trials at the fast speed.
+			 * Drop back to slow for the _next_ attempt */
+			fepriv->state = FESTATE_SEARCHING_SLOW;
+			fepriv->started_auto_step = fepriv->auto_step;
+			return;
+		}
+		fepriv->check_wrapped = 1;
+
+		/* if we've just retuned, enter the ZIGZAG_FAST state.
+		 * This ensures we cannot return from an
+		 * FE_SET_FRONTEND ioctl before the first frontend tune
+		 * occurs */
+		if (fepriv->state & FESTATE_RETUNE) {
+			fepriv->state = FESTATE_TUNING_FAST;
+		}
+	}
+
+	/* slow zigzag */
+	if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+		/* Note: don't bother checking for wrapping; we stay in this
+		 * state until we get a lock */
+		dvb_frontend_swzigzag_autotune(fe, 0);
+	}
+}
+
 static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -330,7 +459,7 @@
 
 	if (fepriv->dvbdev->writers == 1)
 		if (time_after(jiffies, fepriv->release_jiffies +
-					dvb_shutdown_timeout * HZ))
+				  dvb_shutdown_timeout * HZ))
 			return 1;
 
 	return 0;
@@ -355,18 +484,14 @@
 	wake_up_interruptible(&fepriv->wait_queue);
 }
 
-/*
- * FIXME: use linux/kthread.h
- */
 static int dvb_frontend_thread(void *data)
 {
 	struct dvb_frontend *fe = data;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	unsigned long timeout;
 	char name [15];
-	int quality = 0, delay = 3*HZ;
 	fe_status_t s;
-	int check_wrapped = 0;
+	struct dvb_frontend_parameters *params;
 
 	dprintk("%s\n", __FUNCTION__);
 
@@ -377,6 +502,9 @@
 	sigfillset(&current->blocked);
 	unlock_kernel();
 
+	fepriv->check_wrapped = 0;
+	fepriv->quality = 0;
+	fepriv->delay = 3*HZ;
 	fepriv->status = 0;
 	dvb_frontend_init(fe);
 	fepriv->wakeup = 0;
@@ -386,7 +514,7 @@
 
 		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
 							   dvb_frontend_should_wakeup(fe),
-							   delay);
+							   fepriv->delay);
 		if (0 != dvb_frontend_is_exiting(fe)) {
 			/* got signal or quitting */
 			break;
@@ -397,108 +525,22 @@
 		if (down_interruptible(&fepriv->sem))
 			break;
 
-		/* if we've got no parameters, just keep idling */
-		if (fepriv->state & FESTATE_IDLE) {
-			delay = 3*HZ;
-			quality = 0;
-			continue;
-		}
+		/* do an iteration of the tuning loop */
+		if (fe->ops->tune) {
+			/* have we been asked to retune? */
+			params = NULL;
+			if (fepriv->state & FESTATE_RETUNE) {
+				params = &fepriv->parameters;
+				fepriv->state = FESTATE_TUNED;
+			}
 
-		/* get the frontend status */
-		if (fepriv->state & FESTATE_RETUNE) {
-			s = 0;
-		} else {
-			if (fe->ops->read_status)
-				fe->ops->read_status(fe, &s);
+			fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
 			if (s != fepriv->status) {
 				dvb_frontend_add_event(fe, s);
 				fepriv->status = s;
 			}
-		}
-		/* if we're not tuned, and we have a lock, move to the TUNED state */
-		if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
-			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-			fepriv->state = FESTATE_TUNED;
-
-			/* if we're tuned, then we have determined the correct inversion */
-			if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
-			    (fepriv->parameters.inversion == INVERSION_AUTO)) {
-				fepriv->parameters.inversion = fepriv->inversion;
-			}
-			continue;
-		}
-
-		/* if we are tuned already, check we're still locked */
-		if (fepriv->state & FESTATE_TUNED) {
-			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-			/* we're tuned, and the lock is still good... */
-			if (s & FE_HAS_LOCK)
-				continue;
-			else { /* if we _WERE_ tuned, but now don't have a lock */
-				fepriv->state = FESTATE_ZIGZAG_FAST;
-				fepriv->started_auto_step = fepriv->auto_step;
-				check_wrapped = 0;
-			}
-		}
-
-		/* don't actually do anything if we're in the LOSTLOCK state,
-		 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
-		if ((fepriv->state & FESTATE_LOSTLOCK) &&
-		    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
-			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-			continue;
-		}
-
-		/* don't do anything if we're in the DISEQC state, since this
-		 * might be someone with a motorized dish controlled by DISEQC.
-		 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
-		if (fepriv->state & FESTATE_DISEQC) {
-			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-			continue;
-		}
-
-		/* if we're in the RETUNE state, set everything up for a brand
-		 * new scan, keeping the current inversion setting, as the next
-		 * tune is _very_ likely to require the same */
-		if (fepriv->state & FESTATE_RETUNE) {
-			fepriv->lnb_drift = 0;
-			fepriv->auto_step = 0;
-			fepriv->auto_sub_step = 0;
-			fepriv->started_auto_step = 0;
-			check_wrapped = 0;
-		}
-
-		/* fast zigzag. */
-		if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
-			delay = fepriv->min_delay;
-
-			/* peform a tune */
-			if (dvb_frontend_autotune(fe, check_wrapped)) {
-				/* OK, if we've run out of trials at the fast speed.
-				 * Drop back to slow for the _next_ attempt */
-				fepriv->state = FESTATE_SEARCHING_SLOW;
-				fepriv->started_auto_step = fepriv->auto_step;
-				continue;
-			}
-			check_wrapped = 1;
-
-			/* if we've just retuned, enter the ZIGZAG_FAST state.
-			 * This ensures we cannot return from an
-			 * FE_SET_FRONTEND ioctl before the first frontend tune
-			 * occurs */
-			if (fepriv->state & FESTATE_RETUNE) {
-				fepriv->state = FESTATE_TUNING_FAST;
-			}
-		}
-
-		/* slow zigzag */
-		if (fepriv->state & FESTATE_SEARCHING_SLOW) {
-			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-			/* Note: don't bother checking for wrapping; we stay in this
-			 * state until we get a lock */
-			dvb_frontend_autotune(fe, 0);
+		} else {
+			dvb_frontend_swzigzag(fe);
 		}
 	}
 
@@ -733,7 +775,6 @@
 			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
-			fepriv->tone = (fe_sec_tone_mode_t) parg;
 		}
 		break;
 
@@ -747,7 +788,7 @@
 
 	case FE_DISHNETWORK_SEND_LEGACY_CMD:
 		if (fe->ops->dishnetwork_send_legacy_command) {
-			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
+			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		} else if (fe->ops->set_voltage) {
@@ -767,13 +808,13 @@
 			 * initialization, so parg is 8 bits and does not
 			 * include the initialization or start bit
 			 */
-			unsigned int cmd = ((unsigned int) parg) << 1;
+			unsigned long cmd = ((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%04x\n", __FUNCTION__, cmd);
+				printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
 			do_gettimeofday(&nexttime);
 			if (dvb_frontend_debug)
 				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -814,7 +855,7 @@
 
 	case FE_ENABLE_HIGH_LNB_VOLTAGE:
 		if (fe->ops->enable_high_lnb_voltage)
-			err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
+			err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
 		break;
 
 	case FE_SET_FRONTEND: {
@@ -891,6 +932,10 @@
 			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
 		}
 		break;
+
+	case FE_SET_FRONTEND_TUNE_MODE:
+		fepriv->tune_mode_flags = (unsigned long) parg;
+		break;
 	};
 
 	up (&fepriv->sem);
@@ -932,6 +977,9 @@
 
 		/*  empty event queue */
 		fepriv->events.eventr = fepriv->events.eventw = 0;
+
+		/* normal tune mode when opened R/W */
+		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
 	}
 
 	return ret;
@@ -990,7 +1038,6 @@
 	init_MUTEX (&fepriv->events.sem);
 	fe->dvb = dvb;
 	fepriv->inversion = INVERSION_OFF;
-	fepriv->tone = SEC_TONE_OFF;
 
 	printk ("DVB: registering frontend %i (%s)...\n",
 		fe->dvb->num,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 1e0840d..70a6d14 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -58,10 +58,19 @@
 	int (*init)(struct dvb_frontend* fe);
 	int (*sleep)(struct dvb_frontend* fe);
 
+	/* if this is set, it overrides the default swzigzag */
+	int (*tune)(struct dvb_frontend* fe,
+		    struct dvb_frontend_parameters* params,
+		    unsigned int mode_flags,
+		    int *delay,
+		    fe_status_t *status);
+
+	/* these two are only used for the swzigzag code */
 	int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-	int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 	int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
 
+	int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
 	int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
 	int (*read_ber)(struct dvb_frontend* fe, u32* ber);
 	int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
@@ -74,8 +83,9 @@
 	int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
 	int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
 	int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
-	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+	int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
 };
 
 #define MAX_EVENT 8
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 86bba81..6711eb6 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1222,7 +1222,7 @@
 	return if_num;
 }
 
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
 {
 	struct net_device *net = dvbnet->device[num];
 	struct dvb_net_priv *priv;
@@ -1296,9 +1296,9 @@
 
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if ((unsigned int) parg >= DVB_NET_DEVICES_MAX)
+		if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
 			return -EINVAL;
-		ret = dvb_net_remove_if(dvbnet, (unsigned int) parg);
+		ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
 		if (!ret)
 			module_put(dvbdev->adapter->module);
 		return ret;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 283c6e9..77ad241 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -112,10 +112,10 @@
 	split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
 	if (split > 0) {
 		if (!usermem)
-		        memcpy(buf, rbuf->data+rbuf->pread, split);
+			memcpy(buf, rbuf->data+rbuf->pread, split);
 		else
-		        if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-		                return -EFAULT;
+			if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+				return -EFAULT;
 		buf += split;
 		todo -= split;
 		rbuf->pread = 0;
@@ -124,7 +124,7 @@
 		memcpy(buf, rbuf->data+rbuf->pread, todo);
 	else
 		if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-		        return -EFAULT;
+			return -EFAULT;
 
 	rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 
@@ -167,7 +167,7 @@
 }
 
 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-		                int offset, u8* buf, size_t len, int usermem)
+				int offset, u8* buf, size_t len, int usermem)
 {
 	size_t todo;
 	size_t split;
@@ -183,10 +183,10 @@
 	split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
 	if (split > 0) {
 		if (!usermem)
-		        memcpy(buf, rbuf->data+idx, split);
+			memcpy(buf, rbuf->data+idx, split);
 		else
-		        if (copy_to_user(buf, rbuf->data+idx, split))
-		                return -EFAULT;
+			if (copy_to_user(buf, rbuf->data+idx, split))
+				return -EFAULT;
 		buf += split;
 		todo -= split;
 		idx = 0;
@@ -195,7 +195,7 @@
 		memcpy(buf, rbuf->data+idx, todo);
 	else
 		if (copy_to_user(buf, rbuf->data+idx, todo))
-		        return -EFAULT;
+			return -EFAULT;
 
 	return len;
 }
@@ -209,12 +209,12 @@
 	// clean up disposed packets
 	while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
 		if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
-		        pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
-		        pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
-		        DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+			pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+			pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+			DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
 		} else {
-		        // first packet is not disposed, so we stop cleaning now
-		        break;
+			// first packet is not disposed, so we stop cleaning now
+			break;
 		}
 	}
 }
@@ -242,8 +242,8 @@
 		curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
 
 		if (curpktstatus == PKT_READY) {
-		        *pktlen = curpktlen;
-		        return idx;
+			*pktlen = curpktlen;
+			return idx;
 		}
 
 		consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index fa476f6..6d25609 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -106,7 +106,7 @@
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
-		                   size_t len, int usermem);
+				   size_t len, int usermem);
 
 
 /* write routines & macros */
@@ -121,7 +121,7 @@
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
-		                    size_t len);
+				    size_t len);
 
 
 /**
@@ -133,7 +133,7 @@
  * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
  */
 extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
-		                        size_t len);
+					size_t len);
 
 /**
  * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
@@ -149,7 +149,7 @@
  * returns Number of bytes read, or -EFAULT.
  */
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-		                       int offset, u8* buf, size_t len, int usermem);
+				       int offset, u8* buf, size_t len, int usermem);
 
 /**
  * Dispose of a packet in the ring buffer.
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a4aee86..06b696e 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -92,10 +92,10 @@
 		old_fops = file->f_op;
 		file->f_op = fops_get(dvbdev->fops);
 		if(file->f_op->open)
-		        err = file->f_op->open(inode,file);
+			err = file->f_op->open(inode,file);
 		if (err) {
-		        fops_put(file->f_op);
-		        file->f_op = fops_get(old_fops);
+			fops_put(file->f_op);
+			file->f_op = fops_get(old_fops);
 		}
 		fops_put(old_fops);
 		return err;
@@ -356,18 +356,18 @@
 	case _IOC_WRITE:
 	case (_IOC_WRITE | _IOC_READ):
 		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-		        parg = sbuf;
+			parg = sbuf;
 		} else {
-		        /* too big to allocate from stack */
-		        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-		        if (NULL == mbuf)
-		                return -ENOMEM;
-		        parg = mbuf;
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
 		}
 
 		err = -EFAULT;
 		if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-		        goto out;
+			goto out;
 		break;
 	}
 
@@ -384,7 +384,7 @@
 	case _IOC_READ:
 	case (_IOC_WRITE | _IOC_READ):
 		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-		        err = -EFAULT;
+			err = -EFAULT;
 		break;
 	}
 
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 0cc6e4a..74ed585 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -97,7 +97,7 @@
 generic_usercopy()  someday... */
 
 extern int dvb_usercopy(struct inode *inode, struct file *file,
-		            unsigned int cmd, unsigned long arg,
+			    unsigned int cmd, unsigned long arg,
 			    int (*func)(struct inode *inode, struct file *file,
 			    unsigned int cmd, void *arg));
 
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 54e2b29..90a69d3 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -37,16 +37,16 @@
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
 
 	  Devices supported by this driver:
-	    TwinhanDTV USB-Ter (VP7041)
-	    TwinhanDTV Magic Box (VP7041e)
-	    KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
-	    Hama DVB-T USB1.1-Box
-	    DiBcom USB1.1 reference devices (non-public)
-	    Ultima Electronic/Artec T1 USB TVBOX
-	    Compro Videomate DVB-U2000 - DVB-T USB
-	    Grandtec DVB-T USB
-	    Avermedia AverTV DVBT USB1.1
 	    Artec T1 USB1.1 boxes
+	    Avermedia AverTV DVBT USB1.1
+	    Compro Videomate DVB-U2000 - DVB-T USB
+	    DiBcom USB1.1 reference devices (non-public)
+	    Grandtec DVB-T USB
+	    Hama DVB-T USB1.1-Box
+	    KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+	    TwinhanDTV Magic Box (VP7041e)
+	    TwinhanDTV USB-Ter (VP7041)
+	    Ultima Electronic/Artec T1 USB TVBOX
 
 	  The VP7041 seems to be identical to "CTS Portable" (Chinese
 	  Television System).
@@ -54,6 +54,12 @@
 	  Say Y if you own such a device and want to use it. You should build it as
 	  a module.
 
+config DVB_USB_DIBUSB_MB_FAULTY
+	bool "Support faulty USB IDs"
+	depends on DVB_USB_DIBUSB_MB
+	help
+	  Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
 config DVB_USB_DIBUSB_MC
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
 	depends on DVB_USB
@@ -63,8 +69,8 @@
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
 
 	  Devices supported by this driver:
-	    DiBcom USB2.0 reference devices (non-public)
 	    Artec T1 USB2.0 boxes
+	    DiBcom USB2.0 reference devices (non-public)
 
 	  Say Y if you own such a device and want to use it. You should build it as
 	  a module.
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index d05fab0..358ed15 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -11,10 +11,11 @@
  * design, so it can be reused for the "analogue-only" device (if it will
  * appear at all).
  *
- * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
- * part
+ * TODO: Use the cx25840-driver for the analogue part
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
  *	This program is free software; you can redistribute it and/or modify it
  *	under the terms of the GNU General Public License as published by the Free
@@ -25,6 +26,9 @@
 #include "cxusb.h"
 
 #include "cx22702.h"
+#include "lgdt330x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -156,6 +160,99 @@
 	return 0;
 }
 
+static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[4];
+	int i;
+
+	cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[2] &&
+		    keymap[i].data == ircode[3]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+	{ 0xfe, 0x02, KEY_TV },
+	{ 0xfe, 0x0e, KEY_MP3 },
+	{ 0xfe, 0x1a, KEY_DVD },
+	{ 0xfe, 0x1e, KEY_FAVORITES },
+	{ 0xfe, 0x16, KEY_SETUP },
+	{ 0xfe, 0x46, KEY_POWER2 },
+	{ 0xfe, 0x0a, KEY_EPG },
+	{ 0xfe, 0x49, KEY_BACK },
+	{ 0xfe, 0x4d, KEY_MENU },
+	{ 0xfe, 0x51, KEY_UP },
+	{ 0xfe, 0x5b, KEY_LEFT },
+	{ 0xfe, 0x5f, KEY_RIGHT },
+	{ 0xfe, 0x53, KEY_DOWN },
+	{ 0xfe, 0x5e, KEY_OK },
+	{ 0xfe, 0x59, KEY_INFO },
+	{ 0xfe, 0x55, KEY_TAB },
+	{ 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
+	{ 0xfe, 0x12, KEY_NEXTSONG },	/* Skip */
+	{ 0xfe, 0x42, KEY_ENTER	 },	/* Windows/Start */
+	{ 0xfe, 0x15, KEY_VOLUMEUP },
+	{ 0xfe, 0x05, KEY_VOLUMEDOWN },
+	{ 0xfe, 0x11, KEY_CHANNELUP },
+	{ 0xfe, 0x09, KEY_CHANNELDOWN },
+	{ 0xfe, 0x52, KEY_CAMERA },
+	{ 0xfe, 0x5a, KEY_TUNER },	/* Live */
+	{ 0xfe, 0x19, KEY_OPEN },
+	{ 0xfe, 0x0b, KEY_1 },
+	{ 0xfe, 0x17, KEY_2 },
+	{ 0xfe, 0x1b, KEY_3 },
+	{ 0xfe, 0x07, KEY_4 },
+	{ 0xfe, 0x50, KEY_5 },
+	{ 0xfe, 0x54, KEY_6 },
+	{ 0xfe, 0x48, KEY_7 },
+	{ 0xfe, 0x4c, KEY_8 },
+	{ 0xfe, 0x58, KEY_9 },
+	{ 0xfe, 0x13, KEY_ANGLE },	/* Aspect */
+	{ 0xfe, 0x03, KEY_0 },
+	{ 0xfe, 0x1f, KEY_ZOOM },
+	{ 0xfe, 0x43, KEY_REWIND },
+	{ 0xfe, 0x47, KEY_PLAYPAUSE },
+	{ 0xfe, 0x4f, KEY_FASTFORWARD },
+	{ 0xfe, 0x57, KEY_MUTE },
+	{ 0xfe, 0x0d, KEY_STOP },
+	{ 0xfe, 0x01, KEY_RECORD },
+	{ 0xfe, 0x4e, KEY_POWER },
+};
+
+static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
 struct cx22702_config cxusb_cx22702_config = {
 	.demod_address = 0x63,
 
@@ -165,17 +262,47 @@
 	.pll_set  = dvb_usb_pll_set_i2c,
 };
 
+struct lgdt330x_config cxusb_lgdt330x_config = {
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3303,
+	.pll_set       = dvb_usb_pll_set_i2c,
+};
+
+struct mt352_config cxusb_dee1601_config = {
+	.demod_address = 0x0f,
+	.demod_init    = cxusb_dee1601_demod_init,
+	.pll_set       = dvb_usb_pll_set,
+};
+
 /* Callbacks for DVB USB */
-static int cxusb_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
 {
 	u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
 	d->pll_addr = 0x61;
-	memcpy(d->pll_init,bpll,4);
+	memcpy(d->pll_init, bpll, 4);
 	d->pll_desc = &dvb_pll_fmd1216me;
 	return 0;
 }
 
-static int cxusb_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
+{
+	u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
+	/* bpll[2] : unset bit 3, set bits 4&5
+	   bpll[3] : 0x50 - digital, 0x20 - analog */
+	d->pll_addr = 0x61;
+	memcpy(d->pll_init, bpll, 4);
+	d->pll_desc = &dvb_pll_tdvs_tua6034;
+	return 0;
+}
+
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
+{
+	d->pll_addr = 0x61;
+	d->pll_desc = &dvb_pll_thomson_dtt7579;
+	return 0;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
 {
 	u8 b;
 	if (usb_set_interface(d->udev,0,6) < 0)
@@ -189,22 +316,84 @@
 	return -EIO;
 }
 
+static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
+{
+	if (usb_set_interface(d->udev,0,7) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
+{
+	if (usb_set_interface(d->udev,0,0) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+/*
+ * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+ * firmware file before download.
+ */
+
+#define BLUEBIRD_01_ID_OFFSET 6638
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+	if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
+		return -EINVAL;
+
+	if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
+	    fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+
+		/* FIXME: are we allowed to change the fw-data ? */
+		fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
+		fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+
+		return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+	}
+
+	return -EINVAL;
+}
+
 /* DVB USB Driver stuff */
-static struct dvb_usb_properties cxusb_properties;
+static struct dvb_usb_properties cxusb_medion_properties;
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL);
+	if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) {
+		return 0;
+	}
+
+	return -EINVAL;
 }
 
 static struct usb_device_id cxusb_table [] = {
 		{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+		{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+		{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+		{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
+		{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
 		{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
 
-static struct dvb_usb_properties cxusb_properties = {
+static struct dvb_usb_properties cxusb_medion_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 
 	.usb_ctrl = CYPRESS_FX2,
@@ -213,8 +402,8 @@
 
 	.streaming_ctrl   = cxusb_streaming_ctrl,
 	.power_ctrl       = cxusb_power_ctrl,
-	.frontend_attach  = cxusb_frontend_attach,
-	.tuner_attach     = cxusb_tuner_attach,
+	.frontend_attach  = cxusb_cx22702_frontend_attach,
+	.tuner_attach     = cxusb_fmd1216me_tuner_attach,
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
@@ -240,6 +429,91 @@
 	}
 };
 
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.streaming_ctrl   = cxusb_streaming_ctrl,
+	.power_ctrl       = cxusb_power_ctrl,
+	.frontend_attach  = cxusb_lgdt330x_frontend_attach,
+	.tuner_attach     = cxusb_lgh064f_tuner_attach,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 5,
+		.endpoint = 0x02,
+		.u = {
+			.bulk = {
+				.buffersize = 8192,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV5 USB Gold",
+			{ &cxusb_table[1], NULL },
+			{ &cxusb_table[2], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-01.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	/* use usb alt setting 0 for EP4 transfer (dvb-t),
+	   use usb alt setting 7 for EP2 transfer (atsc) */
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.streaming_ctrl   = cxusb_streaming_ctrl,
+	.power_ctrl       = cxusb_power_ctrl,
+	.frontend_attach  = cxusb_dee1601_frontend_attach,
+	.tuner_attach     = cxusb_dee1601_tuner_attach,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.rc_interval      = 150,
+	.rc_key_map       = dvico_mce_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_query         = cxusb_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 5,
+		.endpoint = 0x04,
+		.u = {
+			.bulk = {
+				.buffersize = 8192,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual USB",
+			{ &cxusb_table[3], NULL },
+			{ &cxusb_table[4], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
index 135c2a8..087c994 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -21,6 +21,8 @@
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_OFF 0x37
 
+#define CMD_GET_IR_CODE   0x47
+
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 52ac3e5..dd5a131 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -65,11 +65,11 @@
 		d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
 
 	if (b2[0] == 0xfe) {
-		info("this device has the Thomson Cable onboard. Which is default.");
+		info("This device has the Thomson Cable onboard. Which is default.");
 		dibusb_thomson_tuner_attach(d);
 	} else {
 		u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
-		info("this device has the Panasonic ENV77H11D5 onboard.");
+		info("This device has the Panasonic ENV77H11D5 onboard.");
 		d->pll_addr = 0x60;
 		memcpy(d->pll_init,bpll,4);
 		d->pll_desc = &dvb_pll_tda665x;
@@ -98,15 +98,15 @@
 
 /* do not change the order of the ID table */
 static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM) },
 /* 02 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
 /* 03 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
 /* 04 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
 /* 05 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
 /* 06 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
-/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_COLD) },
-/* 08 */	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_WARM) },
+/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_WARM) },
 /* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
 /* 10 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
 /* 11 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
@@ -117,27 +117,34 @@
 /* 16 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_WARM) },
 /* 17 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_COLD) },
 /* 18 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_WARM) },
-/* 19 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 20 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 19 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
 /* 23 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
 
 /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
 /* 24 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
-/* 25 */	{ USB_DEVICE(USB_VID_KYE,			USB_PID_KYE_DVB_T_COLD) },
-/* 26 */	{ USB_DEVICE(USB_VID_KYE,			USB_PID_KYE_DVB_T_WARM) },
+/* 25 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_COLD) },
+/* 26 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_WARM) },
 
 /* 27 */	{ USB_DEVICE(USB_VID_KWORLD,		USB_PID_KWORLD_VSTREAM_COLD) },
 
-/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,		USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,		USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) },
 
-// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/*
+ * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
+ *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
+ *      have been left on the device. If you don't have such a device but an Artec
+ *      device that's supposed to work with this driver but is not detected by it,
+ *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
+ */
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 /* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
 #endif
+
 			{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -257,7 +264,7 @@
 		}
 	},
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 	.num_device_descs = 2,
 #else
 	.num_device_descs = 1,
@@ -267,11 +274,12 @@
 			{ &dibusb_dib3000mb_table[20], NULL },
 			{ &dibusb_dib3000mb_table[21], NULL },
 		},
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
 			{ &dibusb_dib3000mb_table[30], NULL },
 			{ NULL },
 		},
+		{ NULL },
 #endif
 	}
 };
@@ -323,6 +331,7 @@
 			{ &dibusb_dib3000mb_table[27], NULL },
 			{ NULL }
 		},
+		{ NULL },
 	}
 };
 
@@ -369,6 +378,7 @@
 			{ &dibusb_dib3000mb_table[28], NULL },
 			{ &dibusb_dib3000mb_table[29], NULL },
 		},
+		{ NULL },
 	}
 };
 
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 450417a..e6c55c9 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -32,7 +32,7 @@
 	sndbuf[1] = vv;
 	sndbuf[2] = wo ? wlen : rlen;
 
-	if (!wo) {
+	if (wo) {
 		memcpy(&sndbuf[3],wbuf,wlen);
 		dvb_usb_generic_write(d,sndbuf,7);
 	} else {
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 6e2bac8..130ea7f 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -151,7 +151,7 @@
 		  .cold_ids = { &dtt200u_usb_table[0], NULL },
 		  .warm_ids = { &dtt200u_usb_table[1], NULL },
 		},
-		{ NULL },
+		{ 0 },
 	}
 };
 
@@ -160,7 +160,7 @@
 	.pid_filter_count = 15,
 
 	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-wt220u-01.fw",
+	.firmware = "dvb-usb-wt220u-02.fw",
 
 	.power_ctrl      = dtt200u_power_ctrl,
 	.streaming_ctrl  = dtt200u_streaming_ctrl,
@@ -192,7 +192,7 @@
 		  .cold_ids = { &dtt200u_usb_table[2], NULL },
 		  .warm_ids = { &dtt200u_usb_table[3], NULL },
 		},
-		{ NULL },
+		{ 0 },
 	}
 };
 
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
index 6f1f304..005b0a7 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.h
+++ b/drivers/media/dvb/dvb-usb/dtt200u.h
@@ -13,6 +13,7 @@
 #define _DVB_USB_DTT200U_H_
 
 #define DVB_USB_LOG_PREFIX "dtt200u"
+
 #include "dvb-usb.h"
 
 extern int dvb_usb_dtt200u_debug;
@@ -25,15 +26,15 @@
  *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
  */
 
-#define GET_SPEED            0x00
-#define GET_TUNE_STATUS      0x81
-#define GET_RC_CODE          0x84
-#define GET_CONFIGURATION    0x88
-#define GET_AGC              0x89
-#define GET_SNR              0x8a
-#define GET_VIT_ERR_CNT      0x8c
-#define GET_RS_ERR_CNT       0x8d
-#define GET_RS_UNCOR_BLK_CNT 0x8e
+#define GET_SPEED		0x00
+#define GET_TUNE_STATUS		0x81
+#define GET_RC_CODE		0x84
+#define GET_CONFIGURATION	0x88
+#define GET_AGC			0x89
+#define GET_SNR			0x8a
+#define GET_VIT_ERR_CNT		0x8c
+#define GET_RS_ERR_CNT		0x8d
+#define GET_RS_UNCOR_BLK_CNT	0x8e
 
 /* write
  *  01 - init
@@ -44,12 +45,12 @@
  *  08 - transfer switch
  */
 
-#define SET_INIT         0x01
-#define SET_RF_FREQ      0x02
-#define SET_BANDWIDTH    0x03
-#define SET_PID_FILTER   0x04
-#define RESET_PID_FILTER 0x05
-#define SET_STREAMING    0x08
+#define SET_INIT		0x01
+#define SET_RF_FREQ		0x02
+#define SET_BANDWIDTH		0x03
+#define SET_PID_FILTER		0x04
+#define RESET_PID_FILTER	0x05
+#define SET_STREAMING		0x08
 
 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
index 7300489..a3460bf 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -24,7 +24,7 @@
 #define deb_mem(args...)  dprintk(dvb_usb_debug,0x80,args)
 
 /* commonly used  methods */
-extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
 
 extern int dvb_usb_urb_submit(struct dvb_usb_device *);
 extern int dvb_usb_urb_kill(struct dvb_usb_device *);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
index 5244e39..8535895 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
@@ -9,7 +9,6 @@
  */
 #include "dvb-usb-common.h"
 
-#include <linux/firmware.h>
 #include <linux/usb.h>
 
 struct usb_cypress_controller {
@@ -19,9 +18,10 @@
 };
 
 static struct usb_cypress_controller cypress[] = {
-	{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
-	{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
-	{ .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
+	{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+	{ .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
+	{ .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
 };
 
 /*
@@ -30,71 +30,117 @@
 static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
 {
 	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
 }
 
-int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-	const struct firmware *fw = NULL;
-	u16 addr;
-	u8 *b,*p;
-	int ret = 0,i;
+	struct hexline hx;
+	u8 reset;
+	int ret,pos=0;
 
-	if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
-		err("did not find the firmware file. (%s) "
-			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
-			filename);
+	/* stop the CPU */
+	reset = 1;
+	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+		err("could not stop the USB controller CPU.");
+
+	while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+		if (ret != hx.len) {
+			err("error while transferring firmware "
+				"(transferred size: %d, block size: %d)",
+				ret,hx.len);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	if (ret < 0) {
+		err("firmware download failed at %d with %d",pos,ret);
 		return ret;
 	}
 
-	info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
-
-	p = kmalloc(fw->size,GFP_KERNEL);
-	if (p != NULL) {
-		u8 reset;
-		/*
-		 * you cannot use the fw->data as buffer for
-		 * usb_control_msg, a new buffer has to be
-		 * created
-		 */
-		memcpy(p,fw->data,fw->size);
-
-		/* stop the CPU */
-		reset = 1;
-		if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
-			err("could not stop the USB controller CPU.");
-		for(i = 0; p[i+3] == 0 && i < fw->size; ) {
-			b = (u8 *) &p[i];
-			addr = cpu_to_le16( *((u16 *) &b[1]) );
-
-			deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
-
-			ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
-
-			if (ret != b[0]) {
-				err("error while transferring firmware "
-					"(transferred size: %d, block size: %d)",
-					ret,b[0]);
-				ret = -EINVAL;
-				break;
-			}
-			i += 5 + b[0];
-		}
-		/* length in ret */
-		if (ret > 0)
-			ret = 0;
+	if (ret == 0) {
 		/* restart the CPU */
 		reset = 0;
 		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
 			err("could not restart the USB controller CPU.");
 			ret = -EINVAL;
 		}
-
-		kfree(p);
-	} else {
-		ret = -ENOMEM;
-	}
-	release_firmware(fw);
+	} else
+		ret = -EIO;
 
 	return ret;
 }
+EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+
+	if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			props->firmware,ret);
+		return ret;
+	}
+
+	info("downloading firmware from file '%s'",props->firmware);
+
+	switch (props->usb_ctrl) {
+		case CYPRESS_AN2135:
+		case CYPRESS_AN2235:
+		case CYPRESS_FX2:
+			ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
+			break;
+		case DEVICE_SPECIFIC:
+			if (props->download_firmware)
+				ret = props->download_firmware(udev,fw);
+			else {
+				err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+				ret = -EINVAL;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	release_firmware(fw);
+	return ret;
+}
+
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos)
+{
+	u8 *b = (u8 *) &fw->data[*pos];
+	int data_offs = 4;
+	if (*pos >= fw->size)
+		return 0;
+
+	memset(hx,0,sizeof(struct hexline));
+
+	hx->len  = b[0];
+
+	if ((*pos + hx->len + 4) >= fw->size)
+		return -EINVAL;
+
+	hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
+	hx->type = b[3];
+
+	if (hx->type == 0x04) {
+		/* b[4] and b[5] are the Extended linear address record data field */
+		hx->addr |= (b[4] << 24) | (b[5] << 16);
+/*		hx->len -= 2;
+		data_offs += 2; */
+	}
+	memcpy(hx->data,&b[data_offs],hx->len);
+	hx->chk = b[hx->len + data_offs];
+
+	*pos += hx->len + 5;
+
+	return *pos;
+}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
+
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index da97094..9b25453 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -52,9 +52,8 @@
 	struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
 	int ret = 0;
 
-	/* if there is nothing to initialize */
-	if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
-		d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+	/* if pll_desc is not used */
+	if (d->pll_desc == NULL)
 		return 0;
 
 	if (d->tuner_pass_ctrl)
@@ -80,6 +79,9 @@
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 
+	if (d->pll_desc == NULL)
+		return 0;
+
 	deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
 
 	b[0] = d->pll_addr << 1;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 6be99e5..d229343 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -86,11 +86,15 @@
 #define USB_PID_WINTV_NOVA_T_USB2_COLD		0x9300
 #define USB_PID_WINTV_NOVA_T_USB2_WARM		0x9301
 #define USB_PID_NEBULA_DIGITV				0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGZ201		0xdb00
-#define USB_PID_DVICO_BLUEBIRD_TH7579		0xdb10
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_1		0xdb01
-#define USB_PID_DVICO_BLUEBIRD_TH7579_2		0xdb11
+#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM		0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD		0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM		0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD		0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM		0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD		0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM		0xdb51
 #define USB_PID_MEDION_MD95700				0x0932
 #define USB_PID_KYE_DVB_T_COLD				0x701e
 #define USB_PID_KYE_DVB_T_WARM				0x701f
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index dd8e0b9..2e23060 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -138,6 +138,9 @@
 
 	int ret = -ENOMEM,cold=0;
 
+	if (du != NULL)
+		*du = NULL;
+
 	if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
 		deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
 		return -ENODEV;
@@ -145,39 +148,41 @@
 
 	if (cold) {
 		info("found a '%s' in cold state, will try to load a firmware",desc->name);
-		ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
-	} else {
-		info("found a '%s' in warm state.",desc->name);
-		d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
-		if (d == NULL) {
-			err("no memory for 'struct dvb_usb_device'");
+		ret = dvb_usb_download_firmware(udev,props);
+		if (!props->no_reconnect)
 			return ret;
-		}
-		memset(d,0,sizeof(struct dvb_usb_device));
-
-		d->udev = udev;
-		memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
-		d->desc = desc;
-		d->owner = owner;
-
-		if (d->props.size_of_priv > 0) {
-			d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
-			if (d->priv == NULL) {
-				err("no memory for priv in 'struct dvb_usb_device'");
-				kfree(d);
-				return -ENOMEM;
-			}
-			memset(d->priv,0,d->props.size_of_priv);
-		}
-
-		usb_set_intfdata(intf, d);
-
-		if (du != NULL)
-			*du = d;
-
-		ret = dvb_usb_init(d);
 	}
 
+	info("found a '%s' in warm state.",desc->name);
+	d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+	if (d == NULL) {
+		err("no memory for 'struct dvb_usb_device'");
+		return ret;
+	}
+	memset(d,0,sizeof(struct dvb_usb_device));
+
+	d->udev = udev;
+	memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+	d->desc = desc;
+	d->owner = owner;
+
+	if (d->props.size_of_priv > 0) {
+		d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+		if (d->priv == NULL) {
+			err("no memory for priv in 'struct dvb_usb_device'");
+			kfree(d);
+			return -ENOMEM;
+		}
+		memset(d->priv,0,d->props.size_of_priv);
+	}
+
+	usb_set_intfdata(intf, d);
+
+	if (du != NULL)
+		*du = d;
+
+	ret = dvb_usb_init(d);
+
 	if (ret == 0)
 		info("%s successfully initialized and connected.",desc->name);
 	else
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index b4a1a98..dd56839 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -10,8 +10,8 @@
 
 #include <linux/config.h>
 #include <linux/input.h>
-#include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -94,7 +94,11 @@
  * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
  *  download.
  * @firmware: name of the firmware file.
- *
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ *  DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+    so do the warm initialization right after it
+
  * @size_of_priv: how many bytes shall be allocated for the private field
  *  of struct dvb_usb_device.
  *
@@ -142,11 +146,14 @@
 	int caps;
 	int pid_filter_count;
 
-#define CYPRESS_AN2135  0
-#define CYPRESS_AN2235  1
-#define CYPRESS_FX2     2
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135  1
+#define CYPRESS_AN2235  2
+#define CYPRESS_FX2     3
 	int usb_ctrl;
-	const char *firmware;
+	const char firmware[FIRMWARE_NAME_MAX];
+	int (*download_firmware) (struct usb_device *, const struct firmware *);
+	int no_reconnect;
 
 	int size_of_priv;
 
@@ -326,5 +333,15 @@
 extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
 extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
 
+/* commonly used firmware download types and function */
+struct hexline {
+	u8 len;
+	u32 addr;
+	u8 type;
+	u8 data[255];
+	u8 chk;
+};
+extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *);
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index fac48fc..412039d 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -129,10 +129,6 @@
 		dibusb_read_eeprom_byte(d,i, &b);
 
 		mac[5 - (i - 136)] = b;
-
-/*		deb_ee("%02x ",b);
-		if ((i+1) % 16 == 0)
-			deb_ee("\n");*/
 	}
 
 	return 0;
@@ -153,7 +149,7 @@
 /* 01 */	{ USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
 			{ }		/* Terminating entry */
 };
-MODULE_DEVICE_TABLE (usb, nova_t_table);
+MODULE_DEVICE_TABLE(usb, nova_t_table);
 
 static struct dvb_usb_properties nova_t_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
@@ -198,6 +194,7 @@
 			{ &nova_t_table[0], NULL },
 			{ &nova_t_table[1], NULL },
 		},
+		{ NULL },
 	}
 };
 
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 104b5d0..0885d9f 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -190,7 +190,7 @@
 }
 
 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
-			            struct dvb_diseqc_master_cmd *m)
+				    struct dvb_diseqc_master_cmd *m)
 {
 	struct vp702x_fe_state *st = fe->demodulator_priv;
 	u8 cmd[8],ibuf[10];
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
index 4a3e8c7..a808d48 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -13,47 +13,47 @@
 /* commands are read and written with USB control messages */
 
 /* consecutive read/write operation */
-#define REQUEST_OUT       0xB2
-#define REQUEST_IN		  0xB3
+#define REQUEST_OUT		0xB2
+#define REQUEST_IN		0xB3
 
 /* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
  * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
  * the returning buffer looks as follows
  * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
 
-#define GET_TUNER_STATUS  0x05
+#define GET_TUNER_STATUS	0x05
 /* additional in buffer:
  * 0   1   2    3              4   5   6               7       8
  * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
 
-#define GET_SYSTEM_STRING 0x06
+#define GET_SYSTEM_STRING	0x06
 /* additional in buffer:
  * 0   1   2   3   4   5   6   7   8
  * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
 
-#define SET_DISEQC_CMD    0x08
+#define SET_DISEQC_CMD		0x08
 /* additional out buffer:
  * 0    1  2  3  4
  * len  X1 X2 X3 X4
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success, failure otherwise */
 
-#define SET_LNB_POWER     0x09
+#define SET_LNB_POWER		0x09
 /* additional out buffer:
  * 0    1    2
  * 0x00 0xff 1 = on, 0 = off
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success failure otherwise */
 
-#define GET_MAC_ADDRESS   0x0A
+#define GET_MAC_ADDRESS		0x0A
 /* #define GET_MAC_ADDRESS   0x0B */
 /* additional in buffer:
  * 0   1   2            3    4    5    6    7    8
  * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
 
-#define SET_PID_FILTER    0x11
+#define SET_PID_FILTER		0x11
 /* additional in buffer:
  * 0        1        ... 14       15       16
  * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
@@ -64,39 +64,38 @@
  * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
  */
 
-
 /* one direction requests */
-#define READ_REMOTE_REQ       0xB4
+#define READ_REMOTE_REQ		0xB4
 /* IN  i: 0; v: 0; b[0] == request, b[1] == key */
 
-#define READ_PID_NUMBER_REQ   0xB5
+#define READ_PID_NUMBER_REQ	0xB5
 /* IN  i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
 
-#define WRITE_EEPROM_REQ      0xB6
+#define WRITE_EEPROM_REQ	0xB6
 /* OUT i: offset; v: value to write; no extra buffer */
 
-#define READ_EEPROM_REQ       0xB7
+#define READ_EEPROM_REQ		0xB7
 /* IN  i: bufferlen; v: offset; buffer with bufferlen bytes */
 
-#define READ_STATUS           0xB8
+#define READ_STATUS		0xB8
 /* IN  i: 0; v: 0; bufferlen 10 */
 
-#define READ_TUNER_REG_REQ    0xB9
+#define READ_TUNER_REG_REQ	0xB9
 /* IN  i: 0; v: register; b[0] = value */
 
-#define READ_FX2_REG_REQ      0xBA
+#define READ_FX2_REG_REQ	0xBA
 /* IN  i: offset; v: 0; b[0] = value */
 
-#define WRITE_FX2_REG_REQ     0xBB
+#define WRITE_FX2_REG_REQ	0xBB
 /* OUT i: offset; v: value to write; 1 byte extra buffer */
 
-#define SET_TUNER_POWER_REQ   0xBC
+#define SET_TUNER_POWER_REQ	0xBC
 /* IN  i: 0 = power off, 1 = power on */
 
-#define WRITE_TUNER_REG_REQ   0xBD
+#define WRITE_TUNER_REG_REQ	0xBD
 /* IN  i: register, v: value to write, no extra buffer */
 
-#define RESET_TUNER           0xBE
+#define RESET_TUNER		0xBE
 /* IN  i: 0, v: 0, no extra buffer */
 
 extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3835235..0282049 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -247,7 +247,7 @@
 		  .cold_ids = { &vp7045_usb_table[2], NULL },
 		  .warm_ids = { &vp7045_usb_table[3], NULL },
 		},
-		{ NULL },
+		{ 0 },
 	}
 };
 
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 8e269e1..db3a8b4 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -16,6 +16,12 @@
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_CX24123
+	tristate "Conexant CX24123 based"
+	depends on DVB_CORE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_TDA8083
 	tristate "Philips TDA8083 based"
 	depends on DVB_CORE
@@ -50,18 +56,19 @@
 	depends on DVB_CORE
 
 config DVB_SP8870
- 	tristate "Spase sp8870 based"
+	tristate "Spase sp8870 based"
 	depends on DVB_CORE
 	select FW_LOADER
 	help
- 	  A DVB-T tuner module. Say Y when you want to support this frontend.
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 	  This driver needs external firmware. Please use the command
 	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
-	  download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_SP887X
- 	tristate "Spase sp887x based"
+	tristate "Spase sp887x based"
 	depends on DVB_CORE
 	select FW_LOADER
 	help
@@ -69,7 +76,8 @@
 
 	  This driver needs external firmware. Please use the command
 	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
-	  download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_CX22700
 	tristate "Conexant CX22700 based"
@@ -78,10 +86,10 @@
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_CX22702
- 	tristate "Conexant cx22702 demodulator (OFDM)"
- 	depends on DVB_CORE
- 	help
- 	  A DVB-T tuner module. Say Y when you want to support this frontend.
+	tristate "Conexant cx22702 demodulator (OFDM)"
+	depends on DVB_CORE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_L64781
 	tristate "LSI L64781"
@@ -98,8 +106,9 @@
 
 	  This driver needs external firmware. Please use the commands
 	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
-  	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
-	  download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_NXT6000
 	tristate "NxtWave Communications NXT6000 based"
@@ -140,13 +149,13 @@
 	tristate "VLSI VES1820 based"
 	depends on DVB_CORE
 	help
- 	  A DVB-C tuner module. Say Y when you want to support this frontend.
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_TDA10021
 	tristate "Philips TDA10021 based"
 	depends on DVB_CORE
 	help
- 	  A DVB-C tuner module. Say Y when you want to support this frontend.
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_STV0297
 	tristate "ST STV0297 based"
@@ -164,6 +173,11 @@
 	help
 	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_NXT200X
 	tristate "Nextwave NXT2002/NXT2004 based"
 	depends on DVB_CORE
@@ -172,6 +186,12 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_OR51211
 	tristate "or51211 based (pcHDTV HD2000 card)"
 	depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index a98760f..615ec83 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -32,3 +32,4 @@
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 8ceb9a3..3b132ba 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -255,7 +255,7 @@
 	bcm3510_register_value b;
 	int ret;
 
-	if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+	if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
 		return ret;
 
 	b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
@@ -623,13 +623,13 @@
 		err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
 		return ret;
 	}
-	deb_info("got firmware: %d\n",fw->size);
+	deb_info("got firmware: %zd\n",fw->size);
 
 	b = fw->data;
 	for (i = 0; i < fw->size;) {
 		addr = le16_to_cpu( *( (u16 *)&b[i] ) );
 		len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
-		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
 		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
 			err("firmware download failed: %d\n",ret);
 			return ret;
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 5de0e6d3..0fc899f 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -195,6 +195,16 @@
 	return 0;
 }
 
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct cx22702_state* state = fe->demodulator_priv;
+	dprintk ("%s(%d)\n", __FUNCTION__, enable);
+	if (enable)
+		return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+	else
+		return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+}
+
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
@@ -202,7 +212,7 @@
 	struct cx22702_state* state = fe->demodulator_priv;
 
 	/* set PLL */
-	cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+	cx22702_i2c_gate_ctrl(fe, 1);
 	if (state->config->pll_set) {
 		state->config->pll_set(fe, p);
 	} else if (state->config->pll_desc) {
@@ -216,7 +226,7 @@
 	} else {
 		BUG();
 	}
-	cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+	cx22702_i2c_gate_ctrl(fe, 0);
 
 	/* set inversion */
 	cx22702_set_inversion (state, p->inversion);
@@ -349,11 +359,10 @@
 	cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
 	/* init PLL */
-	if (state->config->pll_init) {
-		cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
+	if (state->config->pll_init)
 		state->config->pll_init(fe);
-		cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
-	}
+
+	cx22702_i2c_gate_ctrl(fe, 0);
 
 	return 0;
 }
@@ -531,6 +540,7 @@
 	.read_signal_strength = cx22702_read_signal_strength,
 	.read_snr = cx22702_read_snr,
 	.read_ucblocks = cx22702_read_ucblocks,
+	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 0c4db80..d15d32c 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/jiffies.h>
 
 #include "dvb_frontend.h"
 #include "cx24110.h"
@@ -56,7 +55,7 @@
 
 static struct {u8 reg; u8 data;} cx24110_regdata[]=
 		      /* Comments beginning with @ denote this value should
-		         be the default */
+			 be the default */
 	{{0x09,0x01}, /* SoftResetAll */
 	 {0x09,0x00}, /* release reset */
 	 {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
@@ -67,26 +66,26 @@
 	 {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
 	 {0x0a,0x00}, /* @ partial chip disables, do not set */
 	 {0x0b,0x01}, /* set output clock in gapped mode, start signal low
-		         active for first byte */
+			 active for first byte */
 	 {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
 	 {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
 	 {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
-		         to avoid starting the BER counter. Reset the
-		         CRC test bit. Finite counting selected */
+			 to avoid starting the BER counter. Reset the
+			 CRC test bit. Finite counting selected */
 	 {0x15,0xff}, /* @ size of the limited time window for RS BER
-		         estimation. It is <value>*256 RS blocks, this
-		         gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
+			 estimation. It is <value>*256 RS blocks, this
+			 gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
 	 {0x16,0x00}, /* @ enable all RS output ports */
 	 {0x17,0x04}, /* @ time window allowed for the RS to sync */
 	 {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
-		         for automatically */
+			 for automatically */
 		      /* leave the current code rate and normalization
-		         registers as they are after reset... */
+			 registers as they are after reset... */
 	 {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
-		         only once */
+			 only once */
 	 {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
-		         estimation. It is <value>*65536 channel bits, i.e.
-		         approx. 38ms at 27.5MS/s, rate 3/4 */
+			 estimation. It is <value>*65536 channel bits, i.e.
+			 approx. 38ms at 27.5MS/s, rate 3/4 */
 	 {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
 		      /* leave front-end AGC parameters at default values */
 		      /* leave decimation AGC parameters at default values */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
new file mode 100644
index 0000000..d661c6f
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -0,0 +1,889 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+    Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+
+    This program is free software; 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24123.h"
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk (KERN_DEBUG "cx24123: " args); \
+	} while (0)
+
+struct cx24123_state
+{
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+	const struct cx24123_config* config;
+
+	struct dvb_frontend frontend;
+
+	u32 lastber;
+	u16 snr;
+	u8  lnbreg;
+
+	/* Some PLL specifics for tuning */
+	u32 VCAarg;
+	u32 VGAarg;
+	u32 bandselectarg;
+	u32 pllarg;
+
+	/* The Demod/Tuner can't easily provide these, we cache them */
+	u32 currentfreq;
+	u32 currentsymbolrate;
+};
+
+/* Various tuner defaults need to be established for a given symbol rate Sps */
+static struct
+{
+	u32 symbolrate_low;
+	u32 symbolrate_high;
+	u32 VCAslope;
+	u32 VCAoffset;
+	u32 VGA1offset;
+	u32 VGA2offset;
+	u32 VCAprogdata;
+	u32 VGAprogdata;
+} cx24123_AGC_vals[] =
+{
+	{
+		.symbolrate_low		= 1000000,
+		.symbolrate_high	= 4999999,
+		.VCAslope		= 0x07,
+		.VCAoffset		= 0x0f,
+		.VGA1offset		= 0x1f8,
+		.VGA2offset		= 0x1f8,
+		.VGAprogdata		= (2 << 18) | (0x1f8 << 9) | 0x1f8,
+		.VCAprogdata		= (4 << 18) | (0x07 << 9) | 0x07,
+	},
+	{
+		.symbolrate_low		=  5000000,
+		.symbolrate_high	= 14999999,
+		.VCAslope		= 0x1f,
+		.VCAoffset		= 0x1f,
+		.VGA1offset		= 0x1e0,
+		.VGA2offset		= 0x180,
+		.VGAprogdata		= (2 << 18) | (0x180 << 9) | 0x1e0,
+		.VCAprogdata		= (4 << 18) | (0x07 << 9) | 0x1f,
+	},
+	{
+		.symbolrate_low		= 15000000,
+		.symbolrate_high	= 45000000,
+		.VCAslope		= 0x3f,
+		.VCAoffset		= 0x3f,
+		.VGA1offset		= 0x180,
+		.VGA2offset		= 0x100,
+		.VGAprogdata		= (2 << 18) | (0x100 << 9) | 0x180,
+		.VCAprogdata		= (4 << 18) | (0x07 << 9) | 0x3f,
+	},
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct
+{
+	u32 freq_low;
+	u32 freq_high;
+	u32 bandselect;
+	u32 VCOdivider;
+	u32 VCOnumber;
+	u32 progdata;
+} cx24123_bandselect_vals[] =
+{
+	{
+		.freq_low	= 950000,
+		.freq_high	= 1018999,
+		.bandselect	= 0x40,
+		.VCOdivider	= 4,
+		.VCOnumber	= 7,
+		.progdata	= (0 << 18) | (0 << 9) | 0x40,
+	},
+	{
+		.freq_low	= 1019000,
+		.freq_high	= 1074999,
+		.bandselect	= 0x80,
+		.VCOdivider	= 4,
+		.VCOnumber	= 8,
+		.progdata	= (0 << 18) | (0 << 9) | 0x80,
+	},
+	{
+		.freq_low	= 1075000,
+		.freq_high	= 1227999,
+		.bandselect	= 0x01,
+		.VCOdivider	= 2,
+		.VCOnumber	= 1,
+		.progdata	= (0 << 18) | (1 << 9) | 0x01,
+	},
+	{
+		.freq_low	= 1228000,
+		.freq_high	= 1349999,
+		.bandselect	= 0x02,
+		.VCOdivider	= 2,
+		.VCOnumber	= 2,
+		.progdata	= (0 << 18) | (1 << 9) | 0x02,
+	},
+	{
+		.freq_low	= 1350000,
+		.freq_high	= 1481999,
+		.bandselect	= 0x04,
+		.VCOdivider	= 2,
+		.VCOnumber	= 3,
+		.progdata	= (0 << 18) | (1 << 9) | 0x04,
+	},
+	{
+		.freq_low	= 1482000,
+		.freq_high	= 1595999,
+		.bandselect	= 0x08,
+		.VCOdivider	= 2,
+		.VCOnumber	= 4,
+		.progdata	= (0 << 18) | (1 << 9) | 0x08,
+	},
+	{
+		.freq_low	= 1596000,
+		.freq_high	= 1717999,
+		.bandselect	= 0x10,
+		.VCOdivider	= 2,
+		.VCOnumber	= 5,
+		.progdata	= (0 << 18) | (1 << 9) | 0x10,
+	},
+	{
+		.freq_low	= 1718000,
+		.freq_high	= 1855999,
+		.bandselect	= 0x20,
+		.VCOdivider	= 2,
+		.VCOnumber	= 6,
+		.progdata	= (0 << 18) | (1 << 9) | 0x20,
+	},
+	{
+		.freq_low	= 1856000,
+		.freq_high	= 2035999,
+		.bandselect	= 0x40,
+		.VCOdivider	= 2,
+		.VCOnumber	= 7,
+		.progdata	= (0 << 18) | (1 << 9) | 0x40,
+	},
+	{
+		.freq_low	= 2036000,
+		.freq_high	= 2149999,
+		.bandselect	= 0x80,
+		.VCOdivider	= 2,
+		.VCOnumber	= 8,
+		.progdata	= (0 << 18) | (1 << 9) | 0x80,
+	},
+};
+
+static struct {
+	u8 reg;
+	u8 data;
+} cx24123_regdata[] =
+{
+	{0x00, 0x03}, /* Reset system */
+	{0x00, 0x00}, /* Clear reset */
+	{0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
+	{0x03, 0x07},
+	{0x04, 0x10},
+	{0x05, 0x04},
+	{0x06, 0x31},
+	{0x0d, 0x02},
+	{0x0e, 0x03},
+	{0x0f, 0xfe},
+	{0x10, 0x01},
+	{0x14, 0x01},
+	{0x15, 0x98},
+	{0x16, 0x00},
+	{0x17, 0x01},
+	{0x1b, 0x05},
+	{0x1c, 0x80},
+	{0x1d, 0x00},
+	{0x1e, 0x00},
+	{0x20, 0x41},
+	{0x21, 0x15},
+	{0x27, 0x14},
+	{0x28, 0x46},
+	{0x29, 0x00},
+	{0x2a, 0xb0},
+	{0x2b, 0x73},
+	{0x2c, 0x00},
+	{0x2d, 0x00},
+	{0x2e, 0x00},
+	{0x2f, 0x00},
+	{0x30, 0x00},
+	{0x31, 0x00},
+	{0x32, 0x8c},
+	{0x33, 0x00},
+	{0x34, 0x00},
+	{0x35, 0x03},
+	{0x36, 0x02},
+	{0x37, 0x3a},
+	{0x3a, 0x00},	/* Enable AGC accumulator */
+	{0x44, 0x00},
+	{0x45, 0x00},
+	{0x46, 0x05},
+	{0x56, 0x41},
+	{0x57, 0xff},
+	{0x67, 0x83},
+};
+
+static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	/* fixme: put the intersil addr int the config */
+	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+		printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	/* cache the write, no way to read back */
+	state->lnbreg = data;
+
+	return 0;
+}
+
+static int cx24123_readreg(struct cx24123_state* state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
+{
+	return state->lnbreg;
+}
+
+static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
+{
+	switch (inversion) {
+	case INVERSION_OFF:
+		cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
+		cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+		break;
+	case INVERSION_ON:
+		cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
+		cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+		break;
+	case INVERSION_AUTO:
+		cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+{
+	u8 val;
+
+	val = cx24123_readreg(state, 0x1b) >> 7;
+
+	if (val == 0)
+		*inversion = INVERSION_OFF;
+	else
+		*inversion = INVERSION_ON;
+
+	return 0;
+}
+
+static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
+{
+	if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+		fec = FEC_AUTO;
+
+	/* Hardware has 5/11 and 3/5 but are never unused */
+	switch (fec) {
+	case FEC_NONE:
+		return cx24123_writereg(state, 0x0f, 0x01);
+	case FEC_1_2:
+		return cx24123_writereg(state, 0x0f, 0x02);
+	case FEC_2_3:
+		return cx24123_writereg(state, 0x0f, 0x04);
+	case FEC_3_4:
+		return cx24123_writereg(state, 0x0f, 0x08);
+	case FEC_5_6:
+		return cx24123_writereg(state, 0x0f, 0x20);
+	case FEC_7_8:
+		return cx24123_writereg(state, 0x0f, 0x80);
+	case FEC_AUTO:
+		return cx24123_writereg(state, 0x0f, 0xae);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
+{
+	int ret;
+	u8 val;
+
+	ret = cx24123_readreg (state, 0x1b);
+	if (ret < 0)
+		return ret;
+	val = ret & 0x07;
+	switch (val) {
+	case 1:
+		*fec = FEC_1_2;
+		break;
+	case 3:
+		*fec = FEC_2_3;
+		break;
+	case 4:
+		*fec = FEC_3_4;
+		break;
+	case 5:
+		*fec = FEC_4_5;
+		break;
+	case 6:
+		*fec = FEC_5_6;
+		break;
+	case 7:
+		*fec = FEC_7_8;
+		break;
+	case 2:	/* *fec = FEC_3_5; break; */
+	case 0:	/* *fec = FEC_5_11; break; */
+		*fec = FEC_AUTO;
+		break;
+	default:
+		*fec = FEC_NONE; // can't happen
+	}
+
+	return 0;
+}
+
+/* fixme: Symbol rates < 3MSps may not work because of precision loss */
+static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
+{
+	u32 val;
+
+	val = (srate / 1185) * 100;
+
+	/* Compensate for scaling up, by removing 17 symbols per 1Msps */
+	val = val - (17 * (srate / 1000000));
+
+	cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
+	cx24123_writereg(state, 0x09, (val >>  8) & 0xff );
+	cx24123_writereg(state, 0x0a, (val      ) & 0xff );
+
+	return 0;
+}
+
+/*
+ * Based on the required frequency and symbolrate, the tuner AGC has to be configured
+ * and the correct band selected. Calculate those values
+ */
+static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	u32 ndiv = 0, adiv = 0, vco_div = 0;
+	int i = 0;
+
+	/* Defaults for low freq, low rate */
+	state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
+	state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
+	state->bandselectarg = cx24123_bandselect_vals[0].progdata;
+	vco_div = cx24123_bandselect_vals[0].VCOdivider;
+
+	/* For the given symbolerate, determine the VCA and VGA programming bits */
+	for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+	{
+		if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
+				(cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
+			state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
+			state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
+		}
+	}
+
+	/* For the given frequency, determine the bandselect programming bits */
+	for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
+	{
+		if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
+				(cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
+			state->bandselectarg = cx24123_bandselect_vals[i].progdata;
+			vco_div = cx24123_bandselect_vals[i].VCOdivider;
+		}
+	}
+
+	/* Determine the N/A dividers for the requested lband freq (in kHz). */
+	/* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
+	ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
+	adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
+
+	if (adiv == 0)
+		adiv++;
+
+	/* determine the correct pll frequency values. */
+	/* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
+	state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
+	state->pllarg |= (ndiv << 5) | adiv;
+
+	return 0;
+}
+
+/*
+ * Tuner data is 21 bits long, must be left-aligned in data.
+ * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ */
+static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	unsigned long timeout;
+
+	/* align the 21 bytes into to bit23 boundary */
+	data = data << 3;
+
+	/* Reset the demod pll word length to 0x15 bits */
+	cx24123_writereg(state, 0x21, 0x15);
+
+	/* write the msb 8 bits, wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
+	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+		if (time_after(jiffies, timeout)) {
+			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* send another 8 bytes, wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+	while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+		if (time_after(jiffies, timeout)) {
+			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+	timeout = jiffies + msecs_to_jiffies(40);
+	cx24123_writereg(state, 0x22, (data) & 0xff );
+	while ((cx24123_readreg(state, 0x20) & 0x80)) {
+		if (time_after(jiffies, timeout)) {
+			printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+			return -EREMOTEIO;
+		}
+		msleep(10);
+	}
+
+	/* Trigger the demod to configure the tuner */
+	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
+	cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
+
+	return 0;
+}
+
+static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	if (cx24123_pll_calculate(fe, p) != 0) {
+		printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* Write the new VCO/VGA */
+	cx24123_pll_writereg(fe, p, state->VCAarg);
+	cx24123_pll_writereg(fe, p, state->VGAarg);
+
+	/* Write the new bandselect and pll args */
+	cx24123_pll_writereg(fe, p, state->bandselectarg);
+	cx24123_pll_writereg(fe, p, state->pllarg);
+
+	return 0;
+}
+
+static int cx24123_initfe(struct dvb_frontend* fe)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	int i;
+
+	/* Configure the demod to a good set of defaults */
+	for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+		cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+
+	if (state->config->pll_init)
+		state->config->pll_init(fe);
+
+	/* Configure the LNB for 14V */
+	if (state->config->use_isl6421)
+		cx24123_writelnbreg(state, 0x0, 0x2a);
+
+	return 0;
+}
+
+static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	u8 val;
+
+	switch (state->config->use_isl6421) {
+
+	case 1:
+
+		val = cx24123_readlnbreg(state, 0x0);
+
+		switch (voltage) {
+		case SEC_VOLTAGE_13:
+			return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
+		case SEC_VOLTAGE_18:
+			return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
+		case SEC_VOLTAGE_OFF:
+			return cx24123_writelnbreg(state, 0x0, val & 0x30);
+		default:
+			return -EINVAL;
+		};
+
+	case 0:
+
+		val = cx24123_readreg(state, 0x29);
+
+		switch (voltage) {
+		case SEC_VOLTAGE_13:
+			dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+			if (state->config->enable_lnb_voltage)
+				state->config->enable_lnb_voltage(fe, 1);
+			return cx24123_writereg(state, 0x29, val | 0x80);
+		case SEC_VOLTAGE_18:
+			dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+			if (state->config->enable_lnb_voltage)
+				state->config->enable_lnb_voltage(fe, 1);
+			return cx24123_writereg(state, 0x29, val & 0x7f);
+		case SEC_VOLTAGE_OFF:
+			dprintk("%s: setting voltage off\n", __FUNCTION__);
+			if (state->config->enable_lnb_voltage)
+				state->config->enable_lnb_voltage(fe, 0);
+			return 0;
+		default:
+			return -EINVAL;
+		};
+	}
+
+	return 0;
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
+				   struct dvb_diseqc_master_cmd *cmd)
+{
+	/* fixme: Implement diseqc */
+	printk("%s: No support yet\n",__FUNCTION__);
+
+	return -ENOTSUPP;
+}
+
+static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	int sync = cx24123_readreg(state, 0x14);
+	int lock = cx24123_readreg(state, 0x20);
+
+	*status = 0;
+	if (lock & 0x01)
+		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+	if (sync & 0x04)
+		*status |= FE_HAS_VITERBI;
+	if (sync & 0x08)
+		*status |= FE_HAS_CARRIER;
+	if (sync & 0x80)
+		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+	return 0;
+}
+
+/*
+ * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
+ * is available, so this value doubles up to satisfy both measurements
+ */
+static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	state->lastber =
+		((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+		(cx24123_readreg(state, 0x1d) << 8 |
+		cx24123_readreg(state, 0x1e));
+
+	/* Do the signal quality processing here, it's derived from the BER. */
+	/* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
+	if (state->lastber < 5000)
+		state->snr = 655*100;
+	else if ( (state->lastber >=   5000) && (state->lastber <  55000) )
+		state->snr = 655*90;
+	else if ( (state->lastber >=  55000) && (state->lastber < 150000) )
+		state->snr = 655*80;
+	else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
+		state->snr = 655*70;
+	else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
+		state->snr = 655*65;
+	else
+		state->snr = 0;
+
+	*ber = state->lastber;
+
+	return 0;
+}
+
+static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+
+	return 0;
+}
+
+static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	*snr = state->snr;
+
+	return 0;
+}
+
+static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	*ucblocks = state->lastber;
+
+	return 0;
+}
+
+static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	state->currentfreq=p->frequency;
+	state->currentsymbolrate = p->u.qpsk.symbol_rate;
+
+	cx24123_set_inversion(state, p->inversion);
+	cx24123_set_fec(state, p->u.qpsk.fec_inner);
+	cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+	cx24123_pll_tune(fe, p);
+
+	/* Enable automatic aquisition and reset cycle */
+	cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
+	cx24123_writereg(state, 0x00, 0x10);
+	cx24123_writereg(state, 0x00, 0);
+
+	return 0;
+}
+
+static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+
+	if (cx24123_get_inversion(state, &p->inversion) != 0) {
+		printk("%s: Failed to get inversion status\n",__FUNCTION__);
+		return -EREMOTEIO;
+	}
+	if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+		printk("%s: Failed to get fec status\n",__FUNCTION__);
+		return -EREMOTEIO;
+	}
+	p->frequency = state->currentfreq;
+	p->u.qpsk.symbol_rate = state->currentsymbolrate;
+
+	return 0;
+}
+
+static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct cx24123_state *state = fe->demodulator_priv;
+	u8 val;
+
+	switch (state->config->use_isl6421) {
+	case 1:
+
+		val = cx24123_readlnbreg(state, 0x0);
+
+		switch (tone) {
+		case SEC_TONE_ON:
+			return cx24123_writelnbreg(state, 0x0, val | 0x10);
+		case SEC_TONE_OFF:
+			return cx24123_writelnbreg(state, 0x0, val & 0x2f);
+		default:
+			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+			return -EINVAL;
+		}
+
+	case 0:
+
+		val = cx24123_readreg(state, 0x29);
+
+		switch (tone) {
+		case SEC_TONE_ON:
+			dprintk("%s: setting tone on\n", __FUNCTION__);
+			return cx24123_writereg(state, 0x29, val | 0x10);
+		case SEC_TONE_OFF:
+			dprintk("%s: setting tone off\n",__FUNCTION__);
+			return cx24123_writereg(state, 0x29, val & 0xef);
+		default:
+			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void cx24123_release(struct dvb_frontend* fe)
+{
+	struct cx24123_state* state = fe->demodulator_priv;
+	dprintk("%s\n",__FUNCTION__);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops cx24123_ops;
+
+struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct cx24123_state* state = NULL;
+	int ret;
+
+	dprintk("%s\n",__FUNCTION__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk("Unable to kmalloc\n");
+		goto error;
+	}
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
+	state->lastber = 0;
+	state->snr = 0;
+	state->lnbreg = 0;
+	state->VCAarg = 0;
+	state->VGAarg = 0;
+	state->bandselectarg = 0;
+	state->pllarg = 0;
+	state->currentfreq = 0;
+	state->currentsymbolrate = 0;
+
+	/* check if the demod is there */
+	ret = cx24123_readreg(state, 0x00);
+	if ((ret != 0xd1) && (ret != 0xe1)) {
+		printk("Version != d1 or e1\n");
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+
+static struct dvb_frontend_ops cx24123_ops = {
+
+	.info = {
+		.name = "Conexant CX24123/CX24109",
+		.type = FE_QPSK,
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 29500,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = cx24123_release,
+
+	.init = cx24123_initfe,
+	.set_frontend = cx24123_set_frontend,
+	.get_frontend = cx24123_get_frontend,
+	.read_status = cx24123_read_status,
+	.read_ber = cx24123_read_ber,
+	.read_signal_strength = cx24123_read_signal_strength,
+	.read_snr = cx24123_read_snr,
+	.read_ucblocks = cx24123_read_ucblocks,
+	.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+	.set_tone = cx24123_set_tone,
+	.set_voltage = cx24123_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24123_attach);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
new file mode 100644
index 0000000..0c922b5
--- /dev/null
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -0,0 +1,51 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 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 CX24123_H
+#define CX24123_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24123_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/*
+	   cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
+	   for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
+	   from register 0x29 of the CX24123 demodulator
+	*/
+	int use_isl6421;
+
+	/* PLL maintenance */
+	int (*pll_init)(struct dvb_frontend* fe);
+	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+	/* Need to set device param for start_dma */
+	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+	void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
+};
+
+extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+					   struct i2c_adapter* i2c);
+
+#endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index f857b86..a3d57ce 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -107,18 +107,19 @@
 };
 EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
-	.name  = "Thomson dtt7611",
-	.min   =  44000000,
-	.max   = 958000000,
+struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+	/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+	.name  = "Thomson dtt761x",
+	.min   =  57000000,
+	.max   = 863000000,
 	.count = 3,
 	.entries = {
-		{ 157250000, 44000000, 62500, 0x8e, 0x39 },
-		{ 454000000, 44000000, 62500, 0x8e, 0x3a },
+		{ 147000000, 44000000, 62500, 0x8e, 0x39 },
+		{ 417000000, 44000000, 62500, 0x8e, 0x3a },
 		{ 999999999, 44000000, 62500, 0x8e, 0x3c },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
 struct dvb_pll_desc dvb_pll_unknown_1 = {
 	.name  = "unknown 1", /* used by dntv live dvb-t */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 497d31d..24d4d2e 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -25,7 +25,7 @@
 extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
 extern struct dvb_pll_desc dvb_pll_lg_z201;
 extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7611;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
 extern struct dvb_pll_desc dvb_pll_unknown_1;
 
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index cb5301865..9d21464 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -27,6 +27,7 @@
  *   DViCO FusionHDTV 3 Gold-T
  *   DViCO FusionHDTV 5 Gold
  *   DViCO FusionHDTV 5 Lite
+ *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *
  * TODO:
@@ -402,6 +403,8 @@
 		state->config->pll_set(fe, param);
 
 	/* Keep track of the new frequency */
+	/* FIXME this is the wrong way to do this...           */
+	/* The tuner is shared with the video4linux analog API */
 	state->current_frequency = param->frequency;
 
 	lgdt330x_SwReset(state);
diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c
index 52c4160..4f263e6 100644
--- a/drivers/media/dvb/frontends/nxt2002.c
+++ b/drivers/media/dvb/frontends/nxt2002.c
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
 #define CRC_CCIT_MASK 0x1021
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a458a3b..a16eeba 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -574,11 +574,11 @@
 		.symbol_rate_max = 9360000,	/* FIXME */
 		.symbol_rate_tolerance = 4000,
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		        FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-		        FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-		        FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		        FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		        FE_CAN_HIERARCHY_AUTO,
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
 	},
 
 	.release = nxt6000_release,
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 531f762..7c3aed1 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -25,7 +25,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
 
@@ -112,7 +113,7 @@
 	u8 tudata[585];
 	int i;
 
-	dprintk("Firmware is %d bytes\n",fw->size);
+	dprintk("Firmware is %zd bytes\n",fw->size);
 
 	/* Get eprom data */
 	tudata[0] = 17;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 1871509..d694775 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -521,8 +521,8 @@
 
 		case FEC_3_4:
 			s5h1420_writereg(state, 0x30, 0x04);
-		        s5h1420_writereg(state, 0x31, 0x12 | inversion);
-		        break;
+			s5h1420_writereg(state, 0x31, 0x12 | inversion);
+			break;
 
 		case FEC_5_6:
 			s5h1420_writereg(state, 0x30, 0x08);
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index fc06cd6..73829e6 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
 
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index e3b6657..eb8a602 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -5,7 +5,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
@@ -581,7 +582,7 @@
 		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-		        FE_CAN_RECOVER
+			FE_CAN_RECOVER
 	},
 
 	.release = sp887x_release,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 177d71d..5bcd00f 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -131,6 +131,13 @@
 	return ret == 2 ? 0 : ret;
 }
 
+int stv0299_enable_plli2c (struct dvb_frontend* fe)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	return stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
+}
+
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
 	dprintk ("%s\n", __FUNCTION__);
@@ -387,7 +394,7 @@
 	};
 }
 
-static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
 {
 	struct stv0299_state* state = fe->demodulator_priv;
 	u8 reg0x08;
@@ -407,7 +414,7 @@
 
 	cmd = cmd << 1;
 	if (debug_legacy_dish_switch)
-		printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+		printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
 
 	do_gettimeofday (&nexttime);
 	if (debug_legacy_dish_switch)
@@ -717,5 +724,6 @@
 	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
 MODULE_LICENSE("GPL");
 
+EXPORT_SYMBOL(stv0299_enable_plli2c);
 EXPORT_SYMBOL(stv0299_writereg);
 EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 9af3d71..32c87b4 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -94,6 +94,7 @@
 };
 
 extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
 
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
 					   struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 425cd19..21255ca 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -95,7 +95,7 @@
 	u8 b0 [] = { reg };
 	u8 b1 [] = { 0 };
 	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-		                  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 	int ret;
 
 	ret = i2c_transfer (state->i2c, msg, 2);
@@ -434,7 +434,7 @@
 		.frequency_max = 858000000,
 		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
 		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
-	#if 0
+#if 0
 		.frequency_tolerance = ???,
 		.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
 	#endif
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index dd02aff..c63e9a5 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -23,7 +23,8 @@
  * This driver needs external firmware. Please use the commands
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
 #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
@@ -271,32 +272,57 @@
 static int tda10046h_set_bandwidth(struct tda1004x_state *state,
 				   fe_bandwidth_t bandwidth)
 {
-	static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
-	static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
-	static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
+	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
+	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
+	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
 
+	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
+	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
+	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
+	int tda10046_clk53m;
+
+	if ((state->config->if_freq == TDA10046_FREQ_045) ||
+	    (state->config->if_freq == TDA10046_FREQ_052))
+		tda10046_clk53m = 0;
+	else
+		tda10046_clk53m = 1;
 	switch (bandwidth) {
 	case BANDWIDTH_6_MHZ:
-		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
+						  sizeof(bandwidth_6mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
+						  sizeof(bandwidth_6mhz_48M));
 		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
 		}
 		break;
 
 	case BANDWIDTH_7_MHZ:
-		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
+						  sizeof(bandwidth_7mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
+						  sizeof(bandwidth_7mhz_48M));
 		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
 		}
 		break;
 
 	case BANDWIDTH_8_MHZ:
-		tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+		if (tda10046_clk53m)
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
+						  sizeof(bandwidth_8mhz_53M));
+		else
+			tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
+						  sizeof(bandwidth_8mhz_48M));
 		if (state->config->if_freq == TDA10046_FREQ_045) {
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+			tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
 		}
 		break;
 
@@ -418,9 +444,22 @@
 static void tda10046_init_plls(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
+	int tda10046_clk53m;
+
+	if ((state->config->if_freq == TDA10046_FREQ_045) ||
+	    (state->config->if_freq == TDA10046_FREQ_052))
+		tda10046_clk53m = 0;
+	else
+		tda10046_clk53m = 1;
 
 	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
+	if(tda10046_clk53m) {
+		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
+	} else {
+		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
+		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
+	}
 	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
 		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -428,26 +467,32 @@
 		dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
 		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
 	}
-	tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+	if(tda10046_clk53m)
+		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
+	else
+		tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
+	/* Note clock frequency is handled implicitly */
 	switch (state->config->if_freq) {
-	case TDA10046_FREQ_3617:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
-		break;
-	case TDA10046_FREQ_3613:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
-		break;
 	case TDA10046_FREQ_045:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
 		break;
 	case TDA10046_FREQ_052:
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
-		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
+		break;
+	case TDA10046_FREQ_3617:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
+		break;
+	case TDA10046_FREQ_3613:
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+		tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
 		break;
 	}
 	tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+	/* let the PLLs settle */
+	msleep(120);
 }
 
 static int tda10046_fwupload(struct dvb_frontend* fe)
@@ -462,13 +507,13 @@
 	/* let the clocks recover from sleep */
 	msleep(5);
 
+	/* The PLLs need to be reprogrammed after sleep */
+	tda10046_init_plls(fe);
+
 	/* don't re-upload unless necessary */
 	if (tda1004x_check_upload_ok(state) == 0)
 		return 0;
 
-	/* set parameters */
-	tda10046_init_plls(fe);
-
 	if (state->config->request_firmware != NULL) {
 		/* request the firmware, this will block until someone uploads it */
 		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
@@ -484,7 +529,6 @@
 			return ret;
 	} else {
 		/* boot from firmware eeprom */
-		/* Hac Note: we might need to do some GPIO Magic here */
 		printk(KERN_INFO "tda1004x: booting from eeprom\n");
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
 		msleep(300);
@@ -606,10 +650,9 @@
 
 	// tda setup
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-	tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
-	tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
+	tda1004x_write_byteI(state, TDA1004X_CONFC1, 8);      // disable pulse killer
 
-	tda10046_init_plls(fe);
 	switch (state->config->agc_config) {
 	case TDA10046_AGC_DEFAULT:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
@@ -626,25 +669,22 @@
 	case TDA10046_AGC_TDA827X:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
 		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
 		break;
 	}
+	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
 	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
-	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+	tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
 	tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
 	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
-	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
-	tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
-	tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
-
 	state->initialised = 1;
 	return 0;
 }
@@ -686,9 +726,9 @@
 
 	// Set standard params.. or put them to auto
 	if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
-	    (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
-	    (fe_params->u.ofdm.constellation == QAM_AUTO) ||
-	    (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+		(fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+		(fe_params->u.ofdm.constellation == QAM_AUTO) ||
+		(fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
 		tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);	// enable auto
 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0);	// turn off constellation bits
 		tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
@@ -851,6 +891,7 @@
 static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
+
 	dprintk("%s\n", __FUNCTION__);
 
 	// inversion status
@@ -875,16 +916,18 @@
 			break;
 		}
 		break;
-
 	case TDA1004X_DEMOD_TDA10046:
 		switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
-		case 0x60:
+		case 0x5c:
+		case 0x54:
 			fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
 			break;
-		case 0x6e:
+		case 0x6a:
+		case 0x60:
 			fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
 			break;
-		case 0x80:
+		case 0x7b:
+		case 0x70:
 			fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
 			break;
 		}
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
index f02842b..84f8f9f 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -8,7 +8,7 @@
 	  Support for PCI cards based on the Pluto2 FPGA like the Satelco
 	  Easywatch Mobile Terrestrial DVB-T Receiver.
 
-          Since these cards have no MPEG decoder onboard, they transmit
+	  Since these cards have no MPEG decoder onboard, they transmit
 	  only compressed MPEG data over the PCI bus, so you need
 	  an external software decoder to watch TV on your computer.
 
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index fa5034a..5b2aadb 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -18,9 +18,10 @@
 	  This driver only supports the fullfeatured cards with
 	  onboard MPEG2 decoder.
 
-          This driver needs an external firmware. Please use the script
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
-          download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+	  This driver needs an external firmware. Please use the script
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 	  Say Y if you own such a card and want to use it.
 
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index 825ab1c..a690730 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -16,7 +16,7 @@
 hostprogs-y	:= fdump
 
 ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h 
+$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
 
 $(obj)/av7110_firm.h:
 	$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 7dae91e..8ce4146 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -133,7 +133,13 @@
 	/* remaining inits according to card and frontend type */
 	av7110->analog_tuner_flags = 0;
 	av7110->current_input = 0;
-	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
+		printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_MSP34x5;
+		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
+	}
+	else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
 		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
 			av7110->dvb_adapter.num);
 		av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -156,10 +162,10 @@
 	else {
 		av7110->adac_type = adac;
 		printk("dvb-ttpci: adac type set to %d @ card %d\n",
-			av7110->dvb_adapter.num, av7110->adac_type);
+			av7110->adac_type, av7110->dvb_adapter.num);
 	}
 
-	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
+	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
 		// switch DVB SCART on
 		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
 		if (ret < 0)
@@ -190,19 +196,17 @@
 
 	av7110_bootarm(av7110);
 	msleep(100);
+
+	init_av7110_av(av7110);
+
+	/* card-specific recovery */
+	if (av7110->recover)
+		av7110->recover(av7110);
+
 	restart_feeds(av7110);
 	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
 
-static void arm_error(struct av7110 *av7110)
-{
-	dprintk(4, "%p\n",av7110);
-
-	av7110->arm_errors++;
-	av7110->arm_ready = 0;
-	recover_arm(av7110);
-}
-
 static void av7110_arm_sync(struct av7110 *av7110)
 {
 	av7110->arm_rmmod = 1;
@@ -240,26 +244,22 @@
 
 		if (down_interruptible(&av7110->dcomlock))
 			break;
-
 		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
 		up(&av7110->dcomlock);
 
-		if (newloops == av7110->arm_loops) {
+		if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
 			printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
 			       av7110->dvb_adapter.num);
 
-			arm_error(av7110);
-			av7710_set_video_mode(av7110, vidmode);
-
-			init_av7110_av(av7110);
+			recover_arm(av7110);
 
 			if (down_interruptible(&av7110->dcomlock))
 				break;
-
 			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
 			up(&av7110->dcomlock);
 		}
 		av7110->arm_loops = newloops;
+		av7110->arm_errors = 0;
 	}
 
 	av7110->arm_thread = NULL;
@@ -510,10 +510,6 @@
 		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
 
 		av7110->video_size.h = h_ar & 0xfff;
-		dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
-			av7110->video_size.w,
-			av7110->video_size.h,
-			av7110->video_size.aspect_ratio);
 
 		event.type = VIDEO_EVENT_SIZE_CHANGED;
 		event.u.size.w = av7110->video_size.w;
@@ -535,6 +531,11 @@
 			event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
 			av7110->videostate.video_format = VIDEO_FORMAT_4_3;
 		}
+
+		dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
+			av7110->video_size.w, av7110->video_size.h,
+			av7110->video_size.aspect_ratio);
+
 		dvb_video_add_event(av7110, &event);
 		break;
 	}
@@ -714,6 +715,8 @@
 static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 			  u16 subpid, u16 pcrpid)
 {
+	u16 aflags = 0;
+
 	dprintk(4, "%p\n", av7110);
 
 	if (vpid == 0x1fff || apid == 0x1fff ||
@@ -725,8 +728,11 @@
 		av7110->pids[DMX_PES_PCR] = 0;
 	}
 
-	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5,
-			     pcrpid, vpid, apid, ttpid, subpid);
+	if (av7110->audiostate.bypass_mode)
+		aflags |= 0x8000;
+
+	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
+			     pcrpid, vpid, apid, ttpid, subpid, aflags);
 }
 
 int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
@@ -1043,7 +1049,7 @@
 	struct dvb_demux *dvbdmx = &av7110->demux;
 	struct dvb_demux_feed *feed;
 	int mode;
-	int i;
+	int i, j;
 
 	dprintk(4, "%p\n", av7110);
 
@@ -1051,10 +1057,21 @@
 	av7110->playing = 0;
 	av7110->rec_mode = 0;
 
-	for (i = 0; i < dvbdmx->filternum; i++) {
+	for (i = 0; i < dvbdmx->feednum; i++) {
 		feed = &dvbdmx->feed[i];
-		if (feed->state == DMX_STATE_GO)
+		if (feed->state == DMX_STATE_GO) {
+			if (feed->type == DMX_TYPE_SEC) {
+				for (j = 0; j < dvbdmx->filternum; j++) {
+					if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
+						continue;
+					if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
+						continue;
+					if (dvbdmx->filter[j].state == DMX_STATE_GO)
+						dvbdmx->filter[j].state = DMX_STATE_READY;
+				}
+			}
 			av7110_start_feed(feed);
+		}
 	}
 
 	if (mode)
@@ -1483,9 +1500,9 @@
 		if (ret == -ENOENT) {
 			printk(KERN_ERR "dvb-ttpci: could not load firmware,"
 			       " file not found: dvb-ttpci-01.fw\n");
-			printk(KERN_ERR "dvb-ttpci: usually this should be in"
-			       " /usr/lib/hotplug/firmware\n");
-			printk(KERN_ERR "dvb-ttpci: and can be downloaded here"
+			printk(KERN_ERR "dvb-ttpci: usually this should be in "
+			       "/usr/lib/hotplug/firmware or /lib/firmware\n");
+			printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
 			       " http://www.linuxtv.org/download/dvb/firmware/\n");
 		} else
 			printk(KERN_ERR "dvb-ttpci: cannot request firmware"
@@ -2110,8 +2127,10 @@
 	struct av7110* av7110 = fe->dvb->priv;
 
 	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
+	if (!ret) {
+		av7110->saved_fe_params = *params;
 		ret = av7110->fe_set_frontend(fe, params);
+	}
 	return ret;
 }
 
@@ -2153,8 +2172,10 @@
 	struct av7110* av7110 = fe->dvb->priv;
 
 	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
+	if (!ret) {
+		av7110->saved_master_cmd = *cmd;
 		ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+	}
 	return ret;
 }
 
@@ -2163,8 +2184,10 @@
 	struct av7110* av7110 = fe->dvb->priv;
 
 	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
+	if (!ret) {
+		av7110->saved_minicmd = minicmd;
 		ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+	}
 	return ret;
 }
 
@@ -2173,8 +2196,10 @@
 	struct av7110* av7110 = fe->dvb->priv;
 
 	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
+	if (!ret) {
+		av7110->saved_tone = tone;
 		ret = av7110->fe_set_tone(fe, tone);
+	}
 	return ret;
 }
 
@@ -2183,12 +2208,14 @@
 	struct av7110* av7110 = fe->dvb->priv;
 
 	int ret = av7110_fe_lock_fix(av7110, 0);
-	if (!ret)
+	if (!ret) {
+		av7110->saved_voltage = voltage;
 		ret = av7110->fe_set_voltage(fe, voltage);
+	}
 	return ret;
 }
 
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 
@@ -2198,6 +2225,23 @@
 	return ret;
 }
 
+static void dvb_s_recover(struct av7110* av7110)
+{
+	av7110_fe_init(av7110->fe);
+
+	av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
+	if (av7110->saved_master_cmd.msg_len) {
+		msleep(20);
+		av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
+	}
+	msleep(20);
+	av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
+	msleep(20);
+	av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
+
+	av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+}
+
 static u8 read_pwm(struct av7110* av7110)
 {
 	u8 b = 0xff;
@@ -2235,6 +2279,7 @@
 				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
 				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
 				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
 				break;
 			}
 
@@ -2244,15 +2289,17 @@
 				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
 				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
 				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
 				break;
 			}
 
 			// Try the grundig 29504-451
-		        av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
 				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
 				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
 				break;
 			}
 
@@ -2274,12 +2321,12 @@
 		case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
 
 			// ALPS TDLB7
-		        av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+			av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
 			break;
 
 		case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
 
-		        av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+			av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
 			break;
 
 		case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
@@ -2289,6 +2336,7 @@
 				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
 				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
 				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->recover = dvb_s_recover;
 			}
 			break;
 
@@ -2314,8 +2362,11 @@
 		case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
 			/* ALPS BSBE1 */
 			av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
-			if (av7110->fe)
+			if (av7110->fe) {
 				av7110->fe->ops->set_voltage = lnbp21_set_voltage;
+				av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+				av7110->recover = dvb_s_recover;
+			}
 			break;
 		}
 	}
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index cce00ef..6ea30df 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -98,7 +98,8 @@
 	int adac_type;	       /* audio DAC type */
 #define DVB_ADAC_TI	  0
 #define DVB_ADAC_CRYSTAL  1
-#define DVB_ADAC_MSP	  2
+#define DVB_ADAC_MSP34x0  2
+#define DVB_ADAC_MSP34x5  3
 #define DVB_ADAC_NONE	 -1
 
 
@@ -228,6 +229,9 @@
 	struct dvb_video_events  video_events;
 	video_size_t		 video_size;
 
+	u16			wssMode;
+	u16			wssData;
+
 	u32			ir_config;
 	u32			ir_command;
 	void			(*ir_handler)(struct av7110 *av7110, u32 ircom);
@@ -245,6 +249,15 @@
 
 	struct dvb_frontend* fe;
 	fe_status_t fe_status;
+
+	/* crash recovery */
+	void				(*recover)(struct av7110* av7110);
+	struct dvb_frontend_parameters	saved_fe_params;
+	fe_sec_voltage_t		saved_voltage;
+	fe_sec_tone_mode_t		saved_tone;
+	struct dvb_diseqc_master_cmd	saved_master_cmd;
+	fe_sec_mini_cmd_t		saved_minicmd;
+
 	int (*fe_init)(struct dvb_frontend* fe);
 	int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
 	int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
@@ -252,7 +265,7 @@
 	int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
 	int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
 	int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-	int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+	int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
 	int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 0696a5a..400face 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -309,7 +309,7 @@
 		i2c_writereg(av7110, 0x20, 0x04, volright);
 		return 0;
 
-	case DVB_ADAC_MSP:
+	case DVB_ADAC_MSP34x0:
 		vol  = (volleft > volright) ? volleft : volright;
 		val	= (vol * 0x73 / 255) << 8;
 		if (vol > 0)
@@ -1256,7 +1256,9 @@
 		break;
 
 	case AUDIO_SET_BYPASS_MODE:
-		ret = -EINVAL;
+		if (FW_VERSION(av7110->arm_app) < 0x2621)
+			ret = -EINVAL;
+		av7110->audiostate.bypass_mode = (int)arg;
 		break;
 
 	case AUDIO_CHANNEL_SELECT:
@@ -1295,7 +1297,11 @@
 		break;
 
 	case AUDIO_GET_CAPABILITIES:
-		*(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+		if (FW_VERSION(av7110->arm_app) < 0x2621)
+			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+		else
+			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
+						AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
 		break;
 
 	case AUDIO_CLEAR_BUFFER:
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 87106e8..cb37745 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -230,6 +230,8 @@
 
 	dprintk(4, "%p\n", av7110);
 
+	av7110->arm_ready = 0;
+
 	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 
 	/* Disable DEBI and GPIO irq */
@@ -361,6 +363,7 @@
 			break;
 		if (err) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+			av7110->arm_errors++;
 			return -ETIMEDOUT;
 		}
 		msleep(1);
@@ -1206,9 +1209,9 @@
 	switch (cap->cmd) {
 	case OSD_CAP_MEMSIZE:
 		if (FW_4M_SDRAM(av7110->arm_app))
-		        cap->val = 1000000;
+			cap->val = 1000000;
 		else
-		        cap->val = 92000;
+			cap->val = 92000;
 		return 0;
 	default:
 		return -EINVAL;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 2a5e87b..84b8329 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -167,7 +167,8 @@
 	LoadVidCode,
 	SetMonitorType,
 	SetPanScanType,
-	SetFreezeMode
+	SetFreezeMode,
+	SetWSSConfig
 };
 
 enum av7110_rec_play_state {
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index f5e59fc..9138132 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -17,6 +17,8 @@
 static struct av7110 *av_list[4];
 static struct input_dev *input_dev;
 
+static u8 delay_timer_finished;
+
 static u16 key_map [256] = {
 	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
 	KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
@@ -112,13 +114,16 @@
 	if (timer_pending(&keyup_timer)) {
 		del_timer(&keyup_timer);
 		if (keyup_timer.data != keycode || new_toggle != old_toggle) {
+			delay_timer_finished = 0;
 			input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
 			input_event(input_dev, EV_KEY, keycode, !0);
 		} else
-			input_event(input_dev, EV_KEY, keycode, 2);
-
-	} else
+			if (delay_timer_finished)
+				input_event(input_dev, EV_KEY, keycode, 2);
+	} else {
+		delay_timer_finished = 0;
 		input_event(input_dev, EV_KEY, keycode, !0);
+	}
 
 	keyup_timer.expires = jiffies + UP_TIMEOUT;
 	keyup_timer.data = keycode;
@@ -145,7 +150,8 @@
 
 static void input_repeat_key(unsigned long data)
 {
-       /* dummy routine to disable autorepeat in the input driver */
+	/* called by the input driver after rep[REP_DELAY] ms */
+	delay_timer_finished = 1;
 }
 
 
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index b5aea41..94cf38c 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -490,6 +490,58 @@
 		dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
 		break;
 	}
+	case VIDIOC_G_SLICED_VBI_CAP:
+	{
+		struct v4l2_sliced_vbi_cap *cap = arg;
+		dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+		memset(cap, 0, sizeof *cap);
+		if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+			cap->service_set = V4L2_SLICED_WSS_625;
+			cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+		}
+		break;
+	}
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *f = arg;
+		dprintk(2, "VIDIOC_G_FMT:\n");
+		if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+		    FW_VERSION(av7110->arm_app) < 0x2623)
+			return -EAGAIN; /* handled by core driver */
+		memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+		if (av7110->wssMode) {
+			f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+			f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+			f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+		}
+		break;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = arg;
+		dprintk(2, "VIDIOC_S_FMT\n");
+		if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+		    FW_VERSION(av7110->arm_app) < 0x2623)
+			return -EAGAIN; /* handled by core driver */
+		if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+		    f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+			memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+			/* WSS controlled by firmware */
+			av7110->wssMode = 0;
+			av7110->wssData = 0;
+			return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+					     SetWSSConfig, 1, 0);
+		} else {
+			memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+			f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+			f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+			f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+			/* WSS controlled by userspace */
+			av7110->wssMode = 1;
+			av7110->wssData = 0;
+		}
+		break;
+	}
 	default:
 		printk("no such ioctl\n");
 		return -ENOIOCTLCMD;
@@ -497,6 +549,46 @@
 	return 0;
 }
 
+static int av7110_vbi_reset(struct inode *inode, struct file *file)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+	dprintk(2, "%s\n", __FUNCTION__);
+	av7110->wssMode = 0;
+	av7110->wssData = 0;
+	if (FW_VERSION(av7110->arm_app) < 0x2623)
+		return 0;
+	else
+		return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+	struct saa7146_fh *fh = file->private_data;
+	struct saa7146_dev *dev = fh->dev;
+	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+	struct v4l2_sliced_vbi_data d;
+	int rc;
+
+	dprintk(2, "%s\n", __FUNCTION__);
+	if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+		return -EINVAL;
+	if (copy_from_user(&d, data, count))
+		return -EFAULT;
+	if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+		return -EINVAL;
+	if (d.id) {
+		av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+		rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
+				   2, 1, av7110->wssData);
+	} else {
+		av7110->wssData = 0;
+		rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+	}
+	return (rc < 0) ? rc : count;
+}
 
 /****************************************************************************
  * INITIALIZATION
@@ -512,6 +604,9 @@
 	{ VIDIOC_S_TUNER,	SAA7146_EXCLUSIVE },
 	{ VIDIOC_G_AUDIO,	SAA7146_EXCLUSIVE },
 	{ VIDIOC_S_AUDIO,	SAA7146_EXCLUSIVE },
+	{ VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+	{ VIDIOC_G_FMT,		SAA7146_BEFORE },
+	{ VIDIOC_S_FMT,		SAA7146_BEFORE },
 	{ 0, 0 }
 };
 
@@ -587,7 +682,7 @@
 
 	printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
 		av7110->dvb_adapter.num);
-	av7110->adac_type = DVB_ADAC_MSP;
+	av7110->adac_type = DVB_ADAC_MSP34x0;
 	msleep(100); // the probing above resets the msp...
 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
@@ -692,12 +787,11 @@
 		saa7146_vv_release(dev);
 		return -ENODEV;
 	}
-	if (av7110->analog_tuner_flags) {
-		if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
-			ERR(("cannot register vbi v4l2 device. skipping.\n"));
-		} else {
+	if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+		ERR(("cannot register vbi v4l2 device. skipping.\n"));
+	} else {
+		if (av7110->analog_tuner_flags)
 			av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
-		}
 	}
 	return 0;
 }
@@ -778,7 +872,7 @@
 static struct saa7146_ext_vv av7110_vv_data_st = {
 	.inputs		= 1,
 	.audios		= 1,
-	.capabilities	= 0,
+	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT,
 	.flags		= 0,
 
 	.stds		= &standard[0],
@@ -787,12 +881,16 @@
 
 	.ioctls		= &ioctls[0],
 	.ioctl		= av7110_ioctl,
+
+	.vbi_fops.open	= av7110_vbi_reset,
+	.vbi_fops.release = av7110_vbi_reset,
+	.vbi_fops.write	= av7110_vbi_write,
 };
 
 static struct saa7146_ext_vv av7110_vv_data_c = {
 	.inputs		= 1,
 	.audios		= 1,
-	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
 	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
 
 	.stds		= &standard[0],
@@ -801,5 +899,9 @@
 
 	.ioctls		= &ioctls[0],
 	.ioctl		= av7110_ioctl,
+
+	.vbi_fops.open	= av7110_vbi_reset,
+	.vbi_fops.release = av7110_vbi_reset,
+	.vbi_fops.write	= av7110_vbi_write,
 };
 
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 9f51bae..f9d0045 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -127,7 +127,7 @@
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
 	udelay(1);
 
-	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
 
 	if (result == -ETIMEDOUT)
 		budget_av->slot_status = 0;
@@ -145,7 +145,7 @@
 	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
 	udelay(1);
 
-	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
 
 	if (result == -ETIMEDOUT)
 		budget_av->slot_status = 0;
@@ -192,7 +192,7 @@
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
-	int timeout = 500; // 5 seconds (4.4.6 Ready)
+	int timeout = 50; // 5 seconds (4.4.6 Ready)
 
 	if (slot != 0)
 		return -EINVAL;
@@ -256,19 +256,37 @@
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
+	int cam_present = 0;
 
 	if (slot != 0)
 		return -EINVAL;
 
-	if (!budget_av->slot_status) {
+	if (!budget_av->slot_status)
+	{
+		// first of all test the card detect line
 		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
 		udelay(1);
 		if (saa7146_read(saa, PSR) & MASK_06)
 		{
+			cam_present = 1;
+		}
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+		// that is unreliable however, so try and read from IO memory
+		if (!cam_present)
+		{
+			saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+			if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
+			{
+				cam_present = 1;
+			}
+		}
+
+		// did we find something?
+		if (cam_present) {
 			printk(KERN_INFO "budget-av: cam inserted\n");
 			budget_av->slot_status = 1;
 		}
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
 	} else if (!open) {
 		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
 		if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
@@ -484,6 +502,140 @@
 	return 0;
 }
 
+#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+
+static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
+					struct i2c_adapter *i2c,
+					struct dvb_frontend_parameters *params)
+{
+	u8 reg0 [2] = { 0x00, 0x00 };
+	u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+	u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+	int _fband;
+	int first_ZF;
+	int R, A, N, P, M;
+	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
+	int freq = params->frequency;
+
+	first_ZF = (freq) / 1000;
+
+	if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
+		   abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
+		_fband = 2;
+	else
+		_fband = 3;
+
+	if (_fband == 2) {
+		if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+				    ((first_ZF >= 1430) && (first_ZF < 1950)))
+			reg0[1] = 0x07;
+		else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+					 ((first_ZF >= 1950) && (first_ZF < 2150)))
+			reg0[1] = 0x0B;
+	}
+
+	if(_fband == 3) {
+		if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+				    ((first_ZF >= 1455) && (first_ZF < 1950)))
+			reg0[1] = 0x07;
+		else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+					 ((first_ZF >= 1950) && (first_ZF < 2150)))
+			reg0[1] = 0x0B;
+		else if ((first_ZF >= 1420) && (first_ZF < 1455))
+			reg0[1] = 0x0F;
+	}
+
+	if (first_ZF > 1525)
+		reg1[1] |= 0x80;
+	else
+		reg1[1] &= 0x7F;
+
+	if (_fband == 2) {
+		if (first_ZF > 1430) { /* 1430MHZ */
+			reg1[1] &= 0xCF; /* N2 */
+			reg2[1] &= 0xCF; /* R2 */
+			reg2[1] |= 0x10;
+		} else {
+			reg1[1] &= 0xCF; /* N2 */
+			reg1[1] |= 0x20;
+			reg2[1] &= 0xCF; /* R2 */
+			reg2[1] |= 0x10;
+		}
+	}
+
+	if (_fband == 3) {
+		if ((first_ZF >= 1455) &&
+				   (first_ZF < 1630)) {
+			reg1[1] &= 0xCF; /* N2 */
+			reg1[1] |= 0x20;
+			reg2[1] &= 0xCF; /* R2 */
+				   } else {
+					   if (first_ZF < 1455) {
+						   reg1[1] &= 0xCF; /* N2 */
+						   reg1[1] |= 0x20;
+						   reg2[1] &= 0xCF; /* R2 */
+						   reg2[1] |= 0x10;
+					   } else {
+						   if (first_ZF >= 1630) {
+							   reg1[1] &= 0xCF; /* N2 */
+							   reg2[1] &= 0xCF; /* R2 */
+							   reg2[1] |= 0x10;
+						   }
+					   }
+				   }
+	}
+
+	/* set ports, enable P0 for symbol rates > 4Ms/s */
+	if (params->u.qpsk.symbol_rate >= 4000000)
+		reg1[1] |= 0x0c;
+	else
+		reg1[1] |= 0x04;
+
+	reg2[1] |= 0x0c;
+
+	R = 64;
+	A = 64;
+	P = 64;	 //32
+
+	M = (freq * R) / 4;		/* in Mhz */
+	N = (M - A * 1000) / (P * 1000);
+
+	reg1[1] |= (N >> 9) & 0x03;
+	reg1[2]	 = (N >> 1) & 0xff;
+	reg1[3]	 = (N << 7) & 0x80;
+
+	reg2[1] |= (R >> 8) & 0x03;
+	reg2[2]	 = R & 0xFF;	/* R */
+
+	reg1[3] |= A & 0x7f;	/* A */
+
+	if (P == 64)
+		reg1[1] |= 0x40; /* Prescaler 64/65 */
+
+	reg0[1] |= 0x03;
+
+	/* already enabled - do not reenable i2c repeater or TX fails */
+	msg.buf = reg0;
+	msg.len = sizeof(reg0);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+
+	stv0299_enable_plli2c(fe);
+	msg.buf = reg1;
+	msg.len = sizeof(reg1);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+
+	stv0299_enable_plli2c(fe);
+	msg.buf = reg2;
+	msg.len = sizeof(reg2);
+	if (i2c_transfer(i2c, &msg, 1) != 1)
+		return -EIO;
+
+	return 0;
+}
+
 static u8 typhoon_cinergy1200s_inittab[] = {
 	0x01, 0x15,
 	0x02, 0x30,
@@ -553,6 +705,18 @@
 	.pll_set = philips_su1278_ty_ci_pll_set,
 };
 
+static struct stv0299_config cinergy_1200s_1894_0010_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+	.pll_set = philips_su1278sh2_tua6100_pll_set,
+};
 
 static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
@@ -749,6 +913,15 @@
 	switch (saa->pci->subsystem_device) {
 
 	case SUBID_DVBS_KNC1:
+		if (saa->pci->subsystem_vendor == 0x1894) {
+			fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
+					     &budget_av->budget.i2c_adap);
+		} else {
+			fe = stv0299_attach(&typhoon_config,
+					     &budget_av->budget.i2c_adap);
+		}
+		break;
+
 	case SUBID_DVBS_KNC1_PLUS:
 	case SUBID_DVBS_TYPHOON:
 		fe = stv0299_attach(&typhoon_config,
@@ -1003,6 +1176,7 @@
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
 	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
+	MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
 	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
 	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 017fcbc..633e68c 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -404,9 +404,7 @@
 	tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
 
 	/* frontend power on */
-	if (bi->type == BUDGET_FS_ACTIVY)
-		saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
-	else
+	if (bi->type != BUDGET_FS_ACTIVY)
 		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 
 	if (budget_register(budget) == 0) {
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index fafe640..238c77b 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -112,6 +112,7 @@
  *   Routines for the Fujitsu Siemens Activy budget card
  *   22 kHz tone and DiSEqC are handled by the frontend.
  *   Voltage must be set here.
+ *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
  */
 static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
 {
@@ -121,11 +122,16 @@
 
 	switch (voltage) {
 		case SEC_VOLTAGE_13:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
 			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
 			break;
 		case SEC_VOLTAGE_18:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
 			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 			break;
+		case SEC_VOLTAGE_OFF:
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);
+			break;
 		default:
 			return -EINVAL;
 	}
@@ -206,7 +212,7 @@
 	return 0;
 }
 
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u8 buf;
@@ -580,6 +586,7 @@
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
 			budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
 			if (lnbp21_init(budget)) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
 				goto error_out;
@@ -624,7 +631,7 @@
 		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-			break;
+			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
 		}
 		break;
 
@@ -632,7 +639,7 @@
 		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-			break;
+			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
 		}
 		break;
 
diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c
index 18aa22b..1f31e91 100644
--- a/drivers/media/dvb/ttpci/ttpci-eeprom.c
+++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c
@@ -13,7 +13,7 @@
     Holger Waechtler	Convergence
 
     Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de>
-		            Metzler Brothers Systementwicklung GbR
+			    Metzler Brothers Systementwicklung GbR
 
     This 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/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index c6c1d41..914587d 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -10,7 +10,7 @@
 	  Support for external USB adapters designed by Technotrend and
 	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
 
-          These devices don't have a MPEG decoder built in, so you need
+	  These devices don't have a MPEG decoder built in, so you need
 	  an external software decoder to watch TV.
 
 	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index c334526..8361101 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -8,14 +8,15 @@
 	  produced by Hauppauge, shipped under the brand name 'DEC2000-t'
 	  and 'DEC3000-s'.
 
-          Even if these devices have a MPEG decoder built in, they transmit
+	  Even if these devices have a MPEG decoder built in, they transmit
 	  only compressed MPEG data over the USB bus, so you need
 	  an external software decoder to watch TV on your computer.
 
-          This driver needs external firmware. Please use the commands
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
-          download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware
+	  or /lib/firmware (depending on configuration of firmware hotplug).
 
 	  Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 8abc218..d8966d1 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -369,7 +369,7 @@
 
 static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
 {
-	struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+	struct ttusb_dec *dec = priv;
 
 	dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
 				       &dec->audio_filter->feed->feed.ts,
@@ -380,7 +380,7 @@
 
 static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
 {
-	struct ttusb_dec *dec = (struct ttusb_dec *)priv;
+	struct ttusb_dec *dec = priv;
 
 	dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
 				       &dec->video_filter->feed->feed.ts,
@@ -965,8 +965,8 @@
 
 	case DMX_TS_PES_TELETEXT:
 		dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
-		dprintk("  pes_type: DMX_TS_PES_TELETEXT\n");
-		break;
+		dprintk("  pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
+		return -ENOSYS;
 
 	case DMX_TS_PES_PCR:
 		dprintk("  pes_type: DMX_TS_PES_PCR\n");
@@ -975,8 +975,8 @@
 		break;
 
 	case DMX_TS_PES_OTHER:
-		dprintk("  pes_type: DMX_TS_PES_OTHER\n");
-		break;
+		dprintk("  pes_type: DMX_TS_PES_OTHER(not supported)\n");
+		return -ENOSYS;
 
 	default:
 		dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
@@ -1182,7 +1182,7 @@
 		     (unsigned long)dec);
 }
 
-static int ttusb_init_rc(struct ttusb_dec *dec)
+static int ttusb_init_rc( struct ttusb_dec *dec)
 {
 	struct input_dev *input_dev;
 	u8 b[] = { 0x00, 0x01 };
@@ -1203,13 +1203,12 @@
 	input_dev->keycode = rc_keys;
 
 	for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
-		set_bit(rc_keys[i], input_dev->keybit);
+		  set_bit(rc_keys[i], input_dev->keybit);
 
 	input_register_device(input_dev);
 
 	if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
 		printk("%s: usb_submit_urb failed\n",__FUNCTION__);
-
 	/* enable irq pipe */
 	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
 
@@ -1395,6 +1394,7 @@
 			/* We can't trust the USB IDs that some firmwares
 			   give the box */
 			switch (model) {
+			case 0x00070001:
 			case 0x00070008:
 			case 0x0007000c:
 				ttusb_dec_set_model(dec, TTUSB_DEC3000S);
@@ -1588,7 +1588,7 @@
 			   int param_length, const u8 params[],
 			   int *result_length, u8 cmd_result[])
 {
-	struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
+	struct ttusb_dec* dec = fe->dvb->priv;
 	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
 }
 
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 725af3a..a5a4617 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -42,8 +42,39 @@
 
 static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
-	*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-		  FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+	struct ttusbdecfe_state* state = fe->demodulator_priv;
+	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00 };
+	u8 result[4];
+	int len, ret;
+
+	*status=0;
+
+	ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
+	if(ret)
+		return ret;
+
+	if(len != 4) {
+		printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	switch(result[3]) {
+		case 1:  /* not tuned yet */
+		case 2:  /* no signal/no lock*/
+			break;
+		case 3:	 /* signal found and locked*/
+			*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+			FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+			break;
+		case 4:
+			*status = FE_TIMEDOUT;
+			break;
+		default:
+			pr_info("%s: returned unknown value: %d\n",
+				__FUNCTION__, result[3]);
+			return -EIO;
+	}
 
 	return 0;
 }
@@ -64,6 +95,16 @@
 	return 0;
 }
 
+static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
+					struct dvb_frontend_tune_settings* fesettings)
+{
+		fesettings->min_delay_ms = 1500;
+		/* Drift compensation makes no sense for DVB-T */
+		fesettings->step_size = 0;
+		fesettings->max_drift = 0;
+		return 0;
+}
+
 static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
 	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
@@ -212,6 +253,8 @@
 
 	.set_frontend = ttusbdecfe_dvbt_set_frontend,
 
+	.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
+
 	.read_status = ttusbdecfe_read_status,
 };
 
@@ -223,11 +266,11 @@
 		.frequency_min		= 950000,
 		.frequency_max		= 2150000,
 		.frequency_stepsize	= 125,
+		.symbol_rate_min        = 1000000,  /* guessed */
+		.symbol_rate_max        = 45000000, /* guessed */
 		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-			FE_CAN_HIERARCHY_AUTO,
+			FE_CAN_QPSK
 	},
 
 	.release = ttusbdecfe_release,
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index c2ebe87..dc292da 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -220,6 +220,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= pcm20_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 877c770..914deab 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -299,6 +299,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl	        = rt_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 5319a9c..523be82 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -256,6 +256,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= az_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 9b04063..f1b5ac8 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -490,6 +490,7 @@
 	.release       	= cadet_release,
 	.read		= cadet_read,
 	.ioctl		= cadet_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 630cc78..42c8fce 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -301,6 +301,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= gemtek_pci_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 6418f03..47173be 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -233,6 +233,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= gemtek_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index e5e2021..c30effd 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -72,6 +72,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= radio_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 02d39a5..3086930 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -80,6 +80,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl	        = radio_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 static struct video_device maxiradio_radio =
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b2256d6..28a47c9 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -199,6 +199,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= rt_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 6f03ce4..0229f79 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -225,6 +225,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= fmi_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 71971e9..26632ce 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -356,6 +356,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = fmr2_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index b03573c..fcfde2e 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -276,6 +276,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= tt_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index b300bed..5a099a5 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -255,6 +255,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= tr_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index f304f3c..8ac9a8e 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -261,6 +261,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= typhoon_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 4c6d6fb..d590e80 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -313,6 +313,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl		= zol_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fc87efc..2fe260f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,6 +7,15 @@
 
 comment "Video Adapters"
 
+config VIDEO_ADV_DEBUG
+	bool "Enable advanced debug functionality"
+	depends on VIDEO_DEV
+	default n
+	---help---
+	  Say Y here to enable advanced debugging functionality on some
+	  V4L devices.
+	  In doubt, say N.
+
 config VIDEO_BT848
 	tristate "BT848 Video For Linux"
 	depends on VIDEO_DEV && PCI && I2C
@@ -342,6 +351,6 @@
 	depends on VIDEO_DEV && I2C && EXPERIMENTAL
 	---help---
 	  Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
-	  video  decoders.
+	  video decoders.
 
 endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 82060f9..dd24896 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -3,15 +3,19 @@
 #
 
 bttv-objs	:=	bttv-driver.o bttv-cards.o bttv-if.o \
-			bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
+			bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+			bttv-input.o
 zoran-objs      :=	zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
+
+msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
-	tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o
+	tda7432.o tda9875.o ir-kbd-i2c.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 881cdcb..7d5a068 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -749,6 +749,7 @@
 	.release	= video_exclusive_release,
 	.read		= ar_read,
 	.ioctl		= ar_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek		= no_llseek,
 };
 
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 1c3ff5f..dda4aa6 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -30,8 +30,9 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
 #include "bttv.h"
 #include "bt832.h"
 
@@ -42,9 +43,10 @@
 				       I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
-/* ---------------------------------------------------------------------- */
+int debug    = 0;    /* debug output */
+module_param(debug,            int, 0644);
 
-#define dprintk     if (debug) printk
+/* ---------------------------------------------------------------------- */
 
 static int bt832_detach(struct i2c_client *client);
 
@@ -61,23 +63,26 @@
 	int i,rc;
 	buf[0]=0x80; // start at register 0 with auto-increment
 	if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-		printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
 
 	for(i=0;i<65;i++)
 		buf[i]=0;
 	if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-		printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
 
 	// Note: On READ the first byte is the current index
 	//  (e.g. 0x80, what we just wrote)
 
-	if(1) {
+	if(debug>1) {
 		int i;
-		printk("BT832 hexdump:\n");
+		v4l_dbg(2,i2c_client_s,"hexdump:");
 		for(i=1;i<65;i++) {
 			if(i!=1) {
-			  if(((i-1)%8)==0) printk(" ");
-			  if(((i-1)%16)==0) printk("\n");
+				if(((i-1)%8)==0) printk(" ");
+				if(((i-1)%16)==0) {
+					printk("\n");
+					v4l_dbg(2,i2c_client_s,"hexdump:");
+				}
 			}
 			printk(" %02x",buf[i]);
 		}
@@ -96,56 +101,56 @@
 	bt832_hexdump(i2c_client_s,buf);
 
 	if(buf[0x40] != 0x31) {
-		printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+		v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
 		kfree(buf);
 		return 0;
 	}
 
-	printk("Write 0 tp VPSTATUS\n");
+	v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
 	buf[0]=BT832_VP_STATUS; // Reg.52
 	buf[1]= 0x00;
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
 	bt832_hexdump(i2c_client_s,buf);
 
 
 	// Leave low power mode:
-	printk("Bt832: leave low power mode.\n");
+	v4l_err(i2c_client_s,"leave low power mode.\n");
 	buf[0]=BT832_CAM_SETUP0; //0x39 57
 	buf[1]=0x08;
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-		printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
 
 	bt832_hexdump(i2c_client_s,buf);
 
-	printk("Write 0 tp VPSTATUS\n");
+	v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
 	buf[0]=BT832_VP_STATUS; // Reg.52
 	buf[1]= 0x00;
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
 	bt832_hexdump(i2c_client_s,buf);
 
 
 	// Enable Output
-	printk("Enable Output\n");
+	v4l_info(i2c_client_s,"Enable Output\n");
 	buf[0]=BT832_VP_CONTROL1; // Reg.40
 	buf[1]= 0x27 & (~0x01); // Default | !skip
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-		printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+		v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
 
 	bt832_hexdump(i2c_client_s,buf);
 
 
 	// for testing (even works when no camera attached)
-	printk("bt832: *** Generate NTSC M Bars *****\n");
+	v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
 	buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
 	buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
 	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-		printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+		v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
 
-	printk("Bt832: Camera Present: %s\n",
+	v4l_info(i2c_client_s,"Camera Present: %s\n",
 		(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
 
 	bt832_hexdump(i2c_client_s,buf);
@@ -159,13 +164,9 @@
 {
 	struct bt832 *t;
 
-	printk("bt832_attach\n");
-
 	client_template.adapter = adap;
 	client_template.addr    = addr;
 
-	printk("bt832: chip found @ 0x%x\n", addr<<1);
-
 	if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(t,0,sizeof(*t));
@@ -173,6 +174,9 @@
 	i2c_set_clientdata(&t->client, t);
 	i2c_attach_client(&t->client);
 
+	v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
+
+
 	if(! bt832_init(&t->client)) {
 		bt832_detach(&t->client);
 		return -1;
@@ -183,13 +187,8 @@
 
 static int bt832_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, bt832_attach);
-#else
-	if (adap->id == I2C_HW_B_BT848)
-		return i2c_probe(adap, &addr_data, bt832_attach);
-#endif
 	return 0;
 }
 
@@ -197,7 +196,7 @@
 {
 	struct bt832 *t = i2c_get_clientdata(client);
 
-	printk("bt832: detach.\n");
+	v4l_info(&t->client,"dettach\n");
 	i2c_detach_client(client);
 	kfree(t);
 	return 0;
@@ -208,7 +207,8 @@
 {
 	struct bt832 *t = i2c_get_clientdata(client);
 
-	printk("bt832: command %x\n",cmd);
+	if (debug>1)
+		v4l_i2c_print_ioctl(&t->client,cmd);
 
 	switch (cmd) {
 		case BT832_HEXDUMP: {
@@ -219,7 +219,7 @@
 		}
 		break;
 		case BT832_REATTACH:
-			printk("bt832: re-attach\n");
+			v4l_info(&t->client,"re-attach\n");
 			i2c_del_driver(&driver);
 			i2c_add_driver(&driver);
 		break;
@@ -231,9 +231,9 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name   = "i2c bt832 driver",
+		.name   = "bt832",
 	},
-	.id             = -1, /* FIXME */
+	.id             = 0, /* FIXME */
 	.attach_adapter = bt832_probe,
 	.detach_client  = bt832_detach,
 	.command        = bt832_command,
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 012be63..1621ab1 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -38,6 +38,7 @@
 #include <asm/io.h>
 
 #include "bttvp.h"
+#include <media/v4l2-common.h>
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
@@ -292,6 +293,9 @@
 	/* likely broken, vendor id doesn't match the other magic views ...
 	 * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
 
+	/* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+	* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
+
 	/* DVB cards (using pci function .1 for mpeg data xfer) */
 	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
 	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
@@ -2136,7 +2140,6 @@
 		.has_remote	= 1,
 		.gpiomask	= 0x1b,
 		.no_gpioirq     = 1,
-		.any_irq		= 1,
 	},
 	[BTTV_BOARD_PV143] = {
 		/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2817,6 +2820,22 @@
 		.tuner_addr	= ADDR_UNSET,
 		.has_radio      = 1,
 	},
+	/* ---- card 0x8f ---------------------------------- */
+	[BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+		.name		= "Hauppauge ImpactVCB (bt878)",
+		.video_inputs	= 4,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.svhs		= -1,
+		.gpiomask	= 0x0f, /* old: 7 */
+		.muxsel		= { 0, 1, 3, 2}, /* Composite 0-3 */
+		.no_msp34xx	= 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3037,26 +3056,33 @@
 		switch (id) {
 		case 1:
 			info = "PAL / mono";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
 			break;
 		case 2:
 			info = "PAL+SECAM / stereo";
 			btv->has_radio = 1;
+			btv->tda9887_conf = TDA9887_QSS;
 			break;
 		case 3:
 			info = "NTSC / stereo";
 			btv->has_radio = 1;
+			btv->tda9887_conf = TDA9887_QSS;
 			break;
 		case 4:
 			info = "PAL+SECAM / mono";
+			btv->tda9887_conf = TDA9887_QSS;
 			break;
 		case 5:
 			info = "NTSC / mono";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
 			break;
 		case 6:
 			info = "NTSC / stereo";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
 			break;
 		case 7:
 			info = "PAL / stereo";
+			btv->tda9887_conf = TDA9887_INTERCARRIER;
 			break;
 		default:
 			info = "oops: unknown card";
@@ -3067,8 +3093,7 @@
 		printk(KERN_INFO
 		       "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
 		       btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
-		btv->tuner_type  = 33;
-		btv->pinnacle_id = id;
+		btv->tuner_type = TUNER_MT2032;
 	}
 }
 
@@ -3370,9 +3395,9 @@
 		bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
 	}
 
-	if (btv->pinnacle_id != UNSET) {
-		bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
-							&btv->pinnacle_id);
+	if (btv->tda9887_conf) {
+		bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
+							&btv->tda9887_conf);
 	}
 
 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3387,8 +3412,6 @@
 		btv->has_remote=1;
 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
 		btv->gpioirq=1;
-	if (bttv_tvcards[btv->c.type].any_irq)
-		btv->any_irq = 1;
 	if (bttv_tvcards[btv->c.type].audio_hook)
 		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
 
@@ -3424,7 +3447,7 @@
 
 	/* tuner modules */
 	tda9887 = 0;
-	if (btv->pinnacle_id != UNSET)
+	if (btv->tda9887_conf)
 		tda9887 = 1;
 	if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
 	    bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
@@ -3471,6 +3494,21 @@
 	tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
 	btv->tuner_type = tv.tuner_type;
 	btv->has_radio  = tv.has_radio;
+
+	printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
+		btv->c.nr, tv.model);
+
+	/*
+	 * Some of the 878 boards have duplicate PCI IDs. Switch the board
+	 * type based on model #.
+	 */
+	if(tv.model == 64900) {
+		printk("bttv%d: Switching board type from %s to %s\n",
+			btv->c.nr,
+			bttv_tvcards[btv->c.type].name,
+			bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
+		btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
+	}
 }
 
 static int terratec_active_radio_upgrade(struct bttv *btv)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 1ddf9ba..0e69703 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -34,13 +34,14 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+
 #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
-#include "bttvp.h"
-
 #include "rds.h"
 
 
@@ -210,6 +211,9 @@
 		.vdelay         = 0x20,
 		.vbipack        = 255,
 		.sram           = 0,
+		/* ITU-R frame line number of the first VBI line
+		   we can capture, of the first and second field. */
+		.vbistart	= { 7,320 },
 	},{
 		.v4l2_id        = V4L2_STD_NTSC_M,
 		.name           = "NTSC",
@@ -226,6 +230,7 @@
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = 1,
+		.vbistart	= { 10, 273 },
 	},{
 		.v4l2_id        = V4L2_STD_SECAM,
 		.name           = "SECAM",
@@ -242,6 +247,7 @@
 		.vdelay         = 0x20,
 		.vbipack        = 255,
 		.sram           = 0, /* like PAL, correct? */
+		.vbistart	= { 7, 320 },
 	},{
 		.v4l2_id        = V4L2_STD_PAL_Nc,
 		.name           = "PAL-Nc",
@@ -258,6 +264,7 @@
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 7, 320 },
 	},{
 		.v4l2_id        = V4L2_STD_PAL_M,
 		.name           = "PAL-M",
@@ -274,6 +281,7 @@
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 10, 273 },
 	},{
 		.v4l2_id        = V4L2_STD_PAL_N,
 		.name           = "PAL-N",
@@ -290,6 +298,7 @@
 		.vdelay         = 0x20,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 7, 320},
 	},{
 		.v4l2_id        = V4L2_STD_NTSC_M_JP,
 		.name           = "NTSC-JP",
@@ -306,6 +315,7 @@
 		.vdelay         = 0x16,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= {10, 273},
 	},{
 		/* that one hopefully works with the strange timing
 		 * which video recorders produce when playing a NTSC
@@ -326,6 +336,7 @@
 		.vbipack        = 255,
 		.vtotal         = 524,
 		.sram           = -1,
+		.vbistart	= { 10, 273 },
 	}
 };
 static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -1510,14 +1521,6 @@
 	.buf_release  = buffer_release,
 };
 
-static const char *v4l1_ioctls[] = {
-	"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
 static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
 {
 	switch (cmd) {
@@ -2206,22 +2209,9 @@
 	unsigned long flags;
 	int retval = 0;
 
-	if (bttv_debug > 1) {
-		switch (_IOC_TYPE(cmd)) {
-		case 'v':
-			printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
-			       btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-			       v4l1_ioctls[_IOC_NR(cmd)] : "???");
-			break;
-		case 'V':
-			printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
-			       btv->c.nr, cmd,  v4l2_ioctl_names[_IOC_NR(cmd)]);
-			break;
-		default:
-			printk("bttv%d: ioctl 0x%x (???)\n",
-			       btv->c.nr, cmd);
-		}
-	}
+	if (bttv_debug > 1)
+		v4l_print_ioctl(btv->c.name, cmd);
+
 	if (btv->errors)
 		bttv_reinit_bt848(btv);
 
@@ -2570,10 +2560,10 @@
 		fmt->count[0]         = fmt2.fmt.vbi.count[0];
 		fmt->start[1]         = fmt2.fmt.vbi.start[1];
 		fmt->count[1]         = fmt2.fmt.vbi.count[1];
-		if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
-			fmt->flags   |= V4L2_VBI_UNSYNC;
-		if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
-			fmt->flags   |= V4L2_VBI_INTERLACED;
+		if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
+			fmt->flags   |= VBI_UNSYNC;
+		if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
+			fmt->flags   |= VBI_INTERLACED;
 		return 0;
 	}
 	case VIDIOCSVBIFMT:
@@ -3120,6 +3110,7 @@
 	.open	  = bttv_open,
 	.release  = bttv_release,
 	.ioctl	  = bttv_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek	  = no_llseek,
 	.read	  = bttv_read,
 	.mmap	  = bttv_mmap,
@@ -3229,6 +3220,7 @@
 	case VIDIOCSFREQ:
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
+	case VIDIOC_LOG_STATUS:
 		return bttv_common_ioctls(btv,cmd,arg);
 
 	default:
@@ -3701,8 +3693,8 @@
 
 	btv=(struct bttv *)dev_id;
 
-	if (btv->any_irq)
-		handled = bttv_any_irq(&btv->c);
+	if (btv->custom_irq)
+		handled = btv->custom_irq(btv);
 
 	count=0;
 	while (1) {
@@ -3738,9 +3730,9 @@
 		if (astat&BT848_INT_VSYNC)
 			btv->field_count++;
 
-		if (astat & BT848_INT_GPINT) {
+		if ((astat & BT848_INT_GPINT) && btv->remote) {
 			wake_up(&btv->gpioq);
-			bttv_gpio_irq(&btv->c);
+			bttv_input_irq(btv);
 		}
 
 		if (astat & BT848_INT_I2CDONE) {
@@ -3946,7 +3938,6 @@
 
 	btv->i2c_rc = -1;
 	btv->tuner_type  = UNSET;
-	btv->pinnacle_id = UNSET;
 	btv->new_input   = UNSET;
 	btv->has_radio=radio[btv->c.nr];
 
@@ -4065,11 +4056,11 @@
 	}
 
 	/* add subdevices */
-	if (btv->has_remote)
-		bttv_sub_add_device(&btv->c, "remote");
 	if (bttv_tvcards[btv->c.type].has_dvb)
 		bttv_sub_add_device(&btv->c, "dvb");
 
+	bttv_input_init(btv);
+
 	/* everything is fine */
 	bttv_num++;
 	return 0;
@@ -4104,6 +4095,7 @@
 	/* tell gpio modules we are leaving ... */
 	btv->shutdown=1;
 	wake_up(&btv->gpioq);
+	bttv_input_fini(btv);
 	bttv_sub_del_devices(&btv->c);
 
 	/* unregister i2c_bus + input */
@@ -4253,7 +4245,7 @@
 	bttv_check_chipset();
 
 	bus_register(&bttv_sub_bus_type);
-	return pci_module_init(&bttv_pci_driver);
+	return pci_register_driver(&bttv_pci_driver);
 }
 
 static void bttv_cleanup_module(void)
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 616a5b7..575ce8b 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -113,24 +113,6 @@
 	}
 }
 
-int bttv_any_irq(struct bttv_core *core)
-{
-	struct bttv_sub_driver *drv;
-	struct bttv_sub_device *dev;
-	struct list_head *item;
-	int handled = 0;
-
-	list_for_each(item,&core->subs) {
-		dev = list_entry(item,struct bttv_sub_device,list);
-		drv = to_bttv_sub_drv(dev->dev.driver);
-		if (drv && drv->any_irq) {
-			if (drv->any_irq(dev))
-				handled = 1;
-		}
-	}
-	return handled;
-}
-
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index d6418c0..748d630 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -28,10 +28,11 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
 
 #include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
 
 static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
 static struct i2c_adapter bttv_i2c_adap_sw_template;
@@ -105,10 +106,8 @@
 
 static struct i2c_adapter bttv_i2c_adap_sw_template = {
 	.owner             = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
 	.class             = I2C_CLASS_TV_ANALOG,
-#endif
-	.name              = "bt848",
+	.name              = "bttv",
 	.id                = I2C_HW_B_BT848,
 	.client_register   = attach_inform,
 };
@@ -275,10 +274,8 @@
 };
 
 static struct i2c_adapter bttv_i2c_adap_hw_template = {
-	.owner         = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
+	.owner             = THIS_MODULE,
 	.class         = I2C_CLASS_TV_ANALOG,
-#endif
 	.name          = "bt878",
 	.id            = I2C_HW_B_BT848 /* FIXME */,
 	.algo          = &bttv_algo,
@@ -441,12 +438,10 @@
 	i2c_set_adapdata(&btv->c.i2c_adap, btv);
 	btv->i2c_client.adapter = &btv->c.i2c_adap;
 
-#ifdef I2C_CLASS_TV_ANALOG
 	if (bttv_tvcards[btv->c.type].no_video)
 		btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
 	if (bttv_tvcards[btv->c.type].has_dvb)
 		btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-#endif
 
 	if (btv->use_i2c_hw) {
 		btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/bttv-input.c
similarity index 73%
rename from drivers/media/video/ir-kbd-gpio.c
rename to drivers/media/video/bttv-input.c
index de1385e..12197f1 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/bttv-input.c
@@ -24,11 +24,9 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
-#include <linux/pci.h>
-
-#include <media/ir-common.h>
 
 #include "bttv.h"
+#include "bttvp.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -156,9 +154,6 @@
 
 /* ---------------------------------------------------------------------- */
 
-/* Ricardo Cerqueira <v4l@cerqueira.org> */
-/* Weird matching, since the remote has "uncommon" keys */
-
 static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
 
 	[ 30 ] = KEY_POWER,       // power
@@ -279,34 +274,6 @@
 	[0x36] = KEY_PC
 };
 
-struct IR {
-	struct bttv_sub_device  *sub;
-	struct input_dev        *input;
-	struct ir_input_state   ir;
-	char                    name[32];
-	char                    phys[32];
-
-	/* Usual gpio signalling */
-
-	u32                     mask_keycode;
-	u32                     mask_keydown;
-	u32                     mask_keyup;
-	u32                     polling;
-	u32                     last_gpio;
-	struct work_struct      work;
-	struct timer_list       timer;
-
-	/* RC5 gpio */
-	u32 rc5_gpio;
-	struct timer_list timer_end;	/* timer_end for code completion */
-	struct timer_list timer_keyup;	/* timer_end for key release */
-	u32 last_rc5;			/* last good rc5 code */
-	u32 last_bit;			/* last raw bit seen */
-	u32 code;			/* raw code under construction */
-	struct timeval base_time;	/* time of last seen code */
-	int active;			/* building raw code */
-};
-
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 static int repeat_delay = 500;
@@ -314,31 +281,17 @@
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
 
-#define DEVNAME "ir-kbd-gpio"
-#define dprintk(fmt, arg...)	if (debug) \
-	printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
-
-static void ir_irq(struct bttv_sub_device *sub);
-static int ir_probe(struct device *dev);
-static int ir_remove(struct device *dev);
-
-static struct bttv_sub_driver driver = {
-	.drv = {
-		.name	= DEVNAME,
-		.probe	= ir_probe,
-		.remove	= ir_remove,
-	},
-	.gpio_irq 	= ir_irq,
-};
+#define DEVNAME "bttv-input"
 
 /* ---------------------------------------------------------------------- */
 
-static void ir_handle_key(struct IR *ir)
+static void ir_handle_key(struct bttv *btv)
 {
+	struct bttv_ir *ir = btv->remote;
 	u32 gpio,data;
 
 	/* read gpio value */
-	gpio = bttv_gpio_read(ir->sub->core);
+	gpio = bttv_gpio_read(&btv->c);
 	if (ir->polling) {
 		if (ir->last_gpio == gpio)
 			return;
@@ -347,56 +300,36 @@
 
 	/* extract data */
 	data = ir_extract_bits(gpio, ir->mask_keycode);
-	dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
+	dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
 		gpio, data,
 		ir->polling               ? "poll"  : "irq",
 		(gpio & ir->mask_keydown) ? " down" : "",
 		(gpio & ir->mask_keyup)   ? " up"   : "");
 
-	if (ir->mask_keydown) {
-		/* bit set on keydown */
-		if (gpio & ir->mask_keydown) {
-			ir_input_keydown(ir->input, &ir->ir, data, data);
-		} else {
-			ir_input_nokey(ir->input, &ir->ir);
-		}
-
-	} else if (ir->mask_keyup) {
-		/* bit cleared on keydown */
-		if (0 == (gpio & ir->mask_keyup)) {
-			ir_input_keydown(ir->input, &ir->ir, data, data);
-		} else {
-			ir_input_nokey(ir->input, &ir->ir);
-		}
-
+	if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+		ir_input_keydown(ir->dev,&ir->ir,data,data);
 	} else {
-		/* can't disturgissh keydown/up :-/ */
-		ir_input_keydown(ir->input, &ir->ir, data, data);
-		ir_input_nokey(ir->input, &ir->ir);
+		ir_input_nokey(ir->dev,&ir->ir);
 	}
+
 }
 
-static void ir_irq(struct bttv_sub_device *sub)
+void bttv_input_irq(struct bttv *btv)
 {
-	struct IR *ir = dev_get_drvdata(&sub->dev);
+	struct bttv_ir *ir = btv->remote;
 
 	if (!ir->polling)
-		ir_handle_key(ir);
+		ir_handle_key(btv);
 }
 
-static void ir_timer(unsigned long data)
+static void bttv_input_timer(unsigned long data)
 {
-	struct IR *ir = (struct IR*)data;
-
-	schedule_work(&ir->work);
-}
-
-static void ir_work(void *data)
-{
-	struct IR *ir = data;
+	struct bttv *btv = (struct bttv*)data;
+	struct bttv_ir *ir = btv->remote;
 	unsigned long timeout;
 
-	ir_handle_key(ir);
+	ir_handle_key(btv);
 	timeout = jiffies + (ir->polling * HZ / 1000);
 	mod_timer(&ir->timer, timeout);
 }
@@ -435,26 +368,26 @@
 			rc5 |= 1;
 			break;
 		case 3:
-			dprintk("bad code: %x\n", org_code);
+			dprintk(KERN_WARNING "bad code: %x\n", org_code);
 			return 0;
 		}
 	}
-	dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+	dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
 		"instr=%x\n", rc5, org_code, RC5_START(rc5),
 		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
 	return rc5;
 }
 
-static int ir_rc5_irq(struct bttv_sub_device *sub)
+static int bttv_rc5_irq(struct bttv *btv)
 {
-	struct IR *ir = dev_get_drvdata(&sub->dev);
+	struct bttv_ir *ir = btv->remote;
 	struct timeval tv;
 	u32 gpio;
 	u32 gap;
 	unsigned long current_jiffies, timeout;
 
 	/* read gpio port */
-	gpio = bttv_gpio_read(ir->sub->core);
+	gpio = bttv_gpio_read(&btv->c);
 
 	/* remote IRQ? */
 	if (!(gpio & 0x20))
@@ -493,14 +426,15 @@
 	}
 
 	/* toggle GPIO pin 4 to reset the irq */
-	bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
-	bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+	bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+	bttv_gpio_write(&btv->c, gpio | (1 << 4));
 	return 1;
 }
 
-static void ir_rc5_timer_end(unsigned long data)
+
+static void bttv_rc5_timer_end(unsigned long data)
 {
-	struct IR *ir = (struct IR *)data;
+	struct bttv_ir *ir = (struct bttv_ir *)data;
 	struct timeval tv;
 	unsigned long current_jiffies, timeout;
 	u32 gap;
@@ -519,20 +453,20 @@
 
 	/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
 	if (gap < 28000) {
-		dprintk("spurious timer_end\n");
+		dprintk(KERN_WARNING "spurious timer_end\n");
 		return;
 	}
 
 	ir->active = 0;
 	if (ir->last_bit < 20) {
 		/* ignore spurious codes (caused by light/other remotes) */
-		dprintk("short code: %x\n", ir->code);
+		dprintk(KERN_WARNING "short code: %x\n", ir->code);
 	} else {
 		u32 rc5 = rc5_decode(ir->code);
 
 		/* two start bits? */
 		if (RC5_START(rc5) != 3) {
-			dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+			dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
 
 			/* right address? */
 		} else if (RC5_ADDR(rc5) == 0x0) {
@@ -542,10 +476,10 @@
 			/* Good code, decide if repeat/repress */
 			if (toggle != RC5_TOGGLE(ir->last_rc5) ||
 			    instr != RC5_INSTR(ir->last_rc5)) {
-				dprintk("instruction %x, toggle %x\n", instr,
+				dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
 					toggle);
-				ir_input_nokey(ir->input, &ir->ir);
-				ir_input_keydown(ir->input, &ir->ir, instr,
+				ir_input_nokey(ir->dev, &ir->ir);
+				ir_input_keydown(ir->dev, &ir->ir, instr,
 						 instr);
 			}
 
@@ -560,34 +494,37 @@
 	}
 }
 
-static void ir_rc5_timer_keyup(unsigned long data)
+static void bttv_rc5_timer_keyup(unsigned long data)
 {
-	struct IR *ir = (struct IR *)data;
+	struct bttv_ir *ir = (struct bttv_ir *)data;
 
-	dprintk("key released\n");
-	ir_input_nokey(ir->input, &ir->ir);
+	dprintk(KERN_DEBUG "key released\n");
+	ir_input_nokey(ir->dev, &ir->ir);
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int ir_probe(struct device *dev)
+int bttv_input_init(struct bttv *btv)
 {
-	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
-	struct IR *ir;
-	struct input_dev *input_dev;
+	struct bttv_ir *ir;
 	IR_KEYTAB_TYPE *ir_codes = NULL;
+	struct input_dev *input_dev;
 	int ir_type = IR_TYPE_OTHER;
 
-	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+	if (!btv->has_remote)
+		return -ENODEV;
+
+	ir = kzalloc(sizeof(*ir),GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!ir || !input_dev) {
 		kfree(ir);
 		input_free_device(input_dev);
 		return -ENOMEM;
 	}
+	memset(ir,0,sizeof(*ir));
 
 	/* detect & configure */
-	switch (sub->core->type) {
+	switch (btv->c.type) {
 	case BTTV_BOARD_AVERMEDIA:
 	case BTTV_BOARD_AVPHONE98:
 	case BTTV_BOARD_AVERMEDIA98:
@@ -643,12 +580,12 @@
 		break;
 	case BTTV_BOARD_NEBULA_DIGITV:
 		ir_codes = ir_codes_nebula;
-		driver.any_irq = ir_rc5_irq;
-		driver.gpio_irq = NULL;
+		btv->custom_irq = bttv_rc5_irq;
 		ir->rc5_gpio = 1;
 		break;
 	}
 	if (NULL == ir_codes) {
+		dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
 		kfree(ir);
 		input_free_device(input_dev);
 		return -ENODEV;
@@ -657,109 +594,92 @@
 	if (ir->rc5_gpio) {
 		u32 gpio;
 	    	/* enable remote irq */
-		bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
-		gpio = bttv_gpio_read(sub->core);
-		bttv_gpio_write(sub->core, gpio & ~(1 << 4));
-		bttv_gpio_write(sub->core, gpio | (1 << 4));
+		bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
+		gpio = bttv_gpio_read(&btv->c);
+		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+		bttv_gpio_write(&btv->c, gpio | (1 << 4));
 	} else {
 		/* init hardware-specific stuff */
-		bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+		bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
 	}
 
 	/* init input device */
+	ir->dev = input_dev;
+
 	snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
-		 sub->core->type);
+		 btv->c.type);
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
-		 pci_name(sub->core->pci));
+		 pci_name(btv->c.pci));
 
 	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
 	input_dev->name = ir->name;
 	input_dev->phys = ir->phys;
 	input_dev->id.bustype = BUS_PCI;
 	input_dev->id.version = 1;
-	if (sub->core->pci->subsystem_vendor) {
-		input_dev->id.vendor  = sub->core->pci->subsystem_vendor;
-		input_dev->id.product = sub->core->pci->subsystem_device;
+	if (btv->c.pci->subsystem_vendor) {
+		input_dev->id.vendor  = btv->c.pci->subsystem_vendor;
+		input_dev->id.product = btv->c.pci->subsystem_device;
 	} else {
-		input_dev->id.vendor  = sub->core->pci->vendor;
-		input_dev->id.product = sub->core->pci->device;
+		input_dev->id.vendor  = btv->c.pci->vendor;
+		input_dev->id.product = btv->c.pci->device;
 	}
-	input_dev->cdev.dev = &sub->core->pci->dev;
+	input_dev->cdev.dev = &btv->c.pci->dev;
 
-	ir->input = input_dev;
-	ir->sub = sub;
-
+	btv->remote = ir;
 	if (ir->polling) {
-		INIT_WORK(&ir->work, ir_work, ir);
 		init_timer(&ir->timer);
-		ir->timer.function = ir_timer;
-		ir->timer.data     = (unsigned long)ir;
-		schedule_work(&ir->work);
+		ir->timer.function = bttv_input_timer;
+		ir->timer.data     = (unsigned long)btv;
+		ir->timer.expires  = jiffies + HZ;
+		add_timer(&ir->timer);
 	} else if (ir->rc5_gpio) {
 		/* set timer_end for code completion */
 		init_timer(&ir->timer_end);
-		ir->timer_end.function = ir_rc5_timer_end;
+		ir->timer_end.function = bttv_rc5_timer_end;
 		ir->timer_end.data = (unsigned long)ir;
 
 		init_timer(&ir->timer_keyup);
-		ir->timer_keyup.function = ir_rc5_timer_keyup;
+		ir->timer_keyup.function = bttv_rc5_timer_keyup;
 		ir->timer_keyup.data = (unsigned long)ir;
 	}
 
 	/* all done */
-	dev_set_drvdata(dev, ir);
-	input_register_device(ir->input);
+	input_register_device(btv->remote->dev);
+	printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
 
 	/* the remote isn't as bouncy as a keyboard */
-	ir->input->rep[REP_DELAY] = repeat_delay;
-	ir->input->rep[REP_PERIOD] = repeat_period;
+	ir->dev->rep[REP_DELAY] = repeat_delay;
+	ir->dev->rep[REP_PERIOD] = repeat_period;
 
 	return 0;
 }
 
-static int ir_remove(struct device *dev)
+void bttv_input_fini(struct bttv *btv)
 {
-	struct IR *ir = dev_get_drvdata(dev);
+	if (btv->remote == NULL)
+		return;
 
-	if (ir->polling) {
-		del_timer(&ir->timer);
+	if (btv->remote->polling) {
+		del_timer_sync(&btv->remote->timer);
 		flush_scheduled_work();
 	}
 
-	if (ir->rc5_gpio) {
+
+	if (btv->remote->rc5_gpio) {
 		u32 gpio;
 
-		del_timer(&ir->timer_end);
+		del_timer_sync(&btv->remote->timer_end);
 		flush_scheduled_work();
 
-		gpio = bttv_gpio_read(ir->sub->core);
-		bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+		gpio = bttv_gpio_read(&btv->c);
+		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
 	}
 
-	input_unregister_device(ir->input);
-	kfree(ir);
-	return 0;
+	input_unregister_device(btv->remote->dev);
+	kfree(btv->remote);
+	btv->remote = NULL;
 }
 
-/* ---------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr, Pavel Machek");
-MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls");
-MODULE_LICENSE("GPL");
-
-static int ir_init(void)
-{
-	return bttv_sub_register(&driver, "remote");
-}
-
-static void ir_fini(void)
-{
-	bttv_sub_unregister(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
-
 
 /*
  * Local variables:
diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c
index f4f58c6..72afdd6 100644
--- a/drivers/media/video/bttv-vbi.c
+++ b/drivers/media/video/bttv-vbi.c
@@ -31,6 +31,12 @@
 #include <asm/io.h>
 #include "bttvp.h"
 
+/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
+   bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
+   HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
+   of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
+#define VBI_OFFSET ((64 + 0) * 2)
+
 #define VBI_DEFLINES 16
 #define VBI_MAXLINES 32
 
@@ -163,40 +169,30 @@
 void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
 {
 	const struct bttv_tvnorm *tvnorm;
-	u32 start0,start1;
-	s32 count0,count1,count;
+	s64 count0,count1,count;
 
 	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
 	f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
 	f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
 	f->fmt.vbi.samples_per_line = 2048;
 	f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-	f->fmt.vbi.offset           = 244;
+	f->fmt.vbi.offset           = VBI_OFFSET;
 	f->fmt.vbi.flags            = 0;
-	switch (fh->btv->tvnorm) {
-	case 1: /* NTSC */
-		start0 = 10;
-		start1 = 273;
-		break;
-	case 0: /* PAL */
-	case 2: /* SECAM */
-	default:
-		start0 = 7;
-		start1 = 320;
-	}
 
-	count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0;
-	count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1;
-	count  = max(count0,count1);
-	if (count > VBI_MAXLINES)
-		count = VBI_MAXLINES;
-	if (count < 1)
-		count = 1;
+	/* s64 to prevent overflow. */
+	count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
+		- tvnorm->vbistart[0];
+	count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
+		- tvnorm->vbistart[1];
+	count  = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
 
-	f->fmt.vbi.start[0] = start0;
-	f->fmt.vbi.start[1] = start1;
+	f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+	f->fmt.vbi.start[1] = tvnorm->vbistart[1];
 	f->fmt.vbi.count[0] = count;
 	f->fmt.vbi.count[1] = count;
+
+	f->fmt.vbi.reserved[0] = 0;
+	f->fmt.vbi.reserved[1] = 0;
 }
 
 void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
@@ -209,21 +205,12 @@
 	f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
 	f->fmt.vbi.samples_per_line = 2048;
 	f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-	f->fmt.vbi.offset           = 244;
+	f->fmt.vbi.offset           = VBI_OFFSET;
+	f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
+	f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
 	f->fmt.vbi.count[0]         = fh->lines;
 	f->fmt.vbi.count[1]         = fh->lines;
 	f->fmt.vbi.flags            = 0;
-	switch (fh->btv->tvnorm) {
-	case 1: /* NTSC */
-		f->fmt.vbi.start[0] = 10;
-		f->fmt.vbi.start[1] = 273;
-		break;
-	case 0: /* PAL */
-	case 2: /* SECAM */
-	default:
-		f->fmt.vbi.start[0] = 7;
-		f->fmt.vbi.start[1] = 319;
-	}
 }
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 93298f0..9feaa6b 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -16,6 +16,8 @@
 
 #include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
@@ -163,6 +165,7 @@
 #define BTTV_BOARD_OSPREY440               0x8c
 #define BTTV_BOARD_ASOUND_SKYEYE	   0x8d
 #define BTTV_BOARD_SABRENT_TVFM   	   0x8e
+#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -210,6 +213,34 @@
 
 struct bttv;
 
+
+struct bttv_ir {
+	struct input_dev        *dev;
+	struct ir_input_state   ir;
+	char                    name[32];
+	char                    phys[32];
+
+	/* Usual gpio signalling */
+
+	u32                     mask_keycode;
+	u32                     mask_keydown;
+	u32                     mask_keyup;
+	u32                     polling;
+	u32                     last_gpio;
+	struct work_struct      work;
+	struct timer_list       timer;
+
+	/* RC5 gpio */
+	u32 rc5_gpio;
+	struct timer_list timer_end;	/* timer_end for code completion */
+	struct timer_list timer_keyup;	/* timer_end for key release */
+	u32 last_rc5;			/* last good rc5 code */
+	u32 last_bit;			/* last raw bit seen */
+	u32 code;			/* raw code under construction */
+	struct timeval base_time;	/* time of last seen code */
+	int active;			/* building raw code */
+};
+
 struct tvcard
 {
 	char *name;
@@ -235,7 +266,6 @@
 	unsigned int has_dvb:1;
 	unsigned int has_remote:1;
 	unsigned int no_gpioirq:1;
-	unsigned int any_irq:1;
 
 	/* other settings */
 	unsigned int pll;
@@ -335,7 +365,6 @@
 	struct device_driver   drv;
 	char                   wanted[BUS_ID_SIZE];
 	void                   (*gpio_irq)(struct bttv_sub_device *sub);
-	int                    (*any_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
@@ -363,6 +392,10 @@
 			 unsigned char b2, int both);
 extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
+extern int bttv_input_init(struct bttv *dev);
+extern void bttv_input_fini(struct bttv *dev);
+extern void bttv_input_irq(struct bttv *dev);
+
 #endif /* _BTTV_H_ */
 /*
  * Local variables:
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index 1e6a563..dd00c20 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -73,6 +73,8 @@
 
 #define UNSET (-1U)
 
+#define clamp(x, low, high) min (max (low, x), high)
+
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm {
@@ -88,6 +90,9 @@
 	u8    vbipack;
 	u16   vtotal;
 	int   sram;
+	/* ITU-R frame line number of the first VBI line we can
+	   capture, of the first and second field. */
+	u16   vbistart[2];
 };
 extern const struct bttv_tvnorm bttv_tvnorms[];
 
@@ -209,7 +214,6 @@
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
 void bttv_gpio_irq(struct bttv_core *core);
-int bttv_any_irq(struct bttv_core *core);
 
 
 /* ---------------------------------------------------------- */
@@ -270,12 +274,13 @@
 	/* card configuration info */
 	unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
 	unsigned int tuner_type;  /* tuner chip type */
-	unsigned int pinnacle_id;
+	unsigned int tda9887_conf;
 	unsigned int svhs;
 	struct bttv_pll_info pll;
 	int triton1;
 	int gpioirq;
-	int any_irq;
+	int (*custom_irq)(struct bttv *btv);
+
 	int use_i2c_hw;
 
 	/* old gpio interface */
@@ -300,7 +305,7 @@
 
 	/* infrared remote */
 	int has_remote;
-	struct bttv_input *remote;
+	struct bttv_ir *remote;
 
 	/* locking */
 	spinlock_t s_lock;
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 0065d0c..6bad93e 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -875,6 +875,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = qcam_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.read		= qcam_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 75442ec..9976db4 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -687,6 +687,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = qcam_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.read		= qcam_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
new file mode 100644
index 0000000..6194b01
--- /dev/null
+++ b/drivers/media/video/compat_ioctl32.c
@@ -0,0 +1,732 @@
+/*
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *	Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
+ * Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/compat.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_COMPAT
+struct video_tuner32 {
+	compat_int_t tuner;
+	char name[32];
+	compat_ulong_t rangelow, rangehigh;
+	u32 flags;	/* It is really u32 in videodev.h */
+	u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+	if(get_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	__copy_from_user(kp->name, up->name, 32);
+	__get_user(kp->rangelow, &up->rangelow);
+	__get_user(kp->rangehigh, &up->rangehigh);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->mode, &up->mode);
+	__get_user(kp->signal, &up->signal);
+	return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
+{
+	if(put_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	__copy_to_user(up->name, kp->name, 32);
+	__put_user(kp->rangelow, &up->rangelow);
+	__put_user(kp->rangehigh, &up->rangehigh);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->mode, &up->mode);
+	__put_user(kp->signal, &up->signal);
+	return 0;
+}
+
+struct video_buffer32 {
+	compat_caddr_t base;
+	compat_int_t height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+	u32 tmp;
+
+	if (get_user(tmp, &up->base))
+		return -EFAULT;
+
+	/* This is actually a physical address stored
+	 * as a void pointer.
+	 */
+	kp->base = (void *)(unsigned long) tmp;
+
+	__get_user(kp->height, &up->height);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->depth, &up->depth);
+	__get_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if(put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->height, &up->height);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->depth, &up->depth);
+	__put_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+struct video_clip32 {
+	s32 x, y, width, height;	/* Its really s32 in videodev.h */
+	compat_caddr_t next;
+};
+
+struct video_window32 {
+	u32 x, y, width, height, chromakey, flags;
+	compat_caddr_t clips;
+	compat_int_t clipcount;
+};
+
+static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+
+	if (file->f_op->unlocked_ioctl)
+		ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+	else if (file->f_op->ioctl) {
+		lock_kernel();
+		ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+		unlock_kernel();
+	}
+
+	return ret;
+}
+
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
+{
+	if(put_user(kp->x, &up->x))
+		return -EFAULT;
+	__put_user(kp->y, &up->y);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->height, &up->height);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->clipcount, &up->clipcount);
+	return 0;
+}
+
+struct v4l2_clip32
+{
+	struct v4l2_rect        c;
+	compat_caddr_t 		next;
+};
+
+struct v4l2_window32
+{
+	struct v4l2_rect        w;
+	enum v4l2_field  	field;
+	__u32			chromakey;
+	compat_caddr_t		clips; /* actually struct v4l2_clip32 * */
+	__u32			clipcount;
+	compat_caddr_t		bitmap;
+};
+
+static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+	if (copy_from_user(&kp->w, &up->w, sizeof(up->w)))
+		return -EFAULT;
+	__get_user(kp->field, &up->field);
+	__get_user(kp->chromakey, &up->chromakey);
+	__get_user(kp->clipcount, &up->clipcount);
+	if (kp->clipcount > 2048)
+		return -EINVAL;
+	if (kp->clipcount) {
+		struct v4l2_clip32 *uclips = compat_ptr(up->clips);
+		struct v4l2_clip *kclips;
+		int n = kp->clipcount;
+
+		kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
+		kp->clips = kclips;
+		while (--n >= 0) {
+			copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c));
+			kclips->next = n ? kclips + 1 : 0;
+			uclips += 1;
+			kclips += 1;
+		}
+	} else
+		kp->clips = 0;
+	return 0;
+}
+
+static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+{
+	if (copy_to_user(&up->w, &kp->w, sizeof(up->w)))
+		return -EFAULT;
+	__put_user(kp->field, &up->field);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->clipcount, &up->clipcount);
+	return 0;
+}
+
+static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+	return copy_from_user(kp, up, sizeof(struct v4l2_pix_format));
+}
+
+static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+{
+	return copy_to_user(up, kp, sizeof(struct v4l2_pix_format));
+}
+
+static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+	return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format));
+}
+
+static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+{
+	return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format));
+}
+
+struct v4l2_format32
+{
+	enum v4l2_buf_type type;
+	union
+	{
+		struct v4l2_pix_format	pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
+		struct v4l2_window32	win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
+		struct v4l2_vbi_format	vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
+		__u8	raw_data[200];        // user-defined
+	} fmt;
+};
+
+static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+	if(get_user(kp->type, &up->type))
+		return -EFAULT;
+	switch (kp->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+	default:
+		printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
+								kp->type);
+		return -ENXIO;
+	}
+}
+
+static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+	if(put_user(kp->type, &up->type))
+		return -EFAULT;
+	switch (kp->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+	default:
+		return -ENXIO;
+	}
+}
+
+struct v4l2_standard32
+{
+	__u32		     index;
+	__u32		     id[2]; /* __u64 would get the alignment wrong */
+	__u8		     name[24];
+	struct v4l2_fract    frameperiod; /* Frames, not fields */
+	__u32		     framelines;
+	__u32		     reserved[4];
+};
+
+static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+	/* other fields are not set by the user, nor used by the driver */
+	return get_user(kp->index, &up->index);
+}
+
+static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+{
+	if(put_user(kp->index, &up->index))
+		return -EFAULT;
+	__copy_to_user(up->id, &kp->id, sizeof(__u64));
+	__copy_to_user(up->name, kp->name, 24);
+	__put_user(kp->frameperiod, &up->frameperiod);
+	__put_user(kp->framelines, &up->framelines);
+	__copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32));
+	return 0;
+}
+
+struct v4l2_buffer32
+{
+	__u32			index;
+	enum v4l2_buf_type      type;
+	__u32			bytesused;
+	__u32			flags;
+	enum v4l2_field		field;
+	struct compat_timeval	timestamp;
+	struct v4l2_timecode	timecode;
+	__u32			sequence;
+
+	/* memory location */
+	enum v4l2_memory        memory;
+	union {
+		__u32           offset;
+		compat_long_t   userptr;
+	} m;
+	__u32			length;
+	__u32			input;
+	__u32			reserved;
+};
+
+static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+
+	if (get_user(kp->index, &up->index))
+		return -EFAULT;
+	__get_user(kp->type, &up->type);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->memory, &up->memory);
+	__get_user(kp->input, &up->input);
+	switch(kp->memory) {
+	case V4L2_MEMORY_MMAP:
+		break;
+	case V4L2_MEMORY_USERPTR:
+		{
+		unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
+
+		__get_user(kp->length, &up->length);
+		__get_user(kp->m.userptr, &tmp);
+		}
+		break;
+	case V4L2_MEMORY_OVERLAY:
+		__get_user(kp->m.offset, &up->m.offset);
+		break;
+	}
+	return 0;
+}
+
+static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+{
+	if (put_user(kp->index, &up->index))
+		return -EFAULT;
+	__put_user(kp->type, &up->type);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->memory, &up->memory);
+	__put_user(kp->input, &up->input);
+	switch(kp->memory) {
+	case V4L2_MEMORY_MMAP:
+		__put_user(kp->length, &up->length);
+		__put_user(kp->m.offset, &up->m.offset);
+		break;
+	case V4L2_MEMORY_USERPTR:
+		__put_user(kp->length, &up->length);
+		__put_user(kp->m.userptr, &up->m.userptr);
+		break;
+	case V4L2_MEMORY_OVERLAY:
+		__put_user(kp->m.offset, &up->m.offset);
+		break;
+	}
+	__put_user(kp->bytesused, &up->bytesused);
+	__put_user(kp->field, &up->field);
+	__put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec);
+	__put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec);
+	__copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode));
+	__put_user(kp->sequence, &up->sequence);
+	__put_user(kp->reserved, &up->reserved);
+	return 0;
+}
+
+struct v4l2_framebuffer32
+{
+	__u32			capability;
+	__u32			flags;
+	compat_caddr_t 		base;
+	struct v4l2_pix_format	fmt;
+};
+
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+	u32 tmp;
+
+	if (get_user(tmp, &up->base))
+		return -EFAULT;
+	kp->base = compat_ptr(tmp);
+	__get_user(kp->capability, &up->capability);
+	__get_user(kp->flags, &up->flags);
+	get_v4l2_pix_format(&kp->fmt, &up->fmt);
+	return 0;
+}
+
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if(put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->capability, &up->capability);
+	__put_user(kp->flags, &up->flags);
+	put_v4l2_pix_format(&kp->fmt, &up->fmt);
+	return 0;
+}
+
+struct v4l2_input32 	/* identical layout, but different size */
+{
+	__u32	     index;		/*  Which input */
+	__u8	     name[32];		/*  Label */
+	__u32	     type;		/*  Type of input */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
+	__u32        tuner;             /*  Associated tuner */
+	__u32	     std[2];		/* __u64 would get the padding wrong */
+	__u32	     status;
+	__u32	     reserved[4];
+};
+
+#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32		_IOR('v',14, u32)
+#define VIDIOCSFREQ32		_IOW('v',15, u32)
+
+#define VIDIOC_G_FMT32		_IOWR ('V',  4, struct v4l2_format32)
+#define VIDIOC_S_FMT32		_IOWR ('V',  5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32	_IOWR ('V',  9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32		_IOR  ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32		_IOW  ('V', 11, struct v4l2_framebuffer32)
+/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
+#define VIDIOC_OVERLAY32	_IOWR ('V', 14, compat_int_t)
+#define VIDIOC_QBUF32		_IOWR ('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32		_IOWR ('V', 17, struct v4l2_buffer32)
+#define VIDIOC_STREAMON32	_IOW  ('V', 18, compat_int_t)
+#define VIDIOC_STREAMOFF32	_IOW  ('V', 19, compat_int_t)
+#define VIDIOC_ENUMSTD32	_IOWR ('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32	_IOWR ('V', 26, struct v4l2_input32)
+/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
+#define VIDIOC_S_CTRL32		_IOW  ('V', 28, struct v4l2_control)
+#define VIDIOC_G_INPUT32	_IOR  ('V', 38, compat_int_t)
+#define VIDIOC_S_INPUT32	_IOWR ('V', 39, compat_int_t)
+#define VIDIOC_TRY_FMT32      	_IOWR ('V', 64, struct v4l2_format32)
+
+enum {
+	MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
+};
+
+static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct video_window32 __user *up = compat_ptr(arg);
+	struct video_window __user *vw;
+	struct video_clip __user *p;
+	int nclips;
+	u32 n;
+
+	if (get_user(nclips, &up->clipcount))
+		return -EFAULT;
+
+	/* Peculiar interface... */
+	if (nclips < 0)
+		nclips = VIDEO_CLIPMAP_SIZE;
+
+	if (nclips > MaxClips)
+		return -ENOMEM;
+
+	vw = compat_alloc_user_space(sizeof(struct video_window) +
+				    nclips * sizeof(struct video_clip));
+
+	p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
+
+	if (get_user(n, &up->x) || put_user(n, &vw->x) ||
+	    get_user(n, &up->y) || put_user(n, &vw->y) ||
+	    get_user(n, &up->width) || put_user(n, &vw->width) ||
+	    get_user(n, &up->height) || put_user(n, &vw->height) ||
+	    get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
+	    get_user(n, &up->flags) || put_user(n, &vw->flags) ||
+	    get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
+	    get_user(n, &up->clips) || put_user(p, &vw->clips))
+		return -EFAULT;
+
+	if (nclips) {
+		struct video_clip32 __user *u = compat_ptr(n);
+		int i;
+		if (!u)
+			return -EINVAL;
+		for (i = 0; i < nclips; i++, u++, p++) {
+			s32 v;
+			if (get_user(v, &u->x) ||
+			    put_user(v, &p->x) ||
+			    get_user(v, &u->y) ||
+			    put_user(v, &p->y) ||
+			    get_user(v, &u->width) ||
+			    put_user(v, &p->width) ||
+			    get_user(v, &u->height) ||
+			    put_user(v, &p->height) ||
+			    put_user(NULL, &p->next))
+				return -EFAULT;
+		}
+	}
+
+	return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+}
+
+static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct video_tuner vt;
+		struct video_buffer vb;
+		struct video_window vw;
+		struct v4l2_format v2f;
+		struct v4l2_buffer v2b;
+		struct v4l2_framebuffer v2fb;
+		struct v4l2_standard v2s;
+		unsigned long vx;
+	} karg;
+	void __user *up = compat_ptr(arg);
+	int compatible_arg = 1;
+	int err = 0;
+
+	/* First, convert the command. */
+	switch(cmd) {
+	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+	case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+	case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+	case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+	case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+	case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+	case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+	case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+	case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+	case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+	case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+	case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+	case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
+	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+	case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+	};
+
+	switch(cmd) {
+	case VIDIOCSTUNER:
+	case VIDIOCGTUNER:
+		err = get_video_tuner32(&karg.vt, up);
+		compatible_arg = 0;
+
+		break;
+
+	case VIDIOCSFBUF:
+		err = get_video_buffer32(&karg.vb, up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOCSFREQ:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_OVERLAY:
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF:
+		err = get_user(karg.vx, (u32 __user *)up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOC_S_FBUF:
+		err = get_v4l2_framebuffer32(&karg.v2fb, up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOC_G_FMT:
+	case VIDIOC_S_FMT:
+	case VIDIOC_TRY_FMT:
+		err = get_v4l2_format32(&karg.v2f, up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOC_QUERYBUF:
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF:
+		err = get_v4l2_buffer32(&karg.v2b, up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOC_ENUMSTD:
+		err = get_v4l2_standard32(&karg.v2s, up);
+		compatible_arg = 0;
+		break;
+
+	case VIDIOCGWIN:
+	case VIDIOCGFBUF:
+	case VIDIOCGFREQ:
+	case VIDIOC_G_FBUF:
+	case VIDIOC_G_INPUT:
+		compatible_arg = 0;
+	};
+
+	if(err)
+		goto out;
+
+	if(compatible_arg)
+		err = native_ioctl(file, cmd, (unsigned long)up);
+	else {
+		mm_segment_t old_fs = get_fs();
+
+		set_fs(KERNEL_DS);
+		err = native_ioctl(file, cmd, (unsigned long)&karg);
+		set_fs(old_fs);
+	}
+	if(err == 0) {
+		switch(cmd) {
+		case VIDIOCGTUNER:
+			err = put_video_tuner32(&karg.vt, up);
+			break;
+
+		case VIDIOCGWIN:
+			err = put_video_window32(&karg.vw, up);
+			break;
+
+		case VIDIOCGFBUF:
+			err = put_video_buffer32(&karg.vb, up);
+			break;
+
+		case VIDIOC_G_FBUF:
+			err = put_v4l2_framebuffer32(&karg.v2fb, up);
+			break;
+
+		case VIDIOC_G_FMT:
+		case VIDIOC_S_FMT:
+		case VIDIOC_TRY_FMT:
+			err = put_v4l2_format32(&karg.v2f, up);
+			break;
+
+		case VIDIOC_QUERYBUF:
+		case VIDIOC_QBUF:
+		case VIDIOC_DQBUF:
+			err = put_v4l2_buffer32(&karg.v2b, up);
+			break;
+
+		case VIDIOC_ENUMSTD:
+			err = put_v4l2_standard32(&karg.v2s, up);
+			break;
+
+		case VIDIOCGFREQ:
+		case VIDIOC_G_INPUT:
+			err = put_user(((u32)karg.vx), (u32 __user *)up);
+			break;
+		};
+	}
+out:
+	return err;
+}
+
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+
+	if (!file->f_op->ioctl)
+		return ret;
+
+	switch (cmd) {
+	case VIDIOCSWIN32:
+		ret = do_set_window(file, cmd, arg);
+		break;
+	case VIDIOCGTUNER32:
+	case VIDIOCSTUNER32:
+	case VIDIOCGWIN32:
+	case VIDIOCGFBUF32:
+	case VIDIOCSFBUF32:
+	case VIDIOCGFREQ32:
+	case VIDIOCSFREQ32:
+	case VIDIOC_QUERYCAP:
+	case VIDIOC_ENUM_FMT:
+	case VIDIOC_G_FMT32:
+	case VIDIOC_S_FMT32:
+	case VIDIOC_REQBUFS:
+	case VIDIOC_QUERYBUF32:
+	case VIDIOC_G_FBUF32:
+	case VIDIOC_S_FBUF32:
+	case VIDIOC_OVERLAY32:
+	case VIDIOC_QBUF32:
+	case VIDIOC_DQBUF32:
+	case VIDIOC_STREAMON32:
+	case VIDIOC_STREAMOFF32:
+	case VIDIOC_G_PARM:
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+	case VIDIOC_ENUMSTD32:
+	case VIDIOC_ENUMINPUT32:
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL32:
+	case VIDIOC_QUERYCTRL:
+	case VIDIOC_G_INPUT32:
+	case VIDIOC_S_INPUT32:
+	case VIDIOC_TRY_FMT32:
+		ret = do_video_ioctl(file, cmd, arg);
+		break;
+
+	/* Little v, the video4linux ioctls (conflict?) */
+	case VIDIOCGCAP:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
+	case VIDIOCGPICT:
+	case VIDIOCSPICT:
+	case VIDIOCCAPTURE:
+	case VIDIOCKEY:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	case VIDIOCSYNC:
+	case VIDIOCMCAPTURE:
+	case VIDIOCGMBUF:
+	case VIDIOCGUNIT:
+	case VIDIOCGCAPTURE:
+	case VIDIOCSCAPTURE:
+
+	/* BTTV specific... */
+	case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
+	case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+	case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+	case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
+		ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+		break;
+	}
+	return ret;
+}
+#else
+long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+#endif
+EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index b7ec9bf..9f59541 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3807,6 +3807,7 @@
 	.read		= cpia_read,
 	.mmap		= cpia_mmap,
 	.ioctl          = cpia_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index 643ead1..b421068 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -27,7 +27,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
@@ -39,21 +39,6 @@
 
 MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
 
-#define cs53l32a_dbg(fmt, arg...) \
-	do { \
-		if (debug) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->driver.name, \
-			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-#define cs53l32a_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define cs53l32a_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
 
 
@@ -74,50 +59,59 @@
 static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
 			    void *arg)
 {
-	int *input = arg;
+	struct v4l2_audio *input = arg;
+	struct v4l2_control *ctrl = arg;
 
 	switch (cmd) {
-	case AUDC_SET_INPUT:
-		switch (*input) {
-		case AUDIO_TUNER:
-			cs53l32a_write(client, 0x01, 0x01);
-			break;
-		case AUDIO_EXTERN:
-			cs53l32a_write(client, 0x01, 0x21);
-			break;
-		case AUDIO_MUTE:
-			cs53l32a_write(client, 0x03, 0xF0);
-			break;
-		case AUDIO_UNMUTE:
-			cs53l32a_write(client, 0x03, 0x30);
-			break;
-		default:
-			cs53l32a_err("Invalid input %d.\n", *input);
+	case VIDIOC_S_AUDIO:
+		/* There are 2 physical inputs, but the second input can be
+		   placed in two modes, the first mode bypasses the PGA (gain),
+		   the second goes through the PGA. Hence there are three
+		   possible inputs to choose from. */
+		if (input->index > 2) {
+			v4l_err(client, "Invalid input %d.\n", input->index);
 			return -EINVAL;
 		}
+		cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
+		break;
+
+	case VIDIOC_G_AUDIO:
+		memset(input, 0, sizeof(*input));
+		input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
+		break;
+
+	case VIDIOC_G_CTRL:
+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+			ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
+			break;
+		}
+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+			return -EINVAL;
+		ctrl->value = (s8)cs53l32a_read(client, 0x04);
 		break;
 
 	case VIDIOC_S_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-
-			if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-				return -EINVAL;
-			if (ctrl->value > 12 || ctrl->value < -90)
-				return -EINVAL;
-			cs53l32a_write(client, 0x04, (u8) ctrl->value);
-			cs53l32a_write(client, 0x05, (u8) ctrl->value);
+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+			cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
 			break;
 		}
+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+			return -EINVAL;
+		if (ctrl->value > 12 || ctrl->value < -96)
+			return -EINVAL;
+		cs53l32a_write(client, 0x04, (u8) ctrl->value);
+		cs53l32a_write(client, 0x05, (u8) ctrl->value);
+		break;
 
 	case VIDIOC_LOG_STATUS:
 		{
 			u8 v = cs53l32a_read(client, 0x01);
 			u8 m = cs53l32a_read(client, 0x03);
+			s8 vol = cs53l32a_read(client, 0x04);
 
-			cs53l32a_info("Input: %s%s\n",
-				      v == 0x21 ? "external line in" : "tuner",
+			v4l_info(client, "Input:  %d%s\n", (v >> 4) & 3,
 				      (m & 0xC0) ? " (muted)" : "");
+			v4l_info(client, "Volume: %d dB\n", vol);
 			break;
 		}
 
@@ -157,12 +151,12 @@
 	client->driver = &i2c_driver;
 	snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
 
-	cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 
 	for (i = 1; i <= 7; i++) {
 		u8 v = cs53l32a_read(client, i);
 
-		cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+		v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
 	}
 
 	/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
@@ -180,7 +174,7 @@
 	for (i = 1; i <= 7; i++) {
 		u8 v = cs53l32a_read(client, i);
 
-		cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+		v4l_dbg(1, client, "Read Reg %d %02x\n", i, v);
 	}
 
 	i2c_attach_client(client);
@@ -190,11 +184,7 @@
 
 static int cs53l32a_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-	if (adapter->id == I2C_HW_B_BT848)
-#endif
 		return i2c_probe(adapter, &addr_data, cs53l32a_attach);
 	return 0;
 }
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 740908f..cb9a798 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -23,11 +23,13 @@
 
 #include "cx25840.h"
 
-inline static int set_audclk_freq(struct i2c_client *client,
-				 enum v4l2_audio_clock_freq freq)
+static int set_audclk_freq(struct i2c_client *client, u32 freq)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
+	if (freq != 32000 && freq != 44100 && freq != 48000)
+		return -EINVAL;
+
 	/* assert soft reset */
 	cx25840_and_or(client, 0x810, ~0x1, 0x01);
 
@@ -35,10 +37,9 @@
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
 	cx25840_write(client, 0x127, 0x50);
 
-	switch (state->audio_input) {
-	case AUDIO_TUNER:
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		switch (freq) {
-		case V4L2_AUDCLK_32_KHZ:
+		case 32000:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f040610);
 
@@ -51,7 +52,7 @@
 			cx25840_write4(client, 0x90c, 0x7ff70108);
 			break;
 
-		case V4L2_AUDCLK_441_KHZ:
+		case 44100:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f040910);
 
@@ -64,7 +65,7 @@
 			cx25840_write4(client, 0x90c, 0x596d0108);
 			break;
 
-		case V4L2_AUDCLK_48_KHZ:
+		case 48000:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f040a10);
 
@@ -77,14 +78,9 @@
 			cx25840_write4(client, 0x90c, 0xaa4f0108);
 			break;
 		}
-		break;
-
-	case AUDIO_EXTERN_1:
-	case AUDIO_EXTERN_2:
-	case AUDIO_INTERN:
-	case AUDIO_RADIO:
+	} else {
 		switch (freq) {
-		case V4L2_AUDCLK_32_KHZ:
+		case 32000:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f04081e);
 
@@ -103,7 +99,7 @@
 			cx25840_write(client, 0x127, 0x54);
 			break;
 
-		case V4L2_AUDCLK_441_KHZ:
+		case 44100:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f040918);
 
@@ -119,7 +115,7 @@
 			cx25840_write4(client, 0x90c, 0x85730108);
 			break;
 
-		case V4L2_AUDCLK_48_KHZ:
+		case 48000:
 			/* VID_PLL and AUX_PLL */
 			cx25840_write4(client, 0x108, 0x0f040a18);
 
@@ -135,7 +131,6 @@
 			cx25840_write4(client, 0x90c, 0x55550108);
 			break;
 		}
-		break;
 	}
 
 	/* deassert soft reset */
@@ -146,51 +141,36 @@
 	return 0;
 }
 
-static int set_input(struct i2c_client *client, int audio_input)
+void cx25840_audio_set_path(struct i2c_client *client)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
-	cx25840_dbg("set audio input (%d)\n", audio_input);
-
 	/* stop microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0);
 
 	/* Mute everything to prevent the PFFT! */
 	cx25840_write(client, 0x8d3, 0x1f);
 
-	switch (audio_input) {
-	case AUDIO_TUNER:
-		/* Set Path1 to Analog Demod Main Channel */
-		cx25840_write4(client, 0x8d0, 0x7038061f);
-
-		/* When the microcontroller detects the
-		 * audio format, it will unmute the lines */
-		cx25840_and_or(client, 0x803, ~0x10, 0x10);
-		break;
-
-	case AUDIO_EXTERN_1:
-	case AUDIO_EXTERN_2:
-	case AUDIO_INTERN:
-	case AUDIO_RADIO:
+	if (state->aud_input == CX25840_AUDIO_SERIAL) {
 		/* Set Path1 to Serial Audio Input */
 		cx25840_write4(client, 0x8d0, 0x12100101);
 
 		/* The microcontroller should not be started for the
 		 * non-tuner inputs: autodetection is specific for
 		 * TV audio. */
-		break;
+	} else {
+		/* Set Path1 to Analog Demod Main Channel */
+		cx25840_write4(client, 0x8d0, 0x7038061f);
 
-	default:
-		cx25840_dbg("Invalid audio input selection %d\n", audio_input);
-		return -EINVAL;
+		/* When the microcontroller detects the
+		 * audio format, it will unmute the lines */
+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
 	}
 
-	state->audio_input = audio_input;
-
-	return set_audclk_freq(client, state->audclk_freq);
+	set_audclk_freq(client, state->audclk_freq);
 }
 
-inline static int get_volume(struct i2c_client *client)
+static int get_volume(struct i2c_client *client)
 {
 	/* Volume runs +18dB to -96dB in 1/2dB steps
 	 * change to fit the msp3400 -114dB to +12dB range */
@@ -201,7 +181,7 @@
 	return vol << 9;
 }
 
-inline static void set_volume(struct i2c_client *client, int volume)
+static void set_volume(struct i2c_client *client, int volume)
 {
 	/* First convert the volume to msp3400 values (0-127) */
 	int vol = volume >> 9;
@@ -218,7 +198,7 @@
 	cx25840_write(client, 0x8d4, 228 - (vol * 2));
 }
 
-inline static int get_bass(struct i2c_client *client)
+static int get_bass(struct i2c_client *client)
 {
 	/* bass is 49 steps +12dB to -12dB */
 
@@ -228,13 +208,13 @@
 	return bass;
 }
 
-inline static void set_bass(struct i2c_client *client, int bass)
+static void set_bass(struct i2c_client *client, int bass)
 {
 	/* PATH1_EQ_BASS_VOL */
 	cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
 }
 
-inline static int get_treble(struct i2c_client *client)
+static int get_treble(struct i2c_client *client)
 {
 	/* treble is 49 steps +12dB to -12dB */
 
@@ -244,13 +224,13 @@
 	return treble;
 }
 
-inline static void set_treble(struct i2c_client *client, int treble)
+static void set_treble(struct i2c_client *client, int treble)
 {
 	/* PATH1_EQ_TREBLE_VOL */
 	cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
 }
 
-inline static int get_balance(struct i2c_client *client)
+static int get_balance(struct i2c_client *client)
 {
 	/* balance is 7 bit, 0 to -96dB */
 
@@ -264,7 +244,7 @@
 	return balance << 8;
 }
 
-inline static void set_balance(struct i2c_client *client, int balance)
+static void set_balance(struct i2c_client *client, int balance)
 {
 	int bal = balance >> 8;
 	if (bal > 0x80) {
@@ -280,17 +260,17 @@
 	}
 }
 
-inline static int get_mute(struct i2c_client *client)
+static int get_mute(struct i2c_client *client)
 {
 	/* check SRC1_MUTE_EN */
 	return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
 }
 
-inline static void set_mute(struct i2c_client *client, int mute)
+static void set_mute(struct i2c_client *client, int mute)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
-	if (state->audio_input == AUDIO_TUNER) {
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		/* Must turn off microcontroller in order to mute sound.
 		 * Not sure if this is the best method, but it does work.
 		 * If the microcontroller is running, then it will undo any
@@ -314,10 +294,9 @@
 	struct v4l2_control *ctrl = arg;
 
 	switch (cmd) {
-	case AUDC_SET_INPUT:
-		return set_input(client, *(int *)arg);
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+		return set_audclk_freq(client, *(u32 *)arg);
+
 	case VIDIOC_G_CTRL:
 		switch (ctrl->id) {
 		case V4L2_CID_AUDIO_VOLUME:
@@ -339,6 +318,7 @@
 			return -EINVAL;
 		}
 		break;
+
 	case VIDIOC_S_CTRL:
 		switch (ctrl->id) {
 		case V4L2_CID_AUDIO_VOLUME:
@@ -360,6 +340,7 @@
 			return -EINVAL;
 		}
 		break;
+
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 3b09f46..d45237d 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -43,11 +43,11 @@
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
-int cx25840_debug = 0;
+int debug = 0;
 
-module_param(cx25840_debug, bool, 0644);
+module_param(debug, bool, 0644);
 
-MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
 I2C_CLIENT_INSMOD;
 
@@ -115,13 +115,13 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int set_input(struct i2c_client *, enum cx25840_input);
-static void input_change(struct i2c_client *);
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+						enum cx25840_audio_input aud_input);
 static void log_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
-static inline void init_dll1(struct i2c_client *client)
+static void init_dll1(struct i2c_client *client)
 {
 	/* This is the Hauppauge sequence used to
 	 * initialize the Delay Lock Loop 1 (ADC DLL). */
@@ -135,7 +135,7 @@
 	cx25840_write(client, 0x15b, 0x10);
 }
 
-static inline void init_dll2(struct i2c_client *client)
+static void init_dll2(struct i2c_client *client)
 {
 	/* This is the Hauppauge sequence used to
 	 * initialize the Delay Lock Loop 2 (ADC DLL). */
@@ -195,10 +195,8 @@
 	/* AC97 shift */
 	cx25840_write(client, 0x8cf, 0x0f);
 
-	/* (re)set video input */
-	set_input(client, state->input);
-	/* (re)set audio input */
-	cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+	/* (re)set input */
+	set_input(client, state->vid_input, state->aud_input);
 
 	/* start microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
@@ -223,7 +221,7 @@
 		cx25840_write(client, 0x80b, 0x10);
 	} else if (std & V4L2_STD_NTSC) {
 		/* NTSC */
-		if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
+		if (state->pvr150_workaround) {
 			/* Certain Hauppauge PVR150 models have a hardware bug
 			   that causes audio to drop out. For these models the
 			   audio standard must be set explicitly.
@@ -259,72 +257,68 @@
 	}
 }
 
-static int set_input(struct i2c_client *client, enum cx25840_input input)
+static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
+						enum cx25840_audio_input aud_input)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
+	u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
+			   vid_input <= CX25840_COMPOSITE8);
+	u8 reg;
 
-	cx25840_dbg("decoder set input (%d)\n", input);
+	v4l_dbg(1, client, "decoder set video input %d, audio input %d\n",
+			vid_input, aud_input);
 
-	switch (input) {
-	case CX25840_TUNER:
-		cx25840_dbg("now setting Tuner input\n");
+	if (is_composite) {
+		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+	} else {
+		int luma = vid_input & 0xf0;
+		int chroma = vid_input & 0xf00;
 
-		if (state->cardtype == CARDTYPE_PVR150 ||
-		    state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
-			/* CH_SEL_ADC2=1 */
-			cx25840_and_or(client, 0x102, ~0x2, 0x02);
+		if ((vid_input & ~0xff0) ||
+		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+			v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
+			return -EINVAL;
 		}
-
-		/* Video Input Control */
-		if (state->cardtype == CARDTYPE_PG600) {
-			cx25840_write(client, 0x103, 0x11);
+		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
+		if (chroma >= CX25840_SVIDEO_CHROMA7) {
+			reg &= 0x3f;
+			reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
 		} else {
-			cx25840_write(client, 0x103, 0x46);
+			reg &= 0xcf;
+			reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
 		}
+	}
 
-		/* INPUT_MODE=0 */
-		cx25840_and_or(client, 0x401, ~0x6, 0x00);
+	switch (aud_input) {
+	case CX25840_AUDIO_SERIAL:
+		/* do nothing, use serial audio input */
 		break;
-
-	case CX25840_COMPOSITE0:
-	case CX25840_COMPOSITE1:
-		cx25840_dbg("now setting Composite input\n");
-
-		/* Video Input Control */
-		if (state->cardtype == CARDTYPE_PG600) {
-			cx25840_write(client, 0x103, 0x00);
-		} else {
-			cx25840_write(client, 0x103, 0x02);
-		}
-
-		/* INPUT_MODE=0 */
-		cx25840_and_or(client, 0x401, ~0x6, 0x00);
-		break;
-
-	case CX25840_SVIDEO0:
-	case CX25840_SVIDEO1:
-		cx25840_dbg("now setting S-Video input\n");
-
-		/* CH_SEL_ADC2=0 */
-		cx25840_and_or(client, 0x102, ~0x2, 0x00);
-
-		/* Video Input Control */
-		if (state->cardtype == CARDTYPE_PG600) {
-			cx25840_write(client, 0x103, 0x02);
-		} else {
-			cx25840_write(client, 0x103, 0x10);
-		}
-
-		/* INPUT_MODE=1 */
-		cx25840_and_or(client, 0x401, ~0x6, 0x02);
-		break;
+	case CX25840_AUDIO4: reg &= ~0x30; break;
+	case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+	case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+	case CX25840_AUDIO7: reg &= ~0xc0; break;
+	case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
 	default:
-		cx25840_err("%d is not a valid input!\n", input);
+		v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
 		return -EINVAL;
 	}
 
-	state->input = input;
+	cx25840_write(client, 0x103, reg);
+	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
+	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
+	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+	cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+	if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+		cx25840_and_or(client, 0x102, ~0x4, 4);
+	else
+		cx25840_and_or(client, 0x102, ~0x4, 0);
+
+	state->vid_input = vid_input;
+	state->aud_input = aud_input;
+	cx25840_audio_set_path(client);
 	input_change(client);
 	return 0;
 }
@@ -395,23 +389,14 @@
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
-	case CX25840_CID_CARDTYPE:
-		switch (ctrl->value) {
-		case CARDTYPE_PVR150:
-		case CARDTYPE_PVR150_WORKAROUND:
-		case CARDTYPE_PG600:
-			state->cardtype = ctrl->value;
-			break;
-		default:
-			return -ERANGE;
-		}
-
-		set_input(client, state->input);
+	case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+		state->pvr150_workaround = ctrl->value;
+		set_input(client, state->vid_input, state->aud_input);
 		break;
 
 	case V4L2_CID_BRIGHTNESS:
 		if (ctrl->value < 0 || ctrl->value > 255) {
-			cx25840_err("invalid brightness setting %d\n",
+			v4l_err(client, "invalid brightness setting %d\n",
 				    ctrl->value);
 			return -ERANGE;
 		}
@@ -421,7 +406,7 @@
 
 	case V4L2_CID_CONTRAST:
 		if (ctrl->value < 0 || ctrl->value > 127) {
-			cx25840_err("invalid contrast setting %d\n",
+			v4l_err(client, "invalid contrast setting %d\n",
 				    ctrl->value);
 			return -ERANGE;
 		}
@@ -431,7 +416,7 @@
 
 	case V4L2_CID_SATURATION:
 		if (ctrl->value < 0 || ctrl->value > 127) {
-			cx25840_err("invalid saturation setting %d\n",
+			v4l_err(client, "invalid saturation setting %d\n",
 				    ctrl->value);
 			return -ERANGE;
 		}
@@ -442,7 +427,7 @@
 
 	case V4L2_CID_HUE:
 		if (ctrl->value < -127 || ctrl->value > 127) {
-			cx25840_err("invalid hue setting %d\n", ctrl->value);
+			v4l_err(client, "invalid hue setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
@@ -455,6 +440,9 @@
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
 		return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -465,11 +453,11 @@
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
-	case CX25840_CID_CARDTYPE:
-		ctrl->value = state->cardtype;
+	case CX25840_CID_ENABLE_PVR150_WORKAROUND:
+		ctrl->value = state->pvr150_workaround;
 		break;
 	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = cx25840_read(client, 0x414) + 128;
+		ctrl->value = (s8)cx25840_read(client, 0x414) + 128;
 		break;
 	case V4L2_CID_CONTRAST:
 		ctrl->value = cx25840_read(client, 0x415) >> 1;
@@ -478,7 +466,7 @@
 		ctrl->value = cx25840_read(client, 0x420) >> 1;
 		break;
 	case V4L2_CID_HUE:
-		ctrl->value = cx25840_read(client, 0x422);
+		ctrl->value = (s8)cx25840_read(client, 0x422);
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 	case V4L2_CID_AUDIO_BASS:
@@ -527,7 +515,7 @@
 
 		if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
 		    (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
-			cx25840_err("%dx%d is not a valid size!\n",
+			v4l_err(client, "%dx%d is not a valid size!\n",
 				    pix->width, pix->height);
 			return -ERANGE;
 		}
@@ -545,7 +533,7 @@
 		else
 			filter = 3;
 
-		cx25840_dbg("decoder set size %dx%d -> scale  %ux%u\n",
+		v4l_dbg(1, client, "decoder set size %dx%d -> scale  %ux%u\n",
 			    pix->width, pix->height, HSC, VSC);
 
 		/* HSCALE=HSC */
@@ -574,17 +562,98 @@
 
 /* ----------------------------------------------------------------------- */
 
+static struct v4l2_queryctrl cx25840_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 128,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 0,
+		.flags 	       = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 58880,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_BALANCE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Balance",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 1,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_AUDIO_BASS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Bass",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+	}, {
+		.id            = V4L2_CID_AUDIO_TREBLE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Treble",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+	},
+};
+
+/* ----------------------------------------------------------------------- */
+
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 			   void *arg)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 	struct v4l2_tuner *vt = arg;
-	int result = 0;
 
 	switch (cmd) {
-	case 0:
-		break;
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	/* ioctls to allow direct access to the
 	 * cx25840 registers for testing */
@@ -615,18 +684,16 @@
 		return cx25840_vbi(client, cmd, arg);
 
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-	case AUDC_SET_INPUT:
-		result = cx25840_audio(client, cmd, arg);
-		break;
+		return cx25840_audio(client, cmd, arg);
 
 	case VIDIOC_STREAMON:
-		cx25840_dbg("enable output\n");
+		v4l_dbg(1, client, "enable output\n");
 		cx25840_write(client, 0x115, 0x8c);
 		cx25840_write(client, 0x116, 0x07);
 		break;
 
 	case VIDIOC_STREAMOFF:
-		cx25840_dbg("disable output\n");
+		v4l_dbg(1, client, "disable output\n");
 		cx25840_write(client, 0x115, 0x00);
 		cx25840_write(client, 0x116, 0x00);
 		break;
@@ -636,28 +703,58 @@
 		break;
 
 	case VIDIOC_G_CTRL:
-		result = get_v4lctrl(client, (struct v4l2_control *)arg);
-		break;
+		return get_v4lctrl(client, (struct v4l2_control *)arg);
 
 	case VIDIOC_S_CTRL:
-		result = set_v4lctrl(client, (struct v4l2_control *)arg);
-		break;
+		return set_v4lctrl(client, (struct v4l2_control *)arg);
+
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
+			if (qc->id && qc->id == cx25840_qctrl[i].id) {
+				memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
+				return 0;
+			}
+		return -EINVAL;
+	}
 
 	case VIDIOC_G_STD:
 		*(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
 		break;
 
 	case VIDIOC_S_STD:
-		result = set_v4lstd(client, *(v4l2_std_id *)arg);
+		state->radio = 0;
+		return set_v4lstd(client, *(v4l2_std_id *)arg);
+
+	case AUDC_SET_RADIO:
+		state->radio = 1;
 		break;
 
 	case VIDIOC_G_INPUT:
-		*(int *)arg = state->input;
+		*(int *)arg = state->vid_input;
 		break;
 
 	case VIDIOC_S_INPUT:
-		result = set_input(client, *(int *)arg);
+		return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input);
+
+	case VIDIOC_S_AUDIO:
+	{
+		struct v4l2_audio *input = arg;
+
+		return set_input(client, state->vid_input, input->index);
+	}
+
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *input = arg;
+
+		memset(input, 0, sizeof(*input));
+		input->index = state->aud_input;
 		break;
+	}
 
 	case VIDIOC_S_FREQUENCY:
 		input_change(client);
@@ -670,6 +767,9 @@
 		u8 vpres = cx25840_read(client, 0x80a) & 0x10;
 		int val = 0;
 
+		if (state->radio)
+			break;
+
 		vt->capability |=
 		    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
 		    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
@@ -724,12 +824,10 @@
 		break;
 
 	case VIDIOC_G_FMT:
-		result = get_v4lfmt(client, (struct v4l2_format *)arg);
-		break;
+		return get_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_S_FMT:
-		result = set_v4lfmt(client, (struct v4l2_format *)arg);
-		break;
+		return set_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_INT_RESET:
 		cx25840_initialize(client, 0);
@@ -741,11 +839,10 @@
 		break;
 
 	default:
-		cx25840_err("invalid ioctl %x\n", cmd);
 		return -EINVAL;
 	}
 
-	return result;
+	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -775,7 +872,7 @@
 	client->driver = &i2c_driver_cx25840;
 	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
 
-	cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+	v4l_dbg(1, client, "detecting cx25840 client on address 0x%x\n", address << 1);
 
 	device_id = cx25840_read(client, 0x101) << 8;
 	device_id |= cx25840_read(client, 0x100);
@@ -783,12 +880,12 @@
 	/* The high byte of the device ID should be
 	 * 0x84 if chip is present */
 	if ((device_id & 0xff00) != 0x8400) {
-		cx25840_dbg("cx25840 not found\n");
+		v4l_dbg(1, client, "cx25840 not found\n");
 		kfree(client);
 		return 0;
 	}
 
-	cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+	v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
 		    (device_id & 0xfff0) >> 4,
 		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
 		    address << 1, adapter->name);
@@ -801,10 +898,10 @@
 
 	i2c_set_clientdata(client, state);
 	memset(state, 0, sizeof(struct cx25840_state));
-	state->input = CX25840_TUNER;
-	state->audclk_freq = V4L2_AUDCLK_48_KHZ;
-	state->audio_input = AUDIO_TUNER;
-	state->cardtype = CARDTYPE_PVR150;
+	state->vid_input = CX25840_COMPOSITE7;
+	state->aud_input = CX25840_AUDIO8;
+	state->audclk_freq = 48000;
+	state->pvr150_workaround = 0;
 
 	cx25840_initialize(client, 1);
 
@@ -815,11 +912,7 @@
 
 static int cx25840_attach_adapter(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-	if (adapter->id == I2C_HW_B_BT848)
-#endif
 		return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
 	return 0;
 }
@@ -846,9 +939,7 @@
 	.driver = {
 		.name = "cx25840",
 	},
-
 	.id = I2C_DRIVERID_CX25840,
-
 	.attach_adapter = cx25840_attach_adapter,
 	.detach_client = cx25840_detach_client,
 	.command = cx25840_command,
@@ -892,11 +983,13 @@
 	u8 pref_mode = cx25840_read(client, 0x809);
 	u8 afc0 = cx25840_read(client, 0x80b);
 	u8 mute_ctl = cx25840_read(client, 0x8d3);
+	int vid_input = state->vid_input;
+	int aud_input = state->aud_input;
 	char *p;
 
-	cx25840_info("Video signal:              %spresent\n",
+	v4l_info(client, "Video signal:              %spresent\n",
 		    (microctrl_vidfmt & 0x10) ? "" : "not ");
-	cx25840_info("Detected format:           %s\n",
+	v4l_info(client, "Detected format:           %s\n",
 		    fmt_strs[gen_stat1 & 0xf]);
 
 	switch (mod_det_stat0) {
@@ -911,7 +1004,7 @@
 	case 0xfe: p = "forced mode"; break;
 	default: p = "not defined";
 	}
-	cx25840_info("Detected audio mode:       %s\n", p);
+	v4l_info(client, "Detected audio mode:       %s\n", p);
 
 	switch (mod_det_stat1) {
 	case 0x00: p = "not defined"; break;
@@ -937,10 +1030,10 @@
 	case 0xff: p = "no detected audio standard"; break;
 	default: p = "not defined";
 	}
-	cx25840_info("Detected audio standard:   %s\n", p);
-	cx25840_info("Audio muted:               %s\n",
+	v4l_info(client, "Detected audio standard:   %s\n", p);
+	v4l_info(client, "Audio muted:               %s\n",
 		    (mute_ctl & 0x2) ? "yes" : "no");
-	cx25840_info("Audio microcontroller:     %s\n",
+	v4l_info(client, "Audio microcontroller:     %s\n",
 		    (download_ctl & 0x10) ? "running" : "stopped");
 
 	switch (audio_config >> 4) {
@@ -962,7 +1055,7 @@
 	case 0x0f: p = "automatic detection"; break;
 	default: p = "undefined";
 	}
-	cx25840_info("Configured audio standard: %s\n", p);
+	v4l_info(client, "Configured audio standard: %s\n", p);
 
 	if ((audio_config >> 4) < 0xF) {
 		switch (audio_config & 0xF) {
@@ -979,7 +1072,7 @@
 		case 0x0a: p = "SAP"; break;
 		default: p = "undefined";
 		}
-		cx25840_info("Configured audio mode:     %s\n", p);
+		v4l_info(client, "Configured audio mode:     %s\n", p);
 	} else {
 		switch (audio_config & 0xF) {
 		case 0x00: p = "BG"; break;
@@ -995,30 +1088,27 @@
 		case 0x0f: p = "automatic standard and mode detection"; break;
 		default: p = "undefined";
 		}
-		cx25840_info("Configured audio system:   %s\n", p);
+		v4l_info(client, "Configured audio system:   %s\n", p);
 	}
 
-	cx25840_info("Specified standard:        %s\n",
+	v4l_info(client, "Specified standard:        %s\n",
 		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
 
-	switch (state->input) {
-	case CX25840_COMPOSITE0: p = "Composite 0"; break;
-	case CX25840_COMPOSITE1: p = "Composite 1"; break;
-	case CX25840_SVIDEO0: p = "S-Video 0"; break;
-	case CX25840_SVIDEO1: p = "S-Video 1"; break;
-	case CX25840_TUNER: p = "Tuner"; break;
+	if (vid_input >= CX25840_COMPOSITE1 &&
+	    vid_input <= CX25840_COMPOSITE8) {
+		v4l_info(client, "Specified video input:     Composite %d\n",
+			vid_input - CX25840_COMPOSITE1 + 1);
+	} else {
+		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
 	}
-	cx25840_info("Specified input:           %s\n", p);
-	cx25840_info("Specified audio input:     %s\n",
-		    state->audio_input == 0 ? "Tuner" : "External");
+	if (aud_input) {
+		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+	} else {
+		v4l_info(client, "Specified audio input:     External\n");
+	}
 
-	switch (state->audclk_freq) {
-	case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
-	case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
-	case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
-	default: p = "undefined";
-	}
-	cx25840_info("Specified audioclock freq: %s\n", p);
+	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
 
 	switch (pref_mode & 0xf) {
 	case 0: p = "mono/language A"; break;
@@ -1031,7 +1121,7 @@
 	case 7: p = "language AB"; break;
 	default: p = "undefined";
 	}
-	cx25840_info("Preferred audio mode:      %s\n", p);
+	v4l_info(client, "Preferred audio mode:      %s\n", p);
 
 	if ((audio_config & 0xf) == 0xf) {
 		switch ((afc0 >> 3) & 0x3) {
@@ -1040,7 +1130,7 @@
 		case 2: p = "autodetect"; break;
 		default: p = "undefined";
 		}
-		cx25840_info("Selected 65 MHz format:    %s\n", p);
+		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
 
 		switch (afc0 & 0x7) {
 		case 0: p = "chroma"; break;
@@ -1050,6 +1140,6 @@
 		case 4: p = "autodetect"; break;
 		default: p = "undefined";
 		}
-		cx25840_info("Selected 45 MHz format:    %s\n", p);
+		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
 	}
 }
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index df9d50a..e1a7823 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -15,7 +15,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -38,7 +37,7 @@
 MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
 MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
 
-static inline void set_i2c_delay(struct i2c_client *client, int delay)
+static void set_i2c_delay(struct i2c_client *client, int delay)
 {
 	struct i2c_algo_bit_data *algod = client->adapter->algo_data;
 
@@ -52,7 +51,7 @@
 	}
 }
 
-static inline void start_fw_load(struct i2c_client *client)
+static void start_fw_load(struct i2c_client *client)
 {
 	/* DL_ADDR_LB=0 DL_ADDR_HB=0 */
 	cx25840_write(client, 0x800, 0x00);
@@ -66,7 +65,7 @@
 		set_i2c_delay(client, 3);
 }
 
-static inline void end_fw_load(struct i2c_client *client)
+static void end_fw_load(struct i2c_client *client)
 {
 	if (fastfw)
 		set_i2c_delay(client, 10);
@@ -77,38 +76,47 @@
 	cx25840_write(client, 0x803, 0x03);
 }
 
-static inline int check_fw_load(struct i2c_client *client, int size)
+static int check_fw_load(struct i2c_client *client, int size)
 {
 	/* DL_ADDR_HB DL_ADDR_LB */
 	int s = cx25840_read(client, 0x801) << 8;
 	s |= cx25840_read(client, 0x800);
 
 	if (size != s) {
-		cx25840_err("firmware %s load failed\n", firmware);
+		v4l_err(client, "firmware %s load failed\n", firmware);
 		return -EINVAL;
 	}
 
-	cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+	v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
 	return 0;
 }
 
-static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+static int fw_write(struct i2c_client *client, u8 * data, int size)
 {
-	if (i2c_master_send(client, data, size) < size) {
+	int sent;
+
+	if ((sent = i2c_master_send(client, data, size)) < size) {
 
 		if (fastfw) {
-			cx25840_err("333MHz i2c firmware load failed\n");
+			v4l_err(client, "333MHz i2c firmware load failed\n");
 			fastfw = 0;
 			set_i2c_delay(client, 10);
 
+			if (sent > 2) {
+				u16 dl_addr = cx25840_read(client, 0x801) << 8;
+				dl_addr |= cx25840_read(client, 0x800);
+				dl_addr -= sent - 2;
+				cx25840_write(client, 0x801, dl_addr >> 8);
+				cx25840_write(client, 0x800, dl_addr & 0xff);
+			}
+
 			if (i2c_master_send(client, data, size) < size) {
-				cx25840_err
-				    ("100MHz i2c firmware load failed\n");
+				v4l_err(client, "100MHz i2c firmware load failed\n");
 				return -ENOSYS;
 			}
 
 		} else {
-			cx25840_err("firmware load i2c failure\n");
+			v4l_err(client, "firmware load i2c failure\n");
 			return -ENOSYS;
 		}
 
@@ -124,7 +132,7 @@
 	int size, send, retval;
 
 	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
-		cx25840_err("unable to open firmware %s\n", firmware);
+		v4l_err(client, "unable to open firmware %s\n", firmware);
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 13ba4e1..04d879d 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -22,7 +22,7 @@
 
 #include "cx25840.h"
 
-static inline int odd_parity(u8 c)
+static int odd_parity(u8 c)
 {
 	c ^= (c >> 4);
 	c ^= (c >> 2);
@@ -31,7 +31,7 @@
 	return c & 1;
 }
 
-static inline int decode_vps(u8 * dst, u8 * p)
+static int decode_vps(u8 * dst, u8 * p)
 {
 	static const u8 biphase_tbl[] = {
 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
index 40aa59f..fd22f30 100644
--- a/drivers/media/video/cx25840/cx25840.h
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -24,48 +24,60 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
-extern int cx25840_debug;
-
-#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
-	printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-	       client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define cx25840_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
-
-/* The CARDTYPE_PVR150_WORKAROUND cardtype activates a workaround for a
-   hardware bug that is present in PVR150 (and possible PVR500) cards that
-   have certain NTSC tuners (tveeprom model numbers 85, 99 and 112). The
+/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
+   present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
+   certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
    audio autodetect fails on some channels for these models and the workaround
    is to select the audio standard explicitly. Many thanks to Hauppauge for
    providing this information. */
-enum cx25840_cardtype {
-	CARDTYPE_PVR150,
-	CARDTYPE_PG600,
-	CARDTYPE_PVR150_WORKAROUND,
+#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_video_input {
+	/* Composite video inputs In1-In8 */
+	CX25840_COMPOSITE1 = 1,
+	CX25840_COMPOSITE2,
+	CX25840_COMPOSITE3,
+	CX25840_COMPOSITE4,
+	CX25840_COMPOSITE5,
+	CX25840_COMPOSITE6,
+	CX25840_COMPOSITE7,
+	CX25840_COMPOSITE8,
+
+	/* S-Video inputs consist of one luma input (In1-In4) ORed with one
+	   chroma input (In5-In8) */
+	CX25840_SVIDEO_LUMA1 = 0x10,
+	CX25840_SVIDEO_LUMA2 = 0x20,
+	CX25840_SVIDEO_LUMA3 = 0x30,
+	CX25840_SVIDEO_LUMA4 = 0x40,
+	CX25840_SVIDEO_CHROMA4 = 0x400,
+	CX25840_SVIDEO_CHROMA5 = 0x500,
+	CX25840_SVIDEO_CHROMA6 = 0x600,
+	CX25840_SVIDEO_CHROMA7 = 0x700,
+	CX25840_SVIDEO_CHROMA8 = 0x800,
+
+	/* S-Video aliases for common luma/chroma combinations */
+	CX25840_SVIDEO1 = 0x510,
+	CX25840_SVIDEO2 = 0x620,
+	CX25840_SVIDEO3 = 0x730,
+	CX25840_SVIDEO4 = 0x840,
 };
 
-enum cx25840_input {
-	CX25840_TUNER,
-	CX25840_COMPOSITE0,
-	CX25840_COMPOSITE1,
-	CX25840_SVIDEO0,
-	CX25840_SVIDEO1
+enum cx25840_audio_input {
+	/* Audio inputs: serial or In4-In8 */
+	CX25840_AUDIO_SERIAL,
+	CX25840_AUDIO4 = 4,
+	CX25840_AUDIO5,
+	CX25840_AUDIO6,
+	CX25840_AUDIO7,
+	CX25840_AUDIO8,
 };
 
 struct cx25840_state {
-	enum cx25840_cardtype cardtype;
-	enum cx25840_input input;
-	int audio_input;
-	enum v4l2_audio_clock_freq audclk_freq;
+	int pvr150_workaround;
+	int radio;
+	enum cx25840_video_input vid_input;
+	enum cx25840_audio_input aud_input;
+	u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -84,6 +96,7 @@
 /* ----------------------------------------------------------------------- */
 /* cx25850-audio.c                                                         */
 int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+void cx25840_audio_set_path(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 /* cx25850-vbi.c                                                           */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 85ba410..76fcb4e 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -29,6 +29,21 @@
 	  You must also select one or more DVB/ATSC demodulators.
 	  If you are unsure which you need, choose all of them.
 
+config VIDEO_CX88_ALSA
+	tristate "ALSA DMA audio support"
+	depends on VIDEO_CX88 && SND
+	select SND_PCM_OSS
+	---help---
+	  This is a video4linux driver for direct (DMA) audio on
+	  Conexant 2388x based TV cards.
+	  It only works with boards with function 01 enabled.
+	  To check if your board supports, use lspci -n.
+	  If supported, you should see 1471:8801 or 1471:8811
+	  PCI device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-alsa.
+
 config VIDEO_CX88_DVB_ALL_FRONTENDS
 	bool "Build all supported frontends for cx2388x based TV cards"
 	default y
@@ -38,6 +53,7 @@
 	select DVB_CX22702
 	select DVB_LGDT330X
 	select DVB_NXT200X
+	select DVB_CX24123
 	---help---
 	  This builds cx88-dvb with all currently supported frontend
 	  demodulators.  If you wish to tweak your configuration, and
@@ -89,3 +105,12 @@
 	---help---
 	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
 	  Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
+
+config VIDEO_CX88_DVB_CX24123
+	bool "Conexant CX24123 DVB-S Support"
+	default y
+	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+	select DVB_CX24123
+	---help---
+	  This adds DVB-S support for cards based on the
+	  Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 54401b0..e4b2134 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -4,7 +4,7 @@
 cx8802-objs	:= cx88-mpeg.o
 
 obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o cx88-vp3054-i2c.o
 
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
@@ -16,5 +16,7 @@
 extra-cflags-$(CONFIG_DVB_LGDT330X)  += -DHAVE_LGDT330X=1
 extra-cflags-$(CONFIG_DVB_MT352)     += -DHAVE_MT352=1
 extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
+extra-cflags-$(CONFIG_DVB_CX24123)   += -DHAVE_CX24123=1
+extra-cflags-$(CONFIG_VIDEO_CX88_DVB)+= -DHAVE_VP3054_I2C=1
 
 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
new file mode 100644
index 0000000..7695b52
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -0,0 +1,848 @@
+/*
+ *
+ *  Support for audio capture
+ *  PCI function #1 of the cx2388x.
+ *
+ *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
+ *    (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ *    Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
+
+#define dprintk_core(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
+
+
+/****************************************************************************
+	Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+/* These can be replaced after done */
+#define MIXER_ADDR_LAST MAX_CX88_INPUT
+
+struct cx88_audio_dev {
+	struct cx88_core           *core;
+	struct cx88_dmaqueue       q;
+
+	/* pci i/o */
+	struct pci_dev             *pci;
+	unsigned char              pci_rev,pci_lat;
+
+	/* audio controls */
+	int                        irq;
+
+	snd_card_t                 *card;
+
+	spinlock_t                 reg_lock;
+
+	unsigned int               dma_size;
+	unsigned int               period_size;
+	unsigned int               num_periods;
+
+	struct videobuf_dmabuf dma_risc;
+
+	int                        mixer_volume[MIXER_ADDR_LAST+1][2];
+	int                        capture_source[MIXER_ADDR_LAST+1][2];
+
+	long int read_count;
+	long int read_offset;
+
+	struct cx88_buffer   *buf;
+
+	long opened;
+	snd_pcm_substream_t *substream;
+
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+
+
+/****************************************************************************
+			Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
+
+
+/****************************************************************************
+				Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Ricardo Cerqueira");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
+			"{{Conexant,23882},"
+			"{{Conexant,23883}");
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+/****************************************************************************
+			Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+int _cx88_start_audio_dma(snd_cx88_card_t *chip)
+{
+	struct cx88_buffer   *buf = chip->buf;
+	struct cx88_core *core=chip->core;
+	struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+
+
+	dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+
+	/* setup fifo + format - out channel */
+	cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
+				buf->bpl, buf->risc.dma);
+
+	/* sets bpl size */
+	cx_write(MO_AUDD_LNGTH, buf->bpl);
+
+	/* reset counter */
+	cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
+
+	dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
+	/* enable irqs */
+	cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
+
+
+	/* Enables corresponding bits at AUD_INT_STAT */
+	cx_write(MO_AUD_INTMSK,
+			(1<<16)|
+			(1<<12)|
+			(1<<4)|
+			(1<<0)
+			);
+
+	/* start dma */
+	cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+	cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+	if (debug)
+		cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+	return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
+{
+	struct cx88_core *core=chip->core;
+	dprintk(1, "Stopping audio DMA\n");
+
+	/* stop dma */
+	cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+	/* disable irqs */
+	cx_clear(MO_PCI_INTMSK, 0x02);
+	cx_clear(MO_AUD_INTMSK,
+			(1<<16)|
+			(1<<12)|
+			(1<<4)|
+			(1<<0)
+			);
+
+	if (debug)
+		cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+
+	return 0;
+}
+
+#define MAX_IRQ_LOOP 10
+
+/*
+ * BOARD Specific: IRQ dma bits
+ */
+static char *cx88_aud_irqs[32] = {
+	"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
+	NULL,					  /* reserved */
+	"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
+	NULL,					  /* reserved */
+	"dnf_of", "upf_uf", "rds_dnf_uf",	  /* 8-10 */
+	NULL,					  /* reserved */
+	"dn_sync", "up_sync", "rds_dn_sync",	  /* 12-14 */
+	NULL,					  /* reserved */
+	"opc_err", "par_err", "rip_err",	  /* 16-18 */
+	"pci_abort", "ber_irq", "mchg_irq"	  /* 19-21 */
+};
+
+/*
+ * BOARD Specific: Threats IRQ audio specific calls
+ */
+static void cx8801_aud_irq(snd_cx88_card_t *chip)
+{
+	struct cx88_core *core = chip->core;
+	u32 status, mask;
+	u32 count;
+
+	status = cx_read(MO_AUD_INTSTAT);
+	mask   = cx_read(MO_AUD_INTMSK);
+	if (0 == (status & mask)) {
+		spin_unlock(&chip->reg_lock);
+		return;
+	}
+	cx_write(MO_AUD_INTSTAT, status);
+	if (debug > 1  ||  (status & mask & ~0xff))
+		cx88_print_irqbits(core->name, "irq aud",
+				   cx88_aud_irqs, status, mask);
+	/* risc op code error */
+	if (status & (1 << 16)) {
+		printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+		cx_clear(MO_AUD_DMACNTRL, 0x11);
+		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
+	}
+
+	/* risc1 downstream */
+	if (status & 0x01) {
+		spin_lock(&chip->reg_lock);
+		count = cx_read(MO_AUDD_GPCNT);
+		spin_unlock(&chip->reg_lock);
+		if (chip->read_count == 0)
+			chip->read_count += chip->dma_size;
+	}
+
+	if  (chip->read_count >= chip->period_size) {
+		dprintk(2, "Elapsing period\n");
+		snd_pcm_period_elapsed(chip->substream);
+	}
+
+	dprintk(3,"Leaving audio IRQ handler...\n");
+
+	/* FIXME: Any other status should deserve a special handling? */
+}
+
+/*
+ * BOARD Specific: Handles IRQ calls
+ */
+static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	snd_cx88_card_t *chip = dev_id;
+	struct cx88_core *core = chip->core;
+	u32 status;
+	int loop, handled = 0;
+
+	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
+		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+		if (0 == status)
+			goto out;
+		dprintk( 3, "cx8801_irq\n" );
+		dprintk( 3, "    loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+		dprintk( 3, "    status: %d\n", status );
+		handled = 1;
+		cx_write(MO_PCI_INTSTAT, status);
+
+		if (status & 0x02)
+		{
+			dprintk( 2, "    ALSA IRQ handling\n" );
+			cx8801_aud_irq(chip);
+		}
+	};
+
+	if (MAX_IRQ_LOOP == loop) {
+		dprintk( 0, "clearing mask\n" );
+		dprintk(1,"%s/0: irq loop -- clearing mask\n",
+		       core->name);
+		cx_clear(MO_PCI_INTMSK,0x02);
+	}
+
+ out:
+	return IRQ_RETVAL(handled);
+}
+
+
+static int dsp_buffer_free(snd_cx88_card_t *chip)
+{
+	BUG_ON(!chip->dma_size);
+
+	dprintk(2,"Freeing buffer\n");
+	videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc);
+	videobuf_dma_free(&chip->dma_risc);
+	btcx_riscmem_free(chip->pci,&chip->buf->risc);
+	kfree(chip->buf);
+
+	chip->dma_size = 0;
+
+       return 0;
+}
+
+/****************************************************************************
+				ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+static snd_pcm_hardware_t snd_cx88_digital_hw = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = (2*2048),
+	.period_bytes_min = 256,
+	.period_bytes_max = 2048,
+	.periods_min = 2,
+	.periods_max = 16,
+};
+
+/*
+ * audio pcm capture runtime free
+ */
+static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+{
+}
+/*
+ * audio pcm capture open callback
+ */
+static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	if (test_and_set_bit(0, &chip->opened))
+		return -EBUSY;
+
+	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0)
+		goto _error;
+
+	chip->substream = substream;
+
+	chip->read_count = 0;
+	chip->read_offset = 0;
+
+	runtime->private_free = snd_card_cx88_runtime_free;
+	runtime->hw = snd_cx88_digital_hw;
+
+	return 0;
+_error:
+	dprintk(1,"Error opening PCM!\n");
+	clear_bit(0, &chip->opened);
+	smp_mb__after_clear_bit();
+	return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(snd_pcm_substream_t *substream)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+	clear_bit(0, &chip->opened);
+	smp_mb__after_clear_bit();
+
+	return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
+				 snd_pcm_hw_params_t * hw_params)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	struct cx88_buffer *buf;
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+
+	chip->period_size = params_period_bytes(hw_params);
+	chip->num_periods = params_periods(hw_params);
+	chip->dma_size = chip->period_size * params_periods(hw_params);
+
+	BUG_ON(!chip->dma_size);
+
+	dprintk(1,"Setting buffer\n");
+
+	buf = kmalloc(sizeof(*buf),GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+	memset(buf,0,sizeof(*buf));
+
+
+	buf->vb.memory = V4L2_MEMORY_MMAP;
+	buf->vb.width  = chip->period_size;
+	buf->vb.height = chip->num_periods;
+	buf->vb.size   = chip->dma_size;
+	buf->vb.field  = V4L2_FIELD_NONE;
+
+	videobuf_dma_init(&buf->vb.dma);
+	videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+			(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+
+	videobuf_dma_pci_map(chip->pci,&buf->vb.dma);
+
+
+	cx88_risc_databuffer(chip->pci, &buf->risc,
+			buf->vb.dma.sglist,
+			buf->vb.width, buf->vb.height);
+
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+	buf->vb.state = STATE_PREPARED;
+
+	buf->bpl = chip->period_size;
+	chip->buf = buf;
+	chip->dma_risc = buf->vb.dma;
+
+	dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
+	substream->runtime->dma_area = chip->dma_risc.vmalloc;
+	return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+{
+
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+	if (substream->runtime->dma_area) {
+		dsp_buffer_free(chip);
+		substream->runtime->dma_area = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+{
+	return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	spin_lock(&chip->reg_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err=_cx88_start_audio_dma(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err=_cx88_stop_audio_dma(chip);
+		break;
+	default:
+		err=-EINVAL;
+		break;
+	}
+
+	spin_unlock(&chip->reg_lock);
+
+	return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+{
+	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	if (chip->read_count) {
+		chip->read_count -= snd_pcm_lib_period_bytes(substream);
+		chip->read_offset += snd_pcm_lib_period_bytes(substream);
+		if (chip->read_offset == chip->dma_size)
+			chip->read_offset = 0;
+	}
+
+	dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
+	return bytes_to_frames(runtime, chip->read_offset);
+
+}
+
+/*
+ * operators
+ */
+static snd_pcm_ops_t snd_cx88_pcm_ops = {
+	.open = snd_cx88_pcm_open,
+	.close = snd_cx88_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_cx88_hw_params,
+	.hw_free = snd_cx88_hw_free,
+	.prepare = snd_cx88_prepare,
+	.trigger = snd_cx88_card_trigger,
+	.pointer = snd_cx88_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+{
+	int err;
+	snd_pcm_t *pcm;
+
+	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = chip;
+	strcpy(pcm->name, name);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+
+	return 0;
+}
+
+/****************************************************************************
+				CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 1;
+	info->value.integer.min = 0;
+	info->value.integer.max = 0x3f;
+
+	return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core=chip->core;
+
+	value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+
+	return 0;
+}
+
+/* OK - TODO: test it */
+static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+	struct cx88_core *core=chip->core;
+	int v;
+	u32 old_control;
+
+	spin_lock_irq(&chip->reg_lock);
+	old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+	v = 0x3f - (value->value.integer.value[0] & 0x3f);
+	cx_andor(AUD_VOL_CTL, 0x3f, v);
+	spin_unlock_irq(&chip->reg_lock);
+
+	return v != old_control;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_volume = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Capture Volume",
+	.info = snd_cx88_capture_volume_info,
+	.get = snd_cx88_capture_volume_get,
+	.put = snd_cx88_capture_volume_put,
+};
+
+
+/****************************************************************************
+			Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
+ * Only boards with eeprom and byte 1 at eeprom=1 have it
+ */
+
+struct pci_device_id cx88_audio_pci_tbl[] = {
+	{0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0, }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Chip-specific destructor
+ */
+
+static int snd_cx88_free(snd_cx88_card_t *chip)
+{
+
+	if (chip->irq >= 0){
+		synchronize_irq(chip->irq);
+		free_irq(chip->irq, chip);
+	}
+
+	cx88_core_put(chip->core,chip->pci);
+
+	pci_disable_device(chip->pci);
+	return 0;
+}
+
+/*
+ * Component Destructor
+ */
+static void snd_cx88_dev_free(snd_card_t * card)
+{
+	snd_cx88_card_t *chip = card->private_data;
+
+	snd_cx88_free(chip);
+}
+
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+static int devno=0;
+static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
+				    snd_cx88_card_t **rchip)
+{
+	snd_cx88_card_t   *chip;
+	struct cx88_core  *core;
+	int               err;
+
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	pci_set_master(pci);
+
+	chip = (snd_cx88_card_t *) card->private_data;
+
+	core = cx88_core_get(pci);
+
+	if (!pci_dma_supported(pci,0xffffffff)) {
+		dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
+		err = -EIO;
+		cx88_core_put(core,pci);
+		return err;
+	}
+
+
+	/* pci init */
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+	spin_lock_init(&chip->reg_lock);
+
+	cx88_reset(core);
+	if (NULL == core) {
+		err = -EINVAL;
+		kfree (chip);
+		return err;
+	}
+	chip->core = core;
+
+	/* get irq */
+	err = request_irq(chip->pci->irq, cx8801_irq,
+			  SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip);
+	if (err < 0) {
+		dprintk(0, "%s: can't get IRQ %d\n",
+		       chip->core->name, chip->pci->irq);
+		return err;
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
+	pci_read_config_byte(pci, PCI_LATENCY_TIMER,  &chip->pci_lat);
+
+	dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%lx\n", core->name, devno,
+	       pci_name(pci), chip->pci_rev, pci->irq,
+	       chip->pci_lat,pci_resource_start(pci,0));
+
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*rchip = chip;
+
+	return 0;
+}
+
+static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+				    const struct pci_device_id *pci_id)
+{
+	snd_card_t       *card;
+	snd_cx88_card_t  *chip;
+	int              err;
+
+	if (devno >= SNDRV_CARDS)
+		return (-ENODEV);
+
+	if (!enable[devno]) {
+		++devno;
+		return (-ENOENT);
+	}
+
+	card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
+	if (!card)
+		return (-ENOMEM);
+
+	card->private_free = snd_cx88_dev_free;
+
+	err = snd_cx88_create(card, pci, &chip);
+	if (err < 0)
+		return (err);
+
+	err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+
+	if (err < 0) {
+		snd_card_free(card);
+		return (err);
+	}
+
+	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
+	if (err < 0) {
+		snd_card_free(card);
+		return (err);
+	}
+
+	strcpy (card->driver, "CX88x");
+	sprintf(card->shortname, "Conexant CX%x", pci->device);
+	sprintf(card->longname, "%s at %#lx",
+		card->shortname, pci_resource_start(pci, 0));
+	strcpy (card->mixername, "CX88");
+
+	dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
+	       card->driver,devno);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return (err);
+	}
+	snd_cx88_cards[devno] = card;
+
+	pci_set_drvdata(pci,card);
+
+	devno++;
+	return 0;
+}
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+{
+	struct cx88_audio_dev *card = pci_get_drvdata(pci);
+
+	snd_card_free((void *)card);
+
+	pci_set_drvdata(pci, NULL);
+
+	devno--;
+}
+
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+	.name     = "cx88_audio",
+	.id_table = cx88_audio_pci_tbl,
+	.probe    = cx88_audio_initdev,
+	.remove   = cx88_audio_finidev,
+	SND_PCI_PM_CALLBACKS
+};
+
+/****************************************************************************
+				LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int cx88_audio_init(void)
+{
+	printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
+	       (CX88_VERSION_CODE >> 16) & 0xff,
+	       (CX88_VERSION_CODE >>  8) & 0xff,
+	       CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+	printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+	return pci_register_driver(&cx88_audio_pci_driver);
+}
+
+/*
+ * module remove
+ */
+static void cx88_audio_fini(void)
+{
+
+	pci_unregister_driver(&cx88_audio_pci_driver);
+}
+
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 74e57a5..a490621 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -32,10 +32,10 @@
 #include <linux/firmware.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
 static unsigned int mpegbufs = 32;
@@ -1375,7 +1375,7 @@
 	struct cx88_core  *core = dev->core;
 
 	if (debug > 1)
-		cx88_print_ioctl(core->name,cmd);
+		v4l_print_ioctl(core->name,cmd);
 
 	switch (cmd) {
 
@@ -1689,6 +1689,18 @@
 	memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
 	memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
 
+	if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
+
+		if (core->tuner_formats & V4L2_STD_525_60) {
+			dev->height = 480;
+			dev->params.vi_frame_rate = 30;
+		} else {
+			dev->height = 576;
+			dev->params.vi_frame_rate = 25;
+		}
+
+	}
+
 	err = cx8802_init_common(dev);
 	if (0 != err)
 		goto fail_free;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 951709a..a76d545 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -611,12 +611,12 @@
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio0  = 0xed12,  /* internal decoder */
+			.gpio0  = 0xed1a,
 			.gpio2  = 0x00ff,
 		},{
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
-			.gpio0  = 0xff01,  /* mono from tuner chip */
+			.gpio0  = 0xff01,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
@@ -708,7 +708,7 @@
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
 		.name           = "DViCO FusionHDTV 3 Gold-T",
-		.tuner_type     = TUNER_THOMSON_DTT7611,
+		.tuner_type     = TUNER_THOMSON_DTT761X,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
@@ -897,6 +897,158 @@
 			.gpio3  = 0x0000,
 		}},
 	},
+	[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
+		.name		= "Hauppauge Nova-S-Plus DVB-S",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+		}},
+		.dvb		= 1,
+	},
+	[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
+		.name		= "Hauppauge Nova-SE2 DVB-S",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+		}},
+		.dvb		= 1,
+	},
+	[CX88_BOARD_KWORLD_DVBS_100] = {
+		.name		= "KWorld DVB-S 100",
+		.tuner_type	= TUNER_ABSENT,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input		= {{
+			.type	= CX88_VMUX_DVB,
+			.vmux	= 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+		}},
+		.dvb		= 1,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR1100] = {
+		.name		= "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input		= {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+		}},
+		/* fixme: Add radio support */
+		.dvb		= 1,
+	},
+	[CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+		.name		= "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type	= UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input		= {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+		}},
+		/* fixme: Add radio support */
+		.dvb		= 1,
+	},
+	[CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
+		.name           = "digitalnow DNTV Live! DVB-T Pro",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+				  TDA9887_PORT2_ACTIVE,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xf80808,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0xf80808,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0xf80808,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0xf80808,
+		},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_KWORLD_DVB_T_CX22702] = {
+		/* Kworld V-stream Xpert DVB-T with Thomson tuner */
+		/* DTT 7579 Conexant CX22702-19 Conexant CX2388x  */
+		/* Manenti Marco <marco_manenti@colman.it> */
+		.name           = "KWorld/VStream XPert DVB-T with cx22702",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
+		.name           = "DViCO FusionHDTV DVB-T Dual Digital",
+		.tuner_type     = TUNER_ABSENT, /* No analog tuner */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x000027df,
+		 },{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x000027df,
+		}},
+		.dvb            = 1,
+	},
+
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1044,6 +1196,54 @@
 		.subvendor = 0x1461,
 		.subdevice = 0x000a,
 		.card      = CX88_BOARD_AVERTV_303,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9200,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9201,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9202,
+		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x08b2,
+		.card      = CX88_BOARD_KWORLD_DVBS_100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9400,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9402,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9800,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9802,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9001,
+		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
+	},{
+		.subvendor = 0x1822,
+		.subdevice = 0x0025,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x08a1,
+		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xdb50,
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1075,20 +1275,19 @@
 	       core->name, core->tuner_type, eeprom_data[0]);
 }
 
-
-/* ----------------------------------------------------------------------- */
-
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
 	struct tveeprom tv;
 
 	tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
 	core->tuner_type = tv.tuner_type;
+	core->tuner_formats = tv.tuner_formats;
 	core->has_radio  = tv.has_radio;
 
 	/* Make sure we support the board model */
 	switch (tv.model)
 	{
+	case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
 	case 90002: /* Nova-T-PCI (9002) */
 	case 92001: /* Nova-S-Plus (Video and IR) */
 	case 92002: /* Nova-S-Plus (Video and IR) */
@@ -1096,7 +1295,9 @@
 	case 90500: /* Nova-T-PCI (oem) */
 	case 90501: /* Nova-T-PCI (oem/IR) */
 	case 92000: /* Nova-SE2 (OEM, No Video or IR) */
-
+	case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+	case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+	case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
 		/* known */
 		break;
 	default:
@@ -1211,12 +1412,21 @@
 		if (0 == core->i2c_rc)
 			leadtek_eeprom(core,eeprom);
 		break;
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
 		if (0 == core->i2c_rc)
 			hauppauge_eeprom(core,eeprom);
 		break;
+	case CX88_BOARD_KWORLD_DVBS_100:
+		cx_write(MO_GP0_IO, 0x000007f8);
+		cx_write(MO_GP1_IO, 0x00000001);
+		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
 		/* GPIO0:0 is hooked to mt352 reset pin */
 		cx_set(MO_GP0_IO, 0x00000101);
 		cx_clear(MO_GP0_IO, 0x00000001);
@@ -1232,6 +1442,9 @@
 		cx_clear(MO_GP0_IO, 0x00000007);
 		cx_set(MO_GP2_IO, 0x00000101);
 		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+		cx_write(MO_GP0_IO, 0x00080808);
+		break;
 	case CX88_BOARD_ATI_HDTVWONDER:
 		if (0 == core->i2c_rc) {
 			/* enable tuner */
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index bb6eb54..9975be1 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -34,6 +34,7 @@
 #include <linux/videodev2.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -76,60 +77,6 @@
 static LIST_HEAD(cx88_devlist);
 static DECLARE_MUTEX(devlist);
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-	"0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-	"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-	"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-	"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-	"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-	"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-	"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-	"44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-	"S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void cx88_print_ioctl(char *name, unsigned int cmd)
-{
-	char *dir;
-
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:              dir = "--"; break;
-	case _IOC_READ:              dir = "r-"; break;
-	case _IOC_WRITE:             dir = "-w"; break;
-	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-	default:                     dir = "??"; break;
-	}
-	switch (_IOC_TYPE(cmd)) {
-	case 'v':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-		       v4l1_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'V':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-		       v4l2_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	default:
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-	}
-}
-
-/* ------------------------------------------------------------------ */
 #define NO_SYNC_LINE (-1U)
 
 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
@@ -291,9 +238,9 @@
  *    channel  22    (u video)  -  2.0k
  *    channel  23    (v video)  -  2.0k
  *    channel  24    (vbi)      -  4.0k
- *    channels 25+26 (audio)    -  0.5k
+ *    channels 25+26 (audio)    -  4.0k
  *    channel  28    (mpeg)     -  4.0k
- *    TOTAL                     = 25.5k
+ *    TOTAL                     = 29.0k
  *
  * Every channel has 160 bytes control data (64 bytes instruction
  * queue and 6 CDT entries), which is close to 2k total.
@@ -359,7 +306,7 @@
 		.ctrl_start = 0x180680,
 		.cdt        = 0x180680 + 64,
 		.fifo_start = 0x185400,
-		.fifo_size  = 0x000200,
+		.fifo_size  = 0x001000,
 		.ptr1_reg   = MO_DMA25_PTR1,
 		.ptr2_reg   = MO_DMA25_PTR2,
 		.cnt1_reg   = MO_DMA25_CNT1,
@@ -371,7 +318,7 @@
 		.ctrl_start = 0x180720,
 		.cdt        = 0x180680 + 64,  /* same as audio IN */
 		.fifo_start = 0x185400,       /* same as audio IN */
-		.fifo_size  = 0x000200,       /* same as audio IN */
+		.fifo_size  = 0x001000,       /* same as audio IN */
 		.ptr1_reg   = MO_DMA26_PTR1,
 		.ptr2_reg   = MO_DMA26_PTR2,
 		.cnt1_reg   = MO_DMA26_CNT1,
@@ -382,7 +329,7 @@
 		.cmds_start = 0x180200,
 		.ctrl_start = 0x1807C0,
 		.cdt        = 0x1807C0 + 64,
-		.fifo_start = 0x185600,
+		.fifo_start = 0x186400,
 		.fifo_size  = 0x001000,
 		.ptr1_reg   = MO_DMA28_PTR1,
 		.ptr2_reg   = MO_DMA28_PTR2,
@@ -848,7 +795,6 @@
 
 	/* start dma */
 	cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
-
 	return 0;
 }
 
@@ -1208,7 +1154,6 @@
 
 /* ------------------------------------------------------------------ */
 
-EXPORT_SYMBOL(cx88_print_ioctl);
 EXPORT_SYMBOL(cx88_print_irqbits);
 
 EXPORT_SYMBOL(cx88_core_irq);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 99ea955..42c012a 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -3,7 +3,7 @@
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
  *
- * (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -31,10 +31,14 @@
 
 #include "cx88.h"
 #include "dvb-pll.h"
+#include <media/v4l2-common.h>
 
 #ifdef HAVE_MT352
 # include "mt352.h"
 # include "mt352_priv.h"
+# ifdef HAVE_VP3054_I2C
+#  include "cx88-vp3054-i2c.h"
+# endif
 #endif
 #ifdef HAVE_CX22702
 # include "cx22702.h"
@@ -48,6 +52,9 @@
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
 #endif
+#ifdef HAVE_CX24123
+# include "cx24123.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -125,6 +132,27 @@
 	return 0;
 }
 
+static int dvico_dual_demod_init(struct dvb_frontend *fe)
+{
+	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+	static u8 reset []         = { RESET,      0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+	static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(200);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
 static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { 0x89, 0x38, 0x39 };
@@ -172,6 +200,98 @@
 	.demod_init    = dntv_live_dvbt_demod_init,
 	.pll_set       = mt352_pll_set,
 };
+
+static struct mt352_config dvico_fusionhdtv_dual = {
+	.demod_address = 0x0F,
+	.demod_init    = dvico_dual_demod_init,
+	.pll_set       = mt352_pll_set,
+};
+
+#ifdef HAVE_VP3054_I2C
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+{
+	static u8 clock_config []  = { 0x89, 0x38, 0x38 };
+	static u8 reset []         = { 0x50, 0x80 };
+	static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 dntv_extra[]     = { 0xB5, 0x7A };
+	static u8 capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+	return 0;
+}
+
+static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+
+	/* this message is to set up ATC and ALC */
+	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+	struct i2c_msg msg =
+		{ .addr = dev->core->pll_addr, .flags = 0,
+		  .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
+	int err;
+
+	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
+				      struct dvb_frontend_parameters* params,
+				      u8* pllbuf)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct i2c_msg msg =
+		{ .addr = dev->core->pll_addr, .flags = 0,
+		  .buf = pllbuf+1, .len = 4 };
+	int err;
+
+	/* Switch PLL to DVB mode */
+	err = philips_fmd1216_pll_init(fe);
+	if (err)
+		return err;
+
+	/* Tune PLL */
+	pllbuf[0] = dev->core->pll_addr << 1;
+	dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
+	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "cx88-dvb: %s error "
+			   "(addr %02x <- %02x, err = %i)\n",
+			   __FUNCTION__, pllbuf[0], pllbuf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static struct mt352_config dntv_live_dvbt_pro_config = {
+	.demod_address = 0x0f,
+	.no_tuner      = 1,
+	.demod_init    = dntv_live_dvbt_pro_demod_init,
+	.pll_set       = dntv_live_dvbt_pro_pll_set,
+};
+#endif
 #endif
 
 #ifdef HAVE_CX22702
@@ -188,6 +308,12 @@
 	.pll_address   = 0x61,
 	.pll_desc      = &dvb_pll_thomson_dtt759x,
 };
+static struct cx22702_config hauppauge_hvr1100_config = {
+	.demod_address = 0x63,
+	.output_mode   = CX22702_SERIAL_OUTPUT,
+	.pll_address   = 0x61,
+	.pll_desc      = &dvb_pll_fmd1216me,
+};
 #endif
 
 #ifdef HAVE_OR51132
@@ -314,6 +440,40 @@
 };
 #endif
 
+#ifdef HAVE_CX24123
+static int cx24123_set_ts_param(struct dvb_frontend* fe,
+	int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = 0x2;
+	return 0;
+}
+
+static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	if (on)
+		cx_write(MO_GP0_IO, 0x000006f9);
+	else
+		cx_write(MO_GP0_IO, 0x000006fB);
+}
+
+static struct cx24123_config hauppauge_novas_config = {
+	.demod_address		= 0x55,
+	.use_isl6421		= 1,
+	.set_ts_params		= cx24123_set_ts_param,
+};
+
+static struct cx24123_config kworld_dvbs_100_config = {
+	.demod_address		= 0x15,
+	.use_isl6421		= 0,
+	.set_ts_params		= cx24123_set_ts_param,
+	.enable_lnb_voltage	= cx24123_enable_lnb_voltage,
+};
+#endif
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
@@ -329,10 +489,16 @@
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_CONEXANT_DVB_T1:
+	case CX88_BOARD_KWORLD_DVB_T_CX22702:
 	case CX88_BOARD_WINFAST_DTV1000:
 		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
 						   &dev->core->i2c_adap);
 		break;
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+		dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
+						   &dev->core->i2c_adap);
+		break;
 #endif
 #ifdef HAVE_MT352
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -355,6 +521,24 @@
 		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
 						 &dev->core->i2c_adap);
 		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+#ifdef HAVE_VP3054_I2C
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_fmd1216me;
+		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
+			&((struct vp3054_i2c_state *)dev->card_priv)->adap);
+#else
+		printk("%s: built without vp3054 support\n", dev->core->name);
+#endif
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+		/* The tin box says DEE1601, but it seems to be DTT7579
+		 * compatible, with a slightly different MT352 AGC gain. */
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+						 &dev->core->i2c_adap);
+		break;
 #endif
 #ifdef HAVE_OR51132
 	case CX88_BOARD_PCHDTV_HD3000:
@@ -393,7 +577,7 @@
 		cx_set(MO_GP0_IO, 9);
 		mdelay(200);
 		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_thomson_dtt7611;
+		dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
 		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
 						    &dev->core->i2c_adap);
 		}
@@ -421,6 +605,17 @@
 						 &dev->core->i2c_adap);
 		break;
 #endif
+#ifdef HAVE_CX24123
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+		dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
+			&dev->core->i2c_adap);
+		break;
+	case CX88_BOARD_KWORLD_DVBS_100:
+		dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
+			&dev->core->i2c_adap);
+		break;
+#endif
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
@@ -473,6 +668,12 @@
 	if (0 != err)
 		goto fail_free;
 
+#ifdef HAVE_VP3054_I2C
+	err = vp3054_i2c_probe(dev);
+	if (0 != err)
+		goto fail_free;
+#endif
+
 	/* dvb stuff */
 	printk("%s/2: cx2388x based dvb card\n", core->name);
 	videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
@@ -484,6 +685,9 @@
 	err = dvb_register(dev);
 	if (0 != err)
 		goto fail_fini;
+
+	/* Maintain a reference to cx88-video can query the 8802 device. */
+	core->dvbdev = dev;
 	return 0;
 
  fail_fini:
@@ -499,9 +703,16 @@
 {
 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
+	/* Destroy any 8802 reference. */
+	dev->core->dvbdev = NULL;
+
 	/* dvb */
 	videobuf_dvb_unregister(&dev->dvb);
 
+#ifdef HAVE_VP3054_I2C
+	vp3054_i2c_remove(dev);
+#endif
+
 	/* common */
 	cx8802_fini_common(dev);
 	cx88_core_put(dev->core,dev->pci);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 4a8fb16..f720901 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 static unsigned int i2c_debug = 0;
 module_param(i2c_debug, int, 0644);
@@ -135,7 +136,17 @@
 {
 	if (0 != core->i2c_rc)
 		return;
-	i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+	if (core->dvbdev) {
+		if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+			core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+
+		i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+		if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+			core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+	} else
+		i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
 static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 461019d..286c85b 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2003 Pavel Machek
  * Copyright (c) 2004 Gerd Knorr
- * Copyright (c) 2004 Chris Pascoe
+ * Copyright (c) 2004, 2005 Chris Pascoe
  *
  * This 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,9 +29,8 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-#include <media/ir-common.h>
-
 #include "cx88.h"
+#include <media/ir-common.h>
 
 /* ---------------------------------------------------------------------- */
 
@@ -258,6 +257,114 @@
 
 /* ---------------------------------------------------------------------- */
 
+/* AVERTV STUDIO 303 Remote */
+static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+	[ 0x2a ] = KEY_KP1,
+	[ 0x32 ] = KEY_KP2,
+	[ 0x3a ] = KEY_KP3,
+	[ 0x4a ] = KEY_KP4,
+	[ 0x52 ] = KEY_KP5,
+	[ 0x5a ] = KEY_KP6,
+	[ 0x6a ] = KEY_KP7,
+	[ 0x72 ] = KEY_KP8,
+	[ 0x7a ] = KEY_KP9,
+	[ 0x0e ] = KEY_KP0,
+
+	[ 0x02 ] = KEY_POWER,
+	[ 0x22 ] = KEY_VIDEO,
+	[ 0x42 ] = KEY_AUDIO,
+	[ 0x62 ] = KEY_ZOOM,
+	[ 0x0a ] = KEY_TV,
+	[ 0x12 ] = KEY_CD,
+	[ 0x1a ] = KEY_TEXT,
+
+	[ 0x16 ] = KEY_SUBTITLE,
+	[ 0x1e ] = KEY_REWIND,
+	[ 0x06 ] = KEY_PRINT,
+
+	[ 0x2e ] = KEY_SEARCH,
+	[ 0x36 ] = KEY_SLEEP,
+	[ 0x3e ] = KEY_SHUFFLE,
+	[ 0x26 ] = KEY_MUTE,
+
+	[ 0x4e ] = KEY_RECORD,
+	[ 0x56 ] = KEY_PAUSE,
+	[ 0x5e ] = KEY_STOP,
+	[ 0x46 ] = KEY_PLAY,
+
+	[ 0x6e ] = KEY_RED,
+	[ 0x0b ] = KEY_GREEN,
+	[ 0x66 ] = KEY_YELLOW,
+	[ 0x03 ] = KEY_BLUE,
+
+	[ 0x76 ] = KEY_LEFT,
+	[ 0x7e ] = KEY_RIGHT,
+	[ 0x13 ] = KEY_DOWN,
+	[ 0x1b ] = KEY_UP,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+	[ 0x16 ] = KEY_POWER,
+	[ 0x5b ] = KEY_HOME,
+
+	[ 0x55 ] = KEY_TV,		/* live tv */
+	[ 0x58 ] = KEY_TUNER,		/* digital Radio */
+	[ 0x5a ] = KEY_RADIO,		/* FM radio */
+	[ 0x59 ] = KEY_DVD,		/* dvd menu */
+	[ 0x03 ] = KEY_1,
+	[ 0x01 ] = KEY_2,
+	[ 0x06 ] = KEY_3,
+	[ 0x09 ] = KEY_4,
+	[ 0x1d ] = KEY_5,
+	[ 0x1f ] = KEY_6,
+	[ 0x0d ] = KEY_7,
+	[ 0x19 ] = KEY_8,
+	[ 0x1b ] = KEY_9,
+	[ 0x0c ] = KEY_CANCEL,
+	[ 0x15 ] = KEY_0,
+	[ 0x4a ] = KEY_CLEAR,
+	[ 0x13 ] = KEY_BACK,
+	[ 0x00 ] = KEY_TAB,
+	[ 0x4b ] = KEY_UP,
+	[ 0x4e ] = KEY_LEFT,
+	[ 0x4f ] = KEY_OK,
+	[ 0x52 ] = KEY_RIGHT,
+	[ 0x51 ] = KEY_DOWN,
+	[ 0x1e ] = KEY_VOLUMEUP,
+	[ 0x0a ] = KEY_VOLUMEDOWN,
+	[ 0x02 ] = KEY_CHANNELDOWN,
+	[ 0x05 ] = KEY_CHANNELUP,
+	[ 0x11 ] = KEY_RECORD,
+	[ 0x14 ] = KEY_PLAY,
+	[ 0x4c ] = KEY_PAUSE,
+	[ 0x1a ] = KEY_STOP,
+	[ 0x40 ] = KEY_REWIND,
+	[ 0x12 ] = KEY_FASTFORWARD,
+	[ 0x41 ] = KEY_PREVIOUSSONG,	/* replay |< */
+	[ 0x42 ] = KEY_NEXTSONG,	/* skip >| */
+	[ 0x54 ] = KEY_CAMERA,		/* capture */
+	[ 0x50 ] = KEY_LANGUAGE,	/* sap */
+	[ 0x47 ] = KEY_TV2,		/* pip */
+	[ 0x4d ] = KEY_SCREEN,
+	[ 0x43 ] = KEY_SUBTITLE,
+	[ 0x10 ] = KEY_MUTE,
+	[ 0x49 ] = KEY_AUDIO,		/* l/r */
+	[ 0x07 ] = KEY_SLEEP,
+	[ 0x08 ] = KEY_VIDEO,		/* a/v */
+	[ 0x0e ] = KEY_PREVIOUS,	/* recall */
+	[ 0x45 ] = KEY_ZOOM,		/* zoom + */
+	[ 0x46 ] = KEY_ANGLE,		/* zoom - */
+	[ 0x56 ] = KEY_RED,
+	[ 0x57 ] = KEY_GREEN,
+	[ 0x5c ] = KEY_YELLOW,
+	[ 0x5d ] = KEY_BLUE,
+};
+
+/* ---------------------------------------------------------------------- */
+
 struct cx88_IR {
 	struct cx88_core *core;
 	struct input_dev *input;
@@ -266,7 +373,7 @@
 	char phys[32];
 
 	/* sample from gpio pin 16 */
-	int sampling;
+	u32 sampling;
 	u32 samples[16];
 	int scount;
 	unsigned long release;
@@ -384,10 +491,13 @@
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 		ir_codes = ir_codes_cinergy_1400;
 		ir_type = IR_TYPE_PD;
-		ir->sampling = 1;
+		ir->sampling = 0xeb04; /* address */
 		break;
 	case CX88_BOARD_HAUPPAUGE:
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+	case CX88_BOARD_HAUPPAUGE_HVR1100:
 		ir_codes = ir_codes_hauppauge_new;
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
@@ -427,6 +537,19 @@
 		ir->mask_keyup = 0x40;
 		ir->polling = 1; /* ms */
 		break;
+	case CX88_BOARD_AVERTV_303:
+	case CX88_BOARD_AVERTV_STUDIO_303:
+		ir_codes         = ir_codes_avertv_303;
+		ir->gpio_addr    = MO_GP2_IO;
+		ir->mask_keycode = 0xfb;
+		ir->mask_keydown = 0x02;
+		ir->polling      = 50; /* ms */
+		break;
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
+		ir_codes = ir_codes_dntv_live_dvbt_pro;
+		ir_type = IR_TYPE_PD;
+		ir->sampling = 0xff00; /* address */
+		break;
 	}
 
 	if (NULL == ir_codes) {
@@ -484,6 +607,10 @@
 	if (NULL == ir)
 		return 0;
 
+	if (ir->sampling) {
+		cx_write(MO_DDSCFG_IO, 0x0);
+		core->pci_irqmask &= ~(1 << 18);
+	}
 	if (ir->polling) {
 		del_timer(&ir->timer);
 		flush_scheduled_work();
@@ -535,6 +662,7 @@
 	/* decode it */
 	switch (core->board) {
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
+	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 		ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
 
 		if (ircode == 0xffffffff) { /* decoding error */
@@ -550,7 +678,7 @@
 			break;
 		}
 
-		if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
+		if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
 			ir_dprintk("pulse distance decoded wrong address\n");
 			break;
 		}
@@ -567,6 +695,8 @@
 		break;
 	case CX88_BOARD_HAUPPAUGE:
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
 		ir_dprintk("biphase decoded: %x\n", ircode);
 		if ((ircode & 0xfffff000) != 0x3000)
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 35e6d0c..c79cc1d 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -78,6 +78,11 @@
 		case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
 			cx_write(TS_SOP_STAT, 1<<13);
 			break;
+		case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+		case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
+			cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
+			udelay(100);
+			break;
 		default:
 			cx_write(TS_SOP_STAT, 0x00);
 			break;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index a1b120c..24118e4 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -132,14 +132,22 @@
 {
 	u32 volume;
 
+#ifndef USING_CX88_ALSA
 	/* restart dma; This avoids buzz in NICAM and is good in others  */
 	cx88_stop_audio_dma(core);
+#endif
 	cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
+#ifndef USING_CX88_ALSA
 	cx88_start_audio_dma(core);
+#endif
 
 	if (cx88_boards[core->board].blackbird) {
 		/* sets sound input from external adc */
-		cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+		if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+		else
+			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+
 		cx_write(AUD_I2SINPUTCNTL, 4);
 		cx_write(AUD_BAUDRATE, 1);
 		/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 24a48f8..9a02515 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -33,6 +33,7 @@
 #include <asm/div64.h>
 
 #include "cx88.h"
+#include <media/v4l2-common.h>
 
 /* Include V4L1 specific functions. Should be removed soon */
 #include <linux/videodev.h>
@@ -240,7 +241,7 @@
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x3f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 0,
@@ -271,7 +272,7 @@
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x7f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 0,
@@ -285,6 +286,7 @@
 			.name          = "Mute",
 			.minimum       = 0,
 			.maximum       = 1,
+			.default_value = 1,
 			.type          = V4L2_CTRL_TYPE_BOOLEAN,
 		},
 		.reg                   = AUD_VOL_CTL,
@@ -298,7 +300,7 @@
 			.minimum       = 0,
 			.maximum       = 0x3f,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x1f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.reg                   = AUD_VOL_CTL,
@@ -917,6 +919,9 @@
 		ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
 		break;
 	}
+	printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+					ctl->id, c->reg, ctl->value,
+					c->mask, c->sreg ? " [shadowed]" : "");
 	return 0;
 }
 
@@ -925,13 +930,13 @@
 {
 	/* struct cx88_core *core = dev->core; */
 	struct cx88_ctrl *c = NULL;
-	u32 v_sat_value;
-	u32 value;
+	u32 value,mask;
 	int i;
-
-	for (i = 0; i < CX8800_CTLS; i++)
-		if (cx8800_ctls[i].v.id == ctl->id)
+	for (i = 0; i < CX8800_CTLS; i++) {
+		if (cx8800_ctls[i].v.id == ctl->id) {
 			c = &cx8800_ctls[i];
+		}
+	}
 	if (NULL == c)
 		return -EINVAL;
 
@@ -939,6 +944,7 @@
 		ctl->value = c->v.minimum;
 	if (ctl->value > c->v.maximum)
 		ctl->value = c->v.maximum;
+	mask=c->mask;
 	switch (ctl->id) {
 	case V4L2_CID_AUDIO_BALANCE:
 		value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
@@ -948,56 +954,44 @@
 		break;
 	case V4L2_CID_SATURATION:
 		/* special v_sat handling */
-		v_sat_value = ctl->value - (0x7f - 0x5a);
-		if (v_sat_value > 0xff)
-			v_sat_value = 0xff;
-		if (v_sat_value < 0x00)
-			v_sat_value = 0x00;
-		cx_andor(MO_UV_SATURATION, 0xff00, v_sat_value << 8);
-		/* fall through to default route for u_sat */
+
+		value = ((ctl->value - c->off) << c->shift) & c->mask;
+
+		if (core->tvnorm->id & V4L2_STD_SECAM) {
+			/* For SECAM, both U and V sat should be equal */
+			value=value<<8|value;
+		} else {
+			/* Keeps U Saturation proportional to V Sat */
+			value=(value*0x5a)/0x7f<<8|value;
+		}
+		mask=0xffff;
+		break;
 	default:
 		value = ((ctl->value - c->off) << c->shift) & c->mask;
 		break;
 	}
-	dprintk(1,"set_control id=0x%X reg=0x%x val=0x%x%s\n",
-		ctl->id, c->reg, value, c->sreg ? " [shadowed]" : "");
+	printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+					ctl->id, c->reg, value,
+					mask, c->sreg ? " [shadowed]" : "");
 	if (c->sreg) {
-		cx_sandor(c->sreg, c->reg, c->mask, value);
+		cx_sandor(c->sreg, c->reg, mask, value);
 	} else {
-		cx_andor(c->reg, c->mask, value);
+		cx_andor(c->reg, mask, value);
 	}
 	return 0;
 }
 
-/* static void init_controls(struct cx8800_dev *dev) */
 static void init_controls(struct cx88_core *core)
 {
-	static struct v4l2_control mute = {
-		.id    = V4L2_CID_AUDIO_MUTE,
-		.value = 1,
-	};
-	static struct v4l2_control volume = {
-		.id    = V4L2_CID_AUDIO_VOLUME,
-		.value = 0x3f,
-	};
-	static struct v4l2_control hue = {
-		.id    = V4L2_CID_HUE,
-		.value = 0x80,
-	};
-	static struct v4l2_control contrast = {
-		.id    = V4L2_CID_CONTRAST,
-		.value = 0x80,
-	};
-	static struct v4l2_control brightness = {
-		.id    = V4L2_CID_BRIGHTNESS,
-		.value = 0x80,
-	};
+	struct v4l2_control ctrl;
+	int i;
 
-	set_control(core,&mute);
-	set_control(core,&volume);
-	set_control(core,&hue);
-	set_control(core,&contrast);
-	set_control(core,&brightness);
+	for (i = 0; i < CX8800_CTLS; i++) {
+		ctrl.id=cx8800_ctls[i].v.id;
+		ctrl.value=cx8800_ctls[i].v.default_value
+				+cx8800_ctls[i].off;
+		set_control(core, &ctrl);
+	}
 }
 
 /* ------------------------------------------------------------------ */
@@ -1125,7 +1119,7 @@
 	int err;
 
 	if (video_debug > 1)
-		cx88_print_ioctl(core->name,cmd);
+		v4l_print_ioctl(core->name,cmd);
 	switch (cmd) {
 
 	/* --- capabilities ------------------------------------------ */
@@ -1261,7 +1255,7 @@
 
 	dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
 	if (video_debug > 1)
-		cx88_print_ioctl(core->name,cmd);
+		v4l_print_ioctl(core->name,cmd);
 
 	switch (cmd) {
 	/* ---------- tv norms ---------- */
@@ -1481,7 +1475,7 @@
 	struct cx88_core  *core = dev->core;
 
 	if (video_debug > 1)
-		cx88_print_ioctl(core->name,cmd);
+		v4l_print_ioctl(core->name,cmd);
 
 	switch (cmd) {
 	case VIDIOC_QUERYCAP:
@@ -1740,6 +1734,7 @@
 	.poll          = video_poll,
 	.mmap	       = video_mmap,
 	.ioctl	       = video_ioctl,
+	.compat_ioctl  = v4l_compat_ioctl32,
 	.llseek        = no_llseek,
 };
 
@@ -1767,6 +1762,7 @@
 	.open          = video_open,
 	.release       = video_release,
 	.ioctl         = radio_ioctl,
+	.compat_ioctl  = v4l_compat_ioctl32,
 	.llseek        = no_llseek,
 };
 
@@ -1928,8 +1924,8 @@
 
 	/* initial device configuration */
 	down(&core->lock);
-	init_controls(core);
 	cx88_set_tvnorm(core,tvnorms);
+	init_controls(core);
 	video_mux(core,0);
 	up(&core->lock);
 
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
new file mode 100644
index 0000000..372cd29
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -0,0 +1,173 @@
+/*
+
+    cx88-vp3054-i2c.c  --  support for the secondary I2C bus of the
+			   DNTV Live! DVB-T Pro (VP-3054), wired as:
+			   GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "cx88.h"
+#include "cx88-vp3054-i2c.h"
+
+
+/* ----------------------------------------------------------------------- */
+
+static void vp3054_bit_setscl(void *data, int state)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+	if (state) {
+		vp3054_i2c->state |=  0x0001;	/* SCL high */
+		vp3054_i2c->state &= ~0x0100;	/* external pullup */
+	} else {
+		vp3054_i2c->state &= ~0x0001;	/* SCL low */
+		vp3054_i2c->state |=  0x0100;	/* drive pin */
+	}
+	cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
+	cx_read(MO_GP0_IO);
+}
+
+static void vp3054_bit_setsda(void *data, int state)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+	if (state) {
+		vp3054_i2c->state |=  0x0002;	/* SDA high */
+		vp3054_i2c->state &= ~0x0200;	/* tristate pin */
+	} else {
+		vp3054_i2c->state &= ~0x0002;	/* SDA low */
+		vp3054_i2c->state |=  0x0200;	/* drive pin */
+	}
+	cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
+	cx_read(MO_GP0_IO);
+}
+
+static int vp3054_bit_getscl(void *data)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	u32 state;
+
+	state = cx_read(MO_GP0_IO);
+	return (state & 0x01) ? 1 : 0;
+}
+
+static int vp3054_bit_getsda(void *data)
+{
+	struct cx8802_dev *dev = data;
+	struct cx88_core *core = dev->core;
+	u32 state;
+
+	state = cx_read(MO_GP0_IO);
+	return (state & 0x02) ? 1 : 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+	.setsda  = vp3054_bit_setsda,
+	.setscl  = vp3054_bit_setscl,
+	.getsda  = vp3054_bit_getsda,
+	.getscl  = vp3054_bit_getscl,
+	.udelay  = 16,
+	.mdelay  = 10,
+	.timeout = 200,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter vp3054_i2c_adap_template = {
+	.name              = "cx2388x",
+	.owner             = THIS_MODULE,
+	.id                = I2C_HW_B_CX2388x,
+};
+
+static struct i2c_client vp3054_i2c_client_template = {
+	.name	= "VP-3054",
+};
+
+int vp3054_i2c_probe(struct cx8802_dev *dev)
+{
+	struct cx88_core *core = dev->core;
+	struct vp3054_i2c_state *vp3054_i2c;
+	int rc;
+
+	if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+		return 0;
+
+	dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+	if (dev->card_priv == NULL)
+		return -ENOMEM;
+	vp3054_i2c = dev->card_priv;
+
+	memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
+	       sizeof(vp3054_i2c->adap));
+	memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
+	       sizeof(vp3054_i2c->algo));
+	memcpy(&vp3054_i2c->client, &vp3054_i2c_client_template,
+	       sizeof(vp3054_i2c->client));
+
+	vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
+
+	vp3054_i2c->adap.dev.parent = &dev->pci->dev;
+	strlcpy(vp3054_i2c->adap.name, core->name,
+		sizeof(vp3054_i2c->adap.name));
+	vp3054_i2c->algo.data = dev;
+	i2c_set_adapdata(&vp3054_i2c->adap, dev);
+	vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
+	vp3054_i2c->client.adapter = &vp3054_i2c->adap;
+
+	vp3054_bit_setscl(dev,1);
+	vp3054_bit_setsda(dev,1);
+
+	rc = i2c_bit_add_bus(&vp3054_i2c->adap);
+	if (0 != rc) {
+		printk("%s: vp3054_i2c register FAILED\n", core->name);
+
+		kfree(dev->card_priv);
+		dev->card_priv = NULL;
+	}
+
+	return rc;
+}
+
+void vp3054_i2c_remove(struct cx8802_dev *dev)
+{
+	struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+
+	if (vp3054_i2c == NULL ||
+	    dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+		return;
+
+	i2c_bit_del_bus(&vp3054_i2c->adap);
+	kfree(vp3054_i2c);
+}
+
+EXPORT_SYMBOL(vp3054_i2c_probe);
+EXPORT_SYMBOL(vp3054_i2c_remove);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
new file mode 100644
index 0000000..b7a0a04
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -0,0 +1,35 @@
+/*
+
+    cx88-vp3054-i2c.h  --  support for the secondary I2C bus of the
+			   DNTV Live! DVB-T Pro (VP-3054), wired as:
+			   GPIO[0] -> SCL, GPIO[1] -> SDA
+
+    (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free 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.
+
+*/
+
+/* ----------------------------------------------------------------------- */
+struct vp3054_i2c_state {
+	struct i2c_adapter         adap;
+	struct i2c_algo_bit_data   algo;
+	struct i2c_client          client;
+	u32                        state;
+};
+
+/* ----------------------------------------------------------------------- */
+int  vp3054_i2c_probe(struct cx8802_dev *dev);
+void vp3054_i2c_remove(struct cx8802_dev *dev);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 77beafc..e9fd55b 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -179,6 +179,14 @@
 #define CX88_BOARD_ATI_HDTVWONDER          34
 #define CX88_BOARD_WINFAST_DTV1000         35
 #define CX88_BOARD_AVERTV_303              36
+#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1  37
+#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1    38
+#define CX88_BOARD_KWORLD_DVBS_100         39
+#define CX88_BOARD_HAUPPAUGE_HVR1100       40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP     41
+#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO     42
+#define CX88_BOARD_KWORLD_DVB_T_CX22702    43
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -280,6 +288,9 @@
 	unsigned int               tda9887_conf;
 	unsigned int               has_radio;
 
+	/* Supported V4L _STD_ tuner formats */
+	unsigned int               tuner_formats;
+
 	/* config info -- dvb */
 	struct dvb_pll_desc        *pll_desc;
 	unsigned int               pll_addr;
@@ -301,6 +312,9 @@
 
 	/* various v4l controls */
 	u32                        freq;
+
+	/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+	struct cx8802_dev          *dvbdev;
 };
 
 struct cx8800_dev;
@@ -411,6 +425,8 @@
 	struct videobuf_dvb        dvb;
 	void*                      fe_handle;
 	int                        (*fe_release)(void *handle);
+
+	void			   *card_priv;
 	/* for switching modulation types */
 	unsigned char              ts_gen_cntrl;
 
@@ -447,7 +463,6 @@
 
 extern void cx88_print_irqbits(char *name, char *tag, char **strings,
 			       u32 bits, u32 mask);
-extern void cx88_print_ioctl(char *name, unsigned int cmd);
 
 extern int cx88_core_irq(struct cx88_core *core, u32 status);
 extern void cx88_wakeup(struct cx88_core *core,
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 57779e6..58f7b41 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -30,6 +30,7 @@
 #include <media/tuner.h>
 #include <media/audiochip.h>
 #include <media/tveeprom.h>
+#include <media/v4l2-common.h>
 #include "msp3400.h"
 
 #include "em28xx.h"
@@ -261,7 +262,6 @@
 	/* request some modules */
 	if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
 		struct tveeprom tv;
-		struct v4l2_audioout ao;
 #ifdef CONFIG_MODULES
 		request_module("tveeprom");
 		request_module("ir-kbd-i2c");
@@ -274,12 +274,8 @@
 
 		dev->tuner_type= tv.tuner_type;
 		if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+			dev->i2s_speed=2048000;
 			dev->has_msp34xx=1;
-			memset (&ao,0,sizeof(ao));
-
-			ao.index=2;
-			ao.mode=V4L2_AUDMODE_32BITS;
-			em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
 		} else
 			dev->has_msp34xx=0;
 	}
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 0cfe754..dff3893 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -32,7 +32,7 @@
 
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
-static unsigned int core_debug;
+static unsigned int core_debug = 0;
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
@@ -41,7 +41,7 @@
 		printk(KERN_INFO "%s %s :"fmt, \
 			 dev->name, __FUNCTION__ , ##arg); } while (0)
 
-static unsigned int reg_debug;
+static unsigned int reg_debug = 0;
 module_param(reg_debug,int,0644);
 MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
 
@@ -50,7 +50,7 @@
 		printk(KERN_INFO "%s %s :"fmt, \
 			 dev->name, __FUNCTION__ , ##arg); } while (0)
 
-static unsigned int isoc_debug;
+static unsigned int isoc_debug = 0;
 module_param(isoc_debug,int,0644);
 MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
 
@@ -63,59 +63,6 @@
 module_param(alt, int, 0644);
 MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-	"0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-	"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-	"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-	"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-	"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-	"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-	"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-	"44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-	"S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void em28xx_print_ioctl(char *name, unsigned int cmd)
-{
-	char *dir;
-
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:              dir = "--"; break;
-	case _IOC_READ:              dir = "r-"; break;
-	case _IOC_WRITE:             dir = "-w"; break;
-	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-	default:                     dir = "??"; break;
-	}
-	switch (_IOC_TYPE(cmd)) {
-	case 'v':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-		       v4l1_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'V':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-		       v4l2_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	default:
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-	}
-}
-
 
 /*
  * em28xx_request_buffers()
@@ -126,7 +73,7 @@
 	const size_t imagesize = PAGE_ALIGN(dev->frame_size);	/*needs to be page aligned cause the buffers can be mapped individually! */
 	void *buff = NULL;
 	u32 i;
-	em28xx_coredbg("requested %i buffers with size %zd", count, imagesize);
+	em28xx_coredbg("requested %i buffers with size %zi", count, imagesize);
 	if (count > EM28XX_NUM_FRAMES)
 		count = EM28XX_NUM_FRAMES;
 
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index d14bcf4..0591a70 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -28,6 +28,7 @@
 #include <linux/video_decoder.h>
 
 #include "em28xx.h"
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 
 /* ----------------------------------------------------------- */
@@ -486,9 +487,7 @@
 	.inc_use = inc_use,
 	.dec_use = dec_use,
 #endif
-#ifdef I2C_CLASS_TV_ANALOG
 	.class = I2C_CLASS_TV_ANALOG,
-#endif
 	.name = "em28xx",
 	.id = I2C_HW_B_EM28XX,
 	.algo = &em28xx_algo,
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 3a56120..fdc25591 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -32,6 +32,7 @@
 
 #include "em28xx.h"
 #include <media/tuner.h>
+#include <media/v4l2-common.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
 		      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -106,8 +107,32 @@
 #define TVNORMS ARRAY_SIZE(tvnorms)
 
 /* supported controls */
+/* Common to all boards */
 static struct v4l2_queryctrl em28xx_qctrl[] = {
 	{
+		.id = V4L2_CID_AUDIO_VOLUME,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Volume",
+		.minimum = 0x0,
+		.maximum = 0x1f,
+		.step = 0x1,
+		.default_value = 0x1f,
+		.flags = 0,
+	},{
+		.id = V4L2_CID_AUDIO_MUTE,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.name = "Mute",
+		.minimum = 0,
+		.maximum = 1,
+		.step = 1,
+		.default_value = 1,
+		.flags = 0,
+	}
+};
+
+/* FIXME: These are specific to saa711x - should be moved to its code */
+static struct v4l2_queryctrl saa711x_qctrl[] = {
+	{
 		.id = V4L2_CID_BRIGHTNESS,
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.name = "Brightness",
@@ -135,24 +160,6 @@
 		.default_value = 0x10,
 		.flags = 0,
 	},{
-		.id = V4L2_CID_AUDIO_VOLUME,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Volume",
-		.minimum = 0x0,
-		.maximum = 0x1f,
-		.step = 0x1,
-		.default_value = 0x1f,
-		.flags = 0,
-	},{
-		.id = V4L2_CID_AUDIO_MUTE,
-		.type = V4L2_CTRL_TYPE_BOOLEAN,
-		.name = "Mute",
-		.minimum = 0,
-		.maximum = 1,
-		.step = 1,
-		.default_value = 1,
-		.flags = 0,
-	},{
 		.id = V4L2_CID_RED_BALANCE,
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.name = "Red chroma balance",
@@ -179,7 +186,7 @@
 		.step = 0x1,
 		.default_value = 0x20,
 		.flags = 0,
-	 }
+	}
 };
 
 static struct usb_driver em28xx_usb_driver;
@@ -280,6 +287,8 @@
 	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
 
 	if (dev->has_msp34xx) {
+		if (dev->i2s_speed)
+			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
 		em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
 		ainput = EM28XX_AUDIO_SRC_TUNER;
 		em28xx_audio_source(dev, ainput);
@@ -674,7 +683,6 @@
  */
 static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 {
-	s32 tmp;
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 		ctrl->value = dev->mute;
@@ -682,6 +690,16 @@
 	case V4L2_CID_AUDIO_VOLUME:
 		ctrl->value = dev->volume;
 		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+	s32 tmp;
+	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
 		if ((tmp = em28xx_brightness_get(dev)) < 0)
 			return -EIO;
@@ -731,6 +749,15 @@
 	case V4L2_CID_AUDIO_VOLUME:
 		dev->volume = ctrl->value;
 		return em28xx_audio_analog_set(dev);
+	default:
+		return -EINVAL;
+	}
+}
+
+/*FIXME: should be moved to saa711x */
+static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
 		return em28xx_brightness_set(dev, ctrl->value);
 	case V4L2_CID_CONTRAST:
@@ -994,14 +1021,34 @@
 	case VIDIOC_QUERYCTRL:
 		{
 			struct v4l2_queryctrl *qc = arg;
-			u8 i, n;
-			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
-			for (i = 0; i < n; i++)
-				if (qc->id && qc->id == em28xx_qctrl[i].id) {
-					memcpy(qc, &(em28xx_qctrl[i]),
+			int i, id=qc->id;
+
+			memset(qc,0,sizeof(*qc));
+			qc->id=id;
+
+			if (!dev->has_msp34xx) {
+				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+					if (qc->id && qc->id == em28xx_qctrl[i].id) {
+						memcpy(qc, &(em28xx_qctrl[i]),
+						sizeof(*qc));
+						return 0;
+					}
+				}
+			}
+			if (dev->decoder == EM28XX_TVP5150) {
+				em28xx_i2c_call_clients(dev,cmd,qc);
+				if (qc->type)
+					return 0;
+				else
+					return -EINVAL;
+			}
+			for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+				if (qc->id && qc->id == saa711x_qctrl[i].id) {
+					memcpy(qc, &(saa711x_qctrl[i]),
 					       sizeof(*qc));
 					return 0;
 				}
+			}
 
 			return -EINVAL;
 		}
@@ -1009,29 +1056,64 @@
 	case VIDIOC_G_CTRL:
 		{
 			struct v4l2_control *ctrl = arg;
+			int retval=-EINVAL;
 
+			if (!dev->has_msp34xx)
+				retval=em28xx_get_ctrl(dev, ctrl);
+			if (retval==-EINVAL) {
+				if (dev->decoder == EM28XX_TVP5150) {
+					em28xx_i2c_call_clients(dev,cmd,arg);
+					return 0;
+				}
 
-			return em28xx_get_ctrl(dev, ctrl);
+				return saa711x_get_ctrl(dev, ctrl);
+			} else return retval;
 		}
 
-	case VIDIOC_S_CTRL_OLD:	/* ??? */
 	case VIDIOC_S_CTRL:
 		{
 			struct v4l2_control *ctrl = arg;
-			u8 i, n;
+			u8 i;
 
-
-			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
-			for (i = 0; i < n; i++)
-				if (ctrl->id == em28xx_qctrl[i].id) {
-					if (ctrl->value <
-					    em28xx_qctrl[i].minimum
-					    || ctrl->value >
-					    em28xx_qctrl[i].maximum)
-						return -ERANGE;
-
-					return em28xx_set_ctrl(dev, ctrl);
+			if (!dev->has_msp34xx){
+				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+					if (ctrl->id == em28xx_qctrl[i].id) {
+						if (ctrl->value <
+						em28xx_qctrl[i].minimum
+						|| ctrl->value >
+						em28xx_qctrl[i].maximum)
+							return -ERANGE;
+						return em28xx_set_ctrl(dev, ctrl);
+					}
 				}
+			}
+
+			if (dev->decoder == EM28XX_TVP5150) {
+				em28xx_i2c_call_clients(dev,cmd,arg);
+				return 0;
+			} else if (!dev->has_msp34xx) {
+				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+					if (ctrl->id == em28xx_qctrl[i].id) {
+						if (ctrl->value <
+						em28xx_qctrl[i].minimum
+						|| ctrl->value >
+						em28xx_qctrl[i].maximum)
+							return -ERANGE;
+						return em28xx_set_ctrl(dev, ctrl);
+					}
+				}
+				for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
+					if (ctrl->id == saa711x_qctrl[i].id) {
+						if (ctrl->value <
+						saa711x_qctrl[i].minimum
+						|| ctrl->value >
+						saa711x_qctrl[i].maximum)
+							return -ERANGE;
+						return saa711x_set_ctrl(dev, ctrl);
+					}
+				}
+			}
+
 			return -EINVAL;
 		}
 
@@ -1187,7 +1269,7 @@
 		return -ENODEV;
 
 	if (video_debug > 1)
-		em28xx_print_ioctl(dev->name,cmd);
+		v4l_print_ioctl(dev->name,cmd);
 
 	switch (cmd) {
 
@@ -1564,6 +1646,8 @@
 	.poll = em28xx_v4l2_poll,
 	.mmap = em28xx_v4l2_mmap,
 	.llseek = no_llseek,
+	.compat_ioctl   = v4l_compat_ioctl32,
+
 };
 
 /******************************** usb interface *****************************************/
@@ -1848,9 +1932,12 @@
 	struct em28xx *dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 
+/*FIXME: IR should be disconnected */
+
 	if (!dev)
 		return;
 
+
 	down_write(&em28xx_disconnect);
 
 	down(&dev->lock);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 5c7a41c..33de9d8 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -1,5 +1,5 @@
 /*
-   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+   em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
 
    Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
 		      Ludovico Cavedon <cavedon@sssup.it>
@@ -216,6 +216,8 @@
 	unsigned int has_msp34xx:1;
 	unsigned int has_tda9887:1;
 
+	u32 i2s_speed;		/* I2S speed for audio digital stream */
+
 	enum em28xx_decoder decoder;
 
 	int tuner_type;		/* type of the tuner */
@@ -293,8 +295,6 @@
 
 /* Provided by em28xx-core.c */
 
-void em28xx_print_ioctl(char *name, unsigned int cmd);
-
 u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
 void em28xx_queue_unusedframes(struct em28xx *dev);
 void em28xx_release_buffers(struct em28xx *dev);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 3cc1d6a..58b0e69 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -279,7 +279,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name   = "ir remote kbd driver",
+		.name   = "ir-kbd-i2c",
 	},
 	.id             = I2C_DRIVERID_INFRARED,
 	.attach_adapter = ir_probe,
@@ -304,18 +304,20 @@
 	ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!ir || !input_dev) {
-		kfree(ir);
 		input_free_device(input_dev);
+		kfree(ir);
 		return -ENOMEM;
 	}
+	memset(ir,0,sizeof(*ir));
 
 	ir->c = client_template;
 	ir->input = input_dev;
 
-	i2c_set_clientdata(&ir->c, ir);
 	ir->c.adapter = adap;
 	ir->c.addr    = addr;
 
+	i2c_set_clientdata(&ir->c, ir);
+
 	switch(addr) {
 	case 0x64:
 		name        = "Pixelview";
@@ -378,13 +380,15 @@
 		 ir->c.dev.bus_id);
 
 	/* init + register input device */
-	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
-	input_dev->id.bustype	= BUS_I2C;
-	input_dev->name		= ir->c.name;
-	input_dev->phys		= ir->phys;
+	ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes);
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->name       = ir->c.name;
+	input_dev->phys       = ir->phys;
 
 	/* register event device */
 	input_register_device(ir->input);
+	printk(DEVNAME ": %s detected at %s [%s]\n",
+	       ir->input->name,ir->input->phys,adap->name);
 
 	/* start polling via eventd */
 	INIT_WORK(&ir->work, ir_work, ir);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 3f2a882..2869464 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1754,6 +1754,7 @@
 	.release	= meye_release,
 	.mmap		= meye_mmap,
 	.ioctl		= meye_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.poll		= meye_poll,
 	.llseek		= no_llseek,
 };
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
new file mode 100644
index 0000000..aa8c556
--- /dev/null
+++ b/drivers/media/video/msp3400-driver.c
@@ -0,0 +1,1274 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * what works and what doesn't:
+ *
+ *  AM-Mono
+ *      Support for Hauppauge cards added (decoding handled by tuner) added by
+ *      Frederic Crozat <fcrozat@mail.dotcom.fr>
+ *
+ *  FM-Mono
+ *      should work. The stereo modes are backward compatible to FM-mono,
+ *      therefore FM-Mono should be allways available.
+ *
+ *  FM-Stereo (B/G, used in germany)
+ *      should work, with autodetect
+ *
+ *  FM-Stereo (satellite)
+ *      should work, no autodetect (i.e. default is mono, but you can
+ *      switch to stereo -- untested)
+ *
+ *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
+ *      should work, with autodetect. Support for NICAM was added by
+ *      Pekka Pietikainen <pp@netppl.fi>
+ *
+ * TODO:
+ *   - better SAT support
+ *
+ * 980623  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *         using soundcore instead of OSS
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/* module parameters */
+static int opmode   = OPMODE_AUTO;
+int debug    = 0;    /* debug output */
+int once     = 0;    /* no continous stereo monitoring */
+int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
+			       the autoscan seems work well only with FM... */
+int standard = 1;    /* Override auto detect of audio standard, if needed. */
+int dolby    = 0;
+
+int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
+					(msp34xxg only) 0x00a0-0x03c0 */
+
+/* read-only */
+module_param(opmode,           int, 0444);
+
+/* read-write */
+module_param(once,             bool, 0644);
+module_param(debug,            int, 0644);
+module_param(stereo_threshold, int, 0644);
+module_param(standard,         int, 0644);
+module_param(amsound,          bool, 0644);
+module_param(dolby,            bool, 0644);
+
+MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
+MODULE_PARM_DESC(once, "No continuous stereo monitoring");
+MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
+MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
+MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
+MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
+MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+
+/* ---------------------------------------------------------------------- */
+
+/* control subaddress */
+#define I2C_MSP_CONTROL 0x00
+/* demodulator unit subaddress */
+#define I2C_MSP_DEM     0x10
+/* DSP unit subaddress */
+#define I2C_MSP_DSP     0x12
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor                   */
+
+int msp_reset(struct i2c_client *client)
+{
+	/* reset and read revision code */
+	static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 };
+	static u8 reset_on[3]  = { I2C_MSP_CONTROL, 0x00, 0x00 };
+	static u8 write[3]     = { I2C_MSP_DSP + 1, 0x00, 0x1e };
+	u8 read[2];
+	struct i2c_msg reset[2] = {
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
+	};
+	struct i2c_msg test[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  },
+	};
+
+	v4l_dbg(3, client, "msp_reset\n");
+	if (i2c_transfer(client->adapter, &reset[0], 1) != 1 ||
+	    i2c_transfer(client->adapter, &reset[1], 1) != 1 ||
+	    i2c_transfer(client->adapter, test, 2) != 2) {
+		v4l_err(client, "chip reset failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int msp_read(struct i2c_client *client, int dev, int addr)
+{
+	int err, retval;
+	u8 write[3];
+	u8 read[2];
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  }
+	};
+
+	write[0] = dev + 1;
+	write[1] = addr >> 8;
+	write[2] = addr & 0xff;
+
+	for (err = 0; err < 3; err++) {
+		if (i2c_transfer(client->adapter, msgs, 2) == 2)
+			break;
+		v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(msecs_to_jiffies(10));
+	}
+	if (err == 3) {
+		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+		msp_reset(client);
+		return -1;
+	}
+	retval = read[0] << 8 | read[1];
+	v4l_dbg(3, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+	return retval;
+}
+
+int msp_read_dem(struct i2c_client *client, int addr)
+{
+	return msp_read(client, I2C_MSP_DEM, addr);
+}
+
+int msp_read_dsp(struct i2c_client *client, int addr)
+{
+	return msp_read(client, I2C_MSP_DSP, addr);
+}
+
+static int msp_write(struct i2c_client *client, int dev, int addr, int val)
+{
+	int err;
+	u8 buffer[5];
+
+	buffer[0] = dev;
+	buffer[1] = addr >> 8;
+	buffer[2] = addr &  0xff;
+	buffer[3] = val  >> 8;
+	buffer[4] = val  &  0xff;
+
+	v4l_dbg(3, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
+	for (err = 0; err < 3; err++) {
+		if (i2c_master_send(client, buffer, 5) == 5)
+			break;
+		v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
+		       dev, addr);
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(msecs_to_jiffies(10));
+	}
+	if (err == 3) {
+		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+		msp_reset(client);
+		return -1;
+	}
+	return 0;
+}
+
+int msp_write_dem(struct i2c_client *client, int addr, int val)
+{
+	return msp_write(client, I2C_MSP_DEM, addr, val);
+}
+
+int msp_write_dsp(struct i2c_client *client, int addr, int val)
+{
+	return msp_write(client, I2C_MSP_DSP, addr, val);
+}
+
+/* ----------------------------------------------------------------------- *
+ * bits  9  8  5 - SCART DSP input Select:
+ *       0  0  0 - SCART 1 to DSP input (reset position)
+ *       0  1  0 - MONO to DSP input
+ *       1  0  0 - SCART 2 to DSP input
+ *       1  1  1 - Mute DSP input
+ *
+ * bits 11 10  6 - SCART 1 Output Select:
+ *       0  0  0 - undefined (reset position)
+ *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ *       1  0  0 - MONO input to SCART 1 Output
+ *       1  1  0 - SCART 1 DA to SCART 1 Output
+ *       0  0  1 - SCART 2 DA to SCART 1 Output
+ *       0  1  1 - SCART 1 Input to SCART 1 Output
+ *       1  1  1 - Mute SCART 1 Output
+ *
+ * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
+ *       0  1  0 - SCART 1 Input to SCART 2 Output
+ *       1  0  0 - MONO input to SCART 2 Output
+ *       0  0  1 - SCART 2 DA to SCART 2 Output
+ *       0  1  1 - SCART 2 Input to SCART 2 Output
+ *       1  1  0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
+
+static int scarts[3][9] = {
+	/* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+	/* SCART DSP Input select */
+	{ 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+	/* SCART1 Output select */
+	{ 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+	/* SCART2 Output select */
+	{ 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+	"mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+};
+
+void msp_set_scart(struct i2c_client *client, int in, int out)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	state->in_scart=in;
+
+	if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+		if (-1 == scarts[out][in])
+			return;
+
+		state->acb &= ~scarts[out][SCART_MASK];
+		state->acb |=  scarts[out][in];
+	} else
+		state->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+	v4l_dbg(1, client, "scart switch: %s => %d (ACB=0x%04x)\n",
+						scart_names[in], out, state->acb);
+	msp_write_dsp(client, 0x13, state->acb);
+
+	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+	msp_write_dem(client, 0x40, state->i2s_mode);
+}
+
+void msp_set_mute(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	v4l_dbg(1, client, "mute audio\n");
+	msp_write_dsp(client, 0x0000, 0);
+	msp_write_dsp(client, 0x0007, 1);
+	if (state->has_scart2_out_volume)
+		msp_write_dsp(client, 0x0040, 1);
+	if (state->has_headphones)
+		msp_write_dsp(client, 0x0006, 0);
+}
+
+void msp_set_audio(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int bal = 0, bass, treble, loudness;
+	int val = 0;
+
+	if (!state->muted)
+		val = (state->volume * 0x7f / 65535) << 8;
+
+	v4l_dbg(1, client, "mute=%s volume=%d\n",
+		state->muted ? "on" : "off", state->volume);
+
+	msp_write_dsp(client, 0x0000, val);
+	msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1));
+	if (state->has_scart2_out_volume)
+		msp_write_dsp(client, 0x0040, state->muted ? 0x1 : (val | 0x1));
+	if (state->has_headphones)
+		msp_write_dsp(client, 0x0006, val);
+	if (!state->has_sound_processing)
+		return;
+
+	if (val)
+		bal = (u8)((state->balance / 256) - 128);
+	bass = ((state->bass - 32768) * 0x60 / 65535) << 8;
+	treble = ((state->treble - 32768) * 0x60 / 65535) << 8;
+	loudness = state->loudness ? ((5 * 4) << 8) : 0;
+
+	v4l_dbg(1, client, "balance=%d bass=%d treble=%d loudness=%d\n",
+		state->balance, state->bass, state->treble, state->loudness);
+
+	msp_write_dsp(client, 0x0001, bal << 8);
+	msp_write_dsp(client, 0x0002, bass);
+	msp_write_dsp(client, 0x0003, treble);
+	msp_write_dsp(client, 0x0004, loudness);
+	if (!state->has_headphones)
+		return;
+	msp_write_dsp(client, 0x0030, bal << 8);
+	msp_write_dsp(client, 0x0031, bass);
+	msp_write_dsp(client, 0x0032, treble);
+	msp_write_dsp(client, 0x0033, loudness);
+}
+
+int msp_modus(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	if (state->radio) {
+		v4l_dbg(1, client, "video mode selected to Radio\n");
+		return 0x0003;
+	}
+
+	if (state->v4l2_std & V4L2_STD_PAL) {
+		v4l_dbg(1, client, "video mode selected to PAL\n");
+
+#if 1
+		/* experimental: not sure this works with all chip versions */
+		return 0x7003;
+#else
+		/* previous value, try this if it breaks ... */
+		return 0x1003;
+#endif
+	}
+	if (state->v4l2_std & V4L2_STD_NTSC) {
+		v4l_dbg(1, client, "video mode selected to NTSC\n");
+		return 0x2003;
+	}
+	if (state->v4l2_std & V4L2_STD_SECAM) {
+		v4l_dbg(1, client, "video mode selected to SECAM\n");
+		return 0x0003;
+	}
+	return 0x0003;
+}
+
+/* ------------------------------------------------------------------------ */
+
+
+static void msp_wake_thread(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	if (NULL == state->kthread)
+		return;
+	msp_set_mute(client);
+	state->watch_stereo = 0;
+	state->restart = 1;
+	wake_up_interruptible(&state->wq);
+}
+
+int msp_sleep(struct msp_state *state, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&state->wq, &wait);
+	if (!kthread_should_stop()) {
+		if (timeout < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		} else {
+			schedule_timeout_interruptible
+						(msecs_to_jiffies(timeout));
+		}
+	}
+
+	remove_wait_queue(&state->wq, &wait);
+	try_to_freeze();
+	return state->restart;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int msp_mode_v4l2_to_v4l1(int rxsubchans)
+{
+	int mode = 0;
+
+	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
+		mode |= VIDEO_SOUND_STEREO;
+	if (rxsubchans & V4L2_TUNER_SUB_LANG2)
+		mode |= VIDEO_SOUND_LANG2;
+	if (rxsubchans & V4L2_TUNER_SUB_LANG1)
+		mode |= VIDEO_SOUND_LANG1;
+	if (mode == 0)
+		mode |= VIDEO_SOUND_MONO;
+	return mode;
+}
+
+static int msp_mode_v4l1_to_v4l2(int mode)
+{
+	if (mode & VIDEO_SOUND_STEREO)
+		return V4L2_TUNER_MODE_STEREO;
+	if (mode & VIDEO_SOUND_LANG2)
+		return V4L2_TUNER_MODE_LANG2;
+	if (mode & VIDEO_SOUND_LANG1)
+		return V4L2_TUNER_MODE_LANG1;
+	return V4L2_TUNER_MODE_MONO;
+}
+
+static void msp_any_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state  = i2c_get_clientdata(client);
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		autodetect_stereo(client);
+		break;
+	case OPMODE_AUTOSELECT:
+		msp34xxg_detect_stereo(client);
+		break;
+	}
+}
+
+static struct v4l2_queryctrl msp_qctrl_std[] = {
+	{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 58880,
+		.flags         = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 1,
+		.flags         = 0,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},
+};
+
+static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
+	{
+		.id            = V4L2_CID_AUDIO_BALANCE,
+		.name          = "Balance",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.flags         = 0,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_BASS,
+		.name          = "Bass",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_TREBLE,
+		.name          = "Treble",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535/100,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_LOUDNESS,
+		.name          = "Loudness",
+		.minimum       = 0,
+		.maximum       = 1,
+		.step          = 1,
+		.default_value = 1,
+		.flags         = 0,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},
+};
+
+
+static void msp_any_set_audmode(struct i2c_client *client, int audmode)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+	case OPMODE_AUTODETECT:
+		state->watch_stereo = 0;
+		msp3400c_setstereo(client, audmode);
+		break;
+	case OPMODE_AUTOSELECT:
+		msp34xxg_set_audmode(client, audmode);
+		break;
+	}
+}
+
+static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = state->volume;
+		break;
+
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = state->muted;
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		ctrl->value = state->balance;
+		break;
+
+	case V4L2_CID_AUDIO_BASS:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		ctrl->value = state->bass;
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		ctrl->value = state->treble;
+		break;
+
+	case V4L2_CID_AUDIO_LOUDNESS:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		ctrl->value = state->loudness;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		state->volume = ctrl->value;
+		if (state->volume == 0)
+			state->balance = 32768;
+		break;
+
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value < 0 || ctrl->value >= 2)
+			return -ERANGE;
+		state->muted = ctrl->value;
+		break;
+
+	case V4L2_CID_AUDIO_BASS:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		state->bass = ctrl->value;
+		break;
+
+	case V4L2_CID_AUDIO_TREBLE:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		state->treble = ctrl->value;
+		break;
+
+	case V4L2_CID_AUDIO_LOUDNESS:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		state->loudness = ctrl->value;
+		break;
+
+	case V4L2_CID_AUDIO_BALANCE:
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		state->balance = ctrl->value;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	msp_set_audio(client);
+	return 0;
+}
+
+static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	u16 *sarg = arg;
+	int scart = 0;
+
+	if (debug >= 2)
+		v4l_i2c_print_ioctl(client, cmd);
+
+	switch (cmd) {
+	case AUDC_SET_INPUT:
+		if (*sarg == state->input)
+			break;
+		state->input = *sarg;
+		switch (*sarg) {
+		case AUDIO_RADIO:
+			/* Hauppauge uses IN2 for the radio */
+			state->mode = MSP_MODE_FM_RADIO;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_EXTERN_1:
+			/* IN1 is often used for external input ... */
+			state->mode = MSP_MODE_EXTERN;
+			scart       = SCART_IN1;
+			break;
+		case AUDIO_EXTERN_2:
+			/* ... sometimes it is IN2 through ;) */
+			state->mode = MSP_MODE_EXTERN;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_TUNER:
+			state->mode = -1;
+			break;
+		default:
+			if (*sarg & AUDIO_MUTE)
+				msp_set_scart(client, SCART_MUTE, 0);
+			break;
+		}
+		if (scart) {
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			state->audmode = V4L2_TUNER_MODE_STEREO;
+			msp_set_scart(client, scart, 0);
+			msp_write_dsp(client, 0x000d, 0x1900);
+			if (state->opmode != OPMODE_AUTOSELECT)
+				msp3400c_setstereo(client, state->audmode);
+		}
+		msp_wake_thread(client);
+		break;
+
+	case AUDC_SET_RADIO:
+		if (state->radio)
+			return 0;
+		state->radio = 1;
+		v4l_dbg(1, client, "switching to radio mode\n");
+		state->watch_stereo = 0;
+		switch (state->opmode) {
+		case OPMODE_MANUAL:
+			/* set msp3400 to FM radio mode */
+			msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+					    MSP_CARRIER(10.7));
+			msp_set_audio(client);
+			break;
+		case OPMODE_AUTODETECT:
+		case OPMODE_AUTOSELECT:
+			/* the thread will do for us */
+			msp_wake_thread(client);
+			break;
+		}
+		break;
+
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCGAUDIO:
+	{
+		struct video_audio *va = arg;
+
+		va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE;
+		if (state->has_sound_processing)
+			va->flags |= VIDEO_AUDIO_BALANCE |
+				VIDEO_AUDIO_BASS |
+				VIDEO_AUDIO_TREBLE;
+		if (state->muted)
+			va->flags |= VIDEO_AUDIO_MUTE;
+		va->volume = state->volume;
+		va->balance = state->volume ? state->balance : 32768;
+		va->bass = state->bass;
+		va->treble = state->treble;
+
+		if (state->radio)
+			break;
+		if (state->opmode == OPMODE_AUTOSELECT)
+			msp_any_detect_stereo(client);
+		va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
+		break;
+	}
+
+	case VIDIOCSAUDIO:
+	{
+		struct video_audio *va = arg;
+
+		state->muted = (va->flags & VIDEO_AUDIO_MUTE);
+		state->volume = va->volume;
+		state->balance = va->balance;
+		state->bass = va->bass;
+		state->treble = va->treble;
+		msp_set_audio(client);
+
+		if (va->mode != 0 && state->radio == 0)
+			msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+		break;
+	}
+
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *vc = arg;
+		int update = 0;
+		v4l2_std_id std;
+
+		if (state->radio)
+			update = 1;
+		state->radio = 0;
+		if (vc->norm == VIDEO_MODE_PAL)
+			std = V4L2_STD_PAL;
+		else if (vc->norm == VIDEO_MODE_SECAM)
+			std = V4L2_STD_SECAM;
+		else
+			std = V4L2_STD_NTSC;
+		if (std != state->v4l2_std) {
+			state->v4l2_std = std;
+			update = 1;
+		}
+		if (update)
+			msp_wake_thread(client);
+		break;
+	}
+
+	case VIDIOCSFREQ:
+	case VIDIOC_S_FREQUENCY:
+	{
+		/* new channel -- kick audio carrier scan */
+		msp_wake_thread(client);
+		break;
+	}
+
+	/* msp34xx specific */
+	case MSP_SET_MATRIX:
+	{
+		struct msp_matrix *mspm = arg;
+
+		msp_set_scart(client, mspm->input, mspm->output);
+		break;
+	}
+
+	/* --- v4l2 ioctls --- */
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+		int update = state->radio || state->v4l2_std != *id;
+
+		state->v4l2_std = *id;
+		state->radio = 0;
+		if (update)
+			msp_wake_thread(client);
+		return 0;
+	}
+
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *i = arg;
+
+		if (i->index != 0)
+			return -EINVAL;
+
+		i->type = V4L2_INPUT_TYPE_TUNER;
+		switch (i->index) {
+		case AUDIO_RADIO:
+			strcpy(i->name, "Radio");
+			break;
+		case AUDIO_EXTERN_1:
+			strcpy(i->name, "Extern 1");
+			break;
+		case AUDIO_EXTERN_2:
+			strcpy(i->name, "Extern 2");
+			break;
+		case AUDIO_TUNER:
+			strcpy(i->name, "Television");
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *a = arg;
+
+		memset(a, 0, sizeof(*a));
+
+		switch (a->index) {
+		case AUDIO_RADIO:
+			strcpy(a->name, "Radio");
+			break;
+		case AUDIO_EXTERN_1:
+			strcpy(a->name, "Extern 1");
+			break;
+		case AUDIO_EXTERN_2:
+			strcpy(a->name, "Extern 2");
+			break;
+		case AUDIO_TUNER:
+			strcpy(a->name, "Television");
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		msp_any_detect_stereo(client);
+		if (state->audmode == V4L2_TUNER_MODE_STEREO) {
+			a->capability = V4L2_AUDCAP_STEREO;
+		}
+
+		break;
+	}
+
+	case VIDIOC_S_AUDIO:
+	{
+		struct v4l2_audio *sarg = arg;
+
+		switch (sarg->index) {
+		case AUDIO_RADIO:
+			/* Hauppauge uses IN2 for the radio */
+			state->mode = MSP_MODE_FM_RADIO;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_EXTERN_1:
+			/* IN1 is often used for external input ... */
+			state->mode = MSP_MODE_EXTERN;
+			scart       = SCART_IN1;
+			break;
+		case AUDIO_EXTERN_2:
+			/* ... sometimes it is IN2 through ;) */
+			state->mode = MSP_MODE_EXTERN;
+			scart       = SCART_IN2;
+			break;
+		case AUDIO_TUNER:
+			state->mode = -1;
+			break;
+		}
+		if (scart) {
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			state->audmode = V4L2_TUNER_MODE_STEREO;
+			msp_set_scart(client, scart, 0);
+			msp_write_dsp(client, 0x000d, 0x1900);
+		}
+		if (sarg->capability == V4L2_AUDCAP_STEREO) {
+			state->audmode = V4L2_TUNER_MODE_STEREO;
+		} else {
+			state->audmode &= ~V4L2_TUNER_MODE_STEREO;
+		}
+		msp_any_set_audmode(client, state->audmode);
+		msp_wake_thread(client);
+		break;
+	}
+
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *vt = arg;
+
+		if (state->radio)
+			break;
+		if (state->opmode == OPMODE_AUTOSELECT)
+			msp_any_detect_stereo(client);
+		vt->audmode    = state->audmode;
+		vt->rxsubchans = state->rxsubchans;
+		vt->capability = V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+		break;
+	}
+
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+
+		if (state->radio)
+			break;
+		/* only set audmode */
+		if (vt->audmode != -1 && vt->audmode != 0)
+			msp_any_set_audmode(client, vt->audmode);
+		break;
+	}
+
+	case VIDIOC_G_AUDOUT:
+	{
+		struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+		int idx = a->index;
+
+		memset(a, 0, sizeof(*a));
+
+		switch (idx) {
+		case 0:
+			strcpy(a->name, "Scart1 Out");
+			break;
+		case 1:
+			strcpy(a->name, "Scart2 Out");
+			break;
+		case 2:
+			strcpy(a->name, "I2S Out");
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	}
+
+	case VIDIOC_S_AUDOUT:
+	{
+		struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
+
+		if (a->index < 0 || a->index > 2)
+			return -EINVAL;
+
+		v4l_dbg(1, client, "Setting audio out on msp34xx to input %i\n", a->index);
+		msp_set_scart(client, state->in_scart, a->index + 1);
+
+		break;
+	}
+
+	case VIDIOC_INT_I2S_CLOCK_FREQ:
+	{
+		u32 *a = (u32 *)arg;
+
+		v4l_dbg(1, client, "Setting I2S speed to %d\n", *a);
+
+		switch (*a) {
+			case 1024000:
+				state->i2s_mode = 0;
+				break;
+			case 2048000:
+				state->i2s_mode = 1;
+				break;
+			default:
+				return -EINVAL;
+		}
+		break;
+	}
+
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
+			if (qc->id && qc->id == msp_qctrl_std[i].id) {
+				memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
+				return 0;
+			}
+		if (!state->has_sound_processing)
+			return -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
+			if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
+				memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
+				return 0;
+			}
+		return -EINVAL;
+	}
+
+	case VIDIOC_G_CTRL:
+		return msp_get_ctrl(client, arg);
+
+	case VIDIOC_S_CTRL:
+		return msp_set_ctrl(client, arg);
+
+	case VIDIOC_LOG_STATUS:
+	{
+		const char *p;
+
+		if (state->opmode == OPMODE_AUTOSELECT)
+			msp_any_detect_stereo(client);
+		v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+				client->name, state->rev1, state->rev2);
+		v4l_info(client, "Audio:    volume %d%s\n",
+				state->volume, state->muted ? " (muted)" : "");
+		if (state->has_sound_processing) {
+			v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
+					state->balance, state->bass, state->treble,
+					state->loudness ? "on" : "off");
+		}
+		switch (state->mode) {
+		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
+		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
+		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
+		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
+		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
+		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
+		case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break;
+		case MSP_MODE_BTSC: p = "BTSC"; break;
+		case MSP_MODE_EXTERN: p = "External input"; break;
+		default: p = "unknown"; break;
+		}
+		if (state->opmode == OPMODE_MANUAL) {
+			v4l_info(client, "Mode:     %s (%s%s)\n", p,
+				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+		} else {
+			v4l_info(client, "Mode:     %s\n", p);
+			v4l_info(client, "Standard: %s (%s%s)\n",
+				msp_standard_std_name(state->std),
+				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
+				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
+		}
+		v4l_info(client, "ACB:      0x%04x\n", state->acb);
+		break;
+	}
+
+	default:
+		/* nothing */
+		break;
+	}
+	return 0;
+}
+
+static int msp_suspend(struct device * dev, pm_message_t state)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+	v4l_dbg(1, client, "suspend\n");
+	msp_reset(client);
+	return 0;
+}
+
+static int msp_resume(struct device * dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+	v4l_dbg(1, client, "resume\n");
+	msp_wake_thread(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver;
+
+static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct msp_state *state;
+	int (*thread_func)(void *data) = NULL;
+	int msp_hard;
+	int msp_family;
+	int msp_revision;
+	int msp_product, msp_prod_hi, msp_prod_lo;
+	int msp_rom;
+
+	client = kmalloc(sizeof(*client), GFP_KERNEL);
+	if (client == NULL)
+		return -ENOMEM;
+	memset(client, 0, sizeof(*client));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver;
+	snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+
+	if (msp_reset(client) == -1) {
+		v4l_dbg(1, client, "msp3400 not found\n");
+		kfree(client);
+		return -1;
+	}
+
+	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	i2c_set_clientdata(client, state);
+
+	memset(state, 0, sizeof(*state));
+	state->v4l2_std = V4L2_STD_NTSC;
+	state->volume = 58880;	/* 0db gain */
+	state->balance = 32768;	/* 0db gain */
+	state->bass = 32768;
+	state->treble = 32768;
+	state->loudness = 0;
+	state->input = -1;
+	state->muted = 0;
+	state->i2s_mode = 0;
+	init_waitqueue_head(&state->wq);
+
+	state->rev1 = msp_read_dsp(client, 0x1e);
+	if (state->rev1 != -1)
+		state->rev2 = msp_read_dsp(client, 0x1f);
+	v4l_dbg(1, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
+	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
+		v4l_dbg(1, client, "not an msp3400 (cannot read chip version)\n");
+		kfree(state);
+		kfree(client);
+		return -1;
+	}
+
+	msp_set_audio(client);
+
+	msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
+	msp_product = (state->rev2 >> 8) & 0xff;
+	msp_prod_hi = msp_product / 10;
+	msp_prod_lo = msp_product % 10;
+	msp_revision = (state->rev1 & 0x0f) + '@';
+	msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
+	msp_rom = state->rev2 & 0x1f;
+	snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
+			msp_family, msp_product,
+			msp_revision, msp_hard, msp_rom);
+
+	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
+	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
+	/* Has radio support: was added with revision G */
+	state->has_radio = msp_revision >= 'G';
+	/* Has headphones output: not for stripped down products */
+	state->has_headphones = msp_prod_lo < 5;
+	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
+	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+	/* Has scart2 and scart3 inputs and scart2 output: not in stripped
+	   down products of the '3' family */
+	state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
+	/* Has scart2 a volume control? Not in pre-D revisions. */
+	state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out;
+	/* Has a configurable i2s out? */
+	state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
+	/* Has subwoofer output: not in pre-D revs and not in stripped down products */
+	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
+	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
+	   stripped down products */
+	state->has_sound_processing = msp_prod_lo < 7;
+	/* Has Virtual Dolby Surround: only in msp34x1 */
+	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
+
+	state->opmode = opmode;
+	if (state->opmode == OPMODE_AUTO) {
+		/* MSP revision G and up have both autodetect and autoselect */
+		if (msp_revision >= 'G')
+			state->opmode = OPMODE_AUTOSELECT;
+		/* MSP revision D and up have autodetect */
+		else if (msp_revision >= 'D')
+			state->opmode = OPMODE_AUTODETECT;
+		else
+			state->opmode = OPMODE_MANUAL;
+	}
+
+	/* hello world :-) */
+	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
+	v4l_info(client, "%s ", client->name);
+	if (state->has_nicam && state->has_radio)
+		printk("supports nicam and radio, ");
+	else if (state->has_nicam)
+		printk("supports nicam, ");
+	else if (state->has_radio)
+		printk("supports radio, ");
+	printk("mode is ");
+
+	/* version-specific initialization */
+	switch (state->opmode) {
+	case OPMODE_MANUAL:
+		printk("manual");
+		thread_func = msp3400c_thread;
+		break;
+	case OPMODE_AUTODETECT:
+		printk("autodetect");
+		thread_func = msp3410d_thread;
+		break;
+	case OPMODE_AUTOSELECT:
+		printk("autodetect and autoselect");
+		thread_func = msp34xxg_thread;
+		break;
+	}
+	printk("\n");
+
+	/* startup control thread if needed */
+	if (thread_func) {
+		state->kthread = kthread_run(thread_func, client, "msp34xx");
+
+		if (state->kthread == NULL)
+			v4l_warn(client, "kernel_thread() failed\n");
+		msp_wake_thread(client);
+	}
+
+	/* done */
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int msp_probe(struct i2c_adapter *adapter)
+{
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adapter, &addr_data, msp_attach);
+	return 0;
+}
+
+static int msp_detach(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int err;
+
+	/* shutdown control thread */
+	if (state->kthread) {
+		state->restart = 1;
+		kthread_stop(state->kthread);
+	}
+	msp_reset(client);
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+
+	kfree(state);
+	kfree(client);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+	.id             = I2C_DRIVERID_MSP3400,
+	.attach_adapter = msp_probe,
+	.detach_client  = msp_detach,
+	.command        = msp_command,
+	.driver = {
+		.name    = "msp3400",
+		.suspend = msp_suspend,
+		.resume  = msp_resume,
+	},
+};
+
+static int __init msp3400_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit msp3400_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver);
+}
+
+module_init(msp3400_init_module);
+module_exit(msp3400_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
new file mode 100644
index 0000000..2b59b68
--- /dev/null
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -0,0 +1,1010 @@
+/*
+ * Programming the mspx4xx sound processor family
+ *
+ * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+#include "msp3400.h"
+
+/* this one uses the automatic sound standard detection of newer msp34xx
+   chip versions */
+static struct {
+	int retval;
+	int main, second;
+	char *name;
+} msp_stdlist[] = {
+	{ 0x0000, 0, 0, "could not detect sound standard" },
+	{ 0x0001, 0, 0, "autodetect start" },
+	{ 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
+	{ 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
+	{ 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
+	{ 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
+	{ 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
+	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
+	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
+	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
+	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
+	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
+	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
+	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
+	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
+	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
+	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
+	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
+	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
+	{     -1, 0, 0, NULL }, /* EOF */
+};
+
+static struct msp3400c_init_data_dem {
+	int fir1[6];
+	int fir2[6];
+	int cdo1;
+	int cdo2;
+	int ad_cv;
+	int mode_reg;
+	int dsp_src;
+	int dsp_matrix;
+} msp3400c_init_data[] = {
+	{	/* AM (for carrier detect / msp3400) */
+		{75, 19, 36, 35, 39, 40},
+		{75, 19, 36, 35, 39, 40},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0500, 0x0020, 0x3000
+	},{	/* AM (for carrier detect / msp3410) */
+		{-1, -1, -8, 2, 59, 126},
+		{-1, -1, -8, 2, 59, 126},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0100, 0x0020, 0x3000
+	},{	/* FM Radio */
+		{-8, -8, 4, 6, 78, 107},
+		{-8, -8, 4, 6, 78, 107},
+		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+		0x00d0, 0x0480, 0x0020, 0x3000
+	},{	/* Terrestial FM-mono + FM-stereo */
+		{3, 18, 27, 48, 66, 72},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0480, 0x0030, 0x3000
+	},{	/* Sat FM-mono */
+		{ 1, 9, 14, 24, 33, 37},
+		{ 3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0480, 0x0000, 0x3000
+	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	},{	/* NICAM/FM -- I (6.0/6.552) */
+		{2, 4, -6, -4, 40, 94},
+		{3, 18, 27, 48, 66, 72},
+		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+		0x00d0, 0x0040, 0x0120, 0x3000
+	},{	/* NICAM/AM -- L (6.5/5.85) */
+		{-2, -8, -10, 10, 50, 86},
+		{-4, -12, -9, 23, 79, 126},
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+		0x00c6, 0x0140, 0x0120, 0x7c03
+	},
+};
+
+struct msp3400c_carrier_detect {
+	int   cdo;
+	char *name;
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
+	/* main carrier */
+	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   },
+	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
+	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
+	{ MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
+	/* PAL B/G */
+	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
+	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
+};
+
+static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
+	/* PAL SAT / SECAM */
+	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
+	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
+	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
+	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
+	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
+	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
+};
+
+/* ------------------------------------------------------------------------ */
+
+const char *msp_standard_std_name(int std)
+{
+	int i;
+
+	for (i = 0; msp_stdlist[i].name != NULL; i++)
+		if (msp_stdlist[i].retval == std)
+			return msp_stdlist[i].name;
+	return "unknown";
+}
+
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+{
+	msp_write_dem(client, 0x0093, cdo1 & 0xfff);
+	msp_write_dem(client, 0x009b, cdo1 >> 12);
+	msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
+	msp_write_dem(client, 0x00ab, cdo2 >> 12);
+	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+}
+
+void msp3400c_setmode(struct i2c_client *client, int type)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int i;
+
+	v4l_dbg(1, client, "setmode: %d\n", type);
+	state->mode       = type;
+	state->audmode    = V4L2_TUNER_MODE_MONO;
+	state->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+	msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+
+	for (i = 5; i >= 0; i--)               /* fir 1 */
+		msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+
+	msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
+	msp_write_dem(client, 0x0005, 0x0040);
+	msp_write_dem(client, 0x0005, 0x0000);
+	for (i = 5; i >= 0; i--)
+		msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+
+	msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+
+	msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
+			    msp3400c_init_data[type].cdo2);
+
+	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+
+	if (dolby) {
+		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+	} else {
+		msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
+		msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
+		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
+	}
+	msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
+	msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+
+	if (state->has_nicam) {
+		/* nicam prescale */
+		msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
+	}
+}
+
+/* turn on/off nicam + stereo */
+void msp3400c_setstereo(struct i2c_client *client, int mode)
+{
+	static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
+	struct msp_state *state = i2c_get_clientdata(client);
+	int nicam = 0;		/* channel source: FM/AM or nicam */
+	int src = 0;
+
+	if (state->opmode == OPMODE_AUTOSELECT) {
+		/* this method would break everything, let's make sure
+		 * it's never called
+		 */
+		v4l_dbg(1, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
+		     mode);
+		return;
+	}
+
+	/* switch demodulator */
+	switch (state->mode) {
+	case MSP_MODE_FM_TERRA:
+		v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]);
+		msp3400c_setcarrier(client, state->second, state->main);
+		switch (mode) {
+		case V4L2_TUNER_MODE_STEREO:
+			msp_write_dsp(client, 0x000e, 0x3001);
+			break;
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+		case V4L2_TUNER_MODE_LANG2:
+			msp_write_dsp(client, 0x000e, 0x3000);
+			break;
+		}
+		break;
+	case MSP_MODE_FM_SAT:
+		v4l_dbg(1, client, "SAT setstereo: %s\n", strmode[mode]);
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+			break;
+		}
+		break;
+	case MSP_MODE_FM_NICAM1:
+	case MSP_MODE_FM_NICAM2:
+	case MSP_MODE_AM_NICAM:
+		v4l_dbg(1, client, "NICAM setstereo: %s\n",strmode[mode]);
+		msp3400c_setcarrier(client,state->second,state->main);
+		if (state->nicam_on)
+			nicam=0x0100;
+		break;
+	case MSP_MODE_BTSC:
+		v4l_dbg(1, client, "BTSC setstereo: %s\n",strmode[mode]);
+		nicam=0x0300;
+		break;
+	case MSP_MODE_EXTERN:
+		v4l_dbg(1, client, "extern setstereo: %s\n",strmode[mode]);
+		nicam = 0x0200;
+		break;
+	case MSP_MODE_FM_RADIO:
+		v4l_dbg(1, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+		break;
+	default:
+		v4l_dbg(1, client, "mono setstereo\n");
+		return;
+	}
+
+	/* switch audio */
+	switch (mode) {
+	case V4L2_TUNER_MODE_STEREO:
+		src = 0x0020 | nicam;
+		break;
+	case V4L2_TUNER_MODE_MONO:
+		if (state->mode == MSP_MODE_AM_NICAM) {
+			v4l_dbg(1, client, "switching to AM mono\n");
+			/* AM mono decoding is handled by tuner, not MSP chip */
+			/* SCART switching control register */
+			msp_set_scart(client, SCART_MONO, 0);
+			src = 0x0200;
+			break;
+		}
+	case V4L2_TUNER_MODE_LANG1:
+		src = 0x0000 | nicam;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		src = 0x0010 | nicam;
+		break;
+	}
+	v4l_dbg(1, client, "setstereo final source/matrix = 0x%x\n", src);
+
+	if (dolby) {
+		msp_write_dsp(client, 0x0008, 0x0520);
+		msp_write_dsp(client, 0x0009, 0x0620);
+		msp_write_dsp(client, 0x000a, src);
+		msp_write_dsp(client, 0x000b, src);
+	} else {
+		msp_write_dsp(client, 0x0008, src);
+		msp_write_dsp(client, 0x0009, src);
+		msp_write_dsp(client, 0x000a, src);
+		msp_write_dsp(client, 0x000b, src);
+		msp_write_dsp(client, 0x000c, src);
+		if (state->has_scart23_in_scart2_out)
+			msp_write_dsp(client, 0x0041, src);
+	}
+}
+
+static void msp3400c_print_mode(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	if (state->main == state->second) {
+		v4l_dbg(1, client, "mono sound carrier: %d.%03d MHz\n",
+		       state->main / 910000, (state->main / 910) % 1000);
+	} else {
+		v4l_dbg(1, client, "main sound carrier: %d.%03d MHz\n",
+		       state->main / 910000, (state->main / 910) % 1000);
+	}
+	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
+		v4l_dbg(1, client, "NICAM/FM carrier  : %d.%03d MHz\n",
+		       state->second / 910000, (state->second/910) % 1000);
+	if (state->mode == MSP_MODE_AM_NICAM)
+		v4l_dbg(1, client, "NICAM/AM carrier  : %d.%03d MHz\n",
+		       state->second / 910000, (state->second / 910) % 1000);
+	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
+		v4l_dbg(1, client, "FM-stereo carrier : %d.%03d MHz\n",
+		       state->second / 910000, (state->second / 910) % 1000);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+int autodetect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int val;
+	int rxsubchans = state->rxsubchans;
+	int newnicam   = state->nicam_on;
+	int update = 0;
+
+	switch (state->mode) {
+	case MSP_MODE_FM_TERRA:
+		val = msp_read_dsp(client, 0x18);
+		if (val > 32767)
+			val -= 65536;
+		v4l_dbg(2, client, "stereo detect register: %d\n", val);
+		if (val > 4096) {
+			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+		} else if (val < -4096) {
+			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		} else {
+			rxsubchans = V4L2_TUNER_SUB_MONO;
+		}
+		newnicam = 0;
+		break;
+	case MSP_MODE_FM_NICAM1:
+	case MSP_MODE_FM_NICAM2:
+	case MSP_MODE_AM_NICAM:
+		val = msp_read_dem(client, 0x23);
+		v4l_dbg(2, client, "nicam sync=%d, mode=%d\n",
+			val & 1, (val & 0x1e) >> 1);
+
+		if (val & 1) {
+			/* nicam synced */
+			switch ((val & 0x1e) >> 1)  {
+			case 0:
+			case 8:
+				rxsubchans = V4L2_TUNER_SUB_STEREO;
+				break;
+			case 1:
+			case 9:
+				rxsubchans = V4L2_TUNER_SUB_MONO
+					| V4L2_TUNER_SUB_LANG1;
+				break;
+			case 2:
+			case 10:
+				rxsubchans = V4L2_TUNER_SUB_MONO
+					| V4L2_TUNER_SUB_LANG1
+					| V4L2_TUNER_SUB_LANG2;
+				break;
+			default:
+				rxsubchans = V4L2_TUNER_SUB_MONO;
+				break;
+			}
+			newnicam = 1;
+		} else {
+			newnicam = 0;
+			rxsubchans = V4L2_TUNER_SUB_MONO;
+		}
+		break;
+	case MSP_MODE_BTSC:
+		val = msp_read_dem(client, 0x200);
+		v4l_dbg(2, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+			val,
+			(val & 0x0002) ? "no"     : "yes",
+			(val & 0x0004) ? "no"     : "yes",
+			(val & 0x0040) ? "stereo" : "mono",
+			(val & 0x0080) ? ", nicam 2nd mono" : "",
+			(val & 0x0100) ? ", bilingual/SAP"  : "");
+		rxsubchans = V4L2_TUNER_SUB_MONO;
+		if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
+		break;
+	}
+	if (rxsubchans != state->rxsubchans) {
+		update = 1;
+		v4l_dbg(1, client, "watch: rxsubchans %d => %d\n",
+			state->rxsubchans,rxsubchans);
+		state->rxsubchans = rxsubchans;
+	}
+	if (newnicam != state->nicam_on) {
+		update = 1;
+		v4l_dbg(1, client, "watch: nicam %d => %d\n",
+			state->nicam_on,newnicam);
+		state->nicam_on = newnicam;
+	}
+	return update;
+}
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+/* stereo/multilang monitoring */
+static void watch_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	if (autodetect_stereo(client)) {
+		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+		else
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+	}
+
+	if (once)
+		state->watch_stereo = 0;
+}
+
+int msp3400c_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = i2c_get_clientdata(client);
+	struct msp3400c_carrier_detect *cd;
+	int count, max1,max2,val1,val2, val,this;
+
+
+	v4l_dbg(1, client, "msp3400 daemon started\n");
+	for (;;) {
+		v4l_dbg(2, client, "msp3400 thread: sleep\n");
+		msp_sleep(state, -1);
+		v4l_dbg(2, client, "msp3400 thread: wakeup\n");
+
+	restart:
+		v4l_dbg(1, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		if (state->radio || MSP_MODE_EXTERN == state->mode) {
+			/* no carrier scan, just unmute */
+			v4l_dbg(1, client, "thread: no carrier scan\n");
+			msp_set_audio(client);
+			continue;
+		}
+
+		/* mute */
+		msp_set_mute(client);
+		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+		val1 = val2 = 0;
+		max1 = max2 = -1;
+		state->watch_stereo = 0;
+
+		/* some time for the tuner to sync */
+		if (msp_sleep(state,200))
+			goto restart;
+
+		/* carrier detect pass #1 -- main carrier */
+		cd = msp3400c_carrier_detect_main;
+		count = ARRAY_SIZE(msp3400c_carrier_detect_main);
+
+		if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			max1 = 3;
+			count = 0;
+			v4l_dbg(1, client, "AM sound override\n");
+		}
+
+		for (this = 0; this < count; this++) {
+			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+			if (msp_sleep(state,100))
+				goto restart;
+			val = msp_read_dsp(client, 0x1b);
+			if (val > 32767)
+				val -= 65536;
+			if (val1 < val)
+				val1 = val, max1 = this;
+			v4l_dbg(1, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
+		}
+
+		/* carrier detect pass #2 -- second (stereo) carrier */
+		switch (max1) {
+		case 1: /* 5.5 */
+			cd = msp3400c_carrier_detect_55;
+			count = ARRAY_SIZE(msp3400c_carrier_detect_55);
+			break;
+		case 3: /* 6.5 */
+			cd = msp3400c_carrier_detect_65;
+			count = ARRAY_SIZE(msp3400c_carrier_detect_65);
+			break;
+		case 0: /* 4.5 */
+		case 2: /* 6.0 */
+		default:
+			cd = NULL;
+			count = 0;
+			break;
+		}
+
+		if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			cd = NULL;
+			count = 0;
+			max2 = 0;
+		}
+		for (this = 0; this < count; this++) {
+			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+			if (msp_sleep(state,100))
+				goto restart;
+			val = msp_read_dsp(client, 0x1b);
+			if (val > 32767)
+				val -= 65536;
+			if (val2 < val)
+				val2 = val, max2 = this;
+			v4l_dbg(1, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
+		}
+
+		/* program the msp3400 according to the results */
+		state->main   = msp3400c_carrier_detect_main[max1].cdo;
+		switch (max1) {
+		case 1: /* 5.5 */
+			if (max2 == 0) {
+				/* B/G FM-stereo */
+				state->second = msp3400c_carrier_detect_55[max2].cdo;
+				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+				state->nicam_on = 0;
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+				state->watch_stereo = 1;
+			} else if (max2 == 1 && state->has_nicam) {
+				/* B/G NICAM */
+				state->second = msp3400c_carrier_detect_55[max2].cdo;
+				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+				state->nicam_on = 1;
+				msp3400c_setcarrier(client, state->second, state->main);
+				state->watch_stereo = 1;
+			} else {
+				goto no_second;
+			}
+			break;
+		case 2: /* 6.0 */
+			/* PAL I NICAM */
+			state->second = MSP_CARRIER(6.552);
+			msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+			state->nicam_on = 1;
+			msp3400c_setcarrier(client, state->second, state->main);
+			state->watch_stereo = 1;
+			break;
+		case 3: /* 6.5 */
+			if (max2 == 1 || max2 == 2) {
+				/* D/K FM-stereo */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+				state->nicam_on = 0;
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+				state->watch_stereo = 1;
+			} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
+				/* L NICAM or AM-mono */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
+				state->nicam_on = 0;
+				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+				msp3400c_setcarrier(client, state->second, state->main);
+				/* volume prescale for SCART (AM mono input) */
+				msp_write_dsp(client, 0x000d, 0x1900);
+				state->watch_stereo = 1;
+			} else if (max2 == 0 && state->has_nicam) {
+				/* D/K NICAM */
+				state->second = msp3400c_carrier_detect_65[max2].cdo;
+				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+				state->nicam_on = 1;
+				msp3400c_setcarrier(client, state->second, state->main);
+				state->watch_stereo = 1;
+			} else {
+				goto no_second;
+			}
+			break;
+		case 0: /* 4.5 */
+		default:
+		no_second:
+			state->second = msp3400c_carrier_detect_main[max1].cdo;
+			msp3400c_setmode(client, MSP_MODE_FM_TERRA);
+			state->nicam_on = 0;
+			msp3400c_setcarrier(client, state->second, state->main);
+			state->rxsubchans = V4L2_TUNER_SUB_MONO;
+			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+			break;
+		}
+
+		/* unmute */
+		msp_set_audio(client);
+
+		if (debug)
+			msp3400c_print_mode(client);
+
+		/* monitor tv audio mode */
+		while (state->watch_stereo) {
+			if (msp_sleep(state,5000))
+				goto restart;
+			watch_stereo(client);
+		}
+	}
+	v4l_dbg(1, client, "thread: exit\n");
+	return 0;
+}
+
+
+int msp3410d_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = i2c_get_clientdata(client);
+	int val, i, std;
+
+	v4l_dbg(1, client, "msp3410 daemon started\n");
+
+	for (;;) {
+		v4l_dbg(2, client, "msp3410 thread: sleep\n");
+		msp_sleep(state,-1);
+		v4l_dbg(2, client, "msp3410 thread: wakeup\n");
+
+	restart:
+		v4l_dbg(1, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		if (state->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			v4l_dbg(1, client, "thread: no carrier scan\n");
+			msp_set_audio(client);
+			continue;
+		}
+
+		/* put into sane state (and mute) */
+		msp_reset(client);
+
+		/* some time for the tuner to sync */
+		if (msp_sleep(state,200))
+			goto restart;
+
+		/* start autodetect */
+		if (state->radio)
+			std = 0x40;
+		else
+			std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+		state->watch_stereo = 0;
+
+		if (debug)
+			v4l_dbg(1, client, "setting standard: %s (0x%04x)\n",
+			       msp_standard_std_name(std), std);
+
+		if (std != 1) {
+			/* programmed some specific mode */
+			val = std;
+		} else {
+			/* triggered autodetect */
+			msp_write_dem(client, 0x20, std);
+			for (;;) {
+				if (msp_sleep(state, 100))
+					goto restart;
+
+				/* check results */
+				val = msp_read_dem(client, 0x7e);
+				if (val < 0x07ff)
+					break;
+				v4l_dbg(1, client, "detection still in progress\n");
+			}
+		}
+		for (i = 0; msp_stdlist[i].name != NULL; i++)
+			if (msp_stdlist[i].retval == val)
+				break;
+		v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+			msp_standard_std_name(val), val);
+		state->main   = msp_stdlist[i].main;
+		state->second = msp_stdlist[i].second;
+		state->std = val;
+
+		if (amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
+				(val != 0x0009)) {
+			/* autodetection has failed, let backup */
+			v4l_dbg(1, client, "autodetection failed,"
+				" switching to backup standard: %s (0x%04x)\n",
+				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
+			val = 0x0009;
+			msp_write_dem(client, 0x20, val);
+		}
+
+		/* set various prescales */
+		msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+		msp_write_dsp(client, 0x0e, 0x2403); /* FM */
+		msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
+		/* set stereo */
+		switch (val) {
+		case 0x0008: /* B/G NICAM */
+		case 0x000a: /* I NICAM */
+			if (val == 0x0008)
+				state->mode = MSP_MODE_FM_NICAM1;
+			else
+				state->mode = MSP_MODE_FM_NICAM2;
+			/* just turn on stereo */
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			state->nicam_on = 1;
+			state->watch_stereo = 1;
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+			break;
+		case 0x0009:
+			state->mode = MSP_MODE_AM_NICAM;
+			state->rxsubchans = V4L2_TUNER_SUB_MONO;
+			state->nicam_on = 1;
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
+			state->watch_stereo = 1;
+			break;
+		case 0x0020: /* BTSC */
+			/* just turn on stereo */
+			state->mode = MSP_MODE_BTSC;
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			state->nicam_on = 0;
+			state->watch_stereo = 1;
+			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+			break;
+		case 0x0040: /* FM radio */
+			state->mode = MSP_MODE_FM_RADIO;
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			state->audmode = V4L2_TUNER_MODE_STEREO;
+			state->nicam_on = 0;
+			state->watch_stereo = 0;
+			/* not needed in theory if we have radio, but
+			   short programming enables carrier mute */
+			msp3400c_setmode(client, MSP_MODE_FM_RADIO);
+			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+					    MSP_CARRIER(10.7));
+			/* scart routing */
+			msp_set_scart(client,SCART_IN2,0);
+			/* msp34xx does radio decoding */
+			msp_write_dsp(client, 0x08, 0x0020);
+			msp_write_dsp(client, 0x09, 0x0020);
+			msp_write_dsp(client, 0x0b, 0x0020);
+			break;
+		case 0x0003:
+		case 0x0004:
+		case 0x0005:
+			state->mode = MSP_MODE_FM_TERRA;
+			state->rxsubchans = V4L2_TUNER_SUB_MONO;
+			state->audmode = V4L2_TUNER_MODE_MONO;
+			state->nicam_on = 0;
+			state->watch_stereo = 1;
+			break;
+		}
+
+		/* unmute, restore misc registers */
+		msp_set_audio(client);
+		msp_write_dsp(client, 0x13, state->acb);
+		if (state->has_i2s_conf)
+			msp_write_dem(client, 0x40, state->i2s_mode);
+
+		/* monitor tv audio mode */
+		while (state->watch_stereo) {
+			if (msp_sleep(state,5000))
+				goto restart;
+			watch_stereo(client);
+		}
+	}
+	v4l_dbg(1, client, "thread: exit\n");
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* msp34xxG + (autoselect no-thread)                                          */
+/* this one uses both automatic standard detection and automatic sound     */
+/* select which are available in the newer G versions                      */
+/* struct msp: only norm, acb and source are really used in this mode      */
+
+/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
+ * the value for source is the same as bit 15:8 of DSP registers 0x08,
+ * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
+ *
+ * this function replaces msp3400c_setstereo
+ */
+static void msp34xxg_set_source(struct i2c_client *client, int source)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	/* fix matrix mode to stereo and let the msp choose what
+	 * to output according to 'source', as recommended
+	 * for MONO (source==0) downmixing set bit[7:0] to 0x30
+	 */
+	int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
+
+	v4l_dbg(1, client, "set source to %d (0x%x)\n", source, value);
+	/* Loudspeaker Output */
+	msp_write_dsp(client, 0x08, value);
+	/* SCART1 DA Output */
+	msp_write_dsp(client, 0x0a, value);
+	/* Quasi-peak detector */
+	msp_write_dsp(client, 0x0c, value);
+	/*
+	 * set identification threshold. Personally, I
+	 * I set it to a higher value that the default
+	 * of 0x190 to ignore noisy stereo signals.
+	 * this needs tuning. (recommended range 0x00a0-0x03c0)
+	 * 0x7f0 = forced mono mode
+	 */
+	/* a2 threshold for stereo/bilingual */
+	msp_write_dem(client, 0x22, stereo_threshold);
+	state->source = source;
+}
+
+/* (re-)initialize the msp34xxg, according to the current norm in state->norm
+ * return 0 if it worked, -1 if it failed
+ */
+static int msp34xxg_reset(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int modus, std;
+
+	if (msp_reset(client))
+		return -1;
+
+	/* make sure that input/output is muted (paranoid mode) */
+	/* ACB, mute DSP input, mute SCART 1 */
+	if (msp_write_dsp(client, 0x13, 0x0f20))
+		return -1;
+
+	if (state->has_i2s_conf)
+		msp_write_dem(client, 0x40, state->i2s_mode);
+
+	/* step-by-step initialisation, as described in the manual */
+	modus = msp_modus(client);
+	if (state->radio)
+		std = 0x40;
+	else
+		std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
+	modus &= ~0x03; /* STATUS_CHANGE = 0 */
+	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION = 1 */
+	if (msp_write_dem(client, 0x30, modus))
+		return -1;
+	if (msp_write_dem(client, 0x20, std))
+		return -1;
+
+	/* write the dsps that may have an influence on
+	   standard/audio autodetection right now */
+	msp34xxg_set_source(client, state->source);
+
+	/* AM/FM Prescale [15:8] 75khz deviation */
+	if (msp_write_dsp(client, 0x0e, 0x3000))
+		return -1;
+
+	/* NICAM Prescale 9db gain (as recommended) */
+	if (msp_write_dsp(client, 0x10, 0x5a00))
+		return -1;
+
+	return 0;
+}
+
+int msp34xxg_thread(void *data)
+{
+	struct i2c_client *client = data;
+	struct msp_state *state = i2c_get_clientdata(client);
+	int val, std, i;
+
+	v4l_dbg(1, client, "msp34xxg daemon started\n");
+
+	state->source = 1; /* default */
+	for (;;) {
+		v4l_dbg(2, client, "msp34xxg thread: sleep\n");
+		msp_sleep(state, -1);
+		v4l_dbg(2, client, "msp34xxg thread: wakeup\n");
+
+	restart:
+		v4l_dbg(1, client, "thread: restart scan\n");
+		state->restart = 0;
+		if (kthread_should_stop())
+			break;
+
+		/* setup the chip*/
+		msp34xxg_reset(client);
+		std = standard;
+		if (std != 0x01)
+			goto unmute;
+
+		/* watch autodetect */
+		v4l_dbg(1, client, "triggered autodetect, waiting for result\n");
+		for (i = 0; i < 10; i++) {
+			if (msp_sleep(state, 100))
+				goto restart;
+
+			/* check results */
+			val = msp_read_dem(client, 0x7e);
+			if (val < 0x07ff) {
+				std = val;
+				break;
+			}
+			v4l_dbg(2, client, "detection still in progress\n");
+		}
+		if (std == 1) {
+			v4l_dbg(1, client, "detection still in progress after 10 tries. giving up.\n");
+			continue;
+		}
+
+	unmute:
+		state->std = std;
+		v4l_dbg(1, client, "current standard: %s (0x%04x)\n",
+			msp_standard_std_name(std), std);
+
+		/* unmute: dispatch sound to scart output, set scart volume */
+		msp_set_audio(client);
+
+		/* restore ACB */
+		if (msp_write_dsp(client, 0x13, state->acb))
+			return -1;
+
+		msp_write_dem(client, 0x40, state->i2s_mode);
+	}
+	v4l_dbg(1, client, "thread: exit\n");
+	return 0;
+}
+
+void msp34xxg_detect_stereo(struct i2c_client *client)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+
+	int status = msp_read_dem(client, 0x0200);
+	int is_bilingual = status & 0x100;
+	int is_stereo = status & 0x40;
+
+	state->rxsubchans = 0;
+	if (is_stereo)
+		state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+	else
+		state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+	if (is_bilingual) {
+		state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+		/* I'm supposed to check whether it's SAP or not
+		 * and set only LANG2/SAP in this case. Yet, the MSP
+		 * does a lot of work to hide this and handle everything
+		 * the same way. I don't want to work around it so unless
+		 * this is a problem, I'll handle SAP just like lang1/lang2.
+		 */
+	}
+	v4l_dbg(1, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+		status, is_stereo, is_bilingual, state->rxsubchans);
+}
+
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+{
+	struct msp_state *state = i2c_get_clientdata(client);
+	int source;
+
+	switch (audmode) {
+	case V4L2_TUNER_MODE_MONO:
+		source = 0; /* mono only */
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
+		/* problem: that could also mean 2 (scart input) */
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		source = 3; /* stereo or A */
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		source = 4; /* stereo or B */
+		break;
+	default:
+		audmode = 0;
+		source  = 1;
+		break;
+	}
+	state->audmode = audmode;
+	msp34xxg_set_source(client, source);
+}
+
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
deleted file mode 100644
index 183253e..0000000
--- a/drivers/media/video/msp3400.c
+++ /dev/null
@@ -1,2229 +0,0 @@
-/*
- * programming the msp34* sound processor family
- *
- * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
- *
- * what works and what doesn't:
- *
- *  AM-Mono
- *      Support for Hauppauge cards added (decoding handled by tuner) added by
- *      Frederic Crozat <fcrozat@mail.dotcom.fr>
- *
- *  FM-Mono
- *      should work. The stereo modes are backward compatible to FM-mono,
- *      therefore FM-Mono should be allways available.
- *
- *  FM-Stereo (B/G, used in germany)
- *      should work, with autodetect
- *
- *  FM-Stereo (satellite)
- *      should work, no autodetect (i.e. default is mono, but you can
- *      switch to stereo -- untested)
- *
- *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
- *      should work, with autodetect. Support for NICAM was added by
- *      Pekka Pietikainen <pp@netppl.fi>
- *
- *
- * TODO:
- *   - better SAT support
- *
- *
- * 980623  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *         using soundcore instead of OSS
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/kthread.h>
-#include <linux/suspend.h>
-#include <asm/semaphore.h>
-#include <asm/pgtable.h>
-
-#include <media/audiochip.h>
-#include "msp3400.h"
-
-#define msp3400_dbg(fmt, arg...) \
-	do { \
-		if (debug) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->driver.name, \
-			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-/* Medium volume debug. */
-#define msp3400_dbg_mediumvol(fmt, arg...) \
-	do { \
-		if (debug >= 2) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-				client->driver->driver.name, \
-				i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-/* High volume debug. Use with care. */
-#define msp3400_dbg_highvol(fmt, arg...) \
-	do { \
-		if (debug >= 16) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-				client->driver->driver.name, \
-				i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-#define msp3400_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_warn(fmt, arg...) do { \
-	printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \
-		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define msp3400_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-		i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-#define OPMODE_AUTO    -1
-#define OPMODE_MANUAL   0
-#define OPMODE_SIMPLE   1   /* use short programming (>= msp3410 only) */
-#define OPMODE_SIMPLER  2   /* use shorter programming (>= msp34xxG)   */
-
-/* insmod parameters */
-static int opmode   = OPMODE_AUTO;
-static int debug    = 0;    /* debug output */
-static int once     = 0;    /* no continous stereo monitoring */
-static int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
-			       the autoscan seems work well only with FM... */
-static int standard = 1;    /* Override auto detect of audio standard, if needed. */
-static int dolby    = 0;
-
-static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
-					(msp34xxg only) 0x00a0-0x03c0 */
-#define DFP_COUNT 0x41
-static const int bl_dfp[] = {
-	0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
-	0x0b, 0x0d, 0x0e, 0x10
-};
-
-#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
-
-struct msp3400c {
-	int rev1,rev2;
-
-	int opmode;
-	int nicam;
-	int mode;
-	int norm;
-	int stereo;
-	int nicam_on;
-	int acb;
-	int in_scart;
-	int i2s_mode;
-	int main, second;	/* sound carrier */
-	int input;
-	int source;             /* see msp34xxg_set_source */
-
-	/* v4l2 */
-	int audmode;
-	int rxsubchans;
-
-	int muted;
-	int left, right;	/* volume */
-	int bass, treble;
-
-	/* shadow register set */
-	int dfp_regs[DFP_COUNT];
-
-	/* thread */
-	struct task_struct   *kthread;
-	wait_queue_head_t    wq;
-	int                  restart:1;
-	int                  watch_stereo:1;
-};
-
-#define MIN(a,b) (((a)>(b))?(b):(a))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff) != 00)
-#define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff) >= 'D'-'@')
-#define HAVE_SIMPLER(msp) ((msp->rev1      & 0xff) >= 'G'-'@')
-#define HAVE_RADIO(msp)   ((msp->rev1      & 0xff) >= 'G'-'@')
-
-#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
-
-/* ---------------------------------------------------------------------- */
-
-/* read-only */
-module_param(opmode,           int, 0444);
-
-/* read-write */
-module_param(once,             int, 0644);
-module_param(debug,            int, 0644);
-module_param(stereo_threshold, int, 0644);
-module_param(standard,         int, 0644);
-module_param(amsound,          int, 0644);
-module_param(dolby,            int, 0644);
-
-MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler");
-MODULE_PARM_DESC(once, "No continuous stereo monitoring");
-MODULE_PARM_DESC(debug, "Enable debug messages");
-MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
-MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
-MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
-MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
-
-/* ---------------------------------------------------------------------- */
-
-#define I2C_MSP3400C       0x80
-#define I2C_MSP3400C_ALT   0x88
-
-#define I2C_MSP3400C_DEM   0x10
-#define I2C_MSP3400C_DFP   0x12
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-	I2C_MSP3400C      >> 1,
-	I2C_MSP3400C_ALT  >> 1,
-	I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-/* functions for talking to the MSP3400C Sound processor                   */
-
-static int msp3400c_reset(struct i2c_client *client)
-{
-	/* reset and read revision code */
-	static char reset_off[3] = { 0x00, 0x80, 0x00 };
-	static char reset_on[3]  = { 0x00, 0x00, 0x00 };
-	static char write[3]     = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e };
-	char read[2];
-	struct i2c_msg reset[2] = {
-		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
-		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
-	};
-	struct i2c_msg test[2] = {
-		{ client->addr, 0,        3, write },
-		{ client->addr, I2C_M_RD, 2, read  },
-	};
-
-	msp3400_dbg_highvol("msp3400c_reset\n");
-	if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
-	     (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
-	     (2 != i2c_transfer(client->adapter,test,2)) ) {
-		msp3400_err("chip reset failed\n");
-		return -1;
-	}
-	return 0;
-}
-
-static int msp3400c_read(struct i2c_client *client, int dev, int addr)
-{
-	int err,retval;
-
-	unsigned char write[3];
-	unsigned char read[2];
-	struct i2c_msg msgs[2] = {
-		{ client->addr, 0,        3, write },
-		{ client->addr, I2C_M_RD, 2, read  }
-	};
-
-	write[0] = dev+1;
-	write[1] = addr >> 8;
-	write[2] = addr & 0xff;
-
-	for (err = 0; err < 3;) {
-		if (2 == i2c_transfer(client->adapter,msgs,2))
-			break;
-		err++;
-		msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
-		       dev, addr);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(msecs_to_jiffies(10));
-	}
-	if (3 == err) {
-		msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
-		msp3400c_reset(client);
-		return -1;
-	}
-	retval = read[0] << 8 | read[1];
-	msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
-	return retval;
-}
-
-static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
-{
-	int err;
-	unsigned char buffer[5];
-
-	buffer[0] = dev;
-	buffer[1] = addr >> 8;
-	buffer[2] = addr &  0xff;
-	buffer[3] = val  >> 8;
-	buffer[4] = val  &  0xff;
-
-	msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
-	for (err = 0; err < 3;) {
-		if (5 == i2c_master_send(client, buffer, 5))
-			break;
-		err++;
-		msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
-		       dev, addr);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(msecs_to_jiffies(10));
-	}
-	if (3 == err) {
-		msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
-		msp3400c_reset(client);
-		return -1;
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------------ */
-
-/* This macro is allowed for *constants* only, gcc must calculate it
-   at compile time.  Remember -- no floats in kernel mode */
-#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
-
-#define MSP_MODE_AM_DETECT   0
-#define MSP_MODE_FM_RADIO    2
-#define MSP_MODE_FM_TERRA    3
-#define MSP_MODE_FM_SAT      4
-#define MSP_MODE_FM_NICAM1   5
-#define MSP_MODE_FM_NICAM2   6
-#define MSP_MODE_AM_NICAM    7
-#define MSP_MODE_BTSC        8
-#define MSP_MODE_EXTERN      9
-
-static struct MSP_INIT_DATA_DEM {
-	int fir1[6];
-	int fir2[6];
-	int cdo1;
-	int cdo2;
-	int ad_cv;
-	int mode_reg;
-	int dfp_src;
-	int dfp_matrix;
-} msp_init_data[] = {
-	{	/* AM (for carrier detect / msp3400) */
-		{75, 19, 36, 35, 39, 40},
-		{75, 19, 36, 35, 39, 40},
-		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-		0x00d0, 0x0500, 0x0020, 0x3000
-	},{	/* AM (for carrier detect / msp3410) */
-		{-1, -1, -8, 2, 59, 126},
-		{-1, -1, -8, 2, 59, 126},
-		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-		0x00d0, 0x0100, 0x0020, 0x3000
-	},{	/* FM Radio */
-		{-8, -8, 4, 6, 78, 107},
-		{-8, -8, 4, 6, 78, 107},
-		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
-		0x00d0, 0x0480, 0x0020, 0x3000
-	},{	/* Terrestial FM-mono + FM-stereo */
-		{3, 18, 27, 48, 66, 72},
-		{3, 18, 27, 48, 66, 72},
-		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-		0x00d0, 0x0480, 0x0030, 0x3000
-	},{	/* Sat FM-mono */
-		{ 1, 9, 14, 24, 33, 37},
-		{ 3, 18, 27, 48, 66, 72},
-		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-		0x00c6, 0x0480, 0x0000, 0x3000
-	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
-		{-2, -8, -10, 10, 50, 86},
-		{3, 18, 27, 48, 66, 72},
-		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-		0x00d0, 0x0040, 0x0120, 0x3000
-	},{	/* NICAM/FM -- I (6.0/6.552) */
-		{2, 4, -6, -4, 40, 94},
-		{3, 18, 27, 48, 66, 72},
-		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
-		0x00d0, 0x0040, 0x0120, 0x3000
-	},{	/* NICAM/AM -- L (6.5/5.85) */
-		{-2, -8, -10, 10, 50, 86},
-		{-4, -12, -9, 23, 79, 126},
-		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-		0x00c6, 0x0140, 0x0120, 0x7c03
-	},
-};
-
-struct CARRIER_DETECT {
-	int   cdo;
-	char *name;
-};
-
-static struct CARRIER_DETECT carrier_detect_main[] = {
-	/* main carrier */
-	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   },
-	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
-	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
-	{ MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
-};
-
-static struct CARRIER_DETECT carrier_detect_55[] = {
-	/* PAL B/G */
-	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
-	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
-};
-
-static struct CARRIER_DETECT carrier_detect_65[] = {
-	/* PAL SAT / SECAM */
-	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
-	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
-	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
-	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
-	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
-	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
-};
-
-#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
-
-/* ----------------------------------------------------------------------- *
- * bits  9  8  5 - SCART DSP input Select:
- *       0  0  0 - SCART 1 to DSP input (reset position)
- *       0  1  0 - MONO to DSP input
- *       1  0  0 - SCART 2 to DSP input
- *       1  1  1 - Mute DSP input
- *
- * bits 11 10  6 - SCART 1 Output Select:
- *       0  0  0 - undefined (reset position)
- *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
- *       1  0  0 - MONO input to SCART 1 Output
- *       1  1  0 - SCART 1 DA to SCART 1 Output
- *       0  0  1 - SCART 2 DA to SCART 1 Output
- *       0  1  1 - SCART 1 Input to SCART 1 Output
- *       1  1  1 - Mute SCART 1 Output
- *
- * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
- *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
- *       0  1  0 - SCART 1 Input to SCART 2 Output
- *       1  0  0 - MONO input to SCART 2 Output
- *       0  0  1 - SCART 2 DA to SCART 2 Output
- *       0  1  1 - SCART 2 Input to SCART 2 Output
- *       1  1  0 - Mute SCART 2 Output
- *
- * Bits 4 to 0 should be zero.
- * ----------------------------------------------------------------------- */
-
-static int scarts[3][9] = {
-	/* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
-	/* SCART DSP Input select */
-	{ 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
-	/* SCART1 Output select */
-	{ 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
-	/* SCART2 Output select */
-	{ 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
-};
-
-static char *scart_names[] = {
-	"mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
-};
-
-static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-
-	msp->in_scart=in;
-
-	if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
-		if (-1 == scarts[out][in])
-			return;
-
-		msp->acb &= ~scarts[out][SCART_MASK];
-		msp->acb |=  scarts[out][in];
-	} else
-		msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
-
-	msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
-						scart_names[in], out, msp->acb);
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
-
-	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
-{
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff);
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-}
-
-static void msp3400c_setvolume(struct i2c_client *client,
-			       int muted, int left, int right)
- {
-	int vol = 0, val = 0, balance = 0;
-
-	if (!muted) {
-		/* 0x7f instead if 0x73 here has sound quality issues,
-		 * probably due to overmodulation + clipping ... */
-		vol = (left > right) ? left : right;
-		val = (vol * 0x73 / 65535) << 8;
-	}
-	if (vol > 0) {
-		balance = ((right - left) * 127) / vol;
-	}
-
-	msp3400_dbg("setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
-		muted ? "on" : "off", left, right, val >> 8, balance);
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
-					muted ? 0x1 : (val | 0x1));
-	msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
-}
-
-static void msp3400c_setbass(struct i2c_client *client, int bass)
-{
-	int val = ((bass-32768) * 0x60 / 65535) << 8;
-
-	msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
-}
-
-static void msp3400c_settreble(struct i2c_client *client, int treble)
-{
-	int val = ((treble-32768) * 0x60 / 65535) << 8;
-
-	msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
-}
-
-static void msp3400c_setmode(struct i2c_client *client, int type)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int i;
-
-	msp3400_dbg("setmode: %d\n",type);
-	msp->mode       = type;
-	msp->audmode    = V4L2_TUNER_MODE_MONO;
-	msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb,          /* ad_cv */
-		       msp_init_data[type].ad_cv);
-
-	for (i = 5; i >= 0; i--)                                   /* fir 1 */
-		msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001,
-			       msp_init_data[type].fir1[i]);
-
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040);
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000);
-	for (i = 5; i >= 0; i--)
-		msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005,
-			       msp_init_data[type].fir2[i]);
-
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083,     /* MODE_REG */
-		       msp_init_data[type].mode_reg);
-
-	msp3400c_setcarrier(client, msp_init_data[type].cdo1,
-			    msp_init_data[type].cdo2);
-
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
-
-	if (dolby) {
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
-			       0x0520); /* I2S1 */
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
-			       0x0620); /* I2S2 */
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
-			       msp_init_data[type].dfp_src);
-	} else {
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,
-			       msp_init_data[type].dfp_src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,
-			       msp_init_data[type].dfp_src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,
-			       msp_init_data[type].dfp_src);
-	}
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,
-		       msp_init_data[type].dfp_src);
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
-		       msp_init_data[type].dfp_matrix);
-
-	if (HAVE_NICAM(msp)) {
-		/* nicam prescale */
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
-	}
-}
-
-/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
-static int best_video_sound(int rxsubchans)
-{
-	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
-		return V4L2_TUNER_MODE_STEREO;
-	if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-		return V4L2_TUNER_MODE_LANG1;
-	if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-		return V4L2_TUNER_MODE_LANG2;
-	return V4L2_TUNER_MODE_MONO;
-}
-
-/* turn on/off nicam + stereo */
-static void msp3400c_setstereo(struct i2c_client *client, int mode)
-{
-	static char *strmode[] = { "0", "mono", "stereo", "3",
-		"lang1", "5", "6", "7", "lang2"
-	};
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int nicam = 0;		/* channel source: FM/AM or nicam */
-	int src = 0;
-
-	if (IS_MSP34XX_G(msp)) {
-		/* this method would break everything, let's make sure
-		 * it's never called
-		 */
-		msp3400_dbg
-		    ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
-		     mode);
-		return;
-	}
-
-	/* switch demodulator */
-	switch (msp->mode) {
-	case MSP_MODE_FM_TERRA:
-		msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
-		msp3400c_setcarrier(client,msp->second,msp->main);
-		switch (mode) {
-		case V4L2_TUNER_MODE_STEREO:
-			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
-			break;
-		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:
-		case V4L2_TUNER_MODE_LANG2:
-			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000);
-			break;
-		}
-		break;
-	case MSP_MODE_FM_SAT:
-		msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
-		switch (mode) {
-		case V4L2_TUNER_MODE_MONO:
-			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
-			break;
-		case V4L2_TUNER_MODE_LANG1:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
-			break;
-		case V4L2_TUNER_MODE_LANG2:
-			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
-			break;
-		}
-		break;
-	case MSP_MODE_FM_NICAM1:
-	case MSP_MODE_FM_NICAM2:
-	case MSP_MODE_AM_NICAM:
-		msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
-		msp3400c_setcarrier(client,msp->second,msp->main);
-		if (msp->nicam_on)
-			nicam=0x0100;
-		break;
-	case MSP_MODE_BTSC:
-		msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
-		nicam=0x0300;
-		break;
-	case MSP_MODE_EXTERN:
-		msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
-		nicam = 0x0200;
-		break;
-	case MSP_MODE_FM_RADIO:
-		msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
-		break;
-	default:
-		msp3400_dbg("mono setstereo\n");
-		return;
-	}
-
-	/* switch audio */
-	switch (best_video_sound(mode)) {
-	case V4L2_TUNER_MODE_STEREO:
-		src = 0x0020 | nicam;
-		break;
-	case V4L2_TUNER_MODE_MONO:
-		if (msp->mode == MSP_MODE_AM_NICAM) {
-			msp3400_dbg("switching to AM mono\n");
-			/* AM mono decoding is handled by tuner, not MSP chip */
-			/* SCART switching control register */
-			msp3400c_set_scart(client,SCART_MONO,0);
-			src = 0x0200;
-			break;
-		}
-	case V4L2_TUNER_MODE_LANG1:
-		src = 0x0000 | nicam;
-		break;
-	case V4L2_TUNER_MODE_LANG2:
-		src = 0x0010 | nicam;
-		break;
-	}
-	msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
-
-	if (dolby) {
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
-	} else {
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
-	}
-}
-
-static void
-msp3400c_print_mode(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-
-	if (msp->main == msp->second) {
-		msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
-		       msp->main/910000,(msp->main/910)%1000);
-	} else {
-		msp3400_dbg("main sound carrier: %d.%03d MHz\n",
-		       msp->main/910000,(msp->main/910)%1000);
-	}
-	if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
-		msp3400_dbg("NICAM/FM carrier   : %d.%03d MHz\n",
-		       msp->second/910000,(msp->second/910)%1000);
-	if (msp->mode == MSP_MODE_AM_NICAM)
-		msp3400_dbg("NICAM/AM carrier   : %d.%03d MHz\n",
-		       msp->second/910000,(msp->second/910)%1000);
-	if (msp->mode == MSP_MODE_FM_TERRA &&
-	    msp->main != msp->second) {
-		msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
-		       msp->second/910000,(msp->second/910)%1000);
-	}
-}
-
-#define MSP3400_MAX 4
-static struct i2c_client *msps[MSP3400_MAX];
-static void msp3400c_restore_dfp(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int i;
-
-	for (i = 0; i < DFP_COUNT; i++) {
-		if (-1 == msp->dfp_regs[i])
-			continue;
-		msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
-	}
-}
-
-/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
-static int msp3400c_write_dfp_with_default(struct i2c_client *client,
-					int addr, int default_value)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int value = default_value;
-	if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
-		value = msp->dfp_regs[addr];
-	return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
-}
-
-/* ----------------------------------------------------------------------- */
-
-struct REGISTER_DUMP {
-	int   addr;
-	char *name;
-};
-
-struct REGISTER_DUMP d1[] = {
-	{0x007e, "autodetect"},
-	{0x0023, "C_AD_BITS "},
-	{0x0038, "ADD_BITS  "},
-	{0x003e, "CIB_BITS  "},
-	{0x0057, "ERROR_RATE"},
-};
-
-static int autodetect_stereo(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int val;
-	int rxsubchans = msp->rxsubchans;
-	int newnicam   = msp->nicam_on;
-	int update = 0;
-
-	switch (msp->mode) {
-	case MSP_MODE_FM_TERRA:
-		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
-		if (val > 32767)
-			val -= 65536;
-		msp3400_dbg("stereo detect register: %d\n",val);
-		if (val > 4096) {
-			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-		} else if (val < -4096) {
-			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-		} else {
-			rxsubchans = V4L2_TUNER_SUB_MONO;
-		}
-		newnicam = 0;
-		break;
-	case MSP_MODE_FM_NICAM1:
-	case MSP_MODE_FM_NICAM2:
-	case MSP_MODE_AM_NICAM:
-		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-		msp3400_dbg("nicam sync=%d, mode=%d\n",
-			val & 1, (val & 0x1e) >> 1);
-
-		if (val & 1) {
-			/* nicam synced */
-			switch ((val & 0x1e) >> 1)  {
-			case 0:
-			case 8:
-				rxsubchans = V4L2_TUNER_SUB_STEREO;
-				break;
-			case 1:
-			case 9:
-				rxsubchans = V4L2_TUNER_SUB_MONO
-					| V4L2_TUNER_SUB_LANG1;
-				break;
-			case 2:
-			case 10:
-				rxsubchans = V4L2_TUNER_SUB_MONO
-					| V4L2_TUNER_SUB_LANG1
-					| V4L2_TUNER_SUB_LANG2;
-				break;
-			default:
-				rxsubchans = V4L2_TUNER_SUB_MONO;
-				break;
-			}
-			newnicam=1;
-		} else {
-			newnicam = 0;
-			rxsubchans = V4L2_TUNER_SUB_MONO;
-		}
-		break;
-	case MSP_MODE_BTSC:
-		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-		msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
-			val,
-			(val & 0x0002) ? "no"     : "yes",
-			(val & 0x0004) ? "no"     : "yes",
-			(val & 0x0040) ? "stereo" : "mono",
-			(val & 0x0080) ? ", nicam 2nd mono" : "",
-			(val & 0x0100) ? ", bilingual/SAP"  : "");
-		rxsubchans = V4L2_TUNER_SUB_MONO;
-		if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
-		if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
-		break;
-	}
-	if (rxsubchans != msp->rxsubchans) {
-		update = 1;
-		msp3400_dbg("watch: rxsubchans %d => %d\n",
-			msp->rxsubchans,rxsubchans);
-		msp->rxsubchans = rxsubchans;
-	}
-	if (newnicam != msp->nicam_on) {
-		update = 1;
-		msp3400_dbg("watch: nicam %d => %d\n",
-			msp->nicam_on,newnicam);
-		msp->nicam_on = newnicam;
-	}
-	return update;
-}
-
-/*
- * A kernel thread for msp3400 control -- we don't want to block the
- * in the ioctl while doing the sound carrier & stereo detect
- */
-
-static int msp34xx_sleep(struct msp3400c *msp, int timeout)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&msp->wq, &wait);
-	if (!kthread_should_stop()) {
-		if (timeout < 0) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
-		} else {
-			schedule_timeout_interruptible
-						(msecs_to_jiffies(timeout));
-		}
-	}
-
-	remove_wait_queue(&msp->wq, &wait);
-	try_to_freeze();
-	return msp->restart;
-}
-
-/* stereo/multilang monitoring */
-static void watch_stereo(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-
-	if (autodetect_stereo(client)) {
-		if (msp->stereo & V4L2_TUNER_MODE_STEREO)
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
-		else if (msp->stereo & VIDEO_SOUND_LANG1)
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
-		else
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-	}
-
-	if (once)
-		msp->watch_stereo = 0;
-}
-
-
-static int msp3400c_thread(void *data)
-{
-	struct i2c_client *client = data;
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	struct CARRIER_DETECT *cd;
-	int count, max1,max2,val1,val2, val,this;
-
-
-	msp3400_info("msp3400 daemon started\n");
-	for (;;) {
-		msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
-		msp34xx_sleep(msp,-1);
-		msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
-
-	restart:
-		msp3400_dbg("thread: restart scan\n");
-		msp->restart = 0;
-		if (kthread_should_stop())
-			break;
-
-		if (VIDEO_MODE_RADIO == msp->norm ||
-		    MSP_MODE_EXTERN  == msp->mode) {
-			/* no carrier scan, just unmute */
-			msp3400_info("thread: no carrier scan\n");
-			msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-			continue;
-		}
-
-		/* mute */
-		msp3400c_setvolume(client, msp->muted, 0, 0);
-		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
-		val1 = val2 = 0;
-		max1 = max2 = -1;
-		msp->watch_stereo = 0;
-
-		/* some time for the tuner to sync */
-		if (msp34xx_sleep(msp,200))
-			goto restart;
-
-		/* carrier detect pass #1 -- main carrier */
-		cd = carrier_detect_main;
-		count = CARRIER_COUNT(carrier_detect_main);
-
-		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
-			/* autodetect doesn't work well with AM ... */
-			max1 = 3;
-			count = 0;
-			msp3400_dbg("AM sound override\n");
-		}
-
-		for (this = 0; this < count; this++) {
-			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
-			if (msp34xx_sleep(msp,100))
-				goto restart;
-			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
-			if (val > 32767)
-				val -= 65536;
-			if (val1 < val)
-				val1 = val, max1 = this;
-			msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
-		}
-
-		/* carrier detect pass #2 -- second (stereo) carrier */
-		switch (max1) {
-		case 1: /* 5.5 */
-			cd = carrier_detect_55;
-			count = CARRIER_COUNT(carrier_detect_55);
-			break;
-		case 3: /* 6.5 */
-			cd = carrier_detect_65;
-			count = CARRIER_COUNT(carrier_detect_65);
-			break;
-		case 0: /* 4.5 */
-		case 2: /* 6.0 */
-		default:
-			cd = NULL;
-			count = 0;
-			break;
-		}
-
-		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
-			/* autodetect doesn't work well with AM ... */
-			cd = NULL;
-			count = 0;
-			max2 = 0;
-		}
-		for (this = 0; this < count; this++) {
-			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
-			if (msp34xx_sleep(msp,100))
-				goto restart;
-			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
-			if (val > 32767)
-				val -= 65536;
-			if (val2 < val)
-				val2 = val, max2 = this;
-			msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
-		}
-
-		/* programm the msp3400 according to the results */
-		msp->main   = carrier_detect_main[max1].cdo;
-		switch (max1) {
-		case 1: /* 5.5 */
-			if (max2 == 0) {
-				/* B/G FM-stereo */
-				msp->second = carrier_detect_55[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-				msp->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-				msp->watch_stereo = 1;
-			} else if (max2 == 1 && HAVE_NICAM(msp)) {
-				/* B/G NICAM */
-				msp->second = carrier_detect_55[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
-				msp->nicam_on = 1;
-				msp3400c_setcarrier(client, msp->second, msp->main);
-				msp->watch_stereo = 1;
-			} else {
-				goto no_second;
-			}
-			break;
-		case 2: /* 6.0 */
-			/* PAL I NICAM */
-			msp->second = MSP_CARRIER(6.552);
-			msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
-			msp->nicam_on = 1;
-			msp3400c_setcarrier(client, msp->second, msp->main);
-			msp->watch_stereo = 1;
-			break;
-		case 3: /* 6.5 */
-			if (max2 == 1 || max2 == 2) {
-				/* D/K FM-stereo */
-				msp->second = carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-				msp->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-				msp->watch_stereo = 1;
-			} else if (max2 == 0 &&
-				   msp->norm == VIDEO_MODE_SECAM) {
-				/* L NICAM or AM-mono */
-				msp->second = carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
-				msp->nicam_on = 0;
-				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-				msp3400c_setcarrier(client, msp->second, msp->main);
-				/* volume prescale for SCART (AM mono input) */
-				msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
-				msp->watch_stereo = 1;
-			} else if (max2 == 0 && HAVE_NICAM(msp)) {
-				/* D/K NICAM */
-				msp->second = carrier_detect_65[max2].cdo;
-				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
-				msp->nicam_on = 1;
-				msp3400c_setcarrier(client, msp->second, msp->main);
-				msp->watch_stereo = 1;
-			} else {
-				goto no_second;
-			}
-			break;
-		case 0: /* 4.5 */
-		default:
-		no_second:
-			msp->second = carrier_detect_main[max1].cdo;
-			msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-			msp->nicam_on = 0;
-			msp3400c_setcarrier(client, msp->second, msp->main);
-			msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-			break;
-		}
-
-		/* unmute */
-		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-		msp3400c_restore_dfp(client);
-
-		if (debug)
-			msp3400c_print_mode(client);
-
-		/* monitor tv audio mode */
-		while (msp->watch_stereo) {
-			if (msp34xx_sleep(msp,5000))
-				goto restart;
-			watch_stereo(client);
-		}
-	}
-	msp3400_dbg("thread: exit\n");
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* this one uses the automatic sound standard detection of newer           */
-/* msp34xx chip versions                                                   */
-
-static struct MODES {
-	int retval;
-	int main, second;
-	char *name;
-} modelist[] = {
-	{ 0x0000, 0, 0, "ERROR" },
-	{ 0x0001, 0, 0, "autodetect start" },
-	{ 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
-	{ 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
-	{ 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
-	{ 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
-	{ 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
-	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
-	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
-	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
-	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
-	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
-	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
-	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
-	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
-	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
-	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
-	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
-	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
-	{     -1, 0, 0, NULL }, /* EOF */
-};
-
-static inline const char *msp34xx_standard_mode_name(int mode)
-{
-	int i;
-	for (i = 0; modelist[i].name != NULL; i++)
-		if (modelist[i].retval == mode)
-			return modelist[i].name;
-	return "unknown";
-}
-
-static int msp34xx_modus(struct i2c_client *client, int norm)
-{
-	switch (norm) {
-	case VIDEO_MODE_PAL:
-		msp3400_dbg("video mode selected to PAL\n");
-
-#if 1
-		/* experimental: not sure this works with all chip versions */
-		return 0x7003;
-#else
-		/* previous value, try this if it breaks ... */
-		return 0x1003;
-#endif
-	case VIDEO_MODE_NTSC:  /* BTSC */
-		msp3400_dbg("video mode selected to NTSC\n");
-		return 0x2003;
-	case VIDEO_MODE_SECAM:
-		msp3400_dbg("video mode selected to SECAM\n");
-		return 0x0003;
-	case VIDEO_MODE_RADIO:
-		msp3400_dbg("video mode selected to Radio\n");
-		return 0x0003;
-	case VIDEO_MODE_AUTO:
-		msp3400_dbg("video mode selected to Auto\n");
-		return 0x2003;
-	default:
-		return 0x0003;
-	}
-}
-
-static int msp34xx_standard(int norm)
-{
-	switch (norm) {
-	case VIDEO_MODE_PAL:
-		return 1;
-	case VIDEO_MODE_NTSC:  /* BTSC */
-		return 0x0020;
-	case VIDEO_MODE_SECAM:
-		return 1;
-	case VIDEO_MODE_RADIO:
-		return 0x0040;
-	default:
-		return 1;
-	}
-}
-
-static int msp3410d_thread(void *data)
-{
-	struct i2c_client *client = data;
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int mode,val,i,std;
-
-	msp3400_info("msp3410 daemon started\n");
-
-	for (;;) {
-		msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
-		msp34xx_sleep(msp,-1);
-		msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
-
-	restart:
-		msp3400_dbg("thread: restart scan\n");
-		msp->restart = 0;
-		if (kthread_should_stop())
-			break;
-
-		if (msp->mode == MSP_MODE_EXTERN) {
-			/* no carrier scan needed, just unmute */
-			msp3400_dbg("thread: no carrier scan\n");
-		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-			continue;
-		}
-
-		/* put into sane state (and mute) */
-		msp3400c_reset(client);
-
-		/* some time for the tuner to sync */
-		if (msp34xx_sleep(msp,200))
-			goto restart;
-
-		/* start autodetect */
-		mode = msp34xx_modus(client, msp->norm);
-		std  = msp34xx_standard(msp->norm);
-		msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
-		msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
-		msp->watch_stereo = 0;
-
-		if (debug)
-			msp3400_dbg("setting mode: %s (0x%04x)\n",
-			       msp34xx_standard_mode_name(std) ,std);
-
-		if (std != 1) {
-			/* programmed some specific mode */
-			val = std;
-		} else {
-			/* triggered autodetect */
-			for (;;) {
-				if (msp34xx_sleep(msp,100))
-					goto restart;
-
-				/* check results */
-				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
-				if (val < 0x07ff)
-					break;
-				msp3400_dbg("detection still in progress\n");
-			}
-		}
-		for (i = 0; modelist[i].name != NULL; i++)
-			if (modelist[i].retval == val)
-				break;
-		msp3400_dbg("current mode: %s (0x%04x)\n",
-			modelist[i].name ? modelist[i].name : "unknown",
-			val);
-		msp->main   = modelist[i].main;
-		msp->second = modelist[i].second;
-
-		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
-			/* autodetection has failed, let backup */
-			msp3400_dbg("autodetection failed,"
-				" switching to backup mode: %s (0x%04x)\n",
-				modelist[8].name ? modelist[8].name : "unknown",val);
-			val = 0x0009;
-			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
-		}
-
-		/* set various prescales */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
-
-		/* set stereo */
-		switch (val) {
-		case 0x0008: /* B/G NICAM */
-		case 0x000a: /* I NICAM */
-			if (val == 0x0008)
-				msp->mode = MSP_MODE_FM_NICAM1;
-			else
-				msp->mode = MSP_MODE_FM_NICAM2;
-			/* just turn on stereo */
-			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			msp->nicam_on = 1;
-			msp->watch_stereo = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
-			break;
-		case 0x0009:
-			msp->mode = MSP_MODE_AM_NICAM;
-			msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-			msp->nicam_on = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
-			msp->watch_stereo = 1;
-			break;
-		case 0x0020: /* BTSC */
-			/* just turn on stereo */
-			msp->mode = MSP_MODE_BTSC;
-			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			msp->nicam_on = 0;
-			msp->watch_stereo = 1;
-			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
-			break;
-		case 0x0040: /* FM radio */
-			msp->mode   = MSP_MODE_FM_RADIO;
-			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			msp->audmode = V4L2_TUNER_MODE_STEREO;
-			msp->nicam_on = 0;
-			msp->watch_stereo = 0;
-			/* not needed in theory if HAVE_RADIO(), but
-			   short programming enables carrier mute */
-			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
-			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
-					    MSP_CARRIER(10.7));
-			/* scart routing */
-			msp3400c_set_scart(client,SCART_IN2,0);
-			/* msp34xx does radio decoding */
-			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
-			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
-			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
-			break;
-		case 0x0003:
-		case 0x0004:
-		case 0x0005:
-			msp->mode   = MSP_MODE_FM_TERRA;
-			msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-			msp->audmode = V4L2_TUNER_MODE_MONO;
-			msp->nicam_on = 0;
-			msp->watch_stereo = 1;
-			break;
-		}
-
-		/* unmute, restore misc registers */
-		msp3400c_setbass(client, msp->bass);
-		msp3400c_settreble(client, msp->treble);
-		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-		msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
-		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-		msp3400c_restore_dfp(client);
-
-		/* monitor tv audio mode */
-		while (msp->watch_stereo) {
-			if (msp34xx_sleep(msp,5000))
-				goto restart;
-			watch_stereo(client);
-		}
-	}
-	msp3400_dbg("thread: exit\n");
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/* msp34xxG + (simpler no-thread)                                          */
-/* this one uses both automatic standard detection and automatic sound     */
-/* select which are available in the newer G versions                      */
-/* struct msp: only norm, acb and source are really used in this mode      */
-
-static void msp34xxg_set_source(struct i2c_client *client, int source);
-
-/* (re-)initialize the msp34xxg, according to the current norm in msp->norm
- * return 0 if it worked, -1 if it failed
- */
-static int msp34xxg_reset(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int modus,std;
-
-	if (msp3400c_reset(client))
-		return -1;
-
-	/* make sure that input/output is muted (paranoid mode) */
-	if (msp3400c_write(client,
-			   I2C_MSP3400C_DFP,
-			   0x13, /* ACB */
-			   0x0f20 /* mute DSP input, mute SCART 1 */))
-		return -1;
-
-	msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-
-	/* step-by-step initialisation, as described in the manual */
-	modus = msp34xx_modus(client, msp->norm);
-	std   = msp34xx_standard(msp->norm);
-	modus &= ~0x03; /* STATUS_CHANGE=0 */
-	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */
-	if (msp3400c_write(client,
-			   I2C_MSP3400C_DEM,
-			   0x30/*MODUS*/,
-			   modus))
-		return -1;
-	if (msp3400c_write(client,
-			   I2C_MSP3400C_DEM,
-			   0x20/*standard*/,
-			   std))
-		return -1;
-
-	/* write the dfps that may have an influence on
-	   standard/audio autodetection right now */
-	msp34xxg_set_source(client, msp->source);
-
-	if (msp3400c_write_dfp_with_default(client, 0x0e,	/* AM/FM Prescale */
-					    0x3000
-					    /* default: [15:8] 75khz deviation */
-	    ))
-		return -1;
-
-	if (msp3400c_write_dfp_with_default(client, 0x10,	/* NICAM Prescale */
-					    0x5a00
-					    /* default: 9db gain (as recommended) */
-	    ))
-		return -1;
-
-	return 0;
-}
-
-static int msp34xxg_thread(void *data)
-{
-	struct i2c_client *client = data;
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int val, std, i;
-
-	msp3400_info("msp34xxg daemon started\n");
-
-	msp->source = 1; /* default */
-	for (;;) {
-		msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
-		msp34xx_sleep(msp,-1);
-		msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
-
-	restart:
-		msp3400_dbg("thread: restart scan\n");
-		msp->restart = 0;
-		if (kthread_should_stop())
-			break;
-
-		/* setup the chip*/
-		msp34xxg_reset(client);
-		std = standard;
-		if (std != 0x01)
-			goto unmute;
-
-		/* watch autodetect */
-		msp3400_dbg("triggered autodetect, waiting for result\n");
-		for (i = 0; i < 10; i++) {
-			if (msp34xx_sleep(msp,100))
-				goto restart;
-
-			/* check results */
-			val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
-			if (val < 0x07ff) {
-				std = val;
-				break;
-			}
-			msp3400_dbg("detection still in progress\n");
-		}
-		if (0x01 == std) {
-			msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
-			continue;
-		}
-
-	unmute:
-		msp3400_dbg("current mode: %s (0x%04x)\n",
-			msp34xx_standard_mode_name(std), std);
-
-		/* unmute: dispatch sound to scart output, set scart volume */
-		msp3400_dbg("unmute\n");
-
-		msp3400c_setbass(client, msp->bass);
-		msp3400c_settreble(client, msp->treble);
-		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
-		/* restore ACB */
-		if (msp3400c_write(client,
-				   I2C_MSP3400C_DFP,
-				   0x13, /* ACB */
-				   msp->acb))
-			return -1;
-
-		msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
-	}
-	msp3400_dbg("thread: exit\n");
-	return 0;
-}
-
-/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
- * the value for source is the same as bit 15:8 of DFP registers 0x08,
- * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
- *
- * this function replaces msp3400c_setstereo
- */
-static void msp34xxg_set_source(struct i2c_client *client, int source)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-
-	/* fix matrix mode to stereo and let the msp choose what
-	 * to output according to 'source', as recommended
-	 * for MONO (source==0) downmixing set bit[7:0] to 0x30
-	 */
-	int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
-	msp3400_dbg("set source to %d (0x%x)\n", source, value);
-	msp3400c_write(client,
-		       I2C_MSP3400C_DFP,
-		       0x08, /* Loudspeaker Output */
-		       value);
-	msp3400c_write(client,
-		       I2C_MSP3400C_DFP,
-		       0x0a, /* SCART1 DA Output */
-		       value);
-	msp3400c_write(client,
-		       I2C_MSP3400C_DFP,
-		       0x0c, /* Quasi-peak detector */
-		       value);
-	/*
-	 * set identification threshold. Personally, I
-	 * I set it to a higher value that the default
-	 * of 0x190 to ignore noisy stereo signals.
-	 * this needs tuning. (recommended range 0x00a0-0x03c0)
-	 * 0x7f0 = forced mono mode
-	 */
-	msp3400c_write(client,
-		       I2C_MSP3400C_DEM,
-		       0x22, /* a2 threshold for stereo/bilingual */
-		       stereo_threshold);
-	msp->source=source;
-}
-
-static void msp34xxg_detect_stereo(struct i2c_client *client)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-
-	int status = msp3400c_read(client,
-				   I2C_MSP3400C_DEM,
-				   0x0200 /* STATUS */);
-	int is_bilingual = status&0x100;
-	int is_stereo = status&0x40;
-
-	msp->rxsubchans = 0;
-	if (is_stereo)
-		msp->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-	else
-		msp->rxsubchans |= V4L2_TUNER_SUB_MONO;
-	if (is_bilingual) {
-		msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2;
-		/* I'm supposed to check whether it's SAP or not
-		 * and set only LANG2/SAP in this case. Yet, the MSP
-		 * does a lot of work to hide this and handle everything
-		 * the same way. I don't want to work around it so unless
-		 * this is a problem, I'll handle SAP just like lang1/lang2.
-		 */
-	}
-	msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
-		status, is_stereo, is_bilingual, msp->rxsubchans);
-}
-
-static void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
-{
-	struct msp3400c *msp = i2c_get_clientdata(client);
-	int source;
-
-	switch (audmode) {
-	case V4L2_TUNER_MODE_MONO:
-		source=0; /* mono only */
-		break;
-	case V4L2_TUNER_MODE_STEREO:
-		source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
-		/* problem: that could also mean 2 (scart input) */
-		break;
-	case V4L2_TUNER_MODE_LANG1:
-		source=3; /* stereo or A */
-		break;
-	case V4L2_TUNER_MODE_LANG2:
-		source=4; /* stereo or B */
-		break;
-	default:
-		audmode = 0;
-		source  = 1;
-		break;
-	}
-	msp->audmode = audmode;
-	msp34xxg_set_source(client, source);
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind);
-static int msp_detach(struct i2c_client *client);
-static int msp_probe(struct i2c_adapter *adap);
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
-
-static int msp_suspend(struct device * dev, pm_message_t state);
-static int msp_resume(struct device * dev);
-
-static void msp_wake_thread(struct i2c_client *client);
-
-static struct i2c_driver driver = {
-	.id             = I2C_DRIVERID_MSP3400,
-	.attach_adapter = msp_probe,
-	.detach_client  = msp_detach,
-	.command        = msp_command,
-	.driver = {
-		.name    = "i2c msp3400 driver",
-		.suspend = msp_suspend,
-		.resume  = msp_resume,
-	},
-};
-
-static struct i2c_client client_template =
-{
-	.name      = "(unset)",
-	.driver    = &driver,
-};
-
-static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct msp3400c *msp;
-	struct i2c_client *client = &client_template;
-	int (*thread_func)(void *data) = NULL;
-	int i;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	if (-1 == msp3400c_reset(&client_template)) {
-		msp3400_dbg("no chip found\n");
-		return -1;
-	}
-
-	if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
-		return -ENOMEM;
-	memcpy(client,&client_template,sizeof(struct i2c_client));
-	if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
-		kfree(client);
-		return -ENOMEM;
-	}
-
-	memset(msp,0,sizeof(struct msp3400c));
-	msp->norm = VIDEO_MODE_NTSC;
-	msp->left = 58880;	/* 0db gain */
-	msp->right = 58880;	/* 0db gain */
-	msp->bass = 32768;
-	msp->treble = 32768;
-	msp->input = -1;
-	msp->muted = 0;
-	msp->i2s_mode = 0;
-	for (i = 0; i < DFP_COUNT; i++)
-		msp->dfp_regs[i] = -1;
-
-	i2c_set_clientdata(client, msp);
-	init_waitqueue_head(&msp->wq);
-
-	if (-1 == msp3400c_reset(client)) {
-		kfree(msp);
-		kfree(client);
-		msp3400_dbg("no chip found\n");
-		return -1;
-	}
-
-	msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
-	if (-1 != msp->rev1)
-		msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
-	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
-		kfree(msp);
-		kfree(client);
-		msp3400_dbg("error while reading chip version\n");
-		return -1;
-	}
-	msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
-
-	msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-
-	snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
-		 ((msp->rev1>>4)&0x0f) + '3',
-		 (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
-		 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
-
-	msp->opmode = opmode;
-	if (OPMODE_AUTO == msp->opmode) {
-		if (HAVE_SIMPLER(msp))
-			msp->opmode = OPMODE_SIMPLER;
-		else if (HAVE_SIMPLE(msp))
-			msp->opmode = OPMODE_SIMPLE;
-		else
-			msp->opmode = OPMODE_MANUAL;
-	}
-
-	/* hello world :-) */
-	msp3400_info("chip=%s", client->name);
-	if (HAVE_NICAM(msp))
-		printk(" +nicam");
-	if (HAVE_SIMPLE(msp))
-		printk(" +simple");
-	if (HAVE_SIMPLER(msp))
-		printk(" +simpler");
-	if (HAVE_RADIO(msp))
-		printk(" +radio");
-
-	/* version-specific initialization */
-	switch (msp->opmode) {
-	case OPMODE_MANUAL:
-		printk(" mode=manual");
-		thread_func = msp3400c_thread;
-		break;
-	case OPMODE_SIMPLE:
-		printk(" mode=simple");
-		thread_func = msp3410d_thread;
-		break;
-	case OPMODE_SIMPLER:
-		printk(" mode=simpler");
-		thread_func = msp34xxg_thread;
-		break;
-	}
-	printk("\n");
-
-	/* startup control thread if needed */
-	if (thread_func) {
-		msp->kthread = kthread_run(thread_func, client, "msp34xx");
-
-		if (NULL == msp->kthread)
-			msp3400_warn("kernel_thread() failed\n");
-		msp_wake_thread(client);
-	}
-
-	/* done */
-	i2c_attach_client(client);
-
-	/* update our own array */
-	for (i = 0; i < MSP3400_MAX; i++) {
-		if (NULL == msps[i]) {
-			msps[i] = client;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int msp_detach(struct i2c_client *client)
-{
-	struct msp3400c *msp  = i2c_get_clientdata(client);
-	int i;
-
-	/* shutdown control thread */
-	if (msp->kthread) {
-		msp->restart = 1;
-		kthread_stop(msp->kthread);
-	}
-	msp3400c_reset(client);
-
-	/* update our own array */
-	for (i = 0; i < MSP3400_MAX; i++) {
-		if (client == msps[i]) {
-			msps[i] = NULL;
-			break;
-		}
-	}
-
-	i2c_detach_client(client);
-
-	kfree(msp);
-	kfree(client);
-	return 0;
-}
-
-static int msp_probe(struct i2c_adapter *adap)
-{
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, msp_attach);
-	return 0;
-}
-
-static void msp_wake_thread(struct i2c_client *client)
-{
-	struct msp3400c *msp  = i2c_get_clientdata(client);
-
-	if (NULL == msp->kthread)
-		return;
-	msp3400c_setvolume(client,msp->muted,0,0);
-	msp->watch_stereo = 0;
-	msp->restart = 1;
-	wake_up_interruptible(&msp->wq);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int mode_v4l2_to_v4l1(int rxsubchans)
-{
-	int mode = 0;
-
-	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
-		mode |= VIDEO_SOUND_STEREO;
-	if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-		mode |= VIDEO_SOUND_LANG2;
-	if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-		mode |= VIDEO_SOUND_LANG1;
-	if (0 == mode)
-		mode |= VIDEO_SOUND_MONO;
-	return mode;
-}
-
-static int mode_v4l1_to_v4l2(int mode)
-{
-	if (mode & VIDEO_SOUND_STEREO)
-		return V4L2_TUNER_MODE_STEREO;
-	if (mode & VIDEO_SOUND_LANG2)
-		return V4L2_TUNER_MODE_LANG2;
-	if (mode & VIDEO_SOUND_LANG1)
-		return V4L2_TUNER_MODE_LANG1;
-	return V4L2_TUNER_MODE_MONO;
-}
-
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
-	struct msp3400c *msp  = i2c_get_clientdata(client);
-
-	switch (msp->opmode) {
-	case OPMODE_MANUAL:
-	case OPMODE_SIMPLE:
-		autodetect_stereo(client);
-		break;
-	case OPMODE_SIMPLER:
-		msp34xxg_detect_stereo(client);
-		break;
-	}
-}
-
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
-	struct msp3400c *msp  = i2c_get_clientdata(client);
-
-	switch (msp->opmode) {
-	case OPMODE_MANUAL:
-	case OPMODE_SIMPLE:
-		msp->watch_stereo = 0;
-		msp3400c_setstereo(client, audmode);
-		break;
-	case OPMODE_SIMPLER:
-		msp34xxg_set_audmode(client, audmode);
-		break;
-	}
-}
-
-
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-	struct msp3400c *msp  = i2c_get_clientdata(client);
-	__u16           *sarg = arg;
-	int scart = 0;
-
-	switch (cmd) {
-
-	case AUDC_SET_INPUT:
-		msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
-
-		if (*sarg == msp->input)
-			break;
-		msp->input = *sarg;
-		switch (*sarg) {
-		case AUDIO_RADIO:
-			/* Hauppauge uses IN2 for the radio */
-			msp->mode   = MSP_MODE_FM_RADIO;
-			scart       = SCART_IN2;
-			break;
-		case AUDIO_EXTERN_1:
-			/* IN1 is often used for external input ... */
-			msp->mode   = MSP_MODE_EXTERN;
-			scart       = SCART_IN1;
-			break;
-		case AUDIO_EXTERN_2:
-			/* ... sometimes it is IN2 through ;) */
-			msp->mode   = MSP_MODE_EXTERN;
-			scart       = SCART_IN2;
-			break;
-		case AUDIO_TUNER:
-			msp->mode   = -1;
-			break;
-		default:
-			if (*sarg & AUDIO_MUTE)
-				msp3400c_set_scart(client,SCART_MUTE,0);
-			break;
-		}
-		if (scart) {
-			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			msp->audmode = V4L2_TUNER_MODE_STEREO;
-			msp3400c_set_scart(client,scart,0);
-			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
-			if (msp->opmode != OPMODE_SIMPLER)
-				msp3400c_setstereo(client, msp->audmode);
-		}
-		msp_wake_thread(client);
-		break;
-
-	case AUDC_SET_RADIO:
-		msp3400_dbg("AUDC_SET_RADIO\n");
-		msp->norm = VIDEO_MODE_RADIO;
-		msp3400_dbg("switching to radio mode\n");
-		msp->watch_stereo = 0;
-		switch (msp->opmode) {
-		case OPMODE_MANUAL:
-			/* set msp3400 to FM radio mode */
-			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
-			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
-					    MSP_CARRIER(10.7));
-			msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-			break;
-		case OPMODE_SIMPLE:
-		case OPMODE_SIMPLER:
-			/* the thread will do for us */
-			msp_wake_thread(client);
-			break;
-		}
-		break;
-		/* work-in-progress:  hook to control the DFP registers */
-	case MSP_SET_DFPREG:
-	{
-		struct msp_dfpreg *r = arg;
-		int i;
-
-		if (r->reg < 0 || r->reg >= DFP_COUNT)
-			return -EINVAL;
-		for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
-			if (r->reg == bl_dfp[i])
-				return -EINVAL;
-		msp->dfp_regs[r->reg] = r->value;
-		msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
-		return 0;
-	}
-	case MSP_GET_DFPREG:
-	{
-		struct msp_dfpreg *r = arg;
-
-		if (r->reg < 0 || r->reg >= DFP_COUNT)
-			return -EINVAL;
-		r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
-		return 0;
-	}
-
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *va = arg;
-
-		msp3400_dbg("VIDIOCGAUDIO\n");
-		va->flags |= VIDEO_AUDIO_VOLUME |
-			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE |
-			VIDEO_AUDIO_MUTABLE;
-		if (msp->muted)
-			va->flags |= VIDEO_AUDIO_MUTE;
-
-		if (msp->muted)
-			va->flags |= VIDEO_AUDIO_MUTE;
-		va->volume = MAX(msp->left, msp->right);
-		va->balance = (32768 * MIN(msp->left, msp->right)) /
-		    (va->volume ? va->volume : 1);
-		va->balance = (msp->left < msp->right) ?
-		    (65535 - va->balance) : va->balance;
-		if (0 == va->volume)
-			va->balance = 32768;
-		va->bass = msp->bass;
-		va->treble = msp->treble;
-
-		msp_any_detect_stereo(client);
-		va->mode = mode_v4l2_to_v4l1(msp->rxsubchans);
-		break;
-	}
-	case VIDIOCSAUDIO:
-	{
-		struct video_audio *va = arg;
-
-		msp3400_dbg("VIDIOCSAUDIO\n");
-		msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
-		msp->left = (MIN(65536 - va->balance, 32768) *
-			     va->volume) / 32768;
-		msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
-		msp->bass = va->bass;
-		msp->treble = va->treble;
-		msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
-			va->volume);
-		msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
-			va->balance);
-		msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
-			va->flags);
-		msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
-			msp->left);
-		msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
-			msp->right);
-		msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
-			msp->bass);
-		msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
-			msp->treble);
-		msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
-			msp->mode);
-		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
-		msp3400c_setbass(client, msp->bass);
-		msp3400c_settreble(client, msp->treble);
-
-		if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
-			msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
-		break;
-	}
-
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *vc = arg;
-
-		msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
-		msp->norm = vc->norm;
-		msp_wake_thread(client);
-		break;
-	}
-
-	case VIDIOCSFREQ:
-	case VIDIOC_S_FREQUENCY:
-	{
-		/* new channel -- kick audio carrier scan */
-		msp3400_dbg("VIDIOCSFREQ\n");
-		msp_wake_thread(client);
-		break;
-	}
-
-	/* msp34xx specific */
-	case MSP_SET_MATRIX:
-	{
-		struct msp_matrix *mspm = arg;
-
-		msp3400_dbg("MSP_SET_MATRIX\n");
-		msp3400c_set_scart(client, mspm->input, mspm->output);
-		break;
-	}
-
-	/* --- v4l2 ioctls --- */
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-
-		/*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
-		if (*id & V4L2_STD_PAL) {
-			msp->norm=VIDEO_MODE_PAL;
-		} else if (*id & V4L2_STD_SECAM) {
-			msp->norm=VIDEO_MODE_SECAM;
-		} else {
-			msp->norm=VIDEO_MODE_NTSC;
-		}
-
-		msp_wake_thread(client);
-		return 0;
-	}
-
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
-
-		if (i->index != 0)
-			return -EINVAL;
-
-		i->type = V4L2_INPUT_TYPE_TUNER;
-		switch (i->index) {
-		case AUDIO_RADIO:
-			strcpy(i->name,"Radio");
-			break;
-		case AUDIO_EXTERN_1:
-			strcpy(i->name,"Extern 1");
-			break;
-		case AUDIO_EXTERN_2:
-			strcpy(i->name,"Extern 2");
-			break;
-		case AUDIO_TUNER:
-			strcpy(i->name,"Television");
-			break;
-		default:
-			return -EINVAL;
-		}
-		return 0;
-	}
-
-	case VIDIOC_G_AUDIO:
-	{
-		struct v4l2_audio *a = arg;
-
-		memset(a,0,sizeof(*a));
-
-		switch (a->index) {
-		case AUDIO_RADIO:
-			strcpy(a->name,"Radio");
-			break;
-		case AUDIO_EXTERN_1:
-			strcpy(a->name,"Extern 1");
-			break;
-		case AUDIO_EXTERN_2:
-			strcpy(a->name,"Extern 2");
-			break;
-		case AUDIO_TUNER:
-			strcpy(a->name,"Television");
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		msp_any_detect_stereo(client);
-		if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
-			a->capability=V4L2_AUDCAP_STEREO;
-		}
-
-		break;
-	}
-	case VIDIOC_S_AUDIO:
-	{
-		struct v4l2_audio *sarg = arg;
-
-		switch (sarg->index) {
-		case AUDIO_RADIO:
-			/* Hauppauge uses IN2 for the radio */
-			msp->mode   = MSP_MODE_FM_RADIO;
-			scart       = SCART_IN2;
-			break;
-		case AUDIO_EXTERN_1:
-			/* IN1 is often used for external input ... */
-			msp->mode   = MSP_MODE_EXTERN;
-			scart       = SCART_IN1;
-			break;
-		case AUDIO_EXTERN_2:
-			/* ... sometimes it is IN2 through ;) */
-			msp->mode   = MSP_MODE_EXTERN;
-			scart       = SCART_IN2;
-			break;
-		case AUDIO_TUNER:
-			msp->mode   = -1;
-			break;
-		}
-		if (scart) {
-			msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			msp->audmode = V4L2_TUNER_MODE_STEREO;
-			msp3400c_set_scart(client,scart,0);
-			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
-		}
-		if (sarg->capability==V4L2_AUDCAP_STEREO) {
-			msp->audmode = V4L2_TUNER_MODE_STEREO;
-		} else {
-			msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
-		}
-		msp_any_set_audmode(client, msp->audmode);
-		msp_wake_thread(client);
-		break;
-	}
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *vt = arg;
-
-		msp_any_detect_stereo(client);
-		vt->audmode    = msp->audmode;
-		vt->rxsubchans = msp->rxsubchans;
-		vt->capability = V4L2_TUNER_CAP_STEREO |
-			V4L2_TUNER_CAP_LANG1|
-			V4L2_TUNER_CAP_LANG2;
-		break;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
-
-		/* only set audmode */
-		if (vt->audmode != -1 && vt->audmode != 0)
-			msp_any_set_audmode(client, vt->audmode);
-		break;
-	}
-
-	case VIDIOC_G_AUDOUT:
-	{
-		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
-		int idx=a->index;
-
-		memset(a,0,sizeof(*a));
-
-		switch (idx) {
-		case 0:
-			strcpy(a->name,"Scart1 Out");
-			break;
-		case 1:
-			strcpy(a->name,"Scart2 Out");
-			break;
-		case 2:
-			strcpy(a->name,"I2S Out");
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-
-	}
-	case VIDIOC_S_AUDOUT:
-	{
-		struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
-
-		if (a->index<0||a->index>2)
-			return -EINVAL;
-
-		if (a->index==2) {
-			if (a->mode == V4L2_AUDMODE_32BITS)
-				msp->i2s_mode=1;
-			else
-				msp->i2s_mode=0;
-		}
-		msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
-						a->index,msp->i2s_mode);
-		msp3400c_set_scart(client,msp->in_scart,a->index+1);
-
-		break;
-	}
-
-	default:
-		/* nothing */
-		break;
-	}
-	return 0;
-}
-
-static int msp_suspend(struct device * dev, pm_message_t state)
-{
-	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
-	msp3400_dbg("msp34xx: suspend\n");
-	msp3400c_reset(client);
-	return 0;
-}
-
-static int msp_resume(struct device * dev)
-{
-	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-
-	msp3400_dbg("msp34xx: resume\n");
-	msp_wake_thread(client);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init msp3400_init_module(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit msp3400_cleanup_module(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(msp3400_init_module);
-module_exit(msp3400_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index 2d9ff40..8a05cf5 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -6,22 +6,28 @@
 
 /* ---------------------------------------------------------------------- */
 
-struct msp_dfpreg {
-    int reg;
-    int value;
-};
-
 struct msp_matrix {
   int input;
   int output;
 };
 
-#define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
-#define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
-
 /* ioctl for MSP_SET_MATRIX will have to be registered */
 #define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
 
+/* This macro is allowed for *constants* only, gcc must calculate it
+   at compile time.  Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
+
+#define MSP_MODE_AM_DETECT   0
+#define MSP_MODE_FM_RADIO    2
+#define MSP_MODE_FM_TERRA    3
+#define MSP_MODE_FM_SAT      4
+#define MSP_MODE_FM_NICAM1   5
+#define MSP_MODE_FM_NICAM2   6
+#define MSP_MODE_AM_NICAM    7
+#define MSP_MODE_BTSC        8
+#define MSP_MODE_EXTERN      9
+
 #define SCART_MASK    0
 #define SCART_IN1     1
 #define SCART_IN2     2
@@ -36,4 +42,84 @@
 #define SCART1_OUT    1
 #define SCART2_OUT    2
 
+#define OPMODE_AUTO       -1
+#define OPMODE_MANUAL      0
+#define OPMODE_AUTODETECT  1   /* use autodetect (>= msp3410 only) */
+#define OPMODE_AUTOSELECT  2   /* use autodetect & autoselect (>= msp34xxG)   */
+
+/* module parameters */
+extern int debug;
+extern int once;
+extern int amsound;
+extern int standard;
+extern int dolby;
+extern int stereo_threshold;
+
+struct msp_state {
+	int rev1, rev2;
+	u8 has_nicam;
+	u8 has_radio;
+	u8 has_headphones;
+	u8 has_ntsc_jp_d_k3;
+	u8 has_scart4;
+	u8 has_scart23_in_scart2_out;
+	u8 has_scart2_out_volume;
+	u8 has_i2s_conf;
+	u8 has_subwoofer;
+	u8 has_sound_processing;
+	u8 has_virtual_dolby_surround;
+	u8 has_dolby_pro_logic;
+
+	int radio;
+	int opmode;
+	int std;
+	int mode;
+	v4l2_std_id v4l2_std;
+	int nicam_on;
+	int acb;
+	int in_scart;
+	int i2s_mode;
+	int main, second;	/* sound carrier */
+	int input;
+	int source;             /* see msp34xxg_set_source */
+
+	/* v4l2 */
+	int audmode;
+	int rxsubchans;
+
+	int volume, muted;
+	int balance, loudness;
+	int bass, treble;
+
+	/* thread */
+	struct task_struct   *kthread;
+	wait_queue_head_t    wq;
+	int                  restart:1;
+	int                  watch_stereo:1;
+};
+
+/* msp3400-driver.c */
+int msp_write_dem(struct i2c_client *client, int addr, int val);
+int msp_write_dsp(struct i2c_client *client, int addr, int val);
+int msp_read_dem(struct i2c_client *client, int addr);
+int msp_read_dsp(struct i2c_client *client, int addr);
+int msp_reset(struct i2c_client *client);
+void msp_set_scart(struct i2c_client *client, int in, int out);
+void msp_set_mute(struct i2c_client *client);
+void msp_set_audio(struct i2c_client *client);
+int msp_modus(struct i2c_client *client);
+int msp_sleep(struct msp_state *state, int timeout);
+
+/* msp3400-kthreads.c */
+const char *msp_standard_std_name(int std);
+void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
+void msp3400c_setmode(struct i2c_client *client, int type);
+void msp3400c_setstereo(struct i2c_client *client, int mode);
+int autodetect_stereo(struct i2c_client *client);
+int msp3400c_thread(void *data);
+int msp3410d_thread(void *data);
+int msp34xxg_thread(void *data);
+void msp34xxg_detect_stereo(struct i2c_client *client);
+void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+
 #endif /* MSP3400_H */
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 2180018..2c19c95 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -20,6 +20,9 @@
 static unsigned int radio_antenna = 0;
 module_param(radio_antenna,     int, 0644);
 
+/* from tuner-core.c */
+extern int debug;
+
 /* ---------------------------------------------------------------------- */
 
 #define MT2032 0x04
@@ -401,7 +404,7 @@
 	div2a=(lo2/8)-1;
 	div2b=lo2-(div2a+1)*8;
 
-	if (tuner_debug > 1) {
+	if (debug > 1) {
 		tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
 		tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
 			  num1,num2,div1a,div1b,div2a,div2b);
@@ -417,7 +420,7 @@
 	buf[5]=div2a;
 	if(num2!=0) buf[5]=buf[5]|0x40;
 
-	if (tuner_debug > 1) {
+	if (debug > 1) {
 		int i;
 		tuner_dbg("bufs is: ");
 		for(i=0;i<6;i++)
@@ -494,11 +497,18 @@
 	t->tv_freq    = NULL;
 	t->radio_freq = NULL;
 	t->standby    = NULL;
+	if (t->std & V4L2_STD_525_60) {
+		tuner_dbg("pinnacle ntsc\n");
+		t->radio_if2 = 41300 * 1000;
+	} else {
+		tuner_dbg("pinnacle pal\n");
+		t->radio_if2 = 33300 * 1000;
+	}
 	name = "unknown";
 
 	i2c_master_send(c,buf,1);
 	i2c_master_recv(c,buf,21);
-	if (tuner_debug) {
+	if (debug) {
 		int i;
 		tuner_dbg("MT20xx hexdump:");
 		for(i=0;i<21;i++) {
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index d04793f..91681aa 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -26,6 +26,7 @@
 #include <media/saa7146_vv.h>
 #include <media/tuner.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #include "mxb.h"
 #include "tea6415c.h"
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 2504207..9e64486 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -883,6 +883,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = pms_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.read           = pms_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index a51c7bd..73b4f0e 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -702,6 +702,7 @@
 	.open		= saa5249_open,
 	.release       	= saa5249_release,
 	.ioctl          = saa5249_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index d60a783..e70b17e 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -427,18 +427,8 @@
 
 static int saa6588_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, saa6588_attach);
-#else
-	switch (adap->id) {
-	case I2C_HW_B_BT848:
-	case I2C_HW_B_RIVA:
-	case I2C_HW_SAA7134:
-		return i2c_probe(adap, &addr_data, saa6588_attach);
-		break;
-	}
-#endif
 	return 0;
 }
 
@@ -496,7 +486,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name = "i2c saa6588 driver",
+		.name = "saa6588",
 	},
 	.id = -1,		/* FIXME */
 	.attach_adapter = saa6588_probe,
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 29e28c7..4a4bc69 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -39,31 +39,18 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/audiochip.h>
+#include <asm/div64.h>
 
 MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
 static int debug = 0;
-module_param(debug, int, 0644);
+module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define saa7115_dbg(fmt,arg...) \
-	do { \
-		if (debug) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->driver.name, \
-			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-#define saa7115_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7115_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
 
 
@@ -73,12 +60,13 @@
 	v4l2_std_id std;
 	int input;
 	int enable;
+	int radio;
 	int bright;
 	int contrast;
 	int hue;
 	int sat;
 	enum v4l2_chip_ident ident;
-	enum v4l2_audio_clock_freq audclk_freq;
+	u32 audclk_freq;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -469,80 +457,6 @@
 	0x00, 0x00
 };
 
-/* ============== SAA7715 AUDIO settings ============= */
-
-/* 48.0 kHz */
-static const unsigned char saa7115_cfg_48_audio[] = {
-	0x34, 0xce,
-	0x35, 0xfb,
-	0x36, 0x30,
-	0x00, 0x00
-};
-
-/* 44.1 kHz */
-static const unsigned char saa7115_cfg_441_audio[] = {
-	0x34, 0xf2,
-	0x35, 0x00,
-	0x36, 0x2d,
-	0x00, 0x00
-};
-
-/* 32.0 kHz */
-static const unsigned char saa7115_cfg_32_audio[] = {
-	0x34, 0xdf,
-	0x35, 0xa7,
-	0x36, 0x20,
-	0x00, 0x00
-};
-
-/* 48.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_48_audio[] = {
-	0x30, 0xcd,
-	0x31, 0x20,
-	0x32, 0x03,
-	0x00, 0x00
-};
-
-/* 48.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_48_audio[] = {
-	0x30, 0x00,
-	0x31, 0xc0,
-	0x32, 0x03,
-	0x00, 0x00
-};
-
-/* 44.1 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_441_audio[] = {
-	0x30, 0xbc,
-	0x31, 0xdf,
-	0x32, 0x02,
-	0x00, 0x00
-};
-
-/* 44.1 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_441_audio[] = {
-	0x30, 0x00,
-	0x31, 0x72,
-	0x32, 0x03,
-	0x00, 0x00
-};
-
-/* 32.0 kHz 60hz */
-static const unsigned char saa7115_cfg_60hz_32_audio[] = {
-	0x30, 0xde,
-	0x31, 0x15,
-	0x32, 0x02,
-	0x00, 0x00
-};
-
-/* 32.0 kHz 50hz */
-static const unsigned char saa7115_cfg_50hz_32_audio[] = {
-	0x30, 0x00,
-	0x31, 0x80,
-	0x32, 0x02,
-	0x00, 0x00
-};
-
 static int saa7115_odd_parity(u8 c)
 {
 	c ^= (c >> 4);
@@ -627,40 +541,38 @@
 }
 
 
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
 {
 	struct saa7115_state *state = i2c_get_clientdata(client);
+	u32 acpf;
+	u32 acni;
+	u32 hz;
+	u64 f;
 
-	saa7115_dbg("set audio clock freq: %d\n", freq);
-	switch (freq) {
-		case V4L2_AUDCLK_32_KHZ:
-			saa7115_writeregs(client, saa7115_cfg_32_audio);
-			if (state->std & V4L2_STD_525_60) {
-				saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
-			} else {
-				saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
-			}
-			break;
-		case V4L2_AUDCLK_441_KHZ:
-			saa7115_writeregs(client, saa7115_cfg_441_audio);
-			if (state->std & V4L2_STD_525_60) {
-				saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
-			} else {
-				saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
-			}
-			break;
-		case V4L2_AUDCLK_48_KHZ:
-			saa7115_writeregs(client, saa7115_cfg_48_audio);
-			if (state->std & V4L2_STD_525_60) {
-				saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
-			} else {
-				saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
-			}
-			break;
-		default:
-			saa7115_dbg("invalid audio setting %d\n", freq);
-			return -EINVAL;
-	}
+	v4l_dbg(1, client, "set audio clock freq: %d\n", freq);
+
+	/* sanity check */
+	if (freq < 32000 || freq > 48000)
+		return -EINVAL;
+
+	/* hz is the refresh rate times 100 */
+	hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
+	/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
+	acpf = (25600 * freq) / hz;
+	/* acni = (256 * freq * 2^23) / crystal_frequency =
+		  (freq * 2^(8+23)) / crystal_frequency =
+		  (freq << 31) / 32.11 MHz */
+	f = freq;
+	f = f << 31;
+	do_div(f, 32110000);
+	acni = f;
+
+	saa7115_write(client, 0x30, acpf & 0xff);
+	saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
+	saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
+	saa7115_write(client, 0x34, acni & 0xff);
+	saa7115_write(client, 0x35, (acni >> 8) & 0xff);
+	saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
 	state->audclk_freq = freq;
 	return 0;
 }
@@ -672,7 +584,7 @@
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
 		if (ctrl->value < 0 || ctrl->value > 255) {
-			saa7115_err("invalid brightness setting %d\n", ctrl->value);
+			v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
@@ -682,7 +594,7 @@
 
 	case V4L2_CID_CONTRAST:
 		if (ctrl->value < 0 || ctrl->value > 127) {
-			saa7115_err("invalid contrast setting %d\n", ctrl->value);
+			v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
@@ -692,7 +604,7 @@
 
 	case V4L2_CID_SATURATION:
 		if (ctrl->value < 0 || ctrl->value > 127) {
-			saa7115_err("invalid saturation setting %d\n", ctrl->value);
+			v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
@@ -702,13 +614,16 @@
 
 	case V4L2_CID_HUE:
 		if (ctrl->value < -127 || ctrl->value > 127) {
-			saa7115_err("invalid hue setting %d\n", ctrl->value);
+			v4l_err(client, "invalid hue setting %d\n", ctrl->value);
 			return -ERANGE;
 		}
 
 		state->hue = ctrl->value;
 		saa7115_write(client, 0x0d, state->hue);
 		break;
+
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -743,12 +658,22 @@
 	struct saa7115_state *state = i2c_get_clientdata(client);
 	int taskb = saa7115_read(client, 0x80) & 0x10;
 
+	/* Prevent unnecessary standard changes. During a standard
+	   change the I-Port is temporarily disabled. Any devices
+	   reading from that port can get confused.
+	   Note that VIDIOC_S_STD is also used to switch from
+	   radio to TV mode, so if a VIDIOC_S_STD is broadcast to
+	   all I2C devices then you do not want to have an unwanted
+	   side-effect here. */
+	if (std == state->std)
+		return;
+
 	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
 	if (std & V4L2_STD_525_60) {
-		saa7115_dbg("decoder set standard 60 Hz\n");
+		v4l_dbg(1, client, "decoder set standard 60 Hz\n");
 		saa7115_writeregs(client, saa7115_cfg_60hz_video);
 	} else {
-		saa7115_dbg("decoder set standard 50 Hz\n");
+		v4l_dbg(1, client, "decoder set standard 50 Hz\n");
 		saa7115_writeregs(client, saa7115_cfg_50hz_video);
 	}
 
@@ -773,24 +698,17 @@
 static void saa7115_log_status(struct i2c_client *client)
 {
 	struct saa7115_state *state = i2c_get_clientdata(client);
-	char *audfreq = "undefined";
 	int reg1e, reg1f;
 	int signalOk;
 	int vcr;
 
-	switch (state->audclk_freq) {
-		case V4L2_AUDCLK_32_KHZ:  audfreq = "32 kHz"; break;
-		case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break;
-		case V4L2_AUDCLK_48_KHZ:  audfreq = "48 kHz"; break;
-	}
-
-	saa7115_info("Audio frequency: %s\n", audfreq);
+	v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
 	if (client->name[6] == '4') {
 		/* status for the saa7114 */
 		reg1f = saa7115_read(client, 0x1f);
 		signalOk = (reg1f & 0xc1) == 0x81;
-		saa7115_info("Video signal:    %s\n", signalOk ? "ok" : "bad");
-		saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+		v4l_info(client, "Video signal:    %s\n", signalOk ? "ok" : "bad");
+		v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
 		return;
 	}
 
@@ -801,21 +719,26 @@
 	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
 	vcr = !(reg1f & 0x10);
 
-	saa7115_info("Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
-	saa7115_info("Frequency:       %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+	if (state->input >= 6) {
+		v4l_info(client, "Input:           S-Video %d\n", state->input - 6);
+	} else {
+		v4l_info(client, "Input:           Composite %d\n", state->input);
+	}
+	v4l_info(client, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+	v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
 
 	switch (reg1e & 0x03) {
 		case 1:
-			saa7115_info("Detected format: NTSC\n");
+			v4l_info(client, "Detected format: NTSC\n");
 			break;
 		case 2:
-			saa7115_info("Detected format: PAL\n");
+			v4l_info(client, "Detected format: PAL\n");
 			break;
 		case 3:
-			saa7115_info("Detected format: SECAM\n");
+			v4l_info(client, "Detected format: SECAM\n");
 			break;
 		default:
-			saa7115_info("Detected format: BW/No color\n");
+			v4l_info(client, "Detected format: BW/No color\n");
 			break;
 	}
 }
@@ -940,7 +863,7 @@
 
 	pix = &(fmt->fmt.pix);
 
-	saa7115_dbg("decoder set size\n");
+	v4l_dbg(1, client, "decoder set size\n");
 
 	/* FIXME need better bounds checking here */
 	if ((pix->width < 1) || (pix->width > 1440))
@@ -966,7 +889,7 @@
 		HPSC = HPSC ? HPSC : 1;
 		HFSC = (int)((1024 * 720) / (HPSC * pix->width));
 
-		saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+		v4l_dbg(1, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
 		/* FIXME hardcodes to "Task B"
 		 * write H prescaler integer */
 		saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
@@ -980,10 +903,10 @@
 		saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
 	} else {
 		if (is_50hz) {
-			saa7115_dbg("Setting full 50hz width\n");
+			v4l_dbg(1, client, "Setting full 50hz width\n");
 			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
 		} else {
-			saa7115_dbg("Setting full 60hz width\n");
+			v4l_dbg(1, client, "Setting full 60hz width\n");
 			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
 		}
 	}
@@ -992,7 +915,7 @@
 
 	if (pix->height != Vsrc) {
 		VSCY = (int)((1024 * Vsrc) / pix->height);
-		saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+		v4l_dbg(1, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
 
 		/* Correct Contrast and Luminance */
 		saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
@@ -1006,10 +929,10 @@
 		saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
 	} else {
 		if (is_50hz) {
-			saa7115_dbg("Setting full 50Hz height\n");
+			v4l_dbg(1, client, "Setting full 50Hz height\n");
 			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
 		} else {
-			saa7115_dbg("Setting full 60hz height\n");
+			v4l_dbg(1, client, "Setting full 60hz height\n");
 			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
 		}
 	}
@@ -1089,6 +1012,48 @@
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
+static struct v4l2_queryctrl saa7115_qctrl[] = {
+	{
+		.id            = V4L2_CID_BRIGHTNESS,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Brightness",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 128,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_CONTRAST,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Contrast",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_SATURATION,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Saturation",
+		.minimum       = 0,
+		.maximum       = 255,
+		.step          = 1,
+		.default_value = 64,
+		.flags         = 0,
+	}, {
+		.id            = V4L2_CID_HUE,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+		.name          = "Hue",
+		.minimum       = -128,
+		.maximum       = 127,
+		.step          = 1,
+		.default_value = 0,
+		.flags 	       = 0,
+	},
+};
+
+/* ----------------------------------------------------------------------- */
+
 static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1103,16 +1068,18 @@
 		return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+		return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
 
 	case VIDIOC_G_TUNER:
 	{
 		struct v4l2_tuner *vt = arg;
 		int status;
 
+		if (state->radio)
+			break;
 		status = saa7115_read(client, 0x1f);
 
-		saa7115_dbg("status: 0x%02x\n", status);
+		v4l_dbg(1, client, "status: 0x%02x\n", status);
 		vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
 		break;
 	}
@@ -1127,20 +1094,38 @@
 	case VIDIOC_S_CTRL:
 		return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
 
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
+			if (qc->id && qc->id == saa7115_qctrl[i].id) {
+				memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
+				return 0;
+			}
+		return -EINVAL;
+	}
+
 	case VIDIOC_G_STD:
 		*(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
 		break;
 
 	case VIDIOC_S_STD:
+		state->radio = 0;
 		saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
 		break;
 
+	case AUDC_SET_RADIO:
+		state->radio = 1;
+		break;
+
 	case VIDIOC_G_INPUT:
 		*(int *)arg = state->input;
 		break;
 
 	case VIDIOC_S_INPUT:
-		saa7115_dbg("decoder set input %d\n", *iarg);
+		v4l_dbg(1, client, "decoder set input %d\n", *iarg);
 		/* inputs from 0-9 are available */
 		if (*iarg < 0 || *iarg > 9) {
 			return -EINVAL;
@@ -1148,7 +1133,7 @@
 
 		if (state->input == *iarg)
 			break;
-		saa7115_dbg("now setting %s input\n",
+		v4l_dbg(1, client, "now setting %s input\n",
 			*iarg >= 6 ? "S-Video" : "Composite");
 		state->input = *iarg;
 
@@ -1165,7 +1150,7 @@
 
 	case VIDIOC_STREAMON:
 	case VIDIOC_STREAMOFF:
-		saa7115_dbg("%s output\n",
+		v4l_dbg(1, client, "%s output\n",
 			(cmd == VIDIOC_STREAMON) ? "enable" : "disable");
 
 		if (state->enable != (cmd == VIDIOC_STREAMON)) {
@@ -1179,7 +1164,7 @@
 		break;
 
 	case VIDIOC_INT_RESET:
-		saa7115_dbg("decoder RESET\n");
+		v4l_dbg(1, client, "decoder RESET\n");
 		saa7115_writeregs(client, saa7115_cfg_reset_scaler);
 		break;
 
@@ -1273,19 +1258,19 @@
 	client->driver = &i2c_driver_saa7115;
 	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
-	saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+	v4l_dbg(1, client, "detecting saa7115 client on address 0x%x\n", address << 1);
 
 	saa7115_write(client, 0, 5);
 	chip_id = saa7115_read(client, 0) & 0x0f;
 	if (chip_id != 4 && chip_id != 5) {
-		saa7115_dbg("saa7115 not found\n");
+		v4l_dbg(1, client, "saa7115 not found\n");
 		kfree(client);
 		return 0;
 	}
 	if (chip_id == 4) {
 		snprintf(client->name, sizeof(client->name) - 1, "saa7114");
 	}
-	saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+	v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
 
 	state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
 	i2c_set_clientdata(client, state);
@@ -1297,14 +1282,15 @@
 	state->std = V4L2_STD_NTSC;
 	state->input = -1;
 	state->enable = 1;
+	state->radio = 0;
 	state->bright = 128;
 	state->contrast = 64;
 	state->hue = 0;
 	state->sat = 64;
 	state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
-	state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+	state->audclk_freq = 48000;
 
-	saa7115_dbg("writing init values\n");
+	v4l_dbg(1, client, "writing init values\n");
 
 	/* init to 60hz/48khz */
 	saa7115_writeregs(client, saa7115_init_auto_input);
@@ -1312,13 +1298,12 @@
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
 	saa7115_writeregs(client, saa7115_cfg_60hz_video);
-	saa7115_writeregs(client, saa7115_cfg_48_audio);
-	saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+	saa7115_set_audio_clock_freq(client, state->audclk_freq);
 	saa7115_writeregs(client, saa7115_cfg_reset_scaler);
 
 	i2c_attach_client(client);
 
-	saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+	v4l_dbg(1, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
 		saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
 
 	return 0;
@@ -1326,11 +1311,7 @@
 
 static int saa7115_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-	if (adapter->id == I2C_HW_B_BT848)
-#endif
 		return i2c_probe(adapter, &addr_data, &saa7115_attach);
 	return 0;
 }
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 8008537..f39a7be0 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -567,9 +567,7 @@
 	.driver = {
 		.name = "saa711x",
 	},
-
 	.id = I2C_DRIVERID_SAA711X,
-
 	.attach_adapter = saa711x_attach_adapter,
 	.detach_client = saa711x_detach_client,
 	.command = saa711x_command,
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index bca6ed0..2009c1b 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -66,30 +66,6 @@
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 MODULE_PARM_DESC(test_image, "test_image (0-1)");
 
-#define saa7127_dbg(fmt, arg...) \
-	do { \
-		if (debug >= 1) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->driver.name, \
-			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-/* High volume debug. Use with care. */
-#define saa7127_dbg_highvol(fmt, arg...) \
-	do { \
-		if (debug == 2) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->driver.name, \
-			       i2c_adapter_id(client->adapter), client->addr , ## arg); \
-	} while (0)
-
-#define saa7127_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define saa7127_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
@@ -336,7 +312,7 @@
 		if (i2c_smbus_write_byte_data(client, reg, val) == 0)
 			return 0;
 	}
-	saa7127_err("I2C Write Problem\n");
+	v4l_err(client, "I2C Write Problem\n");
 	return -1;
 }
 
@@ -362,7 +338,7 @@
 	if (enable && (data->field != 0 || data->line != 16))
 		return -EINVAL;
 	if (state->vps_enable != enable) {
-		saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+		v4l_dbg(1, client, "Turn VPS Signal %s\n", enable ? "on" : "off");
 		saa7127_write(client, 0x54, enable << 7);
 		state->vps_enable = enable;
 	}
@@ -374,7 +350,7 @@
 	state->vps_data[2] = data->data[11];
 	state->vps_data[3] = data->data[12];
 	state->vps_data[4] = data->data[13];
-	saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+	v4l_dbg(1, client, "Set VPS data %02x %02x %02x %02x %02x\n",
 		state->vps_data[0], state->vps_data[1],
 		state->vps_data[2], state->vps_data[3],
 		state->vps_data[4]);
@@ -397,7 +373,7 @@
 	if (enable && (data->field != 0 || data->line != 21))
 		return -EINVAL;
 	if (state->cc_enable != enable) {
-		saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+		v4l_dbg(1, client, "Turn CC %s\n", enable ? "on" : "off");
 		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
 				(state->xds_enable << 7) | (enable << 6) | 0x11);
 		state->cc_enable = enable;
@@ -405,7 +381,7 @@
 	if (!enable)
 		return 0;
 
-	saa7127_dbg_highvol("CC data: %04x\n", cc);
+	v4l_dbg(2, client, "CC data: %04x\n", cc);
 	saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
 	saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
 	state->cc_data = cc;
@@ -423,7 +399,7 @@
 	if (enable && (data->field != 1 || data->line != 21))
 		return -EINVAL;
 	if (state->xds_enable != enable) {
-		saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+		v4l_dbg(1, client, "Turn XDS %s\n", enable ? "on" : "off");
 		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
 				(enable << 7) | (state->cc_enable << 6) | 0x11);
 		state->xds_enable = enable;
@@ -431,7 +407,7 @@
 	if (!enable)
 		return 0;
 
-	saa7127_dbg_highvol("XDS data: %04x\n", xds);
+	v4l_dbg(2, client, "XDS data: %04x\n", xds);
 	saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
 	saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
 	state->xds_data = xds;
@@ -448,7 +424,7 @@
 	if (enable && (data->field != 0 || data->line != 23))
 		return -EINVAL;
 	if (state->wss_enable != enable) {
-		saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+		v4l_dbg(1, client, "Turn WSS %s\n", enable ? "on" : "off");
 		saa7127_write(client, 0x27, enable << 7);
 		state->wss_enable = enable;
 	}
@@ -457,7 +433,7 @@
 
 	saa7127_write(client, 0x26, data->data[0]);
 	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-	saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+	v4l_dbg(1, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
 	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
 	return 0;
 }
@@ -469,11 +445,11 @@
 	struct saa7127_state *state = i2c_get_clientdata(client);
 
 	if (enable) {
-		saa7127_dbg("Enable Video Output\n");
+		v4l_dbg(1, client, "Enable Video Output\n");
 		saa7127_write(client, 0x2d, state->reg_2d);
 		saa7127_write(client, 0x61, state->reg_61);
 	} else {
-		saa7127_dbg("Disable Video Output\n");
+		v4l_dbg(1, client, "Disable Video Output\n");
 		saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
 		saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
 	}
@@ -489,11 +465,11 @@
 	const struct i2c_reg_value *inittab;
 
 	if (std & V4L2_STD_525_60) {
-		saa7127_dbg("Selecting 60 Hz video Standard\n");
+		v4l_dbg(1, client, "Selecting 60 Hz video Standard\n");
 		inittab = saa7127_init_config_60hz;
 		state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
 	} else {
-		saa7127_dbg("Selecting 50 Hz video Standard\n");
+		v4l_dbg(1, client, "Selecting 50 Hz video Standard\n");
 		inittab = saa7127_init_config_50hz;
 		state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
 	}
@@ -544,7 +520,7 @@
 	default:
 		return -EINVAL;
 	}
-	saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+	v4l_dbg(1, client, "Selecting %s output type\n", output_strs[output]);
 
 	/* Configure Encoder */
 	saa7127_write(client, 0x2d, state->reg_2d);
@@ -561,12 +537,12 @@
 
 	switch (input) {
 	case SAA7127_INPUT_TYPE_NORMAL:	/* avia */
-		saa7127_dbg("Selecting Normal Encoder Input\n");
+		v4l_dbg(1, client, "Selecting Normal Encoder Input\n");
 		state->reg_3a_cb = 0;
 		break;
 
 	case SAA7127_INPUT_TYPE_TEST_IMAGE:	/* color bar */
-		saa7127_dbg("Selecting Color Bar generator\n");
+		v4l_dbg(1, client, "Selecting Color Bar generator\n");
 		state->reg_3a_cb = 0x80;
 		break;
 
@@ -633,14 +609,14 @@
 		break;
 
 	case VIDIOC_LOG_STATUS:
-		saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
-		saa7127_info("Input:    %s\n", state->input_type ?  "color bars" : "normal");
-		saa7127_info("Output:   %s\n", state->video_enable ?
+		v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+		v4l_info(client, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
+		v4l_info(client, "Output:   %s\n", state->video_enable ?
 			output_strs[state->output_type] : "disabled");
-		saa7127_info("WSS:      %s\n", state->wss_enable ?
+		v4l_info(client, "WSS:      %s\n", state->wss_enable ?
 			wss_strs[state->wss_mode] : "disabled");
-		saa7127_info("VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
-		saa7127_info("CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
+		v4l_info(client, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
+		v4l_info(client, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
 		break;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -723,7 +699,7 @@
 	client->driver = &i2c_driver_saa7127;
 	snprintf(client->name, sizeof(client->name) - 1, "saa7127");
 
-	saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+	v4l_dbg(1, client, "detecting saa7127 client on address 0x%x\n", address << 1);
 
 	/* First test register 0: Bits 5-7 are a version ID (should be 0),
 	   and bit 2 should also be 0.
@@ -732,7 +708,7 @@
 	   0x1d after a reset and not expected to ever change. */
 	if ((saa7127_read(client, 0) & 0xe4) != 0 ||
 			(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
-		saa7127_dbg("saa7127 not found\n");
+		v4l_dbg(1, client, "saa7127 not found\n");
 		kfree(client);
 		return 0;
 	}
@@ -748,7 +724,7 @@
 
 	/* Configure Encoder */
 
-	saa7127_dbg("Configuring encoder\n");
+	v4l_dbg(1, client, "Configuring encoder\n");
 	saa7127_write_inittab(client, saa7127_init_config_common);
 	saa7127_set_std(client, V4L2_STD_NTSC);
 	saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
@@ -769,12 +745,12 @@
 	read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
 	saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
 	if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-		saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+		v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
 		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
 		saa7127_write_inittab(client, saa7129_init_config_extra);
 		state->ident = V4L2_IDENT_SAA7129;
 	} else {
-		saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+		v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
 		state->ident = V4L2_IDENT_SAA7127;
 	}
 
@@ -787,11 +763,7 @@
 
 static int saa7127_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-	if (adapter->id == I2C_HW_B_BT848)
-#endif
 		return i2c_probe(adapter, &addr_data, saa7127_attach);
 	return 0;
 }
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 4615a98..ad73c4a6 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -9,7 +9,8 @@
 #include <linux/poll.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
 
@@ -509,7 +510,6 @@
 {
 	struct saa6752hs_state *h;
 
-	printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
 
 	if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
 		return -ENOMEM;
@@ -525,6 +525,8 @@
 	i2c_set_clientdata(&h->client, h);
 	i2c_attach_client(&h->client);
 
+	v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1);
+
 	return 0;
 }
 
@@ -598,7 +600,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name   = "i2c saa6752hs MPEG encoder",
+		.name   = "saa6752hs",
 	},
 	.id             = I2C_DRIVERID_SAA6752HS,
 	.attach_adapter = saa6752hs_probe,
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ade05f7..a7a6ab9 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -20,13 +20,13 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 672fb20..77e5be9 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -25,6 +25,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -2555,6 +2556,69 @@
 			.amux   = LINE1,
 		},
 	},
+	[SAA7134_BOARD_CINERGY250PCI] = {
+		/* remote-control does not work. The signal about a
+		   key press comes in via gpio, but the key code
+		   doesn't. Neither does it have an i2c remote control
+		   interface. */
+		.name           = "Terratec Cinergy 250 PCI TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 0x80200000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_svideo,  /* NOT tested */
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE1,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_FLYDVB_TRIO] = {
+		/* LifeView LR319 FlyDVB Trio */
+		/* Peter Missel <peter.missel@onlinehome.de> */
+		.name           = "LifeView FlyDVB Trio",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x00200000,
+		.inputs         = {{
+			.name = name_tv,	/* Analog broadcast/cable TV */
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
+			.tv   = 1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE2,
+		},{
+			.name = name_comp1,	/* Composite signal on S-Video input */
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE2,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2895,6 +2959,12 @@
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1421,
+		.subdevice    = 0x0351,		/* PCI version, new revision */
+		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1421,
 		.subdevice    = 0x0370,		/* cardbus version */
 		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
 	},{
@@ -3002,6 +3072,18 @@
 		.subdevice    = 0x6231,
 		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x153b,
+		.subdevice    = 0x1160,
+		.driver_data  = SAA7134_BOARD_CINERGY250PCI,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,	/* SAA 7131E */
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0319,
+		.driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3090,6 +3172,7 @@
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 23d8747..accbc32 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -95,77 +95,6 @@
 #define dprintk(fmt, arg...)	if (core_debug) \
 	printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
 
-/* ------------------------------------------------------------------ */
-/* debug help functions                                               */
-
-static const char *v4l1_ioctls[] = {
-	"0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
-	"CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
-	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
-	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
-	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-
-static const char *v4l2_ioctls[] = {
-	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
-	"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
-	"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
-	"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
-	"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
-	"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
-	"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
-	"44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
-	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
-	"S_MODULATOR"
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-static const char *osspcm_ioctls[] = {
-	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
-	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
-	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
-	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
-	"SETDUPLEX", "GETODELAY"
-};
-#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-void saa7134_print_ioctl(char *name, unsigned int cmd)
-{
-	char *dir;
-
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:              dir = "--"; break;
-	case _IOC_READ:              dir = "r-"; break;
-	case _IOC_WRITE:             dir = "-w"; break;
-	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-	default:                     dir = "??"; break;
-	}
-	switch (_IOC_TYPE(cmd)) {
-	case 'v':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
-		       v4l1_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'V':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
-		       v4l2_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'P':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
-		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'M':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-		break;
-	default:
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-	}
-}
-
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
 {
 	unsigned long mode,status;
@@ -211,7 +140,7 @@
 	return NOTIFY_DONE;
 }
 
-static int pending_registered;
+static int pending_registered=0;
 static struct notifier_block pending_notifier = {
 	.notifier_call = pending_call,
 };
@@ -610,11 +539,38 @@
 		    card_has_mpeg(dev))
 			saa7134_irq_ts_done(dev,status);
 
-		if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
-			       SAA7134_IRQ_REPORT_GPIO18)) &&
-		    dev->remote)
-			saa7134_input_irq(dev);
+		if (report & SAA7134_IRQ_REPORT_GPIO16) {
+			switch (dev->has_remote) {
+				case SAA7134_REMOTE_GPIO:
+					if  (dev->remote->mask_keydown & 0x10000) {
+						saa7134_input_irq(dev);
+					}
+					break;
 
+				case SAA7134_REMOTE_I2C:
+					break;			/* FIXME: invoke I2C get_key() */
+
+				default:			/* GPIO16 not used by IR remote */
+					break;
+			}
+		}
+
+		if (report & SAA7134_IRQ_REPORT_GPIO18) {
+			switch (dev->has_remote) {
+				case SAA7134_REMOTE_GPIO:
+					if ((dev->remote->mask_keydown & 0x40000) ||
+					    (dev->remote->mask_keyup & 0x40000)) {
+						saa7134_input_irq(dev);
+					}
+					break;
+
+				case SAA7134_REMOTE_I2C:
+					break;			/* FIXME: invoke I2C get_key() */
+
+				default:			/* GPIO18 not used by IR remote */
+					break;
+			}
+		}
 	}
 
 	if (10 == loop) {
@@ -624,13 +580,16 @@
 			printk(KERN_WARNING "%s/irq: looping -- "
 			       "clearing PE (parity error!) enable bit\n",dev->name);
 			saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
-		} else if (report & (SAA7134_IRQ_REPORT_GPIO16 |
-				     SAA7134_IRQ_REPORT_GPIO18)) {
-			/* disable gpio IRQs */
+		} else if (report & SAA7134_IRQ_REPORT_GPIO16) {
+			/* disable gpio16 IRQ */
 			printk(KERN_WARNING "%s/irq: looping -- "
-			       "clearing GPIO enable bits\n",dev->name);
-			saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 |
-						  SAA7134_IRQ2_INTE_GPIO18));
+			       "clearing GPIO16 enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16);
+		} else if (report & SAA7134_IRQ_REPORT_GPIO18) {
+			/* disable gpio18 IRQs */
+			printk(KERN_WARNING "%s/irq: looping -- "
+			       "clearing GPIO18 enable bit\n",dev->name);
+			saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18);
 		} else {
 			/* disable all irqs */
 			printk(KERN_WARNING "%s/irq: looping -- "
@@ -711,10 +670,14 @@
 		SAA7134_IRQ2_INTE_PE      |
 		SAA7134_IRQ2_INTE_AR;
 
-	if (dev->has_remote == SAA7134_REMOTE_GPIO)
-		irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
-			      SAA7134_IRQ2_INTE_GPIO18A |
-			      SAA7134_IRQ2_INTE_GPIO16  );
+	if (dev->has_remote == SAA7134_REMOTE_GPIO) {
+		if (dev->remote->mask_keydown & 0x10000)
+			irq2_mask |= SAA7134_IRQ2_INTE_GPIO16;
+		else if (dev->remote->mask_keydown & 0x40000)
+			irq2_mask |= SAA7134_IRQ2_INTE_GPIO18;
+		else if (dev->remote->mask_keyup & 0x40000)
+			irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A;
+	}
 
 	saa_writel(SAA7134_IRQ1, 0);
 	saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -1156,7 +1119,7 @@
 	printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
 	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-	return pci_module_init(&saa7134_pci_driver);
+	return pci_register_driver(&saa7134_pci_driver);
 }
 
 static void saa7134_fini(void)
@@ -1173,7 +1136,6 @@
 
 /* ----------------------------------------------------------- */
 
-EXPORT_SYMBOL(saa7134_print_ioctl);
 EXPORT_SYMBOL(saa7134_i2c_call_clients);
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e016480..399f995 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -31,6 +31,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 #ifdef HAVE_MT352
 # include "mt352.h"
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 575f3e8..bd4c389 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -29,6 +29,7 @@
 #include "saa7134.h"
 
 #include <media/saa6752hs.h>
+#include <media/v4l2-common.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -163,7 +164,7 @@
 	struct saa7134_dev *dev = file->private_data;
 
 	if (debug > 1)
-		saa7134_print_ioctl(dev->name,cmd);
+		v4l_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case VIDIOC_QUERYCAP:
 	{
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1792d03..6162550 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -30,6 +30,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* ----------------------------------------------------------- */
 
@@ -390,9 +391,7 @@
 
 static struct i2c_adapter saa7134_adap_template = {
 	.owner         = THIS_MODULE,
-#ifdef I2C_CLASS_TV_ANALOG
 	.class         = I2C_CLASS_TV_ANALOG,
-#endif
 	.name          = "saa7134",
 	.id            = I2C_HW_SAA7134,
 	.algo          = &saa7134_algo,
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index ab75ca5..82d28cb 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -56,23 +56,23 @@
 	[   12 ] = KEY_KP8,
 	[   13 ] = KEY_KP9,
 
-	[   14 ] = KEY_TUNER,        // Air/Cable
+	[   14 ] = KEY_MODE,         // Air/Cable
 	[   17 ] = KEY_VIDEO,        // Video
 	[   21 ] = KEY_AUDIO,        // Audio
-	[    0 ] = KEY_POWER,        // Pover
+	[    0 ] = KEY_POWER,        // Power
+	[   24 ] = KEY_TUNER,        // AV Source
 	[    2 ] = KEY_ZOOM,         // Fullscreen
+	[   26 ] = KEY_LANGUAGE,     // Stereo
 	[   27 ] = KEY_MUTE,         // Mute
-	[   20 ] = KEY_VOLUMEUP,
-	[   23 ] = KEY_VOLUMEDOWN,
+	[   20 ] = KEY_VOLUMEUP,     // Volume +
+	[   23 ] = KEY_VOLUMEDOWN,   // Volume -
 	[   18 ] = KEY_CHANNELUP,    // Channel +
 	[   19 ] = KEY_CHANNELDOWN,  // Channel -
-	[    6 ] = KEY_AGAIN,        // Recal
-	[   16 ] = KEY_KPENTER,      // Enter
-
-	[   26 ] = KEY_F22,          // Stereo
-	[   24 ] = KEY_EDIT,         // AV Source
+	[    6 ] = KEY_AGAIN,        // Recall
+	[   16 ] = KEY_ENTER,      // Enter
 };
 
+
 static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
 	[    0 ] = KEY_KP0,
 	[    1 ] = KEY_KP1,
@@ -543,12 +543,22 @@
 	dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
 		gpio, ir->mask_keycode, data);
 
-	if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
-	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-		ir_input_keydown(ir->dev, &ir->ir, data, data);
-	} else {
-		ir_input_nokey(ir->dev, &ir->ir);
+	if (ir->polling) {
+		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+			ir_input_keydown(ir->dev, &ir->ir, data, data);
+		} else {
+			ir_input_nokey(ir->dev, &ir->ir);
+		}
 	}
+	else {	/* IRQ driven mode - handle key press and release in one go */
+		if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+		    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+			ir_input_keydown(ir->dev, &ir->ir, data, data);
+			ir_input_nokey(ir->dev, &ir->ir);
+		}
+	}
+
 	return 0;
 }
 
@@ -686,6 +696,7 @@
 		polling	     = 50; // ms
 		break;
 	case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+	case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
 	case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
 		ir_codes     = videomate_tv_pvr_codes;
 		mask_keycode = 0x00003F;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 8badd2a..7448e38 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -373,6 +373,42 @@
 	return -EINVAL;
 }
 
+static const char *osspcm_ioctls[] = {
+	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
+	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
+	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
+	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
+	"SETDUPLEX", "GETODELAY"
+};
+#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
+
+static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
+{
+	char *dir;
+
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:              dir = "--"; break;
+	case _IOC_READ:              dir = "r-"; break;
+	case _IOC_WRITE:             dir = "-w"; break;
+	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+	default:                     dir = "??"; break;
+	}
+	switch (_IOC_TYPE(cmd)) {
+	case 'P':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
+		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
+		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
+		break;
+	case 'M':
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
+		       name, cmd, dir, _IOC_NR(cmd));
+		break;
+	default:
+		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+		       name, cmd, dir, _IOC_NR(cmd));
+	}
+}
+
 static int dsp_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
@@ -382,7 +418,7 @@
 	int val = 0;
 
 	if (debug > 1)
-		saa7134_print_ioctl(dev->name,cmd);
+		saa7134_oss_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case OSS_GETVERSION:
 		return put_user(SOUND_VERSION, p);
@@ -678,7 +714,7 @@
 	int __user *p = argp;
 
 	if (debug > 1)
-		saa7134_print_ioctl(dev->name,cmd);
+		saa7134_oss_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case OSS_GETVERSION:
 		return put_user(SOUND_VERSION, p);
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 45c852d..adfa8fe 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -29,6 +29,7 @@
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
+#include <media/v4l2-common.h>
 
 /* Include V4L1 specific functions. Should be removed soon */
 #include <linux/videodev.h>
@@ -1689,7 +1690,7 @@
 	int err;
 
 	if (video_debug > 1)
-		saa7134_print_ioctl(dev->name,cmd);
+		v4l_print_ioctl(dev->name,cmd);
 
 	switch (cmd) {
 	case VIDIOC_S_CTRL:
@@ -2142,7 +2143,7 @@
 	struct saa7134_dev *dev = fh->dev;
 
 	if (video_debug > 1)
-		saa7134_print_ioctl(dev->name,cmd);
+		v4l_print_ioctl(dev->name,cmd);
 	switch (cmd) {
 	case VIDIOC_QUERYCAP:
 	{
@@ -2262,6 +2263,7 @@
 	.poll     = video_poll,
 	.mmap	  = video_mmap,
 	.ioctl	  = video_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek   = no_llseek,
 };
 
@@ -2271,6 +2273,7 @@
 	.open	  = video_open,
 	.release  = video_release,
 	.ioctl	  = radio_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek   = no_llseek,
 };
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index add49db..e70eae8 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,6 +37,9 @@
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/video-buf.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
 #include <media/video-buf-dvb.h>
 
 #ifndef TRUE
@@ -47,10 +50,6 @@
 #endif
 #define UNSET (-1U)
 
-#include <sound/driver.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
 /* ----------------------------------------------------------- */
 /* enums                                                       */
 
@@ -209,6 +208,8 @@
 #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
 #define SAA7134_BOARD_PHILIPS_TIGER  81
 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -546,7 +547,6 @@
 
 extern struct list_head  saa7134_devlist;
 
-void saa7134_print_ioctl(char *name, unsigned int cmd);
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
 
 #define SAA7134_PGTABLE_SIZE 4096
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index d4497db..6ee54a4 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1974,6 +1974,7 @@
 	.open		= saa_open,
 	.release	= saa_release,
 	.ioctl		= saa_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.read		= saa_read,
 	.llseek		= no_llseek,
 	.write		= saa_write,
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 549c992..99261f1 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -50,6 +50,7 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -90,9 +91,6 @@
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
-#define dprintk  if (debug) printk
-#define d2printk if (debug > 1) printk
-
 /* The TDA7432 is made by STS-Thompson
  * http://www.st.com
  * http://us.st.com/stonline/books/pdf/docs/4056.pdf
@@ -229,12 +227,12 @@
 static int tda7432_write(struct i2c_client *client, int subaddr, int val)
 {
 	unsigned char buffer[2];
-	d2printk("tda7432: In tda7432_write\n");
-	dprintk("tda7432: Writing %d 0x%x\n", subaddr, val);
+	v4l_dbg(2,client,"In tda7432_write\n");
+	v4l_dbg(1,client,"Writing %d 0x%x\n", subaddr, val);
 	buffer[0] = subaddr;
 	buffer[1] = val;
 	if (2 != i2c_master_send(client,buffer,2)) {
-		printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n",
+		v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
 		       subaddr, val);
 		return -1;
 	}
@@ -247,9 +245,9 @@
 {
 	struct tda7432 *t = i2c_get_clientdata(client);
 	unsigned char buf[16];
-	d2printk("tda7432: In tda7432_set\n");
+	v4l_dbg(2,client,"In tda7432_set\n");
 
-	dprintk(KERN_INFO
+	v4l_dbg(1,client,
 		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
 		t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
 	buf[0]  = TDA7432_IN;
@@ -263,7 +261,7 @@
 	buf[8]  = t->rr;
 	buf[9]  = t->loud;
 	if (10 != i2c_master_send(client,buf,10)) {
-		printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
+		v4l_err(client,"I/O error, trying tda7432_set\n");
 		return -1;
 	}
 
@@ -273,7 +271,7 @@
 static void do_tda7432_init(struct i2c_client *client)
 {
 	struct tda7432 *t = i2c_get_clientdata(client);
-	d2printk("tda7432: In tda7432_init\n");
+	v4l_dbg(2,client,"In tda7432_init\n");
 
 	t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
 		    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
@@ -301,7 +299,6 @@
 {
 	struct tda7432 *t;
 	struct i2c_client *client;
-	d2printk("tda7432: In tda7432_attach\n");
 
 	t = kmalloc(sizeof *t,GFP_KERNEL);
 	if (!t)
@@ -315,21 +312,16 @@
 	i2c_set_clientdata(client, t);
 
 	do_tda7432_init(client);
-	printk(KERN_INFO "tda7432: init\n");
-
 	i2c_attach_client(client);
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
 	return 0;
 }
 
 static int tda7432_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda7432_attach);
-#else
-	if (adap->id == I2C_HW_B_BT848)
-		return i2c_probe(adap, &addr_data, tda7432_attach);
-#endif
 	return 0;
 }
 
@@ -348,7 +340,9 @@
 			   unsigned int cmd, void *arg)
 {
 	struct tda7432 *t = i2c_get_clientdata(client);
-	d2printk("tda7432: In tda7432_command\n");
+	v4l_dbg(2,client,"In tda7432_command\n");
+	if (debug>1)
+		v4l_i2c_print_ioctl(client,cmd);
 
 	switch (cmd) {
 	/* --- v4l ioctls --- */
@@ -359,7 +353,6 @@
 	case VIDIOCGAUDIO:
 	{
 		struct video_audio *va = arg;
-		dprintk("tda7432: VIDIOCGAUDIO\n");
 
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
@@ -414,7 +407,6 @@
 	case VIDIOCSAUDIO:
 	{
 		struct video_audio *va = arg;
-		dprintk("tda7432: VIDEOCSAUDIO\n");
 
 		if(va->flags & VIDEO_AUDIO_VOLUME){
 			if(!maxvol){ /* max +20db */
@@ -490,11 +482,6 @@
 
 	} /* end of VIDEOCSAUDIO case */
 
-	default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
-
-		/* nothing */
-		d2printk("tda7432: Default\n");
-
 	} /* end of (cmd) switch */
 
 	return 0;
@@ -502,7 +489,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name    = "i2c tda7432 driver",
+		.name    = "tda7432",
 	},
 	.id              = I2C_DRIVERID_TDA7432,
 	.attach_adapter  = tda7432_probe,
@@ -519,7 +506,7 @@
 static int __init tda7432_init(void)
 {
 	if ( (loudness < 0) || (loudness > 15) ) {
-		printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
+		printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 61d94dd..2498b76 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -398,14 +398,8 @@
 	return 0;
 }
 
-
 /*---------------------------------------------------------------------*/
 
-#define V4L2_STD_MN	(V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B	(V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH	(V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK	(V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
-
 static void set_audio(struct tuner *t)
 {
 	char* mode;
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 9c3ecf7..299393b 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -257,13 +257,8 @@
 
 static int tda9875_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda9875_attach);
-#else
-	if (adap->id == I2C_HW_B_BT848)
-		return i2c_probe(adap, &addr_data, tda9875_attach);
-#endif
 	return 0;
 }
 
@@ -373,7 +368,7 @@
 
 static struct i2c_driver driver = {
 	.driver = {
-		.name   = "i2c tda9875 driver",
+		.name   = "tda9875",
 	},
 	.id             = I2C_DRIVERID_TDA9875,
 	.attach_adapter = tda9875_probe,
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 7165a1b..9cf47dc 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 
 
@@ -57,7 +57,6 @@
 	v4l2_std_id        std;
 	enum tuner_mode    mode;
 	unsigned int       config;
-	unsigned int       pinnacle_id;
 	unsigned int       using_v4l2;
 	unsigned int 	   radio_mode;
 	unsigned char 	   data[4];
@@ -115,6 +114,9 @@
 #define cAudioGain0             0x00    // bit c7
 #define cAudioGain6             0x80    // bit c7
 
+#define cTopMask                0x1f    // bit c0:4
+#define cTopPalSecamDefault	0x14 	// bit c0:4
+#define cTopNtscRadioDefault 	0x10 	// bit c0:4
 
 //// third reg (e)
 #define cAudioIF_4_5             0x00    // bit e0:1
@@ -146,13 +148,15 @@
 
 static struct tvnorm tvnorms[] = {
 	{
-		.std   = V4L2_STD_PAL_BG,
-		.name  = "PAL-BG",
+		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
+		.name  = "PAL-BGHN",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_5_5   |
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_5_5   |
 			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_PAL_I,
@@ -160,8 +164,10 @@
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_0   |
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_0   |
 			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_PAL_DK,
@@ -169,52 +175,80 @@
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_5   |
-			   cVideoIF_38_00 ),
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
 	},{
-		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_N,
-		.name  = "PAL-M/N",
+		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
+		.name  = "PAL-M/Nc",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  ),
-		.e     = ( cAudioIF_4_5   |
+			   cDeemphasis75  |
+			   cTopNtscRadioDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_4_5   |
 			   cVideoIF_45_75 ),
 	},{
+		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+		.name  = "SECAM-BGH",
+		.b     = ( cPositiveAmTV  |
+			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
+		.e     = ( cGating_36	  |
+			   cAudioIF_5_5   |
+			   cVideoIF_38_90 ),
+	},{
 		.std   = V4L2_STD_SECAM_L,
 		.name  = "SECAM-L",
 		.b     = ( cPositiveAmTV  |
 			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
 		.e     = ( cGating_36	  |
 			   cAudioIF_6_5   |
 			   cVideoIF_38_90 ),
 	},{
+		.std   = V4L2_STD_SECAM_LC,
+		.name  = "SECAM-L'",
+		.b     = ( cOutputPort2Inactive |
+			   cPositiveAmTV  |
+			   cQSS           ),
+		.c     = ( cTopPalSecamDefault),
+		.e     = ( cGating_36	  |
+			   cAudioIF_6_5   |
+			   cVideoIF_33_90 ),
+	},{
 		.std   = V4L2_STD_SECAM_DK,
 		.name  = "SECAM-DK",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
-		.e     = ( cAudioIF_6_5   |
-			   cVideoIF_38_00 ),
+			   cDeemphasis50  |
+			   cTopPalSecamDefault),
+		.e     = ( cGating_36     |
+			   cAudioIF_6_5   |
+			   cVideoIF_38_90 ),
 	},{
 		.std   = V4L2_STD_NTSC_M,
 		.name  = "NTSC-M",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis75  ),
+			   cDeemphasis75  |
+			   cTopNtscRadioDefault),
 		.e     = ( cGating_36     |
 			   cAudioIF_4_5   |
 			   cVideoIF_45_75 ),
 	},{
 		.std   = V4L2_STD_NTSC_M_JP,
-		.name  = "NTSC-JP",
+		.name  = "NTSC-M-JP",
 		.b     = ( cNegativeFmTV  |
 			   cQSS           ),
 		.c     = ( cDeemphasisON  |
-			   cDeemphasis50  ),
+			   cDeemphasis50  |
+			   cTopNtscRadioDefault),
 		.e     = ( cGating_36     |
 			   cAudioIF_4_5   |
 			   cVideoIF_58_75 ),
@@ -226,8 +260,10 @@
 	.b    = ( cFmRadio       |
 		  cQSS           ),
 	.c    = ( cDeemphasisOFF |
-		  cAudioGain6 ),
-	.e    = ( cAudioIF_5_5   |
+		  cAudioGain6    |
+		  cTopNtscRadioDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
 		  cRadioIF_38_90 ),
 };
 
@@ -236,8 +272,10 @@
 	.b    = ( cFmRadio       |
 		  cQSS           ),
 	.c    = ( cDeemphasisON  |
-		  cDeemphasis50),
-	.e    = ( cAudioIF_5_5   |
+		  cDeemphasis75  |
+		  cTopNtscRadioDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
 		  cRadioIF_38_90 ),
 };
 
@@ -400,7 +438,8 @@
 static unsigned int port1  = UNSET;
 static unsigned int port2  = UNSET;
 static unsigned int qss    = UNSET;
-static unsigned int adjust = 0x10;
+static unsigned int adjust = UNSET;
+
 module_param(port1, int, 0644);
 module_param(port2, int, 0644);
 module_param(qss, int, 0644);
@@ -428,8 +467,10 @@
 			buf[1] &= ~cQSS;
 	}
 
-	if (adjust >= 0x00 && adjust < 0x20)
+	if (adjust >= 0x00 && adjust < 0x20) {
+		buf[2] &= ~cTopMask;
 		buf[2] |= adjust;
+	}
 	return 0;
 }
 
@@ -465,6 +506,10 @@
 			break;
 		}
 	}
+	if (t->config & TDA9887_TOP_SET) {
+		buf[2] &= ~cTopMask;
+		buf[2] |= (t->config >> 8) & cTopMask;
+	}
 	if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
 		buf[1] &= ~cQSS;
 	return 0;
@@ -472,38 +517,13 @@
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
-{
-	unsigned int bCarrierMode = UNSET;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
 
-	if (t->std & V4L2_STD_625_50) {
-		if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) {
-			bCarrierMode = cIntercarrier;
-		} else {
-			bCarrierMode = cQSS;
-		}
-	}
-	if (t->std & V4L2_STD_525_60) {
-		if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
-			bCarrierMode = cIntercarrier;
-		} else {
-			bCarrierMode = cQSS;
-		}
-	}
-
-	if (bCarrierMode != UNSET) {
-		buf[1] &= ~0x04;
-		buf[1] |= bCarrierMode;
-	}
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static char pal[] = "-";
 module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
 module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 
 static int tda9887_fixup_std(struct tda9887 *t)
 {
@@ -514,8 +534,17 @@
 		case 'B':
 		case 'g':
 		case 'G':
-			tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
-			t->std = V4L2_STD_PAL_BG;
+		case 'h':
+		case 'H':
+		case 'n':
+		case 'N':
+			if (pal[1] == 'c' || pal[1] == 'C') {
+				tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
+				t->std = V4L2_STD_PAL_Nc;
+			} else {
+				tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
+				t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
+			}
 			break;
 		case 'i':
 		case 'I':
@@ -529,6 +558,11 @@
 			tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
 			t->std = V4L2_STD_PAL_DK;
 			break;
+		case 'm':
+		case 'M':
+			tda9887_dbg("insmod fixup: PAL => PAL-M\n");
+			t->std = V4L2_STD_PAL_M;
+			break;
 		case '-':
 			/* default parameter, do nothing */
 			break;
@@ -539,6 +573,15 @@
 	}
 	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
 		switch (secam[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+			break;
 		case 'd':
 		case 'D':
 		case 'k':
@@ -548,8 +591,13 @@
 			break;
 		case 'l':
 		case 'L':
-			tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
-			t->std = V4L2_STD_SECAM_L;
+			if (secam[1] == 'c' || secam[1] == 'C') {
+				tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
+				t->std = V4L2_STD_SECAM_LC;
+			} else {
+				tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
+				t->std = V4L2_STD_SECAM_L;
+			}
 			break;
 		case '-':
 			/* default parameter, do nothing */
@@ -559,6 +607,26 @@
 			break;
 		}
 	}
+	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+		switch (ntsc[0]) {
+		case 'm':
+		case 'M':
+			tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
+			t->std = V4L2_STD_NTSC_M;
+			break;
+		case 'j':
+		case 'J':
+			tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+			t->std = V4L2_STD_NTSC_M_JP;
+			break;
+		case '-':
+			/* default parameter, do nothing */
+			break;
+		default:
+			tda9887_info("ntsc= argument not recognised\n");
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -581,12 +649,22 @@
 	memset(t->data,0,sizeof(t->data));
 	tda9887_set_tvnorm(t,t->data);
 
+	/* A note on the port settings:
+	   These settings tend to depend on the specifics of the board.
+	   By default they are set to inactive (bit value 1) by this driver,
+	   overwriting any changes made by the tvnorm. This means that it
+	   is the responsibility of the module using the tda9887 to set
+	   these values in case of changes in the tvnorm.
+	   In many cases port 2 should be made active (0) when selecting
+	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
+
+	   For the other standards the tda9887 application note says that
+	   the ports should be set to active (0), but, again, that may
+	   differ depending on the precise hardware configuration.
+	 */
 	t->data[1] |= cOutputPort1Inactive;
 	t->data[1] |= cOutputPort2Inactive;
 
-	if (UNSET != t->pinnacle_id) {
-		tda9887_set_pinnacle(t,t->data);
-	}
 	tda9887_set_config(t,t->data);
 	tda9887_set_insmod(t,t->data);
 
@@ -594,7 +672,6 @@
 		t->data[1] |= cForcedMuteAudioON;
 	}
 
-
 	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
 		t->data[1],t->data[2],t->data[3]);
 	if (debug > 1)
@@ -625,7 +702,6 @@
 
 	t->client      = client_template;
 	t->std         = 0;
-	t->pinnacle_id = UNSET;
 	t->radio_mode = V4L2_TUNER_MODE_STEREO;
 
 	tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
@@ -638,18 +714,8 @@
 
 static int tda9887_probe(struct i2c_adapter *adap)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda9887_attach);
-#else
-	switch (adap->id) {
-	case I2C_HW_B_BT848:
-	case I2C_HW_B_RIVA:
-	case I2C_HW_SAA7134:
-		return i2c_probe(adap, &addr_data, tda9887_attach);
-		break;
-	}
-#endif
 	return 0;
 }
 
@@ -689,14 +755,6 @@
 		tda9887_configure(t);
 		break;
 	}
-	case AUDC_CONFIG_PINNACLE:
-	{
-		int *i = arg;
-
-		t->pinnacle_id = *i;
-		tda9887_configure(t);
-		break;
-	}
 	case TDA9887_SET_CONFIG:
 	{
 		int *i = arg;
@@ -787,7 +845,7 @@
 	}
 	case VIDIOC_LOG_STATUS:
 	{
-		tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+		tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
 		break;
 	}
 	default:
@@ -824,7 +882,7 @@
 	.detach_client  = tda9887_detach,
 	.command        = tda9887_command,
 	.driver = {
-		.name    = "i2c tda9887 driver",
+		.name    = "tda9887",
 		.suspend = tda9887_suspend,
 		.resume  = tda9887_resume,
 	},
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index a9375ef..261b7a3 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -17,6 +17,9 @@
 
 #define PREFIX "TEA5767 "
 
+/* from tuner-core.c */
+extern int debug;
+
 /*****************************************************************************/
 
 /******************************
@@ -246,7 +249,7 @@
 	if (5 != (rc = i2c_master_send(c, buffer, 5)))
 		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 
-	if (tuner_debug) {
+	if (debug) {
 		if (5 != (rc = i2c_master_recv(c, buffer, 5)))
 			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 		else
@@ -264,7 +267,7 @@
 	if (5 != (rc = i2c_master_recv(c, buffer, 5)))
 		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 
-	return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4));
+	return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
 }
 
 static int tea5767_stereo(struct i2c_client *c)
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index c13c7b9..57bc585 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -20,10 +20,9 @@
 #include <linux/init.h>
 
 #include <media/tuner.h>
+#include <media/v4l2-common.h>
 #include <media/audiochip.h>
 
-#include "msp3400.h"
-
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
@@ -38,21 +37,30 @@
 
 /* insmod options used at init time => read/only */
 static unsigned int addr = 0;
-module_param(addr, int, 0444);
-
 static unsigned int no_autodetect = 0;
-module_param(no_autodetect, int, 0444);
-
 static unsigned int show_i2c = 0;
-module_param(show_i2c, int, 0444);
 
 /* insmod options used at runtime => read/write */
-unsigned int tuner_debug = 0;
-module_param(tuner_debug, int, 0644);
+static unsigned int tuner_debug = 0;
+int debug = 0;
 
 static unsigned int tv_range[2] = { 44, 958 };
 static unsigned int radio_range[2] = { 65, 108 };
 
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+module_param(addr, int, 0444);
+module_param(no_autodetect, int, 0444);
+module_param(show_i2c, int, 0444);
+/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */
+module_param(tuner_debug, int, 0444);
+module_param(debug, int, 0644);
+
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_array(tv_range, int, NULL, 0644);
 module_param_array(radio_range, int, NULL, 0644);
 
@@ -249,11 +257,6 @@
 	return 0;
 }
 
-static char pal[] = "-";
-module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "--";
-module_param_string(secam, secam, sizeof(secam), 0644);
-
 /* get more precise norm info from insmod option */
 static int tuner_fixup_std(struct tuner *t)
 {
@@ -285,8 +288,13 @@
 			break;
 		case 'N':
 		case 'n':
-			tuner_dbg ("insmod fixup: PAL => PAL-N\n");
-			t->std = V4L2_STD_PAL_N;
+			if (pal[1] == 'c' || pal[1] == 'C') {
+				tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
+				t->std = V4L2_STD_PAL_Nc;
+			} else {
+				tuner_dbg ("insmod fixup: PAL => PAL-N\n");
+				t->std = V4L2_STD_PAL_N;
+			}
 			break;
 		case '-':
 			/* default parameter, do nothing */
@@ -298,6 +306,15 @@
 	}
 	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
 		switch (secam[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
+			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+			break;
 		case 'd':
 		case 'D':
 		case 'k':
@@ -324,9 +341,60 @@
 		}
 	}
 
+	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+		switch (ntsc[0]) {
+		case 'm':
+		case 'M':
+			tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
+			t->std = V4L2_STD_NTSC_M;
+			break;
+		case 'j':
+		case 'J':
+			tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
+			t->std = V4L2_STD_NTSC_M_JP;
+			break;
+		case '-':
+			/* default parameter, do nothing */
+			break;
+		default:
+			tuner_info("ntsc= argument not recognised\n");
+			break;
+		}
+	}
 	return 0;
 }
 
+static void tuner_status(struct i2c_client *client)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+	unsigned long freq, freq_fraction;
+	const char *p;
+
+	switch (t->mode) {
+		case V4L2_TUNER_RADIO: 	    p = "radio"; break;
+		case V4L2_TUNER_ANALOG_TV:  p = "analog TV"; break;
+		case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
+		default: p = "undefined"; break;
+	}
+	if (t->mode == V4L2_TUNER_RADIO) {
+		freq = t->freq / 16000;
+		freq_fraction = (t->freq % 16000) * 100 / 16000;
+	} else {
+		freq = t->freq / 16;
+		freq_fraction = (t->freq % 16) * 100 / 16;
+	}
+	tuner_info("Tuner mode:      %s\n", p);
+	tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
+	tuner_info("Standard:        0x%08llx\n", t->std);
+	if (t->mode == V4L2_TUNER_RADIO) {
+		if (t->has_signal) {
+			tuner_info("Signal strength: %d\n", t->has_signal(client));
+		}
+		if (t->is_stereo) {
+			tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
+		}
+	}
+}
 /* ---------------------------------------------------------------------- */
 
 /* static var Used only in tuner_attach and tuner_probe */
@@ -352,6 +420,11 @@
 	t->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
 	t->audmode = V4L2_TUNER_MODE_STEREO;
 	t->mode_mask = T_UNINITIALIZED;
+	if (tuner_debug) {
+		debug = tuner_debug;
+		printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
+		printk(KERN_ERR "tuner: use the debug option instead.\n");
+	}
 
 	if (show_i2c) {
 		unsigned char buffer[16];
@@ -478,7 +551,9 @@
 static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tuner *t = i2c_get_clientdata(client);
-	unsigned int *iarg = (int *)arg;
+
+	if (debug>1)
+		v4l_i2c_print_ioctl(&(t->i2c),cmd);
 
 	switch (cmd) {
 	/* --- configuration --- */
@@ -501,18 +576,6 @@
 				t->standby (client);
 			break;
 		}
-	case AUDC_CONFIG_PINNACLE:
-		switch (*iarg) {
-		case 2:
-			tuner_dbg("pinnacle pal\n");
-			t->radio_if2 = 33300 * 1000;
-			break;
-		case 3:
-			tuner_dbg("pinnacle ntsc\n");
-			t->radio_if2 = 41300 * 1000;
-			break;
-		}
-		break;
 	case VIDIOCSAUDIO:
 		if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
 			return 0;
@@ -523,9 +586,6 @@
 		tuner_dbg("VIDIOCSAUDIO not implemented.\n");
 
 		break;
-	case MSP_SET_MATRIX:
-	case TDA9887_SET_CONFIG:
-		break;
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
@@ -708,10 +768,8 @@
 			}
 			break;
 		}
-	default:
-		tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
-					 cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
-					_IOC_NR(cmd), _IOC_SIZE(cmd));
+	case VIDIOC_LOG_STATUS:
+		tuner_status(client);
 		break;
 	}
 
@@ -747,10 +805,10 @@
 	.detach_client = tuner_detach,
 	.command = tuner_command,
 	.driver = {
-		   .name = "tuner",
-		   .suspend = tuner_suspend,
-		   .resume = tuner_resume,
-		   },
+		.name    = "tuner",
+		.suspend = tuner_suspend,
+		.resume  = tuner_resume,
+	},
 };
 static struct i2c_client client_template = {
 	.name = "(tuner unset)",
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index e0c9fdb..e5fb743 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -8,6 +8,10 @@
 #include <linux/videodev.h>
 #include <media/tuner.h>
 
+static int offset = 0;
+module_param(offset, int, 0666);
+MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+
 /* ---------------------------------------------------------------------- */
 
 /* tv standard selection for Temic 4046 FM5
@@ -75,24 +79,20 @@
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
+#define TUNER_MAX_RANGES   3
+
 /* ---------------------------------------------------------------------- */
 
 struct tunertype
 {
 	char *name;
-	unsigned char Vendor;
-	unsigned char Type;
 
-	unsigned short thresh1;  /*  band switch VHF_LO <=> VHF_HI  */
-	unsigned short thresh2;  /*  band switch VHF_HI <=> UHF     */
-	unsigned char VHF_L;
-	unsigned char VHF_H;
-	unsigned char UHF;
+	int count;
+	struct {
+		unsigned short thresh;
+		unsigned char cb;
+	} ranges[TUNER_MAX_RANGES];
 	unsigned char config;
-	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL,
-				   732  =16*45.75 NTSCi,
-				   940  =16*58.75 NTSC-Japan
-				   704  =16*44    ATSC */
 };
 
 /*
@@ -102,158 +102,696 @@
  */
 static struct tunertype tuners[] = {
 	/* 0-9 */
-	{ "Temic PAL (4002 FH5)", TEMIC, PAL,
-	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
-	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
-	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
-	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
-	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
-	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
-	{ "NoTuner", NoTuner, NOTUNER,
-	  0,0,0x00,0x00,0x00,0x00,0x00},
-	{ "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
-	  16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
-	{ "Temic NTSC (4032 FY5)", TEMIC, NTSC,
-	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
-	{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
-	  16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
-	{ "Temic NTSC (4036 FY5)", TEMIC, NTSC,
-	  16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
-	{ "Alps HSBH1", TEMIC, NTSC,
-	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
+	[TUNER_TEMIC_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL (4002 FH5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 140.25 /*MHz*/, 0x02, },
+			{ 16 * 463.25 /*MHz*/, 0x04, },
+			{ 16 * 999.99        , 0x01, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
+		.name   = "Philips PAL_I (FI1246 and compatibles)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 140.25 /*MHz*/, 0xa0, },
+			{ 16 * 463.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
+		.name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0xa0, },
+			{ 16 * 451.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
+		.name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 168.25 /*MHz*/, 0xa7, },
+			{ 16 * 447.25 /*MHz*/, 0x97, },
+			{ 16 * 999.99        , 0x37, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ABSENT] = { /* Tuner Absent */
+		.name   = "NoTuner",
+		.count  = 1,
+		.ranges = {
+			{ 0, 0x00, },
+		},
+		.config = 0x00,
+	},
+	[TUNER_PHILIPS_PAL] = { /* Philips PAL */
+		.name   = "Philips PAL_BG (FI1216 and compatibles)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 168.25 /*MHz*/, 0xa0, },
+			{ 16 * 447.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4032 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0x02, },
+			{ 16 * 463.25 /*MHz*/, 0x04, },
+			{ 16 * 999.99        , 0x01, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
+		.name   = "Temic PAL_I (4062 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0x02, },
+			{ 16 * 450.00 /*MHz*/, 0x04, },
+			{ 16 * 999.99        , 0x01, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4036 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0xa0, },
+			{ 16 * 463.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
+		.name   = "Alps HSBH1",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 137.25 /*MHz*/, 0x01, },
+			{ 16 * 385.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 10-19 */
-	{ "Alps TSBE1", TEMIC, PAL,
-	  16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-	{ "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
-	{ "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
-	{ "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
-	  16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
-	{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "Alps TSCH6", Alps, NTSC,
-	  16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
-	{ "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
-	  16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC_M (MK2)", Philips, NTSC,
-	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-	{ "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
-	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
-	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+	[TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
+		.name   = "Alps TSBE1",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 137.25 /*MHz*/, 0x01, },
+			{ 16 * 385.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
+		.name   = "Alps TSBB5",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 133.25 /*MHz*/, 0x01, },
+			{ 16 * 351.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
+		.name   = "Alps TSBE5",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 133.25 /*MHz*/, 0x01, },
+			{ 16 * 351.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
+		.name   = "Alps TSBC5",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 133.25 /*MHz*/, 0x01, },
+			{ 16 * 351.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4006FH5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
+		.name   = "Alps TSCH6",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 137.25 /*MHz*/, 0x14, },
+			{ 16 * 385.25 /*MHz*/, 0x12, },
+			{ 16 * 999.99        , 0x11, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
+		.name   = "Temic PAL_DK (4016 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 168.25 /*MHz*/, 0xa0, },
+			{ 16 * 456.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
+		.name   = "Philips NTSC_M (MK2)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
+		.name   = "Temic PAL_I (4066 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 169.00 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL* auto (4006 FN5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 169.00 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 20-29 */
-	{ "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
-	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "Temic NTSC (4039 FR5)", TEMIC, NTSC,
-	  16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-	{ "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
-	  16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
-	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
-	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	[TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 141.00 /*MHz*/, 0xa0, },
+			{ 16 * 464.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4039 FR5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 158.00 /*MHz*/, 0xa0, },
+			{ 16 * 453.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
+		.name   = "Temic PAL/SECAM multi (4046 FM5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 169.00 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
+		.name   = "Philips PAL_DK (FI1256 and compatibles)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FQ1216ME)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
+		.name   = "LG PAL_I+FM (TAPC-I001D)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
+		.name   = "LG PAL_I (TAPC-I701D)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC+FM (TPI8NSR01F)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 210.00 /*MHz*/, 0xa0, },
+			{ 16 * 497.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL_BG+FM (TPI8PSB01D)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_PAL] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL_BG (TPI8PSB11D)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0xa0, },
+			{ 16 * 450.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 30-39 */
-	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
-	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
-	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
-	{ "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
-	  16*169,16*464,0xA0,0x90,0x30,0x8e,623},
-	{ "MT20xx universal", Microtune, PAL|NTSC,
+	[TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
+		.name   = "Temic PAL* auto + FM (4009 FN5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 141.00 /*MHz*/, 0xa0, },
+			{ 16 * 464.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
+		.name   = "SHARP NTSC_JP (2U5JF5540)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 137.25 /*MHz*/, 0x01, },
+			{ 16 * 317.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
+		.name   = "Samsung PAL TCPM9091PD27",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 169 /*MHz*/, 0xa0, },
+			{ 16 * 464 /*MHz*/, 0x90, },
+			{ 16 * 999.99     , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_MT2032] = { /* Microtune PAL|NTSC */
+		.name   = "MT20xx universal",
 	  /* see mt20xx.c for details */ },
-	{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
-	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-	{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
-	  16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
-	{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
-	  16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-	{ "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
-	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
-	{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
-	  16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
-	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
-	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+	[TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
+		.name   = "Temic PAL_BG (4106 FH5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 141.00 /*MHz*/, 0xa0, },
+			{ 16 * 464.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
+		.name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 140.25 /*MHz*/, 0x02, },
+			{ 16 * 463.25 /*MHz*/, 0x04, },
+			{ 16 * 999.99        , 0x01, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
+		.name   = "Temic NTSC (4136 FY5)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 158.00 /*MHz*/, 0xa0, },
+			{ 16 * 453.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
+		.name   = "LG PAL (newer TAPC series)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0x01, },
+			{ 16 * 450.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 158.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC (newer TAPC series)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0x01, },
+			{ 16 * 450.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 40-49 */
-	{ "HITACHI V7-J180AT", HITACHI, NTSC,
-	  16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 },
-	{ "Philips PAL_MK (FI1216 MK)", Philips, PAL,
-	  16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
-	{ "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
-	  16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
-	{ "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-	{ "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-	{ "Microtune 4049 FM5", Microtune, PAL,
-	  16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
-	{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
-	  16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
-	{ "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-	{ "Tenna TNF 8831 BGFF)", Philips, PAL,
-	  16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
-	  16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
+	[TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
+		.name   = "HITACHI V7-J180AT",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0x01, },
+			{ 16 * 450.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
+		.name   = "Philips PAL_MK (FI1216 MK)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 140.25 /*MHz*/, 0x01, },
+			{ 16 * 463.25 /*MHz*/, 0xc2, },
+			{ 16 * 999.99        , 0xcf, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
+		.name   = "Philips 1236D ATSC/NTSC dual in",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
+		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
+		.name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
+		.name   = "Microtune 4049 FM5",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 141.00 /*MHz*/, 0xa0, },
+			{ 16 * 464.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
+		.name   = "Panasonic VP27s/ENGE4324D",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 454.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0xce,
+	},
+	[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC (TAPE series)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TNF_8831BGFF] = { /* Philips PAL */
+		.name   = "Tenna TNF 8831 BGFF)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 161.25 /*MHz*/, 0xa0, },
+			{ 16 * 463.25 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
+		.name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 162.00 /*MHz*/, 0xa2, },
+			{ 16 * 457.00 /*MHz*/, 0x94, },
+			{ 16 * 999.99        , 0x31, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 50-59 */
-	{ "TCL 2002N", TCL, NTSC,
-	  16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
-	{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
-	{ "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
-	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
-	{ "Philips FQ1286", Philips, NTSC,
-	  16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
-	{ "tda8290+75", Philips, PAL|NTSC,
+	[TUNER_TCL_2002N] = { /* TCL NTSC */
+		.name   = "TCL 2002N",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 172.00 /*MHz*/, 0x01, },
+			{ 16 * 448.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
+		.name   = "Thomson DTT 7610 (ATSC/NTSC)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0x39, },
+			{ 16 * 454.00 /*MHz*/, 0x3a, },
+			{ 16 * 999.99        , 0x3c, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
+		.name   = "Philips FQ1286",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x41, },
+			{ 16 * 454.00 /*MHz*/, 0x42, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
+		.name   = "tda8290+75",
 	  /* see tda8290.c for details */ },
-	{ "TCL 2002MB", TCL, PAL,
-	  16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
-	{ "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
-	{ "Philips FQ1236A MK4", Philips, NTSC,
-	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-	{ "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC,
-	  16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-	{ "Ymec TVision TVF-5533MF", Philips, NTSC,
-	  16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
+	[TUNER_TCL_2002MB] = { /* TCL PAL */
+		.name   = "TCL 2002MB",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 170.00 /*MHz*/, 0x01, },
+			{ 16 * 450.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0xce,
+	},
+	[TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0xce,
+	},
+	[TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
+		.name   = "Philips FQ1236A MK4",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 442.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
+		.name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0xa0, },
+			{ 16 * 454.00 /*MHz*/, 0x90, },
+			{ 16 * 999.99        , 0x30, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
+		.name   = "Ymec TVision TVF-5533MF",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01, },
+			{ 16 * 454.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
 
 	/* 60-69 */
-	{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
-	  16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
-	{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
-	  16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
-	{ "Philips TEA5767HN FM Radio", Philips, RADIO,
+	[TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
+		/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+		.name   = "Thomson DTT 761X (ATSC/NTSC)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 145.25 /*MHz*/, 0x39, },
+			{ 16 * 415.25 /*MHz*/, 0x3a, },
+			{ 16 * 999.99        , 0x3c, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TENA_9533_DI] = { /* Philips PAL */
+		.name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.25 /*MHz*/, 0x01, },
+			{ 16 * 464.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_TEA5767] = { /* Philips RADIO */
+		.name   = "Philips TEA5767HN FM Radio",
 	  /* see tea5767.c for details */},
-	{ "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
-	  16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
-	{ "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
-	  16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
-	{ "Ymec TVF66T5-B/DFF", Philips, PAL,
-	  16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
-	{ "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
-	  16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
-	{ "Philips TD1316 Hybrid Tuner", Philips, PAL,
-	  16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
-	{ "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
-	  16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
-	{ "Tena TNF 5335 MF", Philips, NTSC,
-	  16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
+	[TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
+		.name   = "Philips FMD1216ME MK3 Hybrid Tuner",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x51, },
+			{ 16 * 442.00 /*MHz*/, 0x52, },
+			{ 16 * 999.99        , 0x54, },
+		},
+		.config = 0x86,
+	},
+	[TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
+		.name   = "LG TDVS-H062F/TUA6034",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0x01 },
+			{ 16 * 455.00 /*MHz*/, 0x02 },
+			{ 16 * 999.99        , 0x04 },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
+		.name   = "Ymec TVF66T5-B/DFF",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.25 /*MHz*/, 0x01, },
+			{ 16 * 464.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
+		.name   = "LG NTSC (TALN mini series)",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 137.25 /*MHz*/, 0x01, },
+			{ 16 * 373.25 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x08, },
+		},
+		.config = 0x8e,
+	},
+	[TUNER_PHILIPS_TD1316] = { /* Philips PAL */
+		.name   = "Philips TD1316 Hybrid Tuner",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 160.00 /*MHz*/, 0xa1, },
+			{ 16 * 442.00 /*MHz*/, 0xa2, },
+			{ 16 * 999.99        , 0xa4, },
+		},
+		.config = 0xc8,
+	},
+	[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
+		.name   = "Philips TUV1236D ATSC/NTSC dual in",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0x01, },
+			{ 16 * 454.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0xce,
+	},
+	[TUNER_TNF_5335MF] = { /* Philips NTSC */
+		.name   = "Tena TNF 5335 MF",
+		.count  = 3,
+		.ranges = {
+			{ 16 * 157.25 /*MHz*/, 0x01, },
+			{ 16 * 454.00 /*MHz*/, 0x02, },
+			{ 16 * 999.99        , 0x04, },
+		},
+		.config = 0x8e,
+	},
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -305,20 +843,19 @@
 	u16 div;
 	struct tunertype *tun;
 	unsigned char buffer[4];
-	int rc;
+	int rc, IFPCoff, i;
 
 	tun = &tuners[t->type];
-	if (freq < tun->thresh1) {
-		config = tun->VHF_L;
-		tuner_dbg("tv: VHF lowrange\n");
-	} else if (freq < tun->thresh2) {
-		config = tun->VHF_H;
-		tuner_dbg("tv: VHF high range\n");
-	} else {
-		config = tun->UHF;
-		tuner_dbg("tv: UHF range\n");
+	for (i = 0; i < tun->count; i++) {
+		if (freq > tun->ranges[i].thresh)
+			continue;
+		break;
 	}
-
+	config = tun->ranges[i].cb;
+	/*  i == 0 -> VHF_LO  */
+	/*  i == 1 -> VHF_HI  */
+	/*  i == 2 -> UHF     */
+	tuner_dbg("tv: range %d\n",i);
 
 	/* tv norm specific stuff for multi-norm tuners */
 	switch (t->type) {
@@ -420,7 +957,37 @@
 	 * frequency in case (wanted frequency < current frequency).
 	 */
 
-	div=freq + tun->IFPCoff;
+	/* IFPCoff = Video Intermediate Frequency - Vif:
+		940  =16*58.75  NTSC/J (Japan)
+		732  =16*45.75  M/N STD
+		704  =16*44     ATSC (at DVB code)
+		632  =16*39.50  I U.K.
+		622.4=16*38.90  B/G D/K I, L STD
+		592  =16*37.00  D China
+		590  =16.36.875 B Australia
+		543.2=16*33.95  L' STD
+		171.2=16*10.70  FM Radio (at set_radio_freq)
+	*/
+
+	if (t->std == V4L2_STD_NTSC_M_JP) {
+		IFPCoff = 940;
+	} else if ((t->std & V4L2_STD_MN) &&
+		  !(t->std & ~V4L2_STD_MN)) {
+		IFPCoff = 732;
+	} else if (t->std == V4L2_STD_SECAM_LC) {
+		IFPCoff = 543;
+	} else {
+		IFPCoff = 623;
+	}
+
+	div=freq + IFPCoff + offset;
+
+	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
+					freq / 16, freq % 16 * 100 / 16,
+					IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+					offset / 16, offset % 16 * 100 / 16,
+					div);
+
 	if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
 		buffer[0] = tun->config;
 		buffer[1] = config;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 0292c5a..b582943 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,6 +31,7 @@
 #include <linux/smp_lock.h>
 
 #include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 #include "tvaudio.h"
 
@@ -46,17 +47,6 @@
 
 #define UNSET    (-1U)
 
-#define tvaudio_info(fmt, arg...) do {\
-	printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
-			chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_warn(fmt, arg...) do {\
-	printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \
-			chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-#define tvaudio_dbg(fmt, arg...) do {\
-	if (debug) \
-		printk(KERN_INFO "tvaudio %d-%04x: " fmt, \
-			chip->c.adapter->nr, chip->c.addr , ##arg); } while (0)
-
 /* ---------------------------------------------------------------------- */
 /* our structs                                                            */
 
@@ -131,7 +121,7 @@
 	/* current settings */
 	__u16 left,right,treble,bass,mode;
 	int prevmode;
-	int norm;
+	int radio;
 
 	/* thread */
 	pid_t                tpid;
@@ -142,8 +132,6 @@
 	int                  watch_stereo;
 };
 
-#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
-
 /* ---------------------------------------------------------------------- */
 /* i2c addresses                                                          */
 
@@ -171,23 +159,23 @@
 	unsigned char buffer[2];
 
 	if (-1 == subaddr) {
-		tvaudio_dbg("%s: chip_write: 0x%x\n",
+		v4l_dbg(1, &chip->c, "%s: chip_write: 0x%x\n",
 			chip->c.name, val);
 		chip->shadow.bytes[1] = val;
 		buffer[0] = val;
 		if (1 != i2c_master_send(&chip->c,buffer,1)) {
-			tvaudio_warn("%s: I/O error (write 0x%x)\n",
+			v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
 				chip->c.name, val);
 			return -1;
 		}
 	} else {
-		tvaudio_dbg("%s: chip_write: reg%d=0x%x\n",
+		v4l_dbg(1, &chip->c, "%s: chip_write: reg%d=0x%x\n",
 			chip->c.name, subaddr, val);
 		chip->shadow.bytes[subaddr+1] = val;
 		buffer[0] = subaddr;
 		buffer[1] = val;
 		if (2 != i2c_master_send(&chip->c,buffer,2)) {
-			tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n",
+			v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
 			chip->c.name, subaddr, val);
 			return -1;
 		}
@@ -212,11 +200,11 @@
 	unsigned char buffer;
 
 	if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
-		tvaudio_warn("%s: I/O error (read)\n",
+		v4l_warn(&chip->c, "%s: I/O error (read)\n",
 		chip->c.name);
 		return -1;
 	}
-	tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name, buffer);
+	v4l_dbg(1, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
 	return buffer;
 }
 
@@ -231,10 +219,10 @@
 	write[0] = subaddr;
 
 	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
-		tvaudio_warn("%s: I/O error (read2)\n", chip->c.name);
+		v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
 		return -1;
 	}
-	tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n",
+	v4l_dbg(1, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
 		chip->c.name, subaddr,read[0]);
 	return read[0];
 }
@@ -247,7 +235,7 @@
 		return 0;
 
 	/* update our shadow register set; print bytes if (debug > 0) */
-	tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:",
+	v4l_dbg(1, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
 		chip->c.name, name,cmd->bytes[0]);
 	for (i = 1; i < cmd->count; i++) {
 		if (debug)
@@ -259,7 +247,7 @@
 
 	/* send data to the chip */
 	if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-		tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name);
+		v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
 		return -1;
 	}
 	return 0;
@@ -286,7 +274,7 @@
 
 	daemonize("%s", chip->c.name);
 	allow_signal(SIGTERM);
-	tvaudio_dbg("%s: thread started\n", chip->c.name);
+	v4l_dbg(1, &chip->c, "%s: thread started\n", chip->c.name);
 
 	for (;;) {
 		add_wait_queue(&chip->wq, &wait);
@@ -298,10 +286,10 @@
 		try_to_freeze();
 		if (chip->done || signal_pending(current))
 			break;
-		tvaudio_dbg("%s: thread wakeup\n", chip->c.name);
+		v4l_dbg(1, &chip->c, "%s: thread wakeup\n", chip->c.name);
 
 		/* don't do anything for radio or if mode != auto */
-		if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0)
+		if (chip->radio || chip->mode != 0)
 			continue;
 
 		/* have a look what's going on */
@@ -311,7 +299,7 @@
 		mod_timer(&chip->wt, jiffies+2*HZ);
 	}
 
-	tvaudio_dbg("%s: thread exiting\n", chip->c.name);
+	v4l_dbg(1, &chip->c, "%s: thread exiting\n", chip->c.name);
 	complete_and_exit(&chip->texit, 0);
 	return 0;
 }
@@ -324,7 +312,7 @@
 	if (mode == chip->prevmode)
 	return;
 
-	tvaudio_dbg("%s: thread checkmode\n", chip->c.name);
+	v4l_dbg(1, &chip->c, "%s: thread checkmode\n", chip->c.name);
 	chip->prevmode = mode;
 
 	if (mode & VIDEO_SOUND_STEREO)
@@ -371,7 +359,7 @@
 	if (val & TDA9840_ST_STEREO)
 		mode |= VIDEO_SOUND_STEREO;
 
-	tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n",
+	v4l_dbg(1, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
 	return mode;
 }
@@ -667,7 +655,7 @@
 		mode |= VIDEO_SOUND_STEREO;
 	if (val & TDA9873_DUAL)
 		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n",
+	v4l_dbg(1, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
 	return mode;
 }
@@ -678,12 +666,12 @@
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-		tvaudio_dbg("tda9873_setmode(): external input\n");
+		v4l_dbg(1, &chip->c, "tda9873_setmode(): external input\n");
 		return;
 	}
 
-	tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-	tvaudio_dbg("tda9873_setmode(): sw_data  = %d\n", sw_data);
+	v4l_dbg(1, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+	v4l_dbg(1, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
 
 	switch (mode) {
 	case VIDEO_SOUND_MONO:
@@ -704,7 +692,7 @@
 	}
 
 	chip_write(chip, TDA9873_SW, sw_data);
-	tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n",
+	v4l_dbg(1, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
 		mode, sw_data);
 }
 
@@ -843,7 +831,7 @@
 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
 		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
 	}
-	tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n",
+	v4l_dbg(1, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
 		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
 	return 1;
 }
@@ -886,7 +874,7 @@
 			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
 	}
 
-	tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+	v4l_dbg(1, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
 		 dsr, nsr, necr, mode);
 	return mode;
 }
@@ -932,7 +920,7 @@
 		chip_write(chip, TDA9874A_AOSR, aosr);
 		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-		tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+		v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
 			mode, aosr, mdacosr);
 
 	} else { /* dic == 0x07 */
@@ -967,7 +955,7 @@
 		chip_write(chip, TDA9874A_FMMR, fmmr);
 		chip_write(chip, TDA9874A_AOSR, aosr);
 
-		tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+		v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
 			mode, fmmr, aosr);
 	}
 }
@@ -981,10 +969,10 @@
 	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
 		return 0;
 
-	tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+	v4l_dbg(1, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
 	if((dic == 0x11)||(dic == 0x07)) {
-		tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+		v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
 		tda9874a_dic = dic;	/* remember device id. */
 		return 1;
 	}
@@ -1196,7 +1184,7 @@
 	}else if (!(val & TA8874Z_B0)){
 		mode |= VIDEO_SOUND_STEREO;
 	}
-	/* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+	/* v4l_dbg(1, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
 	return mode;
 }
 
@@ -1209,7 +1197,7 @@
 {
 	int update = 1;
 	audiocmd *t = NULL;
-	tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode);
+	v4l_dbg(1, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
 
 	switch(mode){
 	case VIDEO_SOUND_MONO:
@@ -1490,7 +1478,7 @@
 	i2c_set_clientdata(&chip->c, chip);
 
 	/* find description for the chip */
-	tvaudio_dbg("chip found @ 0x%x\n", addr<<1);
+	v4l_dbg(1, &chip->c, "chip found @ 0x%x\n", addr<<1);
 	for (desc = chiplist; desc->name != NULL; desc++) {
 		if (0 == *(desc->insmodopt))
 			continue;
@@ -1502,12 +1490,12 @@
 		break;
 	}
 	if (desc->name == NULL) {
-		tvaudio_dbg("no matching chip description found\n");
+		v4l_dbg(1, &chip->c, "no matching chip description found\n");
 		return -EIO;
 	}
-	tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
+	v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
 	if (desc->flags) {
-		tvaudio_dbg("matches:%s%s%s.\n",
+		v4l_dbg(1, &chip->c, "matches:%s%s%s.\n",
 			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
 			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
 			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
@@ -1550,7 +1538,7 @@
 		init_completion(&chip->texit);
 		chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
 		if (chip->tpid < 0)
-			tvaudio_warn("%s: kernel_thread() failed\n",
+			v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
 			       chip->c.name);
 		wake_up_interruptible(&chip->wq);
 	}
@@ -1563,17 +1551,8 @@
 	   because dedicated drivers are used */
 	if ((adap->id == I2C_HW_SAA7146))
 		return 0;
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adap->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, chip_attach);
-#else
-	switch (adap->id) {
-	case I2C_HW_B_BT848:
-	case I2C_HW_B_RIVA:
-	case I2C_HW_SAA7134:
-		return i2c_probe(adap, &addr_data, chip_attach);
-	}
-#endif
 	return 0;
 }
 
@@ -1604,7 +1583,7 @@
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	tvaudio_dbg("%s: chip_command 0x%x\n", chip->c.name, cmd);
+	v4l_dbg(1, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
 
 	switch (cmd) {
 	case AUDC_SET_INPUT:
@@ -1617,7 +1596,7 @@
 		break;
 
 	case AUDC_SET_RADIO:
-		chip->norm = VIDEO_MODE_RADIO;
+		chip->radio = 1;
 		chip->watch_stereo = 0;
 		/* del_timer(&chip->wt); */
 		break;
@@ -1643,7 +1622,7 @@
 			va->bass   = chip->bass;
 			va->treble = chip->treble;
 		}
-		if (chip->norm != VIDEO_MODE_RADIO) {
+		if (!chip->radio) {
 			if (desc->getmode)
 				va->mode = desc->getmode(chip);
 			else
@@ -1678,15 +1657,80 @@
 		}
 		break;
 	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *vc = arg;
 
-		chip->norm = vc->norm;
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *vt = arg;
+		int mode = 0;
+
+		switch (vt->audmode) {
+		case V4L2_TUNER_MODE_MONO:
+			mode = VIDEO_SOUND_MONO;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			mode = VIDEO_SOUND_STEREO;
+			break;
+		case V4L2_TUNER_MODE_LANG1:
+			mode = VIDEO_SOUND_LANG1;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			mode = VIDEO_SOUND_LANG2;
+			break;
+		default:
+			break;
+		}
+
+		if (desc->setmode && mode) {
+			chip->watch_stereo = 0;
+			/* del_timer(&chip->wt); */
+			chip->mode = mode;
+			desc->setmode(chip, mode);
+		}
 		break;
 	}
-	case VIDIOCSFREQ:
+
+	case VIDIOC_G_TUNER:
 	{
+		struct v4l2_tuner *vt = arg;
+		int mode = VIDEO_SOUND_MONO;
+
+		if (chip->radio)
+			break;
+		vt->audmode = 0;
+		vt->rxsubchans = 0;
+		vt->capability = V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+		if (desc->getmode)
+			mode = desc->getmode(chip);
+
+		if (mode & VIDEO_SOUND_MONO)
+			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+		if (mode & VIDEO_SOUND_STEREO)
+			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		if (mode & VIDEO_SOUND_LANG1)
+			vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
+					  V4L2_TUNER_SUB_LANG2;
+
+		mode = chip->mode;
+		if (mode & VIDEO_SOUND_MONO)
+			vt->audmode = V4L2_TUNER_MODE_MONO;
+		if (mode & VIDEO_SOUND_STEREO)
+			vt->audmode = V4L2_TUNER_MODE_STEREO;
+		if (mode & VIDEO_SOUND_LANG1)
+			vt->audmode = V4L2_TUNER_MODE_LANG1;
+		if (mode & VIDEO_SOUND_LANG2)
+			vt->audmode = V4L2_TUNER_MODE_LANG2;
+		break;
+	}
+
+	case VIDIOCSCHAN:
+	case VIDIOC_S_STD:
+		chip->radio = 0;
+		break;
+
+	case VIDIOCSFREQ:
+	case VIDIOC_S_FREQUENCY:
 		chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
 			desc->setmode(chip,VIDEO_SOUND_MONO);
@@ -1695,15 +1739,14 @@
 			mod_timer(&chip->wt, jiffies+2*HZ);
 			/* the thread will call checkmode() later */
 		}
-	}
+		break;
 	}
 	return 0;
 }
 
-
 static struct i2c_driver driver = {
 	.driver = {
-		.name    = "generic i2c audio driver",
+		.name    = "tvaudio",
 	},
 	.id              = I2C_DRIVERID_TVAUDIO,
 	.attach_adapter  = chip_probe,
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 8ac4cb8..fd0acc5 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -40,6 +40,7 @@
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
+#include <media/v4l2-common.h>
 #include <media/audiochip.h>
 
 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
@@ -52,21 +53,19 @@
 
 #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
 
-#define tveeprom_info(fmt, arg...) do {\
-	printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-			c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_warn(fmt, arg...) do {\
-	printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
-			c->adapter->nr, c->addr , ##arg); } while (0)
-#define tveeprom_dbg(fmt, arg...) do {\
+#define tveeprom_info(fmt, arg...) \
+	v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_warn(fmt, arg...) \
+	v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
+#define tveeprom_dbg(fmt, arg...) do { \
 	if (debug) \
-		printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-			c->adapter->nr, c->addr , ##arg); } while (0)
+		v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+	} while (0)
 
-
-/* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff                                           */
-
+/*
+ * The Hauppauge eeprom uses an 8bit field to determine which
+ * tuner formats the tuner supports.
+ */
 static struct HAUPPAUGE_TUNER_FMT
 {
 	int	id;
@@ -74,14 +73,14 @@
 }
 hauppauge_tuner_fmt[] =
 {
-	{ 0x00000000, " unknown1" },
-	{ 0x00000000, " unknown2" },
-	{ 0x00000007, " PAL(B/G)" },
-	{ 0x00001000, " NTSC(M)" },
-	{ 0x00000010, " PAL(I)" },
-	{ 0x00400000, " SECAM(L/L')" },
-	{ 0x00000e00, " PAL(D/K)" },
-	{ 0x03000000, " ATSC/DVB Digital" },
+	{ V4L2_STD_UNKNOWN," UNKNOWN" },
+	{ V4L2_STD_UNKNOWN," FM" },
+	{ V4L2_STD_PAL_BG, " PAL(B/G)" },
+	{ V4L2_STD_NTSC_M, " NTSC(M)" },
+	{ V4L2_STD_PAL_I,  " PAL(I)" },
+	{ V4L2_STD_SECAM_L," SECAM(L/L')" },
+	{ V4L2_STD_PAL_DK, " PAL(D/D1/K)" },
+	{ V4L2_STD_ATSC,   " ATSC/DVB Digital" },
 };
 
 /* This is the full list of possible tuners. Many thanks to Hauppauge for
@@ -387,7 +386,7 @@
 	if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
 			(eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
 		start=0xa0; /* Generic em28xx offset */
-	else if (((eeprom_data[0] & 0xf0) == 0x10) &&
+	else if (((eeprom_data[0] & 0xe1) == 0x01) &&
 					(eeprom_data[1] == 0x00) &&
 					(eeprom_data[2] == 0x00) &&
 					(eeprom_data[8] == 0x84))
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index e837f9f..9e86cae 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -227,13 +227,9 @@
 }
 
 static struct i2c_driver driver = {
-#ifdef I2C_PEC
 	.driver = {
-		.name    = "tv card mixer driver",
+		.name    = "tvmixer",
 	},
-#else
-	.name            = "tv card mixer driver",
-#endif
 	.id              = I2C_DRIVERID_TVMIXER,
 	.detach_adapter  = tvmixer_adapters,
 	.attach_adapter  = tvmixer_adapters,
@@ -267,22 +263,8 @@
 	struct video_audio va;
 	int i,minor;
 
-#ifdef I2C_CLASS_TV_ANALOG
 	if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
 		return -1;
-#else
-	/* TV card ??? */
-	switch (client->adapter->id) {
-	case I2C_HW_SMBUS_VOODOO3:
-	case I2C_HW_B_BT848:
-	case I2C_HW_B_RIVA:
-		/* ok, have a look ... */
-		break;
-	default:
-		/* ignore that one */
-		return -1;
-	}
-#endif
 
 	/* unregister ?? */
 	for (i = 0; i < DEV_MAX; i++) {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index a60442e..c35b804 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -9,6 +9,7 @@
 #include <linux/videodev.h>
 #include <linux/delay.h>
 #include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #include "tvp5150_reg.h"
 
@@ -28,33 +29,38 @@
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define dprintk(num, format, args...) \
+#define tvp5150_info(fmt, arg...) do { \
+	printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
+	       i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
+#define tvp5150_dbg(num, fmt, arg...) \
 	do { \
 		if (debug >= num) \
-			printk(format, ##args); \
-	} while (0)
+			printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\
+				c->driver->driver.name, \
+				i2c_adapter_id(c->adapter), \
+				c->addr , ## arg); } while (0)
 
 /* supported controls */
 static struct v4l2_queryctrl tvp5150_qctrl[] = {
 	{
-	 .id = V4L2_CID_BRIGHTNESS,
-	 .type = V4L2_CTRL_TYPE_INTEGER,
-	 .name = "Brightness",
-	 .minimum = 0,
-	 .maximum = 255,
-	 .step = 1,
-	 .default_value = 0,
-	 .flags = 0,
-	 }, {
-	     .id = V4L2_CID_CONTRAST,
-	     .type = V4L2_CTRL_TYPE_INTEGER,
-	     .name = "Contrast",
-	     .minimum = 0,
-	     .maximum = 255,
-	     .step = 0x1,
-	     .default_value = 0x10,
-	     .flags = 0,
-	     }, {
+		.id = V4L2_CID_BRIGHTNESS,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Brightness",
+		.minimum = 0,
+		.maximum = 255,
+		.step = 1,
+		.default_value = 0,
+		.flags = 0,
+	}, {
+		.id = V4L2_CID_CONTRAST,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step = 0x1,
+		.default_value = 0x10,
+		.flags = 0,
+	}, {
 		 .id = V4L2_CID_SATURATION,
 		 .type = V4L2_CTRL_TYPE_INTEGER,
 		 .name = "Saturation",
@@ -63,16 +69,16 @@
 		 .step = 0x1,
 		 .default_value = 0x10,
 		 .flags = 0,
-		 }, {
-		     .id = V4L2_CID_HUE,
-		     .type = V4L2_CTRL_TYPE_INTEGER,
-		     .name = "Hue",
-		     .minimum = -128,
-		     .maximum = 127,
-		     .step = 0x1,
-		     .default_value = 0x10,
-		     .flags = 0,
-		     }
+	}, {
+		.id = V4L2_CID_HUE,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Hue",
+		.minimum = -128,
+		.maximum = 127,
+		.step = 0x1,
+		.default_value = 0x10,
+		.flags = 0,
+	}
 };
 
 struct tvp5150 {
@@ -94,12 +100,14 @@
 
 	buffer[0] = addr;
 	if (1 != (rc = i2c_master_send(c, buffer, 1)))
-		dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+		tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
 
 	msleep(10);
 
 	if (1 != (rc = i2c_master_recv(c, buffer, 1)))
-		dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+		tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+	tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
 
 	return (buffer[0]);
 }
@@ -109,13 +117,12 @@
 {
 	unsigned char buffer[2];
 	int rc;
-/*	struct tvp5150 *core = i2c_get_clientdata(c); */
 
 	buffer[0] = addr;
 	buffer[1] = value;
-	dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+	tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
 	if (2 != (rc = i2c_master_send(c, buffer, 2)))
-		dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+		tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
 }
 
 static void dump_reg(struct i2c_client *c)
@@ -437,48 +444,346 @@
 static inline void tvp5150_selmux(struct i2c_client *c,
 				  enum tvp5150_input input)
 {
+	int opmode=0;
+
 	struct tvp5150 *decoder = i2c_get_clientdata(c);
 
 	if (!decoder->enable)
 		input |= TVP5150_BLACK_SCREEN;
 
+	switch (input) {
+	case TVP5150_ANALOG_CH0:
+	case TVP5150_ANALOG_CH1:
+		opmode=0x30;		/* TV Mode */
+		break;
+	default:
+		opmode=0;		/* Auto Mode */
+		break;
+	}
+
+	tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
 	tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
 };
 
-static inline void tvp5150_reset(struct i2c_client *c)
+struct i2c_reg_value {
+	unsigned char reg;
+	unsigned char value;
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_default[] = {
+	{ /* 0x00 */
+		TVP5150_VD_IN_SRC_SEL_1,0x00
+	},
+	{ /* 0x01 */
+		TVP5150_ANAL_CHL_CTL,0x15
+	},
+	{ /* 0x02 */
+		TVP5150_OP_MODE_CTL,0x00
+	},
+	{ /* 0x03 */
+		TVP5150_MISC_CTL,0x01
+	},
+	{ /* 0x06 */
+		TVP5150_COLOR_KIL_THSH_CTL,0x10
+	},
+	{ /* 0x07 */
+		TVP5150_LUMA_PROC_CTL_1,0x60
+	},
+	{ /* 0x08 */
+		TVP5150_LUMA_PROC_CTL_2,0x00
+	},
+	{ /* 0x09 */
+		TVP5150_BRIGHT_CTL,0x80
+	},
+	{ /* 0x0a */
+		TVP5150_SATURATION_CTL,0x80
+	},
+	{ /* 0x0b */
+		TVP5150_HUE_CTL,0x00
+	},
+	{ /* 0x0c */
+		TVP5150_CONTRAST_CTL,0x80
+	},
+	{ /* 0x0d */
+		TVP5150_DATA_RATE_SEL,0x47
+	},
+	{ /* 0x0e */
+		TVP5150_LUMA_PROC_CTL_3,0x00
+	},
+	{ /* 0x0f */
+		TVP5150_CONF_SHARED_PIN,0x08
+	},
+	{ /* 0x11 */
+		TVP5150_ACT_VD_CROP_ST_MSB,0x00
+	},
+	{ /* 0x12 */
+		TVP5150_ACT_VD_CROP_ST_LSB,0x00
+	},
+	{ /* 0x13 */
+		TVP5150_ACT_VD_CROP_STP_MSB,0x00
+	},
+	{ /* 0x14 */
+		TVP5150_ACT_VD_CROP_STP_LSB,0x00
+	},
+	{ /* 0x15 */
+		TVP5150_GENLOCK,0x01
+	},
+	{ /* 0x16 */
+		TVP5150_HORIZ_SYNC_START,0x80
+	},
+	{ /* 0x18 */
+		TVP5150_VERT_BLANKING_START,0x00
+	},
+	{ /* 0x19 */
+		TVP5150_VERT_BLANKING_STOP,0x00
+	},
+	{ /* 0x1a */
+		TVP5150_CHROMA_PROC_CTL_1,0x0c
+	},
+	{ /* 0x1b */
+		TVP5150_CHROMA_PROC_CTL_2,0x14
+	},
+	{ /* 0x1c */
+		TVP5150_INT_RESET_REG_B,0x00
+	},
+	{ /* 0x1d */
+		TVP5150_INT_ENABLE_REG_B,0x00
+	},
+	{ /* 0x1e */
+		TVP5150_INTT_CONFIG_REG_B,0x00
+	},
+	{ /* 0x28 */
+		TVP5150_VIDEO_STD,0x00
+	},
+	{ /* 0x2e */
+		TVP5150_MACROVISION_ON_CTR,0x0f
+	},
+	{ /* 0x2f */
+		TVP5150_MACROVISION_OFF_CTR,0x01
+	},
+	{ /* 0xbb */
+		TVP5150_TELETEXT_FIL_ENA,0x00
+	},
+	{ /* 0xc0 */
+		TVP5150_INT_STATUS_REG_A,0x00
+	},
+	{ /* 0xc1 */
+		TVP5150_INT_ENABLE_REG_A,0x00
+	},
+	{ /* 0xc2 */
+		TVP5150_INT_CONF,0x04
+	},
+	{ /* 0xc8 */
+		TVP5150_FIFO_INT_THRESHOLD,0x80
+	},
+	{ /* 0xc9 */
+		TVP5150_FIFO_RESET,0x00
+	},
+	{ /* 0xca */
+		TVP5150_LINE_NUMBER_INT,0x00
+	},
+	{ /* 0xcb */
+		TVP5150_PIX_ALIGN_REG_LOW,0x4e
+	},
+	{ /* 0xcc */
+		TVP5150_PIX_ALIGN_REG_HIGH,0x00
+	},
+	{ /* 0xcd */
+		TVP5150_FIFO_OUT_CTRL,0x01
+	},
+	{ /* 0xcf */
+		TVP5150_FULL_FIELD_ENA_1,0x00
+	},
+	{ /* 0xd0 */
+		TVP5150_FULL_FIELD_ENA_2,0x00
+	},
+	{ /* 0xfc */
+		TVP5150_FULL_FIELD_MODE_REG,0x7f
+	},
+	{ /* end of data */
+		0xff,0xff
+	}
+};
+
+/* Default values as sugested at TVP5150AM1 datasheet */
+static const struct i2c_reg_value tvp5150_init_enable[] = {
+	{
+		TVP5150_CONF_SHARED_PIN, 2
+	},{	/* Automatic offset and AGC enabled */
+		TVP5150_ANAL_CHL_CTL, 0x15
+	},{	/* Activate YCrCb output 0x9 or 0xd ? */
+		TVP5150_MISC_CTL, 0x6f
+	},{	/* Activates video std autodetection for all standards */
+		TVP5150_AUTOSW_MSK, 0x0
+	},{	/* Default format: 0x47. For 4:2:2: 0x40 */
+		TVP5150_DATA_RATE_SEL, 0x47
+	},{
+		TVP5150_CHROMA_PROC_CTL_1, 0x0c
+	},{
+		TVP5150_CHROMA_PROC_CTL_2, 0x54
+	},{	/* Non documented, but initialized on WinTV USB2 */
+		0x27, 0x20
+	},{
+		0xff,0xff
+	}
+};
+
+struct i2c_vbi_ram_value {
+	u16 reg;
+	unsigned char values[26];
+};
+
+struct i2c_vbi_ram_value vbi_ram_default[] =
+{
+	{0x010, /* WST SECAM 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	},
+	{0x030, /* WST PAL B 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	},
+	{0x050, /* WST PAL C 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	},
+	{0x070, /* WST NTSC 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	},
+	{0x090, /* NABTS, NTSC 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+	},
+	{0x0b0, /* NABTS, NTSC-J 6 */
+		{ 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+	},
+	{0x0d0, /* CC, PAL/SECAM 6 */
+		{ 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+	},
+	{0x0f0, /* CC, NTSC 6 */
+		{ 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+	},
+	{0x110, /* WSS, PAL/SECAM 6 */
+		{ 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+	},
+	{0x130, /* WSS, NTSC C */
+		{ 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+	},
+	{0x150, /* VITC, PAL/SECAM 6 */
+		{ 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+	},
+	{0x170, /* VITC, NTSC 6 */
+		{ 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+	},
+	{ (u16)-1 }
+};
+
+static int tvp5150_write_inittab(struct i2c_client *c,
+				 const struct i2c_reg_value *regs)
+{
+	while (regs->reg != 0xff) {
+		tvp5150_write(c, regs->reg, regs->value);
+		regs++;
+	}
+	return 0;
+}
+
+static int tvp5150_vdp_init(struct i2c_client *c,
+				 const struct i2c_vbi_ram_value *regs)
+{
+	unsigned int i;
+
+	/* Disable Full Field */
+	tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
+
+	/* Before programming, Line mode should be at 0xff */
+	for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+		tvp5150_write(c, i, 0xff);
+
+	/* Load Ram Table */
+	while (regs->reg != (u16)-1 ) {
+		tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8);
+		tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg);
+
+		for (i=0;i<16;i++)
+			tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
+
+		regs++;
+	}
+	return 0;
+}
+
+static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
 {
 	struct tvp5150 *decoder = i2c_get_clientdata(c);
+	int fmt=0;
 
-	tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+	decoder->norm=std;
 
-	/* Automatic offset and AGC enabled */
-	tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+	/* First tests should be against specific std */
 
-	/* Normal Operation */
-//      tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+	if (std == V4L2_STD_ALL) {
+		fmt=0;	/* Autodetect mode */
+	} else if (std & V4L2_STD_NTSC_443) {
+		fmt=0xa;
+	} else if (std & V4L2_STD_PAL_M) {
+		fmt=0x6;
+	} else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
+		fmt=0x8;
+	} else {
+		/* Then, test against generic ones */
+		if (std & V4L2_STD_NTSC) {
+			fmt=0x2;
+		} else if (std & V4L2_STD_PAL) {
+			fmt=0x4;
+		} else if (std & V4L2_STD_SECAM) {
+			fmt=0xc;
+		}
+	}
 
-	/* Activate YCrCb output 0x9 or 0xd ? */
-	tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+	tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
+	tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
 
-	/* Activates video std autodetection for all standards */
-	tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+	return 0;
+}
 
-	/* Default format: 0x47, 4:2:2: 0x40 */
-	tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+	u8 type, ver_656, msb_id, lsb_id, msb_rom, lsb_rom;
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
 
+	type=tvp5150_read(c,TVP5150_AUTOSW_MSK);
+	msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID);
+	lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID);
+	msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER);
+	lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER);
+
+	if (type==0xdc) {
+		ver_656=tvp5150_read(c,TVP5150_REV_SELECT);
+		tvp5150_info("tvp%02x%02xam1 detected 656 version is %d.\n",msb_id, lsb_id,ver_656);
+	} else if (type==0xfc) {
+		tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id);
+	} else {
+		tvp5150_info("unknown tvp%02x%02x chip detected(%d).\n",msb_id,lsb_id,type);
+	}
+	tvp5150_info("Rom ver is %d.%d\n",msb_rom,lsb_rom);
+
+	/* Initializes TVP5150 to its default values */
+	tvp5150_write_inittab(c, tvp5150_init_default);
+
+	/* Initializes VDP registers */
+	tvp5150_vdp_init(c, vbi_ram_default);
+
+	/* Selects decoder input */
 	tvp5150_selmux(c, decoder->input);
 
-	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
-	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+	/* Initializes TVP5150 to stream enabled values */
+	tvp5150_write_inittab(c, tvp5150_init_enable);
 
-	tvp5150_write(c, 0x27, 0x20);	/* ?????????? */
-
-	tvp5150_write(c, TVP5150_VIDEO_STD, 0x0);	/* Auto switch */
-
+	/* Initialize image preferences */
 	tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
 	tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
 	tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
 	tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+
+	tvp5150_set_std(c, decoder->norm);
 };
 
 static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -498,9 +803,8 @@
 	case V4L2_CID_HUE:
 		ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
 		return 0;
-	default:
-		return -EINVAL;
 	}
+	return -EINVAL;
 }
 
 static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -520,28 +824,59 @@
 	case V4L2_CID_HUE:
 		tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
 		return 0;
-	default:
-		return -EINVAL;
 	}
+	return -EINVAL;
 }
 
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
-static int tvp5150_command(struct i2c_client *client,
+static int tvp5150_command(struct i2c_client *c,
 			   unsigned int cmd, void *arg)
 {
-	struct tvp5150 *decoder = i2c_get_clientdata(client);
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
 
 	switch (cmd) {
 
 	case 0:
+	case VIDIOC_INT_RESET:
 	case DECODER_INIT:
-		tvp5150_reset(client);
+		tvp5150_reset(c);
+		break;
+	case VIDIOC_S_STD:
+		if (decoder->norm == *(v4l2_std_id *)arg)
+			break;
+		return tvp5150_set_std(c, *(v4l2_std_id *)arg);
+	case VIDIOC_G_STD:
+		*(v4l2_std_id *)arg = decoder->norm;
 		break;
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_INT_G_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+			return -EINVAL;
+		reg->val = tvp5150_read(c, reg->reg & 0xff);
+		break;
+	}
+
+	case VIDIOC_INT_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
+		break;
+	}
+#endif
+
 	case DECODER_DUMP:
-		dump_reg(client);
+		dump_reg(c);
 		break;
 
 	case DECODER_GET_CAPABILITIES:
@@ -600,7 +935,7 @@
 			}
 
 			decoder->input = *iarg;
-			tvp5150_selmux(client, decoder->input);
+			tvp5150_selmux(c, decoder->input);
 
 			break;
 		}
@@ -620,19 +955,18 @@
 
 			decoder->enable = (*iarg != 0);
 
-			tvp5150_selmux(client, decoder->input);
+			tvp5150_selmux(c, decoder->input);
 
 			break;
 		}
 	case VIDIOC_QUERYCTRL:
 		{
 			struct v4l2_queryctrl *qc = arg;
-			u8 i, n;
+			int i;
 
-			dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+			tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n");
 
-			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
-			for (i = 0; i < n; i++)
+			for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
 				if (qc->id && qc->id == tvp5150_qctrl[i].id) {
 					memcpy(qc, &(tvp5150_qctrl[i]),
 					       sizeof(*qc));
@@ -644,16 +978,14 @@
 	case VIDIOC_G_CTRL:
 		{
 			struct v4l2_control *ctrl = arg;
-			dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+			tvp5150_dbg(1, "VIDIOC_G_CTRL called\n");
 
-			return tvp5150_get_ctrl(client, ctrl);
+			return tvp5150_get_ctrl(c, ctrl);
 		}
-	case VIDIOC_S_CTRL_OLD:	/* ??? */
 	case VIDIOC_S_CTRL:
 		{
 			struct v4l2_control *ctrl = arg;
 			u8 i, n;
-			dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
 			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
 			for (i = 0; i < n; i++)
 				if (ctrl->id == tvp5150_qctrl[i].id) {
@@ -662,11 +994,10 @@
 					    || ctrl->value >
 					    tvp5150_qctrl[i].maximum)
 						return -ERANGE;
-					dprintk(1,
-						KERN_DEBUG
-						"VIDIOC_S_CTRL: id=%d, value=%d",
+					tvp5150_dbg(1,
+						"VIDIOC_S_CTRL: id=%d, value=%d\n",
 						ctrl->id, ctrl->value);
-					return tvp5150_set_ctrl(client, ctrl);
+					return tvp5150_set_ctrl(c, ctrl);
 				}
 			return -EINVAL;
 		}
@@ -677,25 +1008,25 @@
 			if (decoder->bright != pic->brightness) {
 				/* We want 0 to 255 we get 0-65535 */
 				decoder->bright = pic->brightness;
-				tvp5150_write(client, TVP5150_BRIGHT_CTL,
+				tvp5150_write(c, TVP5150_BRIGHT_CTL,
 					      decoder->bright >> 8);
 			}
 			if (decoder->contrast != pic->contrast) {
 				/* We want 0 to 255 we get 0-65535 */
 				decoder->contrast = pic->contrast;
-				tvp5150_write(client, TVP5150_CONTRAST_CTL,
+				tvp5150_write(c, TVP5150_CONTRAST_CTL,
 					      decoder->contrast >> 8);
 			}
 			if (decoder->sat != pic->colour) {
 				/* We want 0 to 255 we get 0-65535 */
 				decoder->sat = pic->colour;
-				tvp5150_write(client, TVP5150_SATURATION_CTL,
+				tvp5150_write(c, TVP5150_SATURATION_CTL,
 					      decoder->contrast >> 8);
 			}
 			if (decoder->hue != pic->hue) {
 				/* We want -128 to 127 we get 0-65535 */
 				decoder->hue = pic->hue;
-				tvp5150_write(client, TVP5150_HUE_CTL,
+				tvp5150_write(c, TVP5150_HUE_CTL,
 					      (decoder->hue - 32768) >> 8);
 			}
 			break;
@@ -720,12 +1051,12 @@
 static int tvp5150_detect_client(struct i2c_adapter *adapter,
 				 int address, int kind)
 {
-	struct i2c_client *client;
+	struct i2c_client *c;
 	struct tvp5150 *core;
 	int rv;
 
-	dprintk(1,
-		KERN_INFO
+	if (debug)
+		printk( KERN_INFO
 		"tvp5150.c: detecting tvp5150 client on address 0x%x\n",
 		address << 1);
 
@@ -738,22 +1069,22 @@
 	     I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 		return 0;
 
-	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
+	c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (c == 0)
 		return -ENOMEM;
-	memcpy(client, &client_template, sizeof(struct i2c_client));
+	memcpy(c, &client_template, sizeof(struct i2c_client));
 
 	core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
 	if (core == 0) {
-		kfree(client);
+		kfree(c);
 		return -ENOMEM;
 	}
 	memset(core, 0, sizeof(struct tvp5150));
-	i2c_set_clientdata(client, core);
+	i2c_set_clientdata(c, core);
 
-	rv = i2c_attach_client(client);
+	rv = i2c_attach_client(c);
 
-	core->norm = VIDEO_MODE_AUTO;
+	core->norm = V4L2_STD_ALL;
 	core->input = 2;
 	core->enable = 1;
 	core->bright = 32768;
@@ -762,37 +1093,41 @@
 	core->sat = 32768;
 
 	if (rv) {
-		kfree(client);
+		kfree(c);
 		kfree(core);
 		return rv;
 	}
 
 	if (debug > 1)
-		dump_reg(client);
+		dump_reg(c);
 	return 0;
 }
 
 static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
 {
-	dprintk(1,
-		KERN_INFO
+	if (debug)
+		printk( KERN_INFO
 		"tvp5150.c: starting probe for adapter %s (0x%x)\n",
 		adapter->name, adapter->id);
 	return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
 }
 
-static int tvp5150_detach_client(struct i2c_client *client)
+static int tvp5150_detach_client(struct i2c_client *c)
 {
-	struct tvp5150 *decoder = i2c_get_clientdata(client);
+	struct tvp5150 *decoder = i2c_get_clientdata(c);
 	int err;
 
-	err = i2c_detach_client(client);
+	tvp5150_dbg(1,
+		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
+		c->addr << 1);
+
+	err = i2c_detach_client(c);
 	if (err) {
 		return err;
 	}
 
 	kfree(decoder);
-	kfree(client);
+	kfree(c);
 
 	return 0;
 }
@@ -803,9 +1138,7 @@
 	.driver = {
 		.name = "tvp5150",
 	},
-
-	/* FIXME */
-	.id = I2C_DRIVERID_SAA7110,
+	.id = I2C_DRIVERID_TVP5150,
 
 	.attach_adapter = tvp5150_attach_adapter,
 	.detach_client = tvp5150_detach_client,
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 4134549..2ab5b40 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -951,6 +951,10 @@
 			dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
 			break;
 		}
+		if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
+			err = -EINVAL;
+			break;
+		}
 		memset(fmt, 0, sizeof(*fmt));
 		fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
 		fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
@@ -966,6 +970,11 @@
 	{
 		struct vbi_format      *fmt = arg;
 
+		if (VIDEO_PALETTE_RAW != fmt->sample_format) {
+			err = -EINVAL;
+			break;
+		}
+
 		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
 		memset(fmt2, 0, sizeof(*fmt2));
 
@@ -986,7 +995,7 @@
 
 		if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
 		    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
-		    VIDEO_PALETTE_RAW              != fmt->sample_format    ||
+		    fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
 		    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
 		    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
 		    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 62a7d63..5dbd7c1 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -58,6 +58,8 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/div64.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -190,55 +192,174 @@
 	[V4L2_BUF_TYPE_VBI_OUTPUT]    = "vbi-out",
 };
 
-char *v4l2_ioctl_names[256] = {
-	[0 ... 255]                      = "UNKNOWN",
-	[_IOC_NR(VIDIOC_QUERYCAP)]       = "VIDIOC_QUERYCAP",
-	[_IOC_NR(VIDIOC_RESERVED)]       = "VIDIOC_RESERVED",
-	[_IOC_NR(VIDIOC_ENUM_FMT)]       = "VIDIOC_ENUM_FMT",
-	[_IOC_NR(VIDIOC_G_FMT)]          = "VIDIOC_G_FMT",
-	[_IOC_NR(VIDIOC_S_FMT)]          = "VIDIOC_S_FMT",
-	[_IOC_NR(VIDIOC_REQBUFS)]        = "VIDIOC_REQBUFS",
-	[_IOC_NR(VIDIOC_QUERYBUF)]       = "VIDIOC_QUERYBUF",
-	[_IOC_NR(VIDIOC_G_FBUF)]         = "VIDIOC_G_FBUF",
-	[_IOC_NR(VIDIOC_S_FBUF)]         = "VIDIOC_S_FBUF",
-	[_IOC_NR(VIDIOC_OVERLAY)]        = "VIDIOC_OVERLAY",
-	[_IOC_NR(VIDIOC_QBUF)]           = "VIDIOC_QBUF",
-	[_IOC_NR(VIDIOC_DQBUF)]          = "VIDIOC_DQBUF",
-	[_IOC_NR(VIDIOC_STREAMON)]       = "VIDIOC_STREAMON",
-	[_IOC_NR(VIDIOC_STREAMOFF)]      = "VIDIOC_STREAMOFF",
-	[_IOC_NR(VIDIOC_G_PARM)]         = "VIDIOC_G_PARM",
-	[_IOC_NR(VIDIOC_S_PARM)]         = "VIDIOC_S_PARM",
-	[_IOC_NR(VIDIOC_G_STD)]          = "VIDIOC_G_STD",
-	[_IOC_NR(VIDIOC_S_STD)]          = "VIDIOC_S_STD",
-	[_IOC_NR(VIDIOC_ENUMSTD)]        = "VIDIOC_ENUMSTD",
-	[_IOC_NR(VIDIOC_ENUMINPUT)]      = "VIDIOC_ENUMINPUT",
-	[_IOC_NR(VIDIOC_G_CTRL)]         = "VIDIOC_G_CTRL",
-	[_IOC_NR(VIDIOC_S_CTRL)]         = "VIDIOC_S_CTRL",
-	[_IOC_NR(VIDIOC_G_TUNER)]        = "VIDIOC_G_TUNER",
-	[_IOC_NR(VIDIOC_S_TUNER)]        = "VIDIOC_S_TUNER",
-	[_IOC_NR(VIDIOC_G_AUDIO)]        = "VIDIOC_G_AUDIO",
-	[_IOC_NR(VIDIOC_S_AUDIO)]        = "VIDIOC_S_AUDIO",
-	[_IOC_NR(VIDIOC_QUERYCTRL)]      = "VIDIOC_QUERYCTRL",
-	[_IOC_NR(VIDIOC_QUERYMENU)]      = "VIDIOC_QUERYMENU",
-	[_IOC_NR(VIDIOC_G_INPUT)]        = "VIDIOC_G_INPUT",
-	[_IOC_NR(VIDIOC_S_INPUT)]        = "VIDIOC_S_INPUT",
-	[_IOC_NR(VIDIOC_G_OUTPUT)]       = "VIDIOC_G_OUTPUT",
-	[_IOC_NR(VIDIOC_S_OUTPUT)]       = "VIDIOC_S_OUTPUT",
-	[_IOC_NR(VIDIOC_ENUMOUTPUT)]     = "VIDIOC_ENUMOUTPUT",
-	[_IOC_NR(VIDIOC_G_AUDOUT)]       = "VIDIOC_G_AUDOUT",
-	[_IOC_NR(VIDIOC_S_AUDOUT)]       = "VIDIOC_S_AUDOUT",
-	[_IOC_NR(VIDIOC_G_MODULATOR)]    = "VIDIOC_G_MODULATOR",
-	[_IOC_NR(VIDIOC_S_MODULATOR)]    = "VIDIOC_S_MODULATOR",
-	[_IOC_NR(VIDIOC_G_FREQUENCY)]    = "VIDIOC_G_FREQUENCY",
-	[_IOC_NR(VIDIOC_S_FREQUENCY)]    = "VIDIOC_S_FREQUENCY",
-	[_IOC_NR(VIDIOC_CROPCAP)]        = "VIDIOC_CROPCAP",
-	[_IOC_NR(VIDIOC_G_CROP)]         = "VIDIOC_G_CROP",
-	[_IOC_NR(VIDIOC_S_CROP)]         = "VIDIOC_S_CROP",
-	[_IOC_NR(VIDIOC_G_JPEGCOMP)]     = "VIDIOC_G_JPEGCOMP",
-	[_IOC_NR(VIDIOC_S_JPEGCOMP)]     = "VIDIOC_S_JPEGCOMP",
-	[_IOC_NR(VIDIOC_QUERYSTD)]       = "VIDIOC_QUERYSTD",
-	[_IOC_NR(VIDIOC_TRY_FMT)]        = "VIDIOC_TRY_FMT",
+/* ------------------------------------------------------------------ */
+/* debug help functions                                               */
+
+#ifdef HAVE_V4L1
+static const char *v4l1_ioctls[] = {
+	[_IOC_NR(VIDIOCGCAP)]       = "VIDIOCGCAP",
+	[_IOC_NR(VIDIOCGCHAN)]      = "VIDIOCGCHAN",
+	[_IOC_NR(VIDIOCSCHAN)]      = "VIDIOCSCHAN",
+	[_IOC_NR(VIDIOCGTUNER)]     = "VIDIOCGTUNER",
+	[_IOC_NR(VIDIOCSTUNER)]     = "VIDIOCSTUNER",
+	[_IOC_NR(VIDIOCGPICT)]      = "VIDIOCGPICT",
+	[_IOC_NR(VIDIOCSPICT)]      = "VIDIOCSPICT",
+	[_IOC_NR(VIDIOCCAPTURE)]    = "VIDIOCCAPTURE",
+	[_IOC_NR(VIDIOCGWIN)]       = "VIDIOCGWIN",
+	[_IOC_NR(VIDIOCSWIN)]       = "VIDIOCSWIN",
+	[_IOC_NR(VIDIOCGFBUF)]      = "VIDIOCGFBUF",
+	[_IOC_NR(VIDIOCSFBUF)]      = "VIDIOCSFBUF",
+	[_IOC_NR(VIDIOCKEY)]        = "VIDIOCKEY",
+	[_IOC_NR(VIDIOCGFREQ)]      = "VIDIOCGFREQ",
+	[_IOC_NR(VIDIOCSFREQ)]      = "VIDIOCSFREQ",
+	[_IOC_NR(VIDIOCGAUDIO)]     = "VIDIOCGAUDIO",
+	[_IOC_NR(VIDIOCSAUDIO)]     = "VIDIOCSAUDIO",
+	[_IOC_NR(VIDIOCSYNC)]       = "VIDIOCSYNC",
+	[_IOC_NR(VIDIOCMCAPTURE)]   = "VIDIOCMCAPTURE",
+	[_IOC_NR(VIDIOCGMBUF)]      = "VIDIOCGMBUF",
+	[_IOC_NR(VIDIOCGUNIT)]      = "VIDIOCGUNIT",
+	[_IOC_NR(VIDIOCGCAPTURE)]   = "VIDIOCGCAPTURE",
+	[_IOC_NR(VIDIOCSCAPTURE)]   = "VIDIOCSCAPTURE",
+	[_IOC_NR(VIDIOCSPLAYMODE)]  = "VIDIOCSPLAYMODE",
+	[_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+	[_IOC_NR(VIDIOCGPLAYINFO)]  = "VIDIOCGPLAYINFO",
+	[_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+	[_IOC_NR(VIDIOCGVBIFMT)]    = "VIDIOCGVBIFMT",
+	[_IOC_NR(VIDIOCSVBIFMT)]    = "VIDIOCSVBIFMT"
 };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+#endif
+
+static const char *v4l2_ioctls[] = {
+	[_IOC_NR(VIDIOC_QUERYCAP)]         = "VIDIOC_QUERYCAP",
+	[_IOC_NR(VIDIOC_RESERVED)]         = "VIDIOC_RESERVED",
+	[_IOC_NR(VIDIOC_ENUM_FMT)]         = "VIDIOC_ENUM_FMT",
+	[_IOC_NR(VIDIOC_G_FMT)]            = "VIDIOC_G_FMT",
+	[_IOC_NR(VIDIOC_S_FMT)]            = "VIDIOC_S_FMT",
+	[_IOC_NR(VIDIOC_G_MPEGCOMP)]       = "VIDIOC_G_MPEGCOMP",
+	[_IOC_NR(VIDIOC_S_MPEGCOMP)]       = "VIDIOC_S_MPEGCOMP",
+	[_IOC_NR(VIDIOC_REQBUFS)]          = "VIDIOC_REQBUFS",
+	[_IOC_NR(VIDIOC_QUERYBUF)]         = "VIDIOC_QUERYBUF",
+	[_IOC_NR(VIDIOC_G_FBUF)]           = "VIDIOC_G_FBUF",
+	[_IOC_NR(VIDIOC_S_FBUF)]           = "VIDIOC_S_FBUF",
+	[_IOC_NR(VIDIOC_OVERLAY)]          = "VIDIOC_OVERLAY",
+	[_IOC_NR(VIDIOC_QBUF)]             = "VIDIOC_QBUF",
+	[_IOC_NR(VIDIOC_DQBUF)]            = "VIDIOC_DQBUF",
+	[_IOC_NR(VIDIOC_STREAMON)]         = "VIDIOC_STREAMON",
+	[_IOC_NR(VIDIOC_STREAMOFF)]        = "VIDIOC_STREAMOFF",
+	[_IOC_NR(VIDIOC_G_PARM)]           = "VIDIOC_G_PARM",
+	[_IOC_NR(VIDIOC_S_PARM)]           = "VIDIOC_S_PARM",
+	[_IOC_NR(VIDIOC_G_STD)]            = "VIDIOC_G_STD",
+	[_IOC_NR(VIDIOC_S_STD)]            = "VIDIOC_S_STD",
+	[_IOC_NR(VIDIOC_ENUMSTD)]          = "VIDIOC_ENUMSTD",
+	[_IOC_NR(VIDIOC_ENUMINPUT)]        = "VIDIOC_ENUMINPUT",
+	[_IOC_NR(VIDIOC_G_CTRL)]           = "VIDIOC_G_CTRL",
+	[_IOC_NR(VIDIOC_S_CTRL)]           = "VIDIOC_S_CTRL",
+	[_IOC_NR(VIDIOC_G_TUNER)]          = "VIDIOC_G_TUNER",
+	[_IOC_NR(VIDIOC_S_TUNER)]          = "VIDIOC_S_TUNER",
+	[_IOC_NR(VIDIOC_G_AUDIO)]          = "VIDIOC_G_AUDIO",
+	[_IOC_NR(VIDIOC_S_AUDIO)]          = "VIDIOC_S_AUDIO",
+	[_IOC_NR(VIDIOC_QUERYCTRL)]        = "VIDIOC_QUERYCTRL",
+	[_IOC_NR(VIDIOC_QUERYMENU)]        = "VIDIOC_QUERYMENU",
+	[_IOC_NR(VIDIOC_G_INPUT)]          = "VIDIOC_G_INPUT",
+	[_IOC_NR(VIDIOC_S_INPUT)]          = "VIDIOC_S_INPUT",
+	[_IOC_NR(VIDIOC_G_OUTPUT)]         = "VIDIOC_G_OUTPUT",
+	[_IOC_NR(VIDIOC_S_OUTPUT)]         = "VIDIOC_S_OUTPUT",
+	[_IOC_NR(VIDIOC_ENUMOUTPUT)]       = "VIDIOC_ENUMOUTPUT",
+	[_IOC_NR(VIDIOC_G_AUDOUT)]         = "VIDIOC_G_AUDOUT",
+	[_IOC_NR(VIDIOC_S_AUDOUT)]         = "VIDIOC_S_AUDOUT",
+	[_IOC_NR(VIDIOC_G_MODULATOR)]      = "VIDIOC_G_MODULATOR",
+	[_IOC_NR(VIDIOC_S_MODULATOR)]      = "VIDIOC_S_MODULATOR",
+	[_IOC_NR(VIDIOC_G_FREQUENCY)]      = "VIDIOC_G_FREQUENCY",
+	[_IOC_NR(VIDIOC_S_FREQUENCY)]      = "VIDIOC_S_FREQUENCY",
+	[_IOC_NR(VIDIOC_CROPCAP)]          = "VIDIOC_CROPCAP",
+	[_IOC_NR(VIDIOC_G_CROP)]           = "VIDIOC_G_CROP",
+	[_IOC_NR(VIDIOC_S_CROP)]           = "VIDIOC_S_CROP",
+	[_IOC_NR(VIDIOC_G_JPEGCOMP)]       = "VIDIOC_G_JPEGCOMP",
+	[_IOC_NR(VIDIOC_S_JPEGCOMP)]       = "VIDIOC_S_JPEGCOMP",
+	[_IOC_NR(VIDIOC_QUERYSTD)]         = "VIDIOC_QUERYSTD",
+	[_IOC_NR(VIDIOC_TRY_FMT)]          = "VIDIOC_TRY_FMT",
+	[_IOC_NR(VIDIOC_ENUMAUDIO)]        = "VIDIOC_ENUMAUDIO",
+	[_IOC_NR(VIDIOC_ENUMAUDOUT)]       = "VIDIOC_ENUMAUDOUT",
+	[_IOC_NR(VIDIOC_G_PRIORITY)]       = "VIDIOC_G_PRIORITY",
+	[_IOC_NR(VIDIOC_S_PRIORITY)]       = "VIDIOC_S_PRIORITY",
+#if 1
+	[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
+#endif
+	[_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+static const char *v4l2_int_ioctls[] = {
+#ifdef HAVE_VIDEO_DECODER
+	[_IOC_NR(DECODER_GET_CAPABILITIES)]    = "DECODER_GET_CAPABILITIES",
+	[_IOC_NR(DECODER_GET_STATUS)]          = "DECODER_GET_STATUS",
+	[_IOC_NR(DECODER_SET_NORM)]            = "DECODER_SET_NORM",
+	[_IOC_NR(DECODER_SET_INPUT)]           = "DECODER_SET_INPUT",
+	[_IOC_NR(DECODER_SET_OUTPUT)]          = "DECODER_SET_OUTPUT",
+	[_IOC_NR(DECODER_ENABLE_OUTPUT)]       = "DECODER_ENABLE_OUTPUT",
+	[_IOC_NR(DECODER_SET_PICTURE)]         = "DECODER_SET_PICTURE",
+	[_IOC_NR(DECODER_SET_GPIO)]            = "DECODER_SET_GPIO",
+	[_IOC_NR(DECODER_INIT)]                = "DECODER_INIT",
+	[_IOC_NR(DECODER_SET_VBI_BYPASS)]      = "DECODER_SET_VBI_BYPASS",
+	[_IOC_NR(DECODER_DUMP)]                = "DECODER_DUMP",
+#endif
+	[_IOC_NR(AUDC_SET_RADIO)]              = "AUDC_SET_RADIO",
+	[_IOC_NR(AUDC_SET_INPUT)]              = "AUDC_SET_INPUT",
+
+	[_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
+	[_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
+	[_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
+
+	[_IOC_NR(VIDIOC_INT_S_REGISTER)]       = "VIDIOC_INT_S_REGISTER",
+	[_IOC_NR(VIDIOC_INT_G_REGISTER)]       = "VIDIOC_INT_G_REGISTER",
+	[_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
+	[_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
+	[_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)]  = "VIDIOC_INT_DECODE_VBI_LINE",
+	[_IOC_NR(VIDIOC_INT_S_VBI_DATA)]       = "VIDIOC_INT_S_VBI_DATA",
+	[_IOC_NR(VIDIOC_INT_G_VBI_DATA)]       = "VIDIOC_INT_G_VBI_DATA",
+	[_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)]     = "VIDIOC_INT_G_CHIP_IDENT",
+	[_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)]   = "VIDIOC_INT_I2S_CLOCK_FREQ"
+};
+#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
+
+/* Common ioctl debug function. This function can be used by
+   external ioctl messages as well as internal V4L ioctl */
+void v4l_printk_ioctl(unsigned int cmd)
+{
+	char *dir;
+
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:              dir = "--"; break;
+	case _IOC_READ:              dir = "r-"; break;
+	case _IOC_WRITE:             dir = "-w"; break;
+	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+	default:                     dir = "*ERR*"; break;
+	}
+	switch (_IOC_TYPE(cmd)) {
+	case 'd':
+		printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
+		       (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
+		       v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+		break;
+#ifdef HAVE_V4L1
+	case 'v':
+		printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
+		       (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+		       v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+		break;
+#endif
+	case 'V':
+		printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
+		       (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+		       v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+		break;
+
+	default:
+		printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
+		       _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+	}
+}
 
 /* ----------------------------------------------------------------- */
 
@@ -253,7 +374,7 @@
 
 EXPORT_SYMBOL(v4l2_field_names);
 EXPORT_SYMBOL(v4l2_type_names);
-EXPORT_SYMBOL(v4l2_ioctl_names);
+EXPORT_SYMBOL(v4l_printk_ioctl);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 6de5b00..9a9902c 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -68,7 +68,8 @@
 {
 	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
 
-#if 1 /* needed until all drivers are fixed */
+#if 1
+	/* needed until all drivers are fixed */
 	if (!vfd->release)
 		return;
 #endif
@@ -338,13 +339,14 @@
 	if (vfd->dev)
 		vfd->class_dev.dev = vfd->dev;
 	vfd->class_dev.class       = &video_class;
-	vfd->class_dev.devt       = MKDEV(VIDEO_MAJOR, vfd->minor);
+	vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
 	strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
 	class_device_register(&vfd->class_dev);
 	class_device_create_file(&vfd->class_dev,
-				 &class_device_attr_name);
+				&class_device_attr_name);
 
-#if 1 /* needed until all drivers are fixed */
+#if 1
+	/* needed until all drivers are fixed */
 	if (!vfd->release)
 		printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
 		       "Please fix your driver for proper sysfs support, see "
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index c318ba3..b7b0aff 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -187,6 +187,7 @@
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
 	.ioctl          = w9966_v4l_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.read           = w9966_v4l_read,
 	.llseek         = no_llseek,
 };
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index bbfd55c..c2e6d2e 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -25,7 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/ioctl.h>
@@ -33,20 +32,12 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-#define wm8775_err(fmt, arg...) do { \
-	printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-#define wm8775_info(fmt, arg...) do { \
-	printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
-	       i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
-
-
 static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
 
 
@@ -70,7 +61,7 @@
 	int i;
 
 	if (reg < 0 || reg >= TOT_REGS) {
-		wm8775_err("Invalid register R%d\n", reg);
+		v4l_err(client, "Invalid register R%d\n", reg);
 		return -1;
 	}
 
@@ -80,7 +71,7 @@
 			return 0;
 		}
 	}
-	wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
 	return -1;
 }
 
@@ -88,38 +79,53 @@
 			  void *arg)
 {
 	struct wm8775_state *state = i2c_get_clientdata(client);
-	int *input = arg;
+	struct v4l2_audio *input = arg;
+	struct v4l2_control *ctrl = arg;
 
 	switch (cmd) {
-	case AUDC_SET_INPUT:
+	case VIDIOC_S_AUDIO:
+		/* There are 4 inputs and one output. Zero or more inputs
+		   are multiplexed together to the output. Hence there are
+		   16 combinations.
+		   If only one input is active (the normal case) then the
+		   input values 1, 2, 4 or 8 should be used. */
+		if (input->index > 15) {
+			v4l_err(client, "Invalid input %d.\n", input->index);
+			return -EINVAL;
+		}
+		state->input = input->index;
+		if (state->muted)
+			break;
 		wm8775_write(client, R21, 0x0c0);
 		wm8775_write(client, R14, 0x1d4);
 		wm8775_write(client, R15, 0x1d4);
+		wm8775_write(client, R21, 0x100 + state->input);
+		break;
 
-		if (*input == AUDIO_RADIO) {
-			wm8775_write(client, R21, 0x108);
-			state->input = 8;
-			state->muted = 0;
-			break;
-		}
-		if (*input == AUDIO_MUTE) {
-			state->muted = 1;
-			break;
-		}
-		if (*input == AUDIO_UNMUTE) {
+	case VIDIOC_G_AUDIO:
+		memset(input, 0, sizeof(*input));
+		input->index = state->input;
+		break;
+
+	case VIDIOC_G_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		ctrl->value = state->muted;
+		break;
+
+	case VIDIOC_S_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		state->muted = ctrl->value;
+		wm8775_write(client, R21, 0x0c0);
+		wm8775_write(client, R14, 0x1d4);
+		wm8775_write(client, R15, 0x1d4);
+		if (!state->muted)
 			wm8775_write(client, R21, 0x100 + state->input);
-			state->muted = 0;
-			break;
-		}
-		/* All other inputs... */
-		wm8775_write(client, R21, 0x102);
-		state->input = 2;
-		state->muted = 0;
 		break;
 
 	case VIDIOC_LOG_STATUS:
-		wm8775_info("Input: %s%s\n",
-			    state->input == 8 ? "radio" : "default",
+		v4l_info(client, "Input: %d%s\n", state->input,
 			    state->muted ? " (muted)" : "");
 		break;
 
@@ -170,7 +176,7 @@
 	client->driver = &i2c_driver;
 	snprintf(client->name, sizeof(client->name) - 1, "wm8775");
 
-	wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
 
 	state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
 	if (state == NULL) {
@@ -206,11 +212,7 @@
 
 static int wm8775_probe(struct i2c_adapter *adapter)
 {
-#ifdef I2C_CLASS_TV_ANALOG
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-#else
-	if (adapter->id == I2C_HW_B_BT848)
-#endif
 		return i2c_probe(adapter, &addr_data, wm8775_attach);
 	return 0;
 }
@@ -235,12 +237,10 @@
 	.driver = {
 		.name = "wm8775",
 	},
-
-	.id = I2C_DRIVERID_WM8775,
-
+	.id             = I2C_DRIVERID_WM8775,
 	.attach_adapter = wm8775_probe,
-	.detach_client = wm8775_detach,
-	.command = wm8775_command,
+	.detach_client  = wm8775_detach,
+	.command        = wm8775_command,
 };
 
 
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 4034f1b..15283f4 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -4678,6 +4678,7 @@
 	.open = zoran_open,
 	.release = zoran_close,
 	.ioctl = zoran_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek = no_llseek,
 	.read = zoran_read,
 	.write = zoran_write,
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 0728681..d4c633b 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1490,6 +1490,7 @@
 	.write		= zoran_write,
 	.poll		= zoran_poll,
 	.ioctl		= zoran_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.mmap		= zoran_mmap,
 	.minor		= -1,
 };
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
index 6a5700e..2564680 100644
--- a/drivers/usb/media/dsbr100.c
+++ b/drivers/usb/media/dsbr100.c
@@ -127,6 +127,7 @@
 	.open =		usb_dsbr100_open,
 	.release =     	usb_dsbr100_close,
 	.ioctl =        usb_dsbr100_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =       no_llseek,
 };
 
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
index 3a0e8ce..8af665b 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -4774,6 +4774,7 @@
 	.read =		ov51x_v4l1_read,
 	.mmap =		ov51x_v4l1_mmap,
 	.ioctl =	ov51x_v4l1_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =	no_llseek,
 };
 
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index 09ca612..4f9b0dc 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -154,6 +154,7 @@
 	.poll =		pwc_video_poll,
 	.mmap =		pwc_video_mmap,
 	.ioctl =        pwc_video_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =       no_llseek,
 };
 static struct video_device pwc_template = {
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
index b2ae29a..2ba5622 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -1193,6 +1193,7 @@
         .read =         se401_read,
         .mmap =         se401_mmap,
 	.ioctl =        se401_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =       no_llseek,
 };
 static struct video_device se401_template = {
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index 774038b..b497a6a 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1343,6 +1343,7 @@
 	.read =		stv680_read,
 	.mmap =		stv680_mmap,
 	.ioctl =        stv680_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =       no_llseek,
 };
 static struct video_device stv680_template = {
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
index 4bd1133..63a72e5 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -953,6 +953,7 @@
 	.read =   usbvideo_v4l_read,
 	.mmap =   usbvideo_v4l_mmap,
 	.ioctl =  usbvideo_v4l_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek = no_llseek,
 };
 static const struct video_device usbvideo_template = {
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
index 1c73155..5df1440 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -1236,6 +1236,7 @@
 	.read		= vicam_read,
 	.mmap		= vicam_mmap,
 	.ioctl		= vicam_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek		= no_llseek,
 };
 
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index 3605a6f..bff9434 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -3490,6 +3490,7 @@
 	.release = w9968cf_release,
 	.read =    w9968cf_read,
 	.ioctl =   w9968cf_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
 	.mmap =    w9968cf_mmap,
 	.llseek =  no_llseek,
 };
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 43a2508..55d9a3a 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -207,244 +207,6 @@
 	return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
 }
 
-struct video_tuner32 {
-	compat_int_t tuner;
-	char name[32];
-	compat_ulong_t rangelow, rangehigh;
-	u32 flags;	/* It is really u32 in videodev.h */
-	u16 mode, signal;
-};
-
-static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
-	int i;
-
-	if(get_user(kp->tuner, &up->tuner))
-		return -EFAULT;
-	for(i = 0; i < 32; i++)
-		__get_user(kp->name[i], &up->name[i]);
-	__get_user(kp->rangelow, &up->rangelow);
-	__get_user(kp->rangehigh, &up->rangehigh);
-	__get_user(kp->flags, &up->flags);
-	__get_user(kp->mode, &up->mode);
-	__get_user(kp->signal, &up->signal);
-	return 0;
-}
-
-static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
-	int i;
-
-	if(put_user(kp->tuner, &up->tuner))
-		return -EFAULT;
-	for(i = 0; i < 32; i++)
-		__put_user(kp->name[i], &up->name[i]);
-	__put_user(kp->rangelow, &up->rangelow);
-	__put_user(kp->rangehigh, &up->rangehigh);
-	__put_user(kp->flags, &up->flags);
-	__put_user(kp->mode, &up->mode);
-	__put_user(kp->signal, &up->signal);
-	return 0;
-}
-
-struct video_buffer32 {
-	compat_caddr_t base;
-	compat_int_t height, width, depth, bytesperline;
-};
-
-static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
-	u32 tmp;
-
-	if (get_user(tmp, &up->base))
-		return -EFAULT;
-
-	/* This is actually a physical address stored
-	 * as a void pointer.
-	 */
-	kp->base = (void *)(unsigned long) tmp;
-
-	__get_user(kp->height, &up->height);
-	__get_user(kp->width, &up->width);
-	__get_user(kp->depth, &up->depth);
-	__get_user(kp->bytesperline, &up->bytesperline);
-	return 0;
-}
-
-static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
-	u32 tmp = (u32)((unsigned long)kp->base);
-
-	if(put_user(tmp, &up->base))
-		return -EFAULT;
-	__put_user(kp->height, &up->height);
-	__put_user(kp->width, &up->width);
-	__put_user(kp->depth, &up->depth);
-	__put_user(kp->bytesperline, &up->bytesperline);
-	return 0;
-}
-
-struct video_clip32 {
-	s32 x, y, width, height;	/* Its really s32 in videodev.h */
-	compat_caddr_t next;
-};
-
-struct video_window32 {
-	u32 x, y, width, height, chromakey, flags;
-	compat_caddr_t clips;
-	compat_int_t clipcount;
-};
-
-/* You get back everything except the clips... */
-static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
-	if(put_user(kp->x, &up->x))
-		return -EFAULT;
-	__put_user(kp->y, &up->y);
-	__put_user(kp->width, &up->width);
-	__put_user(kp->height, &up->height);
-	__put_user(kp->chromakey, &up->chromakey);
-	__put_user(kp->flags, &up->flags);
-	__put_user(kp->clipcount, &up->clipcount);
-	return 0;
-}
-
-#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
-#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
-#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
-#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
-#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
-#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
-#define VIDIOCGFREQ32		_IOR('v',14, u32)
-#define VIDIOCSFREQ32		_IOW('v',15, u32)
-
-enum {
-	MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct video_window32 __user *up = compat_ptr(arg);
-	struct video_window __user *vw;
-	struct video_clip __user *p;
-	int nclips;
-	u32 n;
-
-	if (get_user(nclips, &up->clipcount))
-		return -EFAULT;
-
-	/* Peculiar interface... */
-	if (nclips < 0)
-		nclips = VIDEO_CLIPMAP_SIZE;
-
-	if (nclips > MaxClips)
-		return -ENOMEM;
-
-	vw = compat_alloc_user_space(sizeof(struct video_window) +
-				    nclips * sizeof(struct video_clip));
-
-	p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
-	if (get_user(n, &up->x) || put_user(n, &vw->x) ||
-	    get_user(n, &up->y) || put_user(n, &vw->y) ||
-	    get_user(n, &up->width) || put_user(n, &vw->width) ||
-	    get_user(n, &up->height) || put_user(n, &vw->height) ||
-	    get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
-	    get_user(n, &up->flags) || put_user(n, &vw->flags) ||
-	    get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
-	    get_user(n, &up->clips) || put_user(p, &vw->clips))
-		return -EFAULT;
-
-	if (nclips) {
-		struct video_clip32 __user *u = compat_ptr(n);
-		int i;
-		if (!u)
-			return -EINVAL;
-		for (i = 0; i < nclips; i++, u++, p++) {
-			s32 v;
-			if (get_user(v, &u->x) ||
-			    put_user(v, &p->x) ||
-			    get_user(v, &u->y) ||
-			    put_user(v, &p->y) ||
-			    get_user(v, &u->width) ||
-			    put_user(v, &p->width) ||
-			    get_user(v, &u->height) ||
-			    put_user(v, &p->height) ||
-			    put_user(NULL, &p->next))
-				return -EFAULT;
-		}
-	}
-
-	return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p);
-}
-
-static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	union {
-		struct video_tuner vt;
-		struct video_buffer vb;
-		struct video_window vw;
-		unsigned long vx;
-	} karg;
-	mm_segment_t old_fs = get_fs();
-	void __user *up = compat_ptr(arg);
-	int err = 0;
-
-	/* First, convert the command. */
-	switch(cmd) {
-	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
-	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
-	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
-	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
-	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
-	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
-	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
-	};
-
-	switch(cmd) {
-	case VIDIOCSTUNER:
-	case VIDIOCGTUNER:
-		err = get_video_tuner32(&karg.vt, up);
-		break;
-
-	case VIDIOCSFBUF:
-		err = get_video_buffer32(&karg.vb, up);
-		break;
-
-	case VIDIOCSFREQ:
-		err = get_user(karg.vx, (u32 __user *)up);
-		break;
-	};
-	if(err)
-		goto out;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, cmd, (unsigned long)&karg);
-	set_fs(old_fs);
-
-	if(err == 0) {
-		switch(cmd) {
-		case VIDIOCGTUNER:
-			err = put_video_tuner32(&karg.vt, up);
-			break;
-
-		case VIDIOCGWIN:
-			err = put_video_window32(&karg.vw, up);
-			break;
-
-		case VIDIOCGFBUF:
-			err = put_video_buffer32(&karg.vb, up);
-			break;
-
-		case VIDIOCGFREQ:
-			err = put_user(((u32)karg.vx), (u32 __user *)up);
-			break;
-		};
-	}
-out:
-	return err;
-}
-
 struct compat_dmx_event {
 	dmx_event_t	event;
 	compat_time_t	timeStamp;
@@ -3015,14 +2777,6 @@
 #ifdef CONFIG_JBD_DEBUG
 HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl)
 #endif
-HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSWIN32, do_set_window)
-HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl)
 /* One SMB ioctl needs translations. */
 #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
 HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index 119f9d0..3398789 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -218,32 +218,6 @@
 COMPATIBLE_IOCTL(VT_RESIZEX)
 COMPATIBLE_IOCTL(VT_LOCKSWITCH)
 COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v */
-/* Little v, the video4linux ioctls (conflict?) */
-COMPATIBLE_IOCTL(VIDIOCGCAP)
-COMPATIBLE_IOCTL(VIDIOCGCHAN)
-COMPATIBLE_IOCTL(VIDIOCSCHAN)
-COMPATIBLE_IOCTL(VIDIOCGPICT)
-COMPATIBLE_IOCTL(VIDIOCSPICT)
-COMPATIBLE_IOCTL(VIDIOCCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCKEY)
-COMPATIBLE_IOCTL(VIDIOCGAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSYNC)
-COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCGMBUF)
-COMPATIBLE_IOCTL(VIDIOCGUNIT)
-COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
-/* BTTV specific... */
-COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
-COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
-COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
 /* Little p (/dev/rtc, /dev/envctrl, etc.) */
 COMPATIBLE_IOCTL(RTC_AIE_ON)
 COMPATIBLE_IOCTL(RTC_AIE_OFF)
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index d41df70..c8cbd90 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -240,6 +240,15 @@
 };
 
 
+/**
+ * When set, this flag will disable any zigzagging or other "normal" tuning
+ * behaviour. Additionally, there will be no automatic monitoring of the lock
+ * status, and hence no frontend events will be generated. If a frontend device
+ * is closed, this flag will be automatically turned off when the device is
+ * reopened read-write.
+ */
+#define FE_TUNE_MODE_ONESHOT 0x01
+
 
 #define FE_GET_INFO		   _IOR('o', 61, struct dvb_frontend_info)
 
@@ -260,6 +269,7 @@
 
 #define FE_SET_FRONTEND		   _IOW('o', 76, struct dvb_frontend_parameters)
 #define FE_GET_FRONTEND		   _IOR('o', 77, struct dvb_frontend_parameters)
+#define FE_SET_FRONTEND_TUNE_MODE  _IO('o', 81) /* unsigned int */
 #define FE_GET_EVENT		   _IOR('o', 78, struct dvb_frontend_event)
 
 #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index fb46f8d..6ff2d36 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -103,6 +103,7 @@
 #define I2C_DRIVERID_SAA711X	73	/* saa711x video encoders	*/
 #define I2C_DRIVERID_AKITAIOEXP	74	/* IO Expander on Sharp SL-C1000 */
 #define I2C_DRIVERID_INFRARED	75	/* I2C InfraRed on Video boards */
+#define I2C_DRIVERID_TVP5150	76	/* TVP5150 video decoder        */
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h
index 0e9e48b..121e26d 100644
--- a/include/linux/video_decoder.h
+++ b/include/linux/video_decoder.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_VIDEO_DECODER_H
 #define _LINUX_VIDEO_DECODER_H
 
+#define HAVE_VIDEO_DECODER 1
+
 struct video_decoder_capability { /* this name is too long */
 	__u32	flags;
 #define	VIDEO_DECODER_PAL	1	/* can decode PAL signal */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 1cded68..ce40675 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -642,6 +642,12 @@
 #define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
 #define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
 
+/* some merged standards */
+#define V4L2_STD_MN	(V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
+#define V4L2_STD_B	(V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
+#define V4L2_STD_GH	(V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
+#define V4L2_STD_DK	(V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
+
 /* some common needed stuff */
 #define V4L2_STD_PAL_BG		(V4L2_STD_PAL_B		|\
 				 V4L2_STD_PAL_B1	|\
@@ -662,7 +668,8 @@
 				 V4L2_STD_SECAM_G	|\
 				 V4L2_STD_SECAM_H	|\
 				 V4L2_STD_SECAM_DK	|\
-				 V4L2_STD_SECAM_L)
+				 V4L2_STD_SECAM_L       |\
+				 V4L2_STD_SECAM_LC)
 
 #define V4L2_STD_525_60		(V4L2_STD_PAL_M		|\
 				 V4L2_STD_PAL_60	|\
@@ -888,7 +895,6 @@
 
 /*  Flags for the 'mode' field */
 #define V4L2_AUDMODE_AVL		0x00001
-#define V4L2_AUDMODE_32BITS		0x00002
 
 struct v4l2_audioout
 {
@@ -1110,7 +1116,6 @@
 /* names for fancy debug output */
 extern char *v4l2_field_names[];
 extern char *v4l2_type_names[];
-extern char *v4l2_ioctl_names[];
 
 /*  Compatibility layer interface  --  v4l1-compat module */
 typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
@@ -1118,6 +1123,11 @@
 int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
 			       int cmd, void *arg, v4l2_kioctl driver_ioctl);
 
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+				unsigned long arg);
+
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_VIDEODEV2_H */
 
diff --git a/include/media/audiochip.h b/include/media/audiochip.h
index b7d4b09..295d256 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -23,11 +23,6 @@
 
 /* ---------------------------------------------------------------------- */
 
-/* v4l device was opened in Radio mode */
-#define AUDC_SET_RADIO        _IO('m',2)
-/* select from TV,radio,extern,MUTE */
-#define AUDC_SET_INPUT        _IOW('m',17,int)
-
 /* audio inputs */
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
@@ -40,15 +35,4 @@
 #define AUDIO_MUTE         0x80
 #define AUDIO_UNMUTE       0x81
 
-/* all the stuff below is obsolete and just here for reference.  I'll
- * remove it once the driver is tested and works fine.
- *
- * Instead creating alot of tiny API's for all kinds of different
- * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not
- * yet...).  It is a bit less flexible, but most/all used i2c chips
- * make sense in v4l context only.  So I think that's acceptable...
- */
-
-/* misc stuff to pass around config info to i2c chips */
-#define AUDC_CONFIG_PINNACLE  _IOW('m',32,int)
 #endif /* AUDIOCHIP_H */
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 16af929..e5e749e 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -178,6 +178,8 @@
 
 	struct saa7146_extension_ioctls *ioctls;
 	int (*ioctl)(struct saa7146_fh*, unsigned int cmd, void *arg);
+
+	struct file_operations vbi_fops;
 };
 
 struct saa7146_use_ops  {
diff --git a/include/media/tuner.h b/include/media/tuner.h
index b37cde6..7674b12 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -82,9 +82,9 @@
 #define TUNER_PHILIPS_FM1236_MK3	43
 
 #define TUNER_PHILIPS_4IN1		44	/* ATI TV Wonder Pro - Conexant */
-/* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
+/* Microtune merged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */
 #define TUNER_MICROTUNE_4049FM5 	45
-#define TUNER_MICROTUNE_4042_FI5	46
+#define TUNER_PANASONIC_VP27		46
 #define TUNER_LG_NTSC_TAPE		47
 
 #define TUNER_TNF_8831BGFF		48
@@ -102,7 +102,7 @@
 #define TUNER_YMEC_TVF_8531MF		58
 #define TUNER_YMEC_TVF_5533MF		59	/* Pixelview Pro Ultra NTSC */
 
-#define TUNER_THOMSON_DTT7611		60	/* DViCO FusionHDTV 3 Gold-T */
+#define TUNER_THOMSON_DTT761X		60	/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 #define TUNER_TENA_9533_DI		61
 #define TUNER_TEA5767			62	/* Only FM Radio Tuner */
 #define TUNER_PHILIPS_FMD1216ME_MK3	63
@@ -115,47 +115,26 @@
 #define TUNER_PHILIPS_TUV1236D		68	/* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69	/* Sabrent Bt848   */
 
-#define NOTUNER 0
-#define PAL     1	/* PAL_BG */
-#define PAL_I   2
-#define NTSC    3
-#define SECAM   4
-#define ATSC    5
-#define RADIO   6
-
-#define NoTuner 0
-#define Philips 1
-#define TEMIC   2
-#define Sony    3
-#define Alps    4
-#define LGINNOTEK 5
-#define SHARP   6
-#define Samsung 7
-#define Microtune 8
-#define HITACHI 9
-#define Panasonic 10
-#define TCL     11
-#define THOMSON 12
-
-#define TUNER_SET_TYPE_ADDR          _IOW('T',3,int)
-#define TUNER_SET_STANDBY            _IOW('T',4,int)
-#define TDA9887_SET_CONFIG           _IOW('t',5,int)
-
 /* tv card specific */
-# define TDA9887_PRESENT             (1<<0)
-# define TDA9887_PORT1_INACTIVE      (1<<1)
-# define TDA9887_PORT2_INACTIVE      (1<<2)
-# define TDA9887_QSS                 (1<<3)
-# define TDA9887_INTERCARRIER        (1<<4)
-# define TDA9887_PORT1_ACTIVE        (1<<5)
-# define TDA9887_PORT2_ACTIVE        (1<<6)
-# define TDA9887_INTERCARRIER_NTSC   (1<<7)
+#define TDA9887_PRESENT 		(1<<0)
+#define TDA9887_PORT1_INACTIVE 		(1<<1)
+#define TDA9887_PORT2_INACTIVE 		(1<<2)
+#define TDA9887_QSS 			(1<<3)
+#define TDA9887_INTERCARRIER 		(1<<4)
+#define TDA9887_PORT1_ACTIVE 		(1<<5)
+#define TDA9887_PORT2_ACTIVE 		(1<<6)
+#define TDA9887_INTERCARRIER_NTSC 	(1<<7)
+/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */
+#define TDA9887_TOP_MASK 		(0x3f << 8)
+#define TDA9887_TOP_SET 		(1 << 13)
+#define TDA9887_TOP(top) 		(TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8))
+
 /* config options */
-# define TDA9887_DEEMPHASIS_MASK     (3<<16)
-# define TDA9887_DEEMPHASIS_NONE     (1<<16)
-# define TDA9887_DEEMPHASIS_50       (2<<16)
-# define TDA9887_DEEMPHASIS_75       (3<<16)
-# define TDA9887_AUTOMUTE            (1<<18)
+#define TDA9887_DEEMPHASIS_MASK 	(3<<16)
+#define TDA9887_DEEMPHASIS_NONE 	(1<<16)
+#define TDA9887_DEEMPHASIS_50 		(2<<16)
+#define TDA9887_DEEMPHASIS_75 		(3<<16)
+#define TDA9887_AUTOMUTE 		(1<<18)
 
 #ifdef __KERNEL__
 
@@ -167,10 +146,26 @@
 	T_STANDBY	= 1 << 31
 };
 
+/* Older boards only had a single tuner device. Nowadays multiple tuner
+   devices may be present on a single board. Using TUNER_SET_TYPE_ADDR
+   to pass the tuner_setup structure it is possible to setup each tuner
+   device in turn.
+
+   Since multiple devices may be present it is no longer sufficient to
+   send a command to a single i2c device. Instead you should broadcast
+   the command to all i2c devices.
+
+   By setting the mode_mask correctly you can select which commands are
+   accepted by a specific tuner device. For example, set mode_mask to
+   T_RADIO if the device is a radio-only tuner. That specific tuner will
+   only accept commands when the tuner is in radio mode and ignore them
+   when the tuner is set to TV mode.
+ */
+
 struct tuner_setup {
-	unsigned short	addr;
-	unsigned int	type;
-	unsigned int	mode_mask;
+	unsigned short	addr; 	/* I2C address */
+	unsigned int	type;   /* Tuner type */
+	unsigned int	mode_mask;  /* Allowed tuner modes */
 };
 
 struct tuner {
@@ -207,7 +202,6 @@
 	void (*standby)(struct i2c_client *c);
 };
 
-extern unsigned int tuner_debug;
 extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
@@ -219,15 +213,15 @@
 
 #define tuner_warn(fmt, arg...) do {\
 	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 #define tuner_info(fmt, arg...) do {\
 	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 #define tuner_dbg(fmt, arg...) do {\
-	if (tuner_debug) \
-		printk(KERN_DEBUG "%s %d-%04x: " fmt, \
-			t->i2c.driver->driver.name, \
-			t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+	extern int debug; \
+	if (debug) \
+		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index d3fd481..3cc3132 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -26,12 +26,57 @@
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
-/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
-enum v4l2_audio_clock_freq {
-	V4L2_AUDCLK_32_KHZ  = 32000,
-	V4L2_AUDCLK_441_KHZ = 44100,
-	V4L2_AUDCLK_48_KHZ  = 48000,
-};
+/* v4l debugging and diagnostics */
+
+/* Common printk constucts for v4l-i2c drivers. These macros create a unique
+   prefix consisting of the driver name, the adapter number and the i2c
+   address. */
+#define v4l_printk(level, name, adapter, addr, fmt, arg...) \
+	printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg)
+
+#define v4l_client_printk(level, client, fmt, arg...)			    \
+	v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \
+		   (client)->addr, fmt , ## arg)
+
+#define v4l_err(client, fmt, arg...) \
+	v4l_client_printk(KERN_ERR, client, fmt , ## arg)
+
+#define v4l_warn(client, fmt, arg...) \
+	v4l_client_printk(KERN_WARNING, client, fmt , ## arg)
+
+#define v4l_info(client, fmt, arg...) \
+	v4l_client_printk(KERN_INFO, client, fmt , ## arg)
+
+/* These three macros assume that the debug level is set with a module
+   parameter called 'debug'. */
+#define v4l_dbg(level, client, fmt, arg...)				     \
+	do { 								     \
+		extern int debug;					     \
+		if (debug >= (level))					     \
+			v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \
+	} while (0)
+
+/* Prints the ioctl in a human-readable format */
+extern void v4l_printk_ioctl(unsigned int cmd);
+
+/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
+#define v4l_print_ioctl(name, cmd)  		 \
+	do {  					 \
+		printk(KERN_DEBUG "%s: ", name); \
+		v4l_printk_ioctl(cmd);		 \
+	} while (0)
+
+/* Use this macro in I2C drivers where 'client' is the struct i2c_client
+   pointer */
+#define v4l_i2c_print_ioctl(client, cmd) 		   \
+	do {      					   \
+		v4l_client_printk(KERN_DEBUG, client, ""); \
+		v4l_printk_ioctl(cmd);			   \
+	} while (0)
+
+/* ------------------------------------------------------------------------- */
+
+/* Internal ioctls */
 
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
 struct v4l2_register {
@@ -70,6 +115,20 @@
 	V4L2_IDENT_CX25843 = 243,
 };
 
+/* audio ioctls */
+/* v4l device was opened in Radio mode */
+#define AUDC_SET_RADIO        _IO('d',88)
+/* select from TV,radio,extern,MUTE */
+#define AUDC_SET_INPUT        _IOW('d',89,int)
+
+/* tuner ioctls */
+/* Sets tuner type and its I2C addr */
+#define TUNER_SET_TYPE_ADDR          _IOW('d',90,int)
+/* Puts tuner on powersaving state, disabling it, except for i2c */
+#define TUNER_SET_STANDBY            _IOW('d',91,int)
+/* Sets tda9887 specific stuff, like port1, port2 and qss */
+#define TDA9887_SET_CONFIG           _IOW('d',92,int)
+
 /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
 #define	VIDIOC_INT_S_REGISTER 		_IOR ('d', 100, struct v4l2_register)
 #define	VIDIOC_INT_G_REGISTER 		_IOWR('d', 101, struct v4l2_register)
@@ -77,10 +136,12 @@
 /* Reset the I2C chip */
 #define VIDIOC_INT_RESET            	_IO  ('d', 102)
 
-/* Set the frequency of the audio clock output.
+/* Set the frequency (in Hz) of the audio clock output.
    Used to slave an audio processor to the video decoder, ensuring that audio
-   and video remain synchronized. */
-#define VIDIOC_INT_AUDIO_CLOCK_FREQ 	_IOR ('d', 103, enum v4l2_audio_clock_freq)
+   and video remain synchronized.
+   Usual values for the frequency are 48000, 44100 or 32000 Hz.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ 	_IOW ('d', 103, u32)
 
 /* Video decoders that support sliced VBI need to implement this ioctl.
    Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
@@ -107,4 +168,10 @@
    be made. */
 #define VIDIOC_INT_G_CHIP_IDENT		_IOR ('d', 107, enum v4l2_chip_ident *)
 
+/* Sets I2S speed in bps. This is used to provide a standard way to select I2S
+   clock used by driving digital audio streams at some board designs.
+   Usual values for the frequency are 1024000 and 2048000.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_I2S_CLOCK_FREQ 	_IOW ('d', 108, u32)
+
 #endif /* V4L2_COMMON_H_ */