diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
index 2dc260b2b0a4a417c0e489b4713037373d1b0dd5..068070ff13cd0a4673d9333341b39ea5b77daf41 100644
--- a/Documentation/dvb/avermedia.txt
+++ b/Documentation/dvb/avermedia.txt
@@ -150,7 +150,8 @@ Getting the card going
 
    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 be6eb4c759915ff4c56db77c8448e14da3b3aaca..75c28a174092f5236e9dddc98444fff4b84e9183 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -23,7 +23,7 @@ use IO::Handle;
 
 @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 @@ for ($i=0; $i < scalar(@components); $i++) {
     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 @@ sub nxt2002 {
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
     checkstandard();
-    
+
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
     verify("$tmpdir/SkyNETU.sys", $hash);
@@ -308,6 +312,19 @@ sub or51132_vsb {
     $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 5c1e984c26a76827e27a5b2bed80ce35666bc060..b2f271cd784bc5ce41100ce123a6d1bf9a4f0a64 100644
--- a/Documentation/dvb/ttusb-dec.txt
+++ b/Documentation/dvb/ttusb-dec.txt
@@ -41,4 +41,5 @@ Hotplug Firmware Loading for 2.6 kernels
 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 330246ac80f80f282e987d83d78acac8856ddc14..74fb085e178b9da6c37cd3efa0224626665ec371 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 a1017d1a85d4b83988865fc47af683023fa22ba6..34b6e59f2968244421e23739d852b69610f83393 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 efb708ec116ace349ccabdb31ccc0a1123fe5238..cb3a59bbeb172b0aad3a7b95e6a9123482a340ae 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 9d6544ea9f41881f0df7fea74f4f31b90211b9e5..0bf3d5bf9ef8c2a837fee536e9da636c7dd4bc36 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
 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=48 - Tenna TNF 8831 BGFF)
 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=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 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 09ec964dec5c07742e4afa923c80f7f360762a07..b614612be7b439252c97451ced9e9de34a93609e 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
 
 	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 @@ static int fops_release(struct inode *inode, struct file *file)
 		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 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
 		BUG();
 		return 0;
 	}
+
 	return videobuf_mmap_mapper(q,vma);
 }
 
@@ -381,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
 		}
 	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_read(struct file *file, char __user *data, size_t count, lof
 	}
 }
 
+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 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 	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 ec52dff8cb695a35fb72687b1aa508c5196b1b97..33bec8a6843b49bdc05ec9345326bad23a316a11 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
 
 	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 063986ec16b51752868cf1d8440875202327aac7..468d3c9590755bfa44bc7ec7fdcf2d20b3756071 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -500,9 +500,9 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
 }
 
 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 1d961023b837c973852225cc0ba621205d4651ed..7ebac7949df3789aa165ba472a26d6fc319a9651 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -151,8 +151,8 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
 
 	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 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
 		return 0;
 	}
 	case VIDIOC_OVERLAY:
-
-
-
-
 	{
 		int on = *(int *)arg;
 		int err = 0;
@@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	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 21a9045b3ef6f1358cea5d823ed86dfb7553ba05..0b940e152b7973ceb6db8f504fd7e8f36782b013 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 flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
 }
 
 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 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
 /* 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;
+
+		ops->set_voltage = flexcop_set_voltage;
 
-		fc->fe_sleep             = fc->fe->ops->sleep;
-		fc->fe->ops->sleep       = flexcop_sleep;
+		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 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 	} 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;
+
+		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->fe_sleep                        = fc->fe->ops->sleep;
-		fc->fe->ops->sleep                  = flexcop_sleep;
+		fc->fe_sleep                = ops->sleep;
+		ops->sleep                  = flexcop_sleep;
 
-		fc->dev_type                        = FC_SKY_OLD;
+		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 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 	} 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 23cc6431e2b819fc70ae92ea51b93af856ebd64c..3153f9513c6319386eeadb753befc05fb48e544a 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -39,11 +39,13 @@ extern const char *flexcop_device_names[];
 /* 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 8977c7a313df5aadb4bf66ab0722b6f0e1a69aa8..3a2ff1cc24b709eb70fad464b0deb36ac9744fbe 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
 	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);
-
-	} 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);
+		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);
+		}
+		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 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 
 	.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 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 
 	.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 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 
 	.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 2239651969c88f236c073d691e4598722fdc27d3..c650b4bf7f5f8caee597fb19455ad0dd70593290 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message,
 		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 77977e9c013e7d1e1bfd0b157a5f461e9418502b..01b4e0aac0491fc0620414f84f1207263d9a0f1e 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 	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 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 			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 @@ static int dvb_bt8xx_probe(struct device *dev)
 		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 @@ static int dvb_bt8xx_probe(struct device *dev)
 		 * 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 7cf4c4a888ec6626055380d4c7b1406799c6dfc0..6018fcdba1e6dc6ec02fa9a61d1a742c6b2bca71 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING
 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_QUERY_INTERVAL
 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_ENABLE_RC_INPUT_DEVICE
 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 1d69bf031fb97efdce8c04c1e32520fa074a4bcc..c4b4c5b6b7c803d2ae7e8c7299901be9380a94fd 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -131,6 +131,8 @@ struct cinergyt2 {
 
 	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 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 	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 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 	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 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-	int err;
+	int err = -ERESTARTSYS;
 
-	if ((err = dvb_generic_open(inode, file)))
+	if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+		return -ERESTARTSYS;
+
+	if ((err = dvb_generic_open(inode, file))) {
+		up(&cinergyt2->sem);
 		return err;
+	}
 
-	if (down_interruptible(&cinergyt2->sem))
-		return -ERESTARTSYS;
 
 	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 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
 	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 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
 
 	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 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
 {
 	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 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
 				(__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 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
 		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 @@ static void cinergyt2_query_rc (void *data)
 	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 int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
 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 @@ static void cinergyt2_query (void *data)
 	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 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
 {
 	struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-	if (down_interruptible(&cinergyt2->sem))
-		return;
+	flush_scheduled_work();
 
 	cinergyt2_unregister_rc(cinergyt2);
 
+	cancel_delayed_work(&cinergyt2->query_work);
+	wake_up_interruptible(&cinergyt2->poll_wq);
+
 	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);
+	cinergyt2->disconnect_pending = 1;
 
-	cinergyt2_free_stream_urbs(cinergyt2);
-	up(&cinergyt2->sem);
-	kfree(cinergyt2);
+	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 @@ static int cinergyt2_resume (struct usb_interface *intf)
 	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_exit (cinergyt2_exit);
 
 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 a9a7b342104816b0c78d870efd6030567cee86d8..12ee912a5705176af05f73be9e61ffa2e140687d 100644
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ b/drivers/media/dvb/dvb-core/Kconfig
@@ -5,7 +5,7 @@ config DVB_CORE
 	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 c6baac20f529062fae13e894181a520460ae6ce0..7adb50c1e8ebb0c3f9ab8a5e60c9c9f7784b4328 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 5956c35d34accd234cf1cf5ecf4bc0fdd0a2f12f..4bb779aeff6af804f3682fca089b5e075add7f18 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 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 
 	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 c49fd0bd7181dd89a2c67d73a891e5073cde6e9f..772003fb18219fa741cd060f3af7271ef53c29f0 100644
--- a/drivers/media/dvb/dvb-core/dvb_filter.c
+++ b/drivers/media/dvb/dvb-core/dvb_filter.c
@@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp)
 
 	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 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t
 	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 95ea5095e07e07ae0ecb5d46240aaa297d7b7442..4a08c4ab67309190b07e8bb1491d12fdd695b8cd 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
 
 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 @@ struct dvb_frontend_private {
 	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 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
 		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 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
  * @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 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
 	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 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 
 	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 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
 	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 @@ static int dvb_frontend_thread(void *data)
 	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 @@ static int dvb_frontend_thread(void *data)
 
 		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 @@ static int dvb_frontend_thread(void *data)
 		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 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			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 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
 	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 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			 * 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 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
 	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 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			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 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
 		/*  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 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
 	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 1e0840d02f1f5e0307cbd7b9cc1d9eabc53c7f56..70a6d14efda72dddb4b2cb9b92127e77534ce853 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
 	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 @@ struct dvb_frontend_ops {
 	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 86bba81e851e0efe9eeed9b06979493328439dcc..6711eb6a058c9bc6548bb323c684785e549a3466 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
 	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 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
 
 		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 283c6e9339a4651b5b6c954e124d7e38025a1d0a..77ad2410f4d3cd29cfb3a63a72c6dd6512c22cba 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
 	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 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
 		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_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
 }
 
 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 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 	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 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 		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 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
 	// 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 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
 		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 fa476f662f82c453da2028ca8267fee6b6ae11f8..6d25609727719df623adfd83fde491fb1d071cf2 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
 ** 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 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
 ** 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 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
  * 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 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
  * 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 a4aee8665854f49691e2f695b6803fa792a80b33..06b696e9acbdf0857ac9a4fd34473accc43fa3b8 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file)
 		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 @@ int dvb_usercopy(struct inode *inode, struct file *file,
 	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 @@ int dvb_usercopy(struct inode *inode, struct file *file,
 	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 0cc6e4a0e27c7e37924c36be26403822536c6b36..74ed5853f0fb02c1d0be40518d7426b50c2d3b44 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become
 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 54e2b29076b12efc981d328cf09d51dce144ccd7..90a69d343b79833c429263e22b9faf4c57b689a1 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB
 	  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
+	    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
-	    Avermedia AverTV DVBT USB1.1
-	    Artec T1 USB1.1 boxes
+	    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 @@ config DVB_USB_DIBUSB_MB
 	  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 @@ config DVB_USB_DIBUSB_MC
 	  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 d05fab01cccdb9b34093b0dfdda028b45ad27275..358ed153865ff1c6731ca6108978b5d83e19c0f7 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 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
 	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 @@ struct cx22702_config cxusb_cx22702_config = {
 	.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 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d)
 	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 @@ static struct dvb_usb_properties cxusb_properties = {
 
 	.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_properties = {
 	}
 };
 
+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 135c2a81f5817f5685745d22966483737afd7190..087c99427853f6a51496b6598f7aec5bb8941859 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug;
 #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 52ac3e5adf5dd99de63a18821f57e258f8fcab69..dd5a131958862a8bd7090dc2328c81fc499bfc1a 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
 		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 @@ static int dibusb_probe(struct usb_interface *intf,
 
 /* 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 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
 /* 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 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
 		}
 	},
 
-#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 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
 			{ &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 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
 			{ &dibusb_dib3000mb_table[27], NULL },
 			{ NULL }
 		},
+		{ NULL },
 	}
 };
 
@@ -369,6 +378,7 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
 			{ &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 450417a9e64b6632fd62cc3affd346a55203da9d..e6c55c9c9417d2afe8bf67a0b906c0342548f56c 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
 	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 6e2bac873445700e7d83b1e5317763b3e16263db..130ea7f21f5e62eb27331a3d6bfcef03c0b18939 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = {
 		  .cold_ids = { &dtt200u_usb_table[0], NULL },
 		  .warm_ids = { &dtt200u_usb_table[1], NULL },
 		},
-		{ NULL },
+		{ 0 },
 	}
 };
 
@@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = {
 	.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 @@ static struct dvb_usb_properties wt220u_properties = {
 		  .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 6f1f3042e21a54a5ce3f70be303601d66d5670dc..005b0a7df3585d1653e61d8b8a63a9278a0ab7cf 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 @@ extern int dvb_usb_dtt200u_debug;
  *  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 @@ extern int dvb_usb_dtt200u_debug;
  *  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 7300489d3e2420b66bcdf21450394faab5106e22..a3460bf2d9fa56eb1ab4495678a51ede6b0d4b63 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 @@ extern int dvb_usb_disable_rc_polling;
 #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 5244e39770a0e425cc691420240bde8ea1deb715..8535895819fb5e1d8d72bdadbdd6f07ace87fe97 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 @@ struct usb_cypress_controller {
 };
 
 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 struct usb_cypress_controller cypress[] = {
 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;
 		}
+	} else
+		ret = -EIO;
 
-		kfree(p);
-	} else {
-		ret = -ENOMEM;
+	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;
 	}
-	release_firmware(fw);
 
+	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 da970947dfc72e5a77df1a4fa4a552c8ad16b038..9b254532af4dddd6e528c16c0a5770b3d8612173 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 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
 	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 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep
 {
 	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 6be99e537e12904bf4475c6e3bc3f837ad80627d..d229343832265f175af3f7778e3b556ed817ac34 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 dd8e0b94edbab6ae619c1a0d91abc667071b5ffc..2e23060cbbca736c4f8a0ea690ee3a893d36b9e9 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 dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
 	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,38 +148,40 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
 	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;
+	}
+
+	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,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);
-		}
+		memset(d->priv,0,d->props.size_of_priv);
+	}
 
-		usb_set_intfdata(intf, d);
+	usb_set_intfdata(intf, d);
 
-		if (du != NULL)
-			*du = d;
+	if (du != NULL)
+		*du = d;
 
-		ret = dvb_usb_init(d);
-	}
+	ret = dvb_usb_init(d);
 
 	if (ret == 0)
 		info("%s successfully initialized and connected.",desc->name);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index b4a1a98006c7d9f8abcf95686cb93db84b401fde..dd568396e594819aa0fba7e90bec3b7137605e86 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 @@ struct dvb_usb_device;
  * @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 @@ struct dvb_usb_properties {
 	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_init_i2c(struct dvb_frontend *);
 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 fac48fc7a4aca3e2b7df0f455be0190d48eb8133..412039d8dbae728a730fac25742701a7fe288ad2 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 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[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 @@ static struct usb_device_id nova_t_table [] = {
 /* 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 @@ static struct dvb_usb_properties nova_t_properties = {
 			{ &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 104b5d016c7b17e3c76376164b8c2464c18e9299..0885d9fb2bf231a6373fbbc30725d0adaf5ae67d 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_get_frontend(struct dvb_frontend* fe,
 }
 
 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 4a3e8c7eca2b862de2721e88f8707b7e94f5b2c9..a808d48e7bf24092ac6be65c6996c3582c42b354 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -13,47 +13,47 @@ extern int dvb_usb_vp702x_debug;
 /* 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 @@ extern int dvb_usb_vp702x_debug;
  * 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 3835235b68dff0f18793c0b711af42c3160ed6cd..028204956bb007ba31684552c20b844af5459f36 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = {
 		  .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 8e269e1c1f9dfb68e2ecae64e1a6b656da267741..db3a8b40031eaa379edaaa066f5d0423860a5b91 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -16,6 +16,12 @@ config DVB_CX24110
 	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 @@ comment "DVB-T (terrestrial) frontends"
 	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 @@ config DVB_SP887X
 
 	  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 @@ config DVB_CX22700
 	  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 @@ config DVB_TDA1004X
 
 	  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 @@ config DVB_VES1820
 	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 @@ config DVB_NXT2002
 	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 @@ config DVB_NXT200X
 	  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 a98760fe08a18a7c60d4f4e661dfe0fce514dfb3..615ec830e1c911d8c1adb28b93f73b51259e4bcd 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 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 8ceb9a33c7af35bb2fdd70cb9aa513f2947dd71d..3b132bafd4de0f0f39bcf87ab83b5b05ae444c88 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st)
 	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 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
 		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 5de0e6d350b1ae7223bee890f9710efda14f87d3..0fc899f81c5e9be0a16b1f263a09465fc3adeb96 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
 	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 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
 	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 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
 	} 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 @@ static int cx22702_init (struct dvb_frontend* fe)
 	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 @@ static struct dvb_frontend_ops cx22702_ops = {
 	.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 0c4db80ec332b7611e210308204e8a808b64e686..d15d32c51dc5dd466f133bbad301b1cc3824cb2f 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 int debug;
 
 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 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
 	 {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 0000000000000000000000000000000000000000..d661c6f9cbe527cfc0138ea79f2fc12fe315e310
--- /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 0000000000000000000000000000000000000000..0c922b5e9263e3579bf0a1a0a38b53d87366a35c
--- /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 f857b869616c305cff9cf1b66135eaa303eb6841..a3d57ce9dd1230ded1a291ad590e39703dcf7c54 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
 };
 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 497d31dcf41ebd0e832004ce6194f02a4b913287..24d4d2e9acd8fdcc6361621454af2c43a110cb18 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_dtt759x;
 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 cb5301865d07e9d0775bb9bb588ff3b05a3483fd..9d214643b87a4c65e1551070adfc636165bc13c4 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 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
 		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 52c416043a628f24dd24cc65279a4f45057f306a..4f263e65ba1419af035891219640146b63e8a327 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 a458a3bfff7009fa3ed80f99822edcef2e23507d..a16eeba0020d8484a8a43c44032eb754e831fdba 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = {
 		.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 531f76246e5f71bdd226632f4f908a5d8fcc60ec..7c3aed1f546be2609631206639271fbd6f9b178b 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 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
 	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 18715091aed8e779e2a64f1241a057aecf642574..d69477596921909e38ab53fda4d236f979352eb8 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
 
 		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 fc06cd6b46c3c843df95422811cb35faf3a44646..73829e647e50ad0cccb0e2f8cf6f8b18ada520ff 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 e3b6657822432e98f39fe3a6c6630d092a096581..eb8a602198ca99ad6990c783f31a305c368214b8 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 @@ static struct dvb_frontend_ops sp887x_ops = {
 		.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 177d71d56b67ac579ac9111c5397bffcbfa01dbe..5bcd00f792e63ac7dbe255223103c91b4015865e 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
 	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_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
 	};
 }
 
-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 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
 
 	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 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
 	      "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 9af3d71c89dbe9a6c5e5a90f54fe6bdd6f2c692f..32c87b4c2f1375ec78c267db07cc666130eb6642 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -94,6 +94,7 @@ struct stv0299_config
 };
 
 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 425cd19136fe351ed339077cb2e80863a2bf4268..21255cac9793e89b07a3627a076120364cb83163 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
 	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 @@ static struct dvb_frontend_ops tda10021_ops = {
 		.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 dd02aff467fe49c4acc7cd2674472cce88a10ad0..c63e9a5084eb7ffcb1c50b9efebee1a0f85b946c 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 tda10045h_set_bandwidth(struct tda1004x_state *state,
 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 int tda10045_fwupload(struct dvb_frontend* fe)
 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 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
 		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 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
 	/* 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 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
 			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 @@ static int tda10046_init(struct dvb_frontend* fe)
 
 	// 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 @@ static int tda10046_init(struct dvb_frontend* fe)
 	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 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
 	// 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_set_fe(struct dvb_frontend* fe,
 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 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
 			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 f02842be0d602b70dc3bca573ef0546bf496109c..84f8f9f52869a778f797d7dc2bfffb73f61b52b1 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -8,7 +8,7 @@ config DVB_PLUTO2
 	  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 fa5034a9ecf588ae955b751818b955814fc6eeb3..5b2aadb8385c2b92ee1d3b57145975fc185d848d 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -18,9 +18,10 @@ config DVB_AV7110
 	  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 825ab1c38a4f75f60077caa22a828514a3fedd91..a690730ac39d831054956e4a953ce560e18b7486 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 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 7dae91e5863c002c885e4247b8b253dfe37dc90c..8ce4146f55f12cc96953e1f96e6b0826fa3ea684 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110)
 	/* 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 @@ static void init_av7110_av(struct av7110 *av7110)
 	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,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
 
 	av7110_bootarm(av7110);
 	msleep(100);
-	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);
+	init_av7110_av(av7110);
+
+	/* card-specific recovery */
+	if (av7110->recover)
+		av7110->recover(av7110);
 
-	av7110->arm_errors++;
-	av7110->arm_ready = 0;
-	recover_arm(av7110);
+	restart_feeds(av7110);
+	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
 
 static void av7110_arm_sync(struct av7110 *av7110)
@@ -240,26 +244,22 @@ static int arm_thread(void *data)
 
 		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 @@ static void gpioirq(unsigned long data)
 		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 @@ static void gpioirq(unsigned long data)
 			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 struct dvb_device dvbdev_osd = {
 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 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 		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 @@ static void restart_feeds(struct av7110 *av7110)
 	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 @@ static void restart_feeds(struct av7110 *av7110)
 	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 @@ static int get_firmware(struct av7110* av7110)
 		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 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
 	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 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
 	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 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
 	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 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 	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 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
 	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 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
 	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 @@ static int frontend_init(struct av7110 *av7110)
 				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 @@ static int frontend_init(struct av7110 *av7110)
 				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 @@ static int frontend_init(struct av7110 *av7110)
 		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 @@ static int frontend_init(struct av7110 *av7110)
 				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 @@ static int frontend_init(struct av7110 *av7110)
 		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 cce00ef293e94fa41daa0419f54cca8b85778d61..6ea30df2e823c3dc54cf10699df7d2af4609ac3b 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -98,7 +98,8 @@ struct av7110 {
 	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 av7110 {
 	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 av7110 {
 
 	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 @@ struct av7110 {
 	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 0696a5a4f85594c963758fdc53b9b2932a320fe4..400facec740717d5d97f37af108b86dfe8373d0b 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
 		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 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 		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 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 		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 87106e8bf35bc83b3fa61c85018caae6c6436687..cb377452b57dcfef26ffa9cd070588f060fe55f2 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
 
 	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 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 			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 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
 	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 2a5e87ba10521129f04738ea5d9d178598581acd..84b83299b8bec7642c931ebf65177393860517e8 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
 	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 f5e59fc924afeaf1f75ebd320544a05eba209ba3..9138132ad25f3d10e93f4819e06ba70fe4a3ef22 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -17,6 +17,8 @@ static int av_cnt;
 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 @@ static void av7110_emit_key(unsigned long parm)
 	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_register_keys(void)
 
 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 b5aea4129fa7304aebdd237678f91760cd6aeb48..94cf38c7e8a809f8f5cf5ce2bba99c9f160aea0d 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 		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 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 	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 @@ static struct saa7146_extension_ioctls ioctls[] = {
 	{ 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 @@ int av7110_init_analog_module(struct av7110 *av7110)
 
 	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 @@ int av7110_init_v4l(struct av7110 *av7110)
 		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 int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 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 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
 
 	.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 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
 
 	.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 9f51bae7194c26430d98dc0ed86b2478f1a935d6..f9d00452e6393132c9bc044b8215bffca5eba680 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
 	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 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
 	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 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
 	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 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
 {
 	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 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
 	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 @@ static struct stv0299_config cinergy_1200s_config = {
 	.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 @@ static void frontend_init(struct budget_av *budget_av)
 	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 @@ MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 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 017fcbccb8cc8c1eb737e7b41916001c16f2496b..633e68c341c87d2c99ed72e1f434693b5bfc1c4f 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
 	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 fafe6407b3d0d3deb7ba658ea440321de1da44ee..238c77b52f89f7f0f759ec4dc99acd3487a240ae 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
  *   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 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
 
 	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 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 	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 @@ static void frontend_init(struct budget *budget)
 		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 @@ static void frontend_init(struct budget *budget)
 		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 @@ static void frontend_init(struct budget *budget)
 		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 18aa22b5478d654d15e37cddd7712c57bd09e609..1f31e91195b0c6817718d5ca4f6658247064416f 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 c6c1d41a2efb70c77b46db6a80450282d7fe4fdf..914587d52b57622131592134d7feef0e9d651c6b 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -10,7 +10,7 @@ config DVB_TTUSB_BUDGET
 	  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 c334526af66f27c436864294ca0377f48b7e1499..83611012ef345242460527b2452940bfa356e34f 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -8,14 +8,15 @@ config DVB_TTUSB_DEC
 	  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 8abc21890129f18867a12ed07a5dc6b9b478440e..d8966d1d25ee7c613df1411d20d558a00351d81a 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_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
 
 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_audio_pes2ts_cb(void *priv, unsigned char *data)
 
 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 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
 
 	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 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
 		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 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
 		     (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 @@ static int ttusb_init_rc(struct ttusb_dec *dec)
 	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 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec)
 			/* 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 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
 			   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 725af3af5b27105f5c2e8555e68de691272e41fc..a5a46175fa0969e302e59e75e14afa5a2e5cf2ab 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -42,8 +42,39 @@ struct ttusbdecfe_state {
 
 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 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron
 	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 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
 
 	.set_frontend = ttusbdecfe_dvbt_set_frontend,
 
+	.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
+
 	.read_status = ttusbdecfe_read_status,
 };
 
@@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
 		.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 c2ebe8754a9569bf326430a08920e3a096a2aa07..dc292da2605ffb4204dfcfb7c24b1ffc23256c42 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -220,6 +220,7 @@ static struct file_operations pcm20_fops = {
 	.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 877c770558e9c407350da4ea90d92b2e875cefd2..914deab4e04440c462e28a28998ff2c8c2e92141 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -299,6 +299,7 @@ static struct file_operations rtrack_fops = {
 	.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 5319a9c9a9796bbf4e0d769a3e120cd98d5dc952..523be820f9c64c3f6fd48fa226aebea16f5489ae 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -256,6 +256,7 @@ static struct file_operations aztech_fops = {
 	.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 9b0406318f2d9d31fa74f98dca827d343a1c1443..f1b5ac81e9d2bc734d6dd3345c12d0bd46fa235e 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -490,6 +490,7 @@ static struct file_operations cadet_fops = {
 	.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 630cc786d0a4f5065c357b150435dc1108a5dce7..42c8fce04aa2650aeded8b2f6e21f9adec07ac85 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -301,6 +301,7 @@ static struct file_operations gemtek_pci_fops = {
 	.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 6418f03b9ce4b74b1711e03a718efe952028bd06..47173be97b9fa5dbd74d84e6e5ebce0007393609 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -233,6 +233,7 @@ static struct file_operations gemtek_fops = {
 	.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 e5e2021a7312f4c82eee58b96e2a5bde455809dc..c30effdf711feb6ba8e5457b5c908ca472abeb52 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -72,6 +72,7 @@ static struct file_operations maestro_fops = {
 	.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 02d39a50d5ed2b742d6e2b65678056a249e096b7..30869308332af3bff2d3af7ba6e2098f0738fe0a 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -80,6 +80,7 @@ static struct file_operations maxiradio_fops = {
 	.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 b2256d675b4434f8f8553b13d4892089a6edff6e..28a47c9e7a819a4791d122d02380ca12e46ffd40 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -199,6 +199,7 @@ static struct file_operations rtrack2_fops = {
 	.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 6f03ce4dd7b0e4fb076c72dcfe9cdec20b122c8f..0229f792a05969717a7271356a03a1a6c51da3ce 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -225,6 +225,7 @@ static struct file_operations fmi_fops = {
 	.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 71971e9bb3422c36acb8280becdfbf03a9c37944..26632cead09a7dc7dd5d59388b719b6f3684b842 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -356,6 +356,7 @@ static struct file_operations fmr2_fops = {
 	.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 b03573c6840e56e632bd52f60aa90aabc45abc81..fcfde2e4f1958d47d1c4ec34d69f610cb1733e0b 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -276,6 +276,7 @@ static struct file_operations terratec_fops = {
 	.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 b300bedf7c743825cdffd13b5a58c212d28ff8e2..5a099a50d4d060e1af66e7a31711d7b3182fb2c8 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -255,6 +255,7 @@ static struct file_operations trust_fops = {
 	.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 f304f3c147637c92a7956f88c7fc548429f3338a..8ac9a8ef909441e98171dbb4b4f4e65d5c16b749 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -261,6 +261,7 @@ static struct file_operations typhoon_fops = {
 	.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 4c6d6fb49034e04a04d1c2d220e574b5aed1d434..d590e80c922e336a69d610f26f18f3cf28898652 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -313,6 +313,7 @@ static struct file_operations zoltrix_fops =
 	.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 fc87efc5049c0c64ef3e660393ef042840e84a8a..2fe260fff85dd25b8d952f23dfbaff412cea4848 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,6 +7,15 @@ menu "Video For Linux"
 
 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 @@ config VIDEO_DECODER
 	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 82060f9909d89db008fa0c5c48dc32b46d5b0cc3..dd24896906fe732022303e7d8418bb075b1475f4 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 881cdcb1875d3f6dce6f9200065e27fe502738f7..7d5a068353f28d8c65ee077ceefa2e7f3d56fd60 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -749,6 +749,7 @@ static struct file_operations ar_fops = {
 	.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 1c3ff5f38a6d4e70d763330ee547396ec828429e..dda4aa6bef27c6da07a6fc104faef8972075edfe 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 @@ static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
 				       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 bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
 	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 @@ int bt832_init(struct i2c_client *i2c_client_s)
 	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 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 {
 	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 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 	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_attach(struct i2c_adapter *adap, int addr, int kind)
 
 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 @@ static int bt832_detach(struct i2c_client *client)
 {
 	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 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	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 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		}
 		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 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 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 012be639aa1861577dc2a5a4d98d6bbdab839068..1621ab133d232aa87b633039959c5def48071f10 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 @@ static struct CARD {
 	/* 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 @@ struct tvcard bttv_tvcards[] = {
 		.has_remote	= 1,
 		.gpiomask	= 0x1b,
 		.no_gpioirq     = 1,
-		.any_irq		= 1,
 	},
 	[BTTV_BOARD_PV143] = {
 		/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2817,6 +2820,22 @@ struct tvcard bttv_tvcards[] = {
 		.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 @@ static void miro_pinnacle_gpio(struct bttv *btv)
 		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 @@ static void miro_pinnacle_gpio(struct bttv *btv)
 		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 @@ void __devinit bttv_init_card2(struct bttv *btv)
 		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 @@ void __devinit bttv_init_card2(struct bttv *btv)
 		btv->has_remote=1;
 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
 		btv->gpioirq=1;
-	if (bttv_tvcards[btv->c.type].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 @@ void __devinit bttv_init_card2(struct bttv *btv)
 
 	/* 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 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
 	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 1ddf9ba613ef96c3e8b142dd41d322c02391cb3c..0e697034678806bd3b2a89b5c18bb1e267e211cd 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 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.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 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = 1,
+		.vbistart	= { 10, 273 },
 	},{
 		.v4l2_id        = V4L2_STD_SECAM,
 		.name           = "SECAM",
@@ -242,6 +247,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.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 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 7, 320 },
 	},{
 		.v4l2_id        = V4L2_STD_PAL_M,
 		.name           = "PAL-M",
@@ -274,6 +281,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.vdelay         = 0x1a,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 10, 273 },
 	},{
 		.v4l2_id        = V4L2_STD_PAL_N,
 		.name           = "PAL-N",
@@ -290,6 +298,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.vdelay         = 0x20,
 		.vbipack        = 144,
 		.sram           = -1,
+		.vbistart	= { 7, 320},
 	},{
 		.v4l2_id        = V4L2_STD_NTSC_M_JP,
 		.name           = "NTSC-JP",
@@ -306,6 +315,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.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 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
 		.vbipack        = 255,
 		.vtotal         = 524,
 		.sram           = -1,
+		.vbistart	= { 10, 273 },
 	}
 };
 static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -1510,14 +1521,6 @@ static struct videobuf_queue_ops bttv_video_qops = {
 	.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 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 		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 @@ static struct file_operations bttv_fops =
 	.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 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 	case VIDIOCSFREQ:
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
+	case VIDIOC_LOG_STATUS:
 		return bttv_common_ioctls(btv,cmd,arg);
 
 	default:
@@ -3701,8 +3693,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 
 	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 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 		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 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
 	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 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 	}
 
 	/* 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 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
 	/* 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 @@ static int bttv_init_module(void)
 	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 616a5b7e510c5c68c80ea845bf746d135c165dfa..575ce8b8e714d995a92c2f6f0daa53c09e6b2dac 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -113,24 +113,6 @@ void bttv_gpio_irq(struct bttv_core *core)
 	}
 }
 
-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 d6418c023d39070e0c2a2bb47913e1a6518c73bc..748d630c7fe49b06c16635b992edbfba6cda7c3c 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_algo_bit_data bttv_i2c_algo_bit_template = {
 
 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_algorithm bttv_algo = {
 };
 
 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 @@ int __devinit init_bttv_i2c(struct bttv *btv)
 	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 de1385e5d05ecce6871247c9cffe648a7a1bf0e3..12197f1b27578a7957dac30f78613f4f1b81ae55 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 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
 /* ---------------------------------------------------------------------- */
 
-/* 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 @@ static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
 	[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 @@ module_param(repeat_delay, int, 0644);
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
 
-#define DEVNAME "ir-kbd-gpio"
-#define dprintk(fmt, arg...)	if (debug) \
-	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 @@ static void ir_handle_key(struct IR *ir)
 
 	/* 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)
-{
-	struct IR *ir = dev_get_drvdata(&sub->dev);
 
-	if (!ir->polling)
-		ir_handle_key(ir);
 }
 
-static void ir_timer(unsigned long data)
+void bttv_input_irq(struct bttv *btv)
 {
-	struct IR *ir = (struct IR*)data;
+	struct bttv_ir *ir = btv->remote;
 
-	schedule_work(&ir->work);
+	if (!ir->polling)
+		ir_handle_key(btv);
 }
 
-static void ir_work(void *data)
+static void bttv_input_timer(unsigned long 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 @@ static u32 rc5_decode(unsigned int code)
 			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 @@ static int ir_rc5_irq(struct bttv_sub_device *sub)
 	}
 
 	/* 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 @@ static void ir_rc5_timer_end(unsigned long data)
 
 	/* 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 @@ static void ir_rc5_timer_end(unsigned long data)
 			/* 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_end(unsigned long data)
 	}
 }
 
-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 @@ static int ir_probe(struct device *dev)
 		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 @@ static int ir_probe(struct device *dev)
 	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;
-
-	ir->input = input_dev;
-	ir->sub = sub;
+	input_dev->cdev.dev = &btv->c.pci->dev;
 
+	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;
-}
-
-/* ---------------------------------------------------------------------- */
-
-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");
+	input_unregister_device(btv->remote->dev);
+	kfree(btv->remote);
+	btv->remote = NULL;
 }
 
-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 f4f58c60f152b2d178156c211ef13aad1a493bd5..72afdd64b8821f217d0f713ea6c9e07028053dae 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_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
 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 @@ void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
 	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 93298f06e0199b4776b010c93bbc8c58008c15d8..9feaa6bab2074906a374e4aecb2493b749a2c598 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_core {
 
 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 @@ struct tvcard
 	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 bttv_sub_driver {
 	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 @@ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
 			 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 1e6a5632c3c71a48ca479d69efdc4514376608d0..dd00c20ab95efb54c605117a20b6ddc7784f87d5 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 @@ struct bttv_tvnorm {
 	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 @@ extern struct bus_type bttv_sub_bus_type;
 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 @@ struct bttv {
 	/* 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 @@ struct bttv {
 
 	/* 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 0065d0c240d1465f5d93251430a1a8aa07f0e939..6bad93ef969fd402d6131a1a9c0d0a594c769d3b 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -875,6 +875,7 @@ static struct file_operations qcam_fops = {
 	.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 75442ec49f352b0a4e9c2cbf245abc3a930b71f7..9976db4f6da8f77d6f41961bc6115a23c82a25f2 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -687,6 +687,7 @@ static struct file_operations qcam_fops = {
 	.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 0000000000000000000000000000000000000000..6194b01255768484e066e2d7fc7f273938d6c60b
--- /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 b7ec9bf45085ea6e31ba526938654eb24a32f647..9f59541155d9bfbd004d22d2aed584b5173f8677 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3807,6 +3807,7 @@ static struct file_operations cpia_fops = {
 	.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 643ead1a87eea504324110193e5b5daf35fce6d2..b421068f7ea30bc3bf778cdd747b1e45284f9fc3 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_param(debug, bool, 0644);
 
 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_read(struct i2c_client *client, u8 reg)
 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 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
 	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 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
 	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_attach(struct i2c_adapter *adapter, int address, int kind)
 
 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 740908f8027d050ad1810d3f497b1a0ff2f3a253..cb9a7981e4081bc9ac284b2ff26c47b6f84fdd23 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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 	/* 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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			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 @@ inline static int set_audclk_freq(struct i2c_client *client,
 			cx25840_write4(client, 0x90c, 0x55550108);
 			break;
 		}
-		break;
 	}
 
 	/* deassert soft reset */
@@ -146,51 +141,36 @@ inline static int set_audclk_freq(struct i2c_client *client,
 	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 @@ inline static int get_volume(struct i2c_client *client)
 	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 @@ inline static void set_volume(struct i2c_client *client, int volume)
 	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 @@ inline static int get_bass(struct i2c_client *client)
 	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 @@ inline static int get_treble(struct i2c_client *client)
 	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 @@ inline static int get_balance(struct i2c_client *client)
 	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 void set_balance(struct i2c_client *client, int balance)
 	}
 }
 
-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 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 	struct v4l2_control *ctrl = arg;
 
 	switch (cmd) {
-	case AUDC_SET_INPUT:
-		return set_input(client, *(int *)arg);
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+		return set_audclk_freq(client, *(u32 *)arg);
+
 	case VIDIOC_G_CTRL:
 		switch (ctrl->id) {
 		case V4L2_CID_AUDIO_VOLUME:
@@ -339,6 +318,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 			return -EINVAL;
 		}
 		break;
+
 	case VIDIOC_S_CTRL:
 		switch (ctrl->id) {
 		case V4L2_CID_AUDIO_VOLUME:
@@ -360,6 +340,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 			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 3b09f46dddf68028fab1f486954897df846fce1d..d45237d508c45e868dafa4b3afef8103756ea72f 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -43,11 +43,11 @@ MODULE_LICENSE("GPL");
 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 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
 
 /* ----------------------------------------------------------------------- */
 
-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 @@ static inline void init_dll1(struct i2c_client *client)
 	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 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
 	/* 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 @@ static void input_change(struct i2c_client *client)
 		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 void input_change(struct i2c_client *client)
 	}
 }
 
-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 (state->cardtype == CARDTYPE_PVR150 ||
-		    state->cardtype == CARDTYPE_PVR150_WORKAROUND) {
-			/* CH_SEL_ADC2=1 */
-			cx25840_and_or(client, 0x102, ~0x2, 0x02);
-		}
-
-		/* Video Input Control */
-		if (state->cardtype == CARDTYPE_PG600) {
-			cx25840_write(client, 0x103, 0x11);
-		} else {
-			cx25840_write(client, 0x103, 0x46);
-		}
-
-		/* INPUT_MODE=0 */
-		cx25840_and_or(client, 0x401, ~0x6, 0x00);
-		break;
-
-	case CX25840_COMPOSITE0:
-	case CX25840_COMPOSITE1:
-		cx25840_dbg("now setting Composite input\n");
+	if (is_composite) {
+		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
+	} else {
+		int luma = vid_input & 0xf0;
+		int chroma = vid_input & 0xf00;
 
-		/* Video Input Control */
-		if (state->cardtype == CARDTYPE_PG600) {
-			cx25840_write(client, 0x103, 0x00);
-		} else {
-			cx25840_write(client, 0x103, 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;
 		}
-
-		/* 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);
+		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, 0x10);
+			reg &= 0xcf;
+			reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
 		}
+	}
 
-		/* INPUT_MODE=1 */
-		cx25840_and_or(client, 0x401, ~0x6, 0x02);
+	switch (aud_input) {
+	case CX25840_AUDIO_SERIAL:
+		/* do nothing, use serial audio input */
 		break;
+	case CX25840_AUDIO4: reg &= ~0x30; break;
+	case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+	case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+	case CX25840_AUDIO7: reg &= ~0xc0; break;
+	case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
 	default:
-		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 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
-	case CX25840_CID_CARDTYPE:
-		switch (ctrl->value) {
-		case CARDTYPE_PVR150:
-		case CARDTYPE_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 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
 	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 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
 	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 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
 	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 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 	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 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
-	case CX25840_CID_CARDTYPE:
-		ctrl->value = state->cardtype;
+	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 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 		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 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 		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 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 		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 int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 /* ----------------------------------------------------------------------- */
 
+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 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		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 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		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 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		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 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		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 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		break;
 
 	default:
-		cx25840_err("invalid ioctl %x\n", cmd);
 		return -EINVAL;
 	}
 
-	return result;
+	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -775,7 +872,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 	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 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 	/* 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 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 
 	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_detect_client(struct i2c_adapter *adapter, int address,
 
 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 @@ static struct i2c_driver i2c_driver_cx25840 = {
 	.driver = {
 		.name = "cx25840",
 	},
-
 	.id = I2C_DRIVERID_CX25840,
-
 	.attach_adapter = cx25840_attach_adapter,
 	.detach_client = cx25840_detach_client,
 	.command = cx25840_command,
@@ -892,11 +983,13 @@ static void log_status(struct i2c_client *client)
 	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 @@ static void log_status(struct i2c_client *client)
 	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 @@ static void log_status(struct i2c_client *client)
 	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 @@ static void log_status(struct i2c_client *client)
 	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 @@ static void log_status(struct i2c_client *client)
 		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 @@ static void log_status(struct i2c_client *client)
 		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");
-
-	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";
+	if (aud_input) {
+		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+	} else {
+		v4l_info(client, "Specified audio input:     External\n");
 	}
-	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 @@ static void log_status(struct i2c_client *client)
 	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 @@ static void log_status(struct i2c_client *client)
 		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 @@ static void log_status(struct i2c_client *client)
 		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 df9d50a75542461c22ee79535ed84d63196bc95a..e1a7823d82cdeee0e81d3d44b664a72f8da1a93d 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_param(firmware, charp, 0444);
 MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
 MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
 
-static inline void set_i2c_delay(struct i2c_client *client, int delay)
+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 set_i2c_delay(struct i2c_client *client, int delay)
 	}
 }
 
-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 @@ static inline void start_fw_load(struct i2c_client *client)
 		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 @@ static inline void end_fw_load(struct i2c_client *client)
 	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 cx25840_loadfw(struct i2c_client *client)
 	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 13ba4e15ddea9ae10ae25597d7d3039cc4552c9d..04d879da7d63f9e3ecc6094bec9d08662d184d43 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 @@ static inline int odd_parity(u8 c)
 	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 40aa59f9c52595b6142f8a1f2483d2347c8bb927..fd22f30dcc1bf6ed1155b3f651bd0e2875f5b71d 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 @@ int cx25840_loadfw(struct i2c_client *client);
 /* ----------------------------------------------------------------------- */
 /* 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 85ba4106dc79456621e090da7aba453808b9f0d5..76fcb4e995c92d86f14e864f762106aab4ed6e8e 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -29,6 +29,21 @@ config VIDEO_CX88_DVB
 	  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 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
 	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 @@ config VIDEO_CX88_DVB_NXT200X
 	---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 54401b02b7ce75c13dfc24df48c3b85c8d9196a7..e4b2134fe567ee8725125cd11d0907537e1e8189 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -4,7 +4,7 @@ cx8800-objs	:= cx88-video.o cx88-vbi.o
 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_OR51132)   += -DHAVE_OR51132=1
 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 0000000000000000000000000000000000000000..7695b521eb354a72eb6d6d12d16f0ad1976f4eab
--- /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 74e57a53116ff58d5b5bbecc9ad7f9ef3f977db8..a490621193132bbf294f5211c279f28542a20fc0 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 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
 	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 951709aa88ba37e77fe63f901162736f0306d300..a76d54503b6f45d094bcf0fe8eb68b5a3b387c55 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -611,12 +611,12 @@ struct cx88_board cx88_boards[] = {
 		.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 @@ struct cx88_board cx88_boards[] = {
 	},
 	[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 @@ struct cx88_board cx88_boards[] = {
 			.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 @@ struct cx88_subid cx88_subids[] = {
 		.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 @@ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
 	       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 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 	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 @@ void cx88_card_setup(struct cx88_core *core)
 		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 @@ void cx88_card_setup(struct cx88_core *core)
 		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 bb6eb54e19ceddcb4726ee9dfc5117baa8c73ef1..9975be1aca38979340b70a7a061d56702f7a1b41 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 unsigned int cx88_devcount;
 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 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
  *    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 @@ struct sram_channel cx88_sram_channels[] = {
 		.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 @@ struct sram_channel cx88_sram_channels[] = {
 		.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 @@ struct sram_channel cx88_sram_channels[] = {
 		.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 @@ int cx88_start_audio_dma(struct cx88_core *core)
 
 	/* start dma */
 	cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
-
 	return 0;
 }
 
@@ -1208,7 +1154,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
 
 /* ------------------------------------------------------------------ */
 
-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 99ea955f5987c058a50dabacee8b2377c3fbc75a..42c012aaa849de3314182fce35a435f8a9f9043f 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 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 	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 @@ static struct mt352_config dntv_live_dvbt_config = {
 	.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 @@ static struct cx22702_config hauppauge_novat_config = {
 	.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 @@ static struct nxt200x_config ati_hdtvwonder = {
 };
 #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 @@ static int dvb_register(struct cx8802_dev *dev)
 		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 @@ static int dvb_register(struct cx8802_dev *dev)
 		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 @@ static int dvb_register(struct cx8802_dev *dev)
 		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);
 		}
@@ -420,6 +604,17 @@ static int dvb_register(struct cx8802_dev *dev)
 		dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
 						 &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",
@@ -473,6 +668,12 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
 	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 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
 	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 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev)
 {
 	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 4a8fb161b16a935c205340ee85814c1c3991760b..f720901e963866bec677d1bed8354c7d71a77535 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 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
 {
 	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 461019dca90101262f502c6dc44dcfea45882b27..286c85b6bdf9a507232eadd2a44bc0e287067ecb 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 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
 
 /* ---------------------------------------------------------------------- */
 
+/* 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 @@ struct cx88_IR {
 	char phys[32];
 
 	/* sample from gpio pin 16 */
-	int sampling;
+	u32 sampling;
 	u32 samples[16];
 	int scount;
 	unsigned long release;
@@ -384,10 +491,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 	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 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		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 @@ int cx88_ir_fini(struct cx88_core *core)
 	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 @@ void cx88_ir_irq(struct cx88_core *core)
 	/* 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 @@ void cx88_ir_irq(struct cx88_core *core)
 			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 @@ void cx88_ir_irq(struct cx88_core *core)
 		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 35e6d0c2b872b8d2650e723d5ae1126b32c59792..c79cc1d2bf8b1f95c27d7151189b52195ab9b401 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -78,6 +78,11 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 		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 a1b120c8a9b51f9adc4188f49c420b3b4dc44f8f..24118e43e73a7c46d8319954c5a749813dd14ce1 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -132,14 +132,22 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
 {
 	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 24a48f8a48c18a16be2dd96e278703ae7f153753..9a02515fe18bc440b6c7a26fc32faf9e7f03ec14 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 @@ static struct cx88_ctrl cx8800_ctls[] = {
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x3f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 0,
@@ -271,7 +272,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
-			.default_value = 0,
+			.default_value = 0x7f,
 			.type          = V4L2_CTRL_TYPE_INTEGER,
 		},
 		.off                   = 0,
@@ -285,6 +286,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
 			.name          = "Mute",
 			.minimum       = 0,
 			.maximum       = 1,
+			.default_value = 1,
 			.type          = V4L2_CTRL_TYPE_BOOLEAN,
 		},
 		.reg                   = AUD_VOL_CTL,
@@ -298,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
 			.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 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
 		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 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 {
 	/* 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 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 		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 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 		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 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 
 	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 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ static struct file_operations video_fops =
 	.poll          = video_poll,
 	.mmap	       = video_mmap,
 	.ioctl	       = video_ioctl,
+	.compat_ioctl  = v4l_compat_ioctl32,
 	.llseek        = no_llseek,
 };
 
@@ -1767,6 +1762,7 @@ static struct file_operations radio_fops =
 	.open          = video_open,
 	.release       = video_release,
 	.ioctl         = radio_ioctl,
+	.compat_ioctl  = v4l_compat_ioctl32,
 	.llseek        = no_llseek,
 };
 
@@ -1928,8 +1924,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
 	/* 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 0000000000000000000000000000000000000000..372cd29cedbd73ef4fbdf6df5519ff726a2d7de8
--- /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 0000000000000000000000000000000000000000..b7a0a04d2423e4034d7c35a6de9f0712f13aca6d
--- /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 77beafc5c32764c81d67f89bdf3cfd784935a842..e9fd55b57fa61d3b691ee757f8f9388fcd1c1bd3 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -179,6 +179,14 @@ extern struct sram_channel cx88_sram_channels[];
 #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 @@ struct cx88_core {
 	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 @@ struct cx88_core {
 
 	/* 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 cx8802_dev {
 	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 @@ struct cx8802_dev {
 
 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 57779e63f35d344264ac94395542b532eec92b1a..58f7b4194a0d51a6359475923c93c84e6583dad5 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 @@ void em28xx_card_setup(struct em28xx *dev)
 	/* 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 @@ void em28xx_card_setup(struct em28xx *dev)
 
 		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 0cfe75416ec64a7af3242ccec6e8e4722796f35a..dff3893f32fdaa18d940f5309bd18354dbc8b3e5 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 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 		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 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
 		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 @@ static int alt = EM28XX_PINOUT;
 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 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
 	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 d14bcf4ceaeae621fad398f63cc4f7f74f139189..0591a705b7a1f9aed6f9f113610c16f7578479f8 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 @@ static struct i2c_adapter em28xx_adap_template = {
 	.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 3a56120397aeb45791f36fe23fd14480ca64c84a..fdc255918ddef1e11d8416cb170ceb1baecd1a3f 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,7 +107,31 @@ static const unsigned char saa7114_i2c_init[] = {
 #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,
@@ -134,24 +159,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
 		.step = 0x1,
 		.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,
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
 		.step = 0x1,
 		.default_value = 0x20,
 		.flags = 0,
-	 }
+	}
 };
 
 static struct usb_driver em28xx_usb_driver;
@@ -280,6 +287,8 @@ static void video_mux(struct em28xx *dev, int index)
 	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_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
  */
 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 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 	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 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
 	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 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
 	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 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
 	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;
-
-
-			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;
+			u8 i;
+
+			if (!dev->has_msp34xx){
+				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+					if (ctrl->id == em28xx_qctrl[i].id) {
+						if (ctrl->value <
+						em28xx_qctrl[i].minimum
+						|| ctrl->value >
+						em28xx_qctrl[i].maximum)
+							return -ERANGE;
+						return em28xx_set_ctrl(dev, ctrl);
+					}
+				}
+			}
 
-					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 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
 		return -ENODEV;
 
 	if (video_debug > 1)
-		em28xx_print_ioctl(dev->name,cmd);
+		v4l_print_ioctl(dev->name,cmd);
 
 	switch (cmd) {
 
@@ -1564,6 +1646,8 @@ static struct file_operations em28xx_v4l_fops = {
 	.poll = em28xx_v4l2_poll,
 	.mmap = em28xx_v4l2_mmap,
 	.llseek = no_llseek,
+	.compat_ioctl   = v4l_compat_ioctl32,
+
 };
 
 /******************************** usb interface *****************************************/
@@ -1848,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 	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 5c7a41ce69f37c69daaa441134a4c0fab301f304..33de9d846af5ed1cd1311784ad19daf928c00298 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 @@ struct em28xx {
 	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 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
 
 /* 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 3cc1d6a6019bf8f1b090c748e184ab0fe4072601..58b0e698282206e0e028423d202be8c24d5db35c 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -279,7 +279,7 @@ static int ir_probe(struct i2c_adapter *adap);
 
 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 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 	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 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 		 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 3f2a882bc20a6a6b31b00af7bef5278596f253db..2869464aee0d699677efccf99593dcdeb11526d3 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1754,6 +1754,7 @@ static struct file_operations meye_fops = {
 	.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 0000000000000000000000000000000000000000..aa8c556b6ba1f2e9ff413a33248c6302791515ed
--- /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 0000000000000000000000000000000000000000..2b59b6847535afeec755de3785d0e8efd0aec6b4
--- /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 183253e2dd91cbb25d52c8fccffadeb700f9cbc1..0000000000000000000000000000000000000000
--- 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 2d9ff40f0b09c0f6c8a3de98f60a82fe64c5c91e..8a05cf500a8cf8d882d830fb6cdc0c1556308a1e 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 @@ struct msp_matrix {
 #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 2180018f06de95af017850d319441650d1f16acb..2c19c9588c0287cb1c407b8fb665299b737e83d3 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -20,6 +20,9 @@ module_param(tv_antenna,        int, 0644);
 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 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
 	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 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
 	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 @@ int microtune_init(struct i2c_client *c)
 	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 d04793fb80fcae21cee6ceb903eb753ec7bf1006..91681aa6c6574261102deb36a60fe47fad63e005 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 2504207b2e3da83167668a1f947e965b79308704..9e6448639480c75f22553f4e4a9b924a7b194101 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -883,6 +883,7 @@ static struct file_operations pms_fops = {
 	.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 a51c7bd96618ef767123dfec1b3a923b29fb5520..73b4f0e2abf086d7974e76b6148f2822a8b33ecc 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -702,6 +702,7 @@ static struct file_operations saa_fops = {
 	.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 d60a783e04730b53c67c1a0b6ca5f4a8e2a8dfd3..e70b17ef36e9d0938d7b805f51527c0d8edd6f82 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -427,18 +427,8 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
 
 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 int saa6588_command(struct i2c_client *client, unsigned int cmd,
 
 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 29e28c742cd4b3e407c7845cefbf237e8212edde..4a4bc69fb0e97a7e95218a3fb563d51a68e841c6 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 @@ struct saa7115_state {
 	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 @@ static const unsigned char saa7115_init_misc[] = {
 	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_decode_wss(u8 * p)
 }
 
 
-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 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 	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 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
 	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 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
 	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 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
 
 	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 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
 	struct saa7115_state *state = i2c_get_clientdata(client);
 	int taskb = saa7115_read(client, 0x80) & 0x10;
 
+	/* 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 v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
 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 @@ static void saa7115_log_status(struct i2c_client *client)
 	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 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 
 	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 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 		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 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 		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 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 
 	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 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
 		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 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
 
 /* ============ 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 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 		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 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 	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 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 
 		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 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 
 	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 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
 		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 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
 	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 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
 	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 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
 	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_attach(struct i2c_adapter *adapter, int address, int kind)
 
 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 8008537391b5425ed3ce71c92cf3267cc6a2b580..f39a7be08588010fe5c29393793f2e576c5cbf1c 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -567,9 +567,7 @@ static struct i2c_driver i2c_driver_saa711x = {
 	.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 bca6ed0e27525e5b5d06068add0f2183a36a89eb..2009c1bc47207c1b1f4e8d8eb75d5e6027399e22 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -66,30 +66,6 @@ module_param(test_image, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 MODULE_PARM_DESC(test_image, "test_image (0-1)");
 
-#define saa7127_dbg(fmt, arg...) \
-	do { \
-		if (debug >= 1) \
-			printk(KERN_INFO "%s debug %d-%04x: " fmt, \
-			       client->driver->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 @@ static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
 		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 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 	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 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 	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 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
 	if (enable && (data->field != 0 || data->line != 21))
 		return -EINVAL;
 	if (state->cc_enable != enable) {
-		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 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
 	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 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 	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 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 	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 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 	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 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 
 	saa7127_write(client, 0x26, data->data[0]);
 	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-	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 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable)
 	struct saa7127_state *state = i2c_get_clientdata(client);
 
 	if (enable) {
-		saa7127_dbg("Enable Video Output\n");
+		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 @@ static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
 	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 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
 	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 @@ static int saa7127_set_input_type(struct i2c_client *client, int input)
 
 	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 @@ static int saa7127_command(struct i2c_client *client,
 		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 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 	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 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 	   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 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 
 	/* 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 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 	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_attach(struct i2c_adapter *adapter, int address, int kind)
 
 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 4615a982ac64c8470544611f8854ddd50b39c405..ad73c4a60f2b2078f788d2d45aed9502bd065441 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 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
 {
 	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 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
 	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 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 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 ade05f75fdb05d2c23165c42091913ca56f67859..a7a6ab9298a91062f67c2c1a089cd2ee87c35e57 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 672fb205959f8b21be1f6dc45c4635b8e6907d9e..77e5be98e4c67887d3b33c4fcf2d33e0d28a0d68 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 @@ struct saa7134_board saa7134_boards[] = {
 			.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);
@@ -2891,6 +2955,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.subvendor    = 0x1421,
 		.subdevice    = 0x0350,		/* PCI version */
 		.driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+	},{
+		.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,
@@ -3001,6 +3071,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.subvendor    = 0x1462,
 		.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,
@@ -3090,6 +3172,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 	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 23d8747338edee3e11dfb0d8d37ea04645f21cb9..accbc32725cf9d9fdd190c0ff5590e83d8d97291 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -95,77 +95,6 @@ int (*dmasound_exit)(struct saa7134_dev *dev);
 #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 @@ static int pending_call(struct notifier_block *self, unsigned long state,
 	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 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
 		    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 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
 			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 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
 		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 @@ static int saa7134_init(void)
 	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 @@ module_exit(saa7134_fini);
 
 /* ----------------------------------------------------------- */
 
-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 e016480c3468139c9f85b1650c29e6b300a1053e..399f9952596c30a64c46abd1162bcd7108a7e6ee 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 575f3e835f91e102aaba4a9719191f4c6cbd1ca8..bd4c389d4c37a6d190f61130ce8d686c630b8b73 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 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
 	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 1792d03d621d44596b0b75b7a5c149a6f0250b4c..6162550c413604c97069ae751ad5dbd415f0db14 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_algorithm saa7134_algo = {
 
 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 ab75ca5ac356b16862b0957f9a85d56dd5f650b4..82d28cbf289f1a1fe1bb5e22168ee32d8de2e001 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -56,23 +56,23 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
 	[   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 @@ static int build_key(struct saa7134_dev *dev)
 	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 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 		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 8badd2a9cb2ff08d1e5fe07661999c245e6708eb..7448e386a804cf0f6b50f202859d2fb9bcadb65b 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -373,6 +373,42 @@ static ssize_t dsp_write(struct file *file, const char __user *buffer,
 	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 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
 	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 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
 	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 45c852df13ed56c24c2f0332314144a1ef05d3ff..adfa8fe49a11547c468e5a418f88e841d106deb4 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 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 	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 @@ static struct file_operations video_fops =
 	.poll     = video_poll,
 	.mmap	  = video_mmap,
 	.ioctl	  = video_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek   = no_llseek,
 };
 
@@ -2271,6 +2273,7 @@ static struct file_operations radio_fops =
 	.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 add49db1ad41130d9d39408cdcd8975ff0f9c869..e70eae8d29bbed0bf4cb5ff7b6afb57dacb15079 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 @@ struct saa7134_format {
 #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 @@ struct saa7134_dev {
 
 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 d4497dbae05c7b641abaa617e9f17563847ecd0e..6ee54a45411f19ae95b1cf9f3cebe6b8b8b0f82d 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1974,6 +1974,7 @@ static struct file_operations saa_fops =
 	.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 549c9929f107a84c76861df192c5db736aa3b541..99261f15e66ebebdb15a3ea9921ff1029188d291 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 @@ struct tda7432 {
 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 struct i2c_client client_template;
 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 @@ static int tda7432_set(struct i2c_client *client)
 {
 	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 @@ static int tda7432_set(struct i2c_client *client)
 	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 int tda7432_set(struct i2c_client *client)
 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 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
 {
 	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 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
 	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 @@ static int tda7432_command(struct i2c_client *client,
 			   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 @@ static int tda7432_command(struct i2c_client *client,
 	case VIDIOCGAUDIO:
 	{
 		struct video_audio *va = arg;
-		dprintk("tda7432: VIDIOCGAUDIO\n");
 
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
@@ -414,7 +407,6 @@ static int tda7432_command(struct i2c_client *client,
 	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 @@ static int tda7432_command(struct i2c_client *client,
 
 	} /* 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 int tda7432_command(struct i2c_client *client,
 
 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 struct i2c_client client_template =
 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 61d94ddaff41f836f925a96a997266623aabb8c8..2498b76df429c3d36cd48588703a4e0513b896e7 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -398,14 +398,8 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 	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 9c3ecf7a0fedef2b25f0fd19ac0d9a8b2a30ffcc..299393bf900a38c7fd67754a8845a8be102f070e 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -257,13 +257,8 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
 
 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 int tda9875_command(struct i2c_client *client,
 
 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 7165a1b9625a475a00283fc36c0daa1551fb9336..9cf47dc65579c28acc2b9fcf4224593884484745 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 @@ struct tda9887 {
 	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 @@ static struct i2c_client client_template;
 #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 i2c_client client_template;
 
 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 @@ static struct tvnorm tvnorms[] = {
 		.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 @@ static struct tvnorm tvnorms[] = {
 		.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 @@ static struct tvnorm radio_stereo = {
 	.b    = ( cFmRadio       |
 		  cQSS           ),
 	.c    = ( cDeemphasisOFF |
-		  cAudioGain6 ),
-	.e    = ( cAudioIF_5_5   |
+		  cAudioGain6    |
+		  cTopNtscRadioDefault),
+	.e    = ( cTunerGainLow  |
+		  cAudioIF_5_5   |
 		  cRadioIF_38_90 ),
 };
 
@@ -236,8 +272,10 @@ static struct tvnorm radio_mono = {
 	.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 int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
 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 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
 			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 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
 			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_config(struct tda9887 *t, char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
-{
-	unsigned int bCarrierMode = UNSET;
-
-	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[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
 
-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 @@ static int tda9887_fixup_std(struct tda9887 *t)
 		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 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			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 @@ static int tda9887_fixup_std(struct tda9887 *t)
 	}
 	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 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			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 @@ static int tda9887_fixup_std(struct tda9887 *t)
 			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 @@ static int tda9887_configure(struct tda9887 *t)
 	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 @@ static int tda9887_configure(struct tda9887 *t)
 		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 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
 
 	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_attach(struct i2c_adapter *adap, int addr, int kind)
 
 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_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		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 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
 	}
 	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 @@ static struct i2c_driver driver = {
 	.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 a9375ef05de121b5986060fc6c464f97d0d53e3f..261b7a3c041735ce88337db628495c2c0c485526 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 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
 	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 @@ static int tea5767_signal(struct i2c_client *c)
 	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 c13c7b95ef35860f581c008d3f15e0f07fcfba74..57bc585a6955c135dfad3c37fefd0f4eaf58c79c 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 @@ I2C_CLIENT_INSMOD;
 
 /* 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 @@ static inline int check_mode(struct tuner *t, char *cmd)
 	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 @@ static int tuner_fixup_std(struct tuner *t)
 			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 @@ static int tuner_fixup_std(struct tuner *t)
 	}
 	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 @@ static int tuner_fixup_std(struct tuner *t)
 		}
 	}
 
+	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 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
 	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 inline int check_v4l2(struct tuner *t)
 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 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 				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;
@@ -522,9 +585,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		/* Should be implemented, since bttv calls it */
 		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
@@ -708,10 +768,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 			}
 			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 @@ static struct i2c_driver driver = {
 	.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 e0c9fdb9914a673846ba6ffb3aae3cee5d55d7c3..e5fb7436583692041008d01af5aee86d55f58cf6 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 @@ struct tunertype
  */
 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 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 	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 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 	 * 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 0292c5abf14aab3fe1355a31c0bc8abab3e8a01a..b582943a0d3e57406f9d3ed1434c20f26586b873 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 @@ MODULE_LICENSE("GPL");
 
 #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 @@ struct CHIPSTATE {
 	/* current settings */
 	__u16 left,right,treble,bass,mode;
 	int prevmode;
-	int norm;
+	int radio;
 
 	/* thread */
 	pid_t                tpid;
@@ -142,8 +132,6 @@ struct CHIPSTATE {
 	int                  watch_stereo;
 };
 
-#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
-
 /* ---------------------------------------------------------------------- */
 /* i2c addresses                                                          */
 
@@ -171,23 +159,23 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
 	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 @@ static int chip_read(struct CHIPSTATE *chip)
 	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 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
 	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 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 		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 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 
 	/* 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 @@ static int chip_thread(void *data)
 
 	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 @@ static int chip_thread(void *data)
 		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 @@ static int chip_thread(void *data)
 		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 @@ static void generic_checkmode(struct CHIPSTATE *chip)
 	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 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
 	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 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
 		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 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-		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 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 	}
 
 	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 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
 		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 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
 			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 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 		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 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 		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 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
 	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 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
 	}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 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
 	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 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
 	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 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
 		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 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
 		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 @@ static int chip_probe(struct i2c_adapter *adap)
 	   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 @@ static int chip_command(struct i2c_client *client,
 	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 @@ static int chip_command(struct i2c_client *client,
 		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 @@ static int chip_command(struct i2c_client *client,
 			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 @@ static int chip_command(struct i2c_client *client,
 		}
 		break;
 	}
-	case VIDIOCSCHAN:
+
+	case VIDIOC_S_TUNER:
 	{
-		struct video_channel *vc = arg;
+		struct v4l2_tuner *vt = arg;
+		int mode = 0;
 
-		chip->norm = vc->norm;
+		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 @@ static int chip_command(struct i2c_client *client,
 			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 8ac4cb82a45949841d0383e0c3c2178139ab0d38..fd0acc5da66771e5c5af5aa73bff79537ea3ea30 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 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #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)
-
-
-/* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff                                           */
+		v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+	} while (0)
 
+/*
+ * 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 @@ static struct HAUPPAUGE_TUNER_FMT
 }
 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 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 	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 e837f9f7fed6924aae480db9e3b4458828cdaa1c..9e86caeb96a7b530da89b05e18a0cb44d53d7865 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -227,13 +227,9 @@ static int tvmixer_release(struct inode *inode, struct file *file)
 }
 
 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 @@ static int tvmixer_clients(struct i2c_client *client)
 	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 a60442ea4f94274d26995c29f492ea90b2c644e8..c35b8042eee58dd84bd7080a28801762bb36c4c9 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 @@ static int debug = 0;
 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 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
 		 .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 @@ static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
 
 	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 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
 {
 	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 @@ enum tvp5150_input {
 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[] =
 {
-	struct tvp5150 *decoder = i2c_get_clientdata(c);
+	{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 }
+};
 
-	tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+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;
+}
 
-	/* Automatic offset and AGC enabled */
-	tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+static int tvp5150_vdp_init(struct i2c_client *c,
+				 const struct i2c_vbi_ram_value *regs)
+{
+	unsigned int i;
 
-	/* Normal Operation */
-//      tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+	/* Disable Full Field */
+	tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
 
-	/* Activate YCrCb output 0x9 or 0xd ? */
-	tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+	/* 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);
 
-	/* Activates video std autodetection for all standards */
-	tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+	/* 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);
 
-	/* Default format: 0x47, 4:2:2: 0x40 */
-	tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+		for (i=0;i<16;i++)
+			tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
 
-	tvp5150_selmux(c, decoder->input);
+		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;
+
+	decoder->norm=std;
+
+	/* First tests should be against specific std */
+
+	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;
+		}
+	}
+
+	tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
+	tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
 
-	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
-	tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+	return 0;
+}
 
-	tvp5150_write(c, 0x27, 0x20);	/* ?????????? */
+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);
 
-	tvp5150_write(c, TVP5150_VIDEO_STD, 0x0);	/* Auto switch */
+	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);
+
+	/* Initializes TVP5150 to stream enabled values */
+	tvp5150_write_inittab(c, tvp5150_init_enable);
+
+	/* 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 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
 	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 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
 	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 @@ static int tvp5150_command(struct i2c_client *client,
 			}
 
 			decoder->input = *iarg;
-			tvp5150_selmux(client, decoder->input);
+			tvp5150_selmux(c, decoder->input);
 
 			break;
 		}
@@ -620,19 +955,18 @@ static int tvp5150_command(struct i2c_client *client,
 
 			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 @@ static int tvp5150_command(struct i2c_client *client,
 	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 @@ static int tvp5150_command(struct i2c_client *client,
 					    || 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 @@ static int tvp5150_command(struct i2c_client *client,
 			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 struct i2c_client client_template = {
 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 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
 	     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 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
 	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 @@ static struct i2c_driver driver = {
 	.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 4134549d11a81c67f6d3156769a5da1201605b62..2ab5b4093800bc789c992e067e8bc21b9e54f442 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -951,6 +951,10 @@ v4l_compat_translate_ioctl(struct inode         *inode,
 			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 @@ v4l_compat_translate_ioctl(struct inode         *inode,
 	{
 		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 @@ v4l_compat_translate_ioctl(struct inode         *inode,
 
 		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 62a7d636ef1123bc1b9c2ccb8fd409e2ecbc7855..5dbd7c1b362a2d7f88e21fd914e8b639dae3a5be 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 @@ char *v4l2_type_names[] = {
 	[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_prio_check);
 
 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 6de5b0094b8253bd4a0b1dafc4822f43a1d1f982..9a9902c56ae72f81d06ebf58088baf73e05cc28a 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -68,7 +68,8 @@ static void video_release(struct class_device *cd)
 {
 	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 @@ int video_register_device(struct video_device *vfd, int type, int nr)
 	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 c318ba32fbafa9ba88f31abf647b91dbef32ccb5..b7b0afffd21434b0fb7bc2c0e24c79175b063b42 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -187,6 +187,7 @@ static struct file_operations w9966_fops = {
 	.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 bbfd55cd9948f6433ba2e7d3a61923cb0b711848..c2e6d2e9f5f12ad70bcd52c6421debeef62dda25 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 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
 	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 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
 			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 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
 			  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 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
 	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_attach(struct i2c_adapter *adapter, int address, int kind)
 
 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 @@ static struct i2c_driver i2c_driver = {
 	.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 4034f1b45366922bffe95a4f3005c298ee7510d9..15283f44e79f6b56ba6bd708f8710ed9779156aa 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -4678,6 +4678,7 @@ static struct file_operations zoran_fops = {
 	.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 07286816d7dfd4828df6aa879f17e02c864ac2d1..d4c633b8a7f5cc71420ee3816614907c522f22db 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1490,6 +1490,7 @@ static struct video_device zr36120_template=
 	.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 6a5700e9d4280eb7575426be882920953f1705dd..25646804d5be012c0e121bf0e44eb6b943162272 100644
--- a/drivers/usb/media/dsbr100.c
+++ b/drivers/usb/media/dsbr100.c
@@ -127,6 +127,7 @@ static struct file_operations usb_dsbr100_fops = {
 	.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 3a0e8ce67ebedc10c22b38a224db5b3fcad63fc1..8af665bbe330b40478b7d2588a263ccc8849f739 100644
--- a/drivers/usb/media/ov511.c
+++ b/drivers/usb/media/ov511.c
@@ -4774,6 +4774,7 @@ static struct file_operations ov511_fops = {
 	.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 09ca6128ac209a213ca76e2c656d1daca2d662ac..4f9b0dc6fd7bdd6fd22e71588c23b045c2747ec2 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -154,6 +154,7 @@ static struct file_operations pwc_fops = {
 	.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 b2ae29af59404f89434b7e5d7f1f2d7cd229d7cc..2ba562285fda9b42c3e39f5d3f376e0332c1907e 100644
--- a/drivers/usb/media/se401.c
+++ b/drivers/usb/media/se401.c
@@ -1193,6 +1193,7 @@ static struct file_operations se401_fops = {
         .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 774038b352cd1e7644eb42c97fc0cbe9e877fc89..b497a6a0a2060eccf5ff81da5ef558728d2f9f84 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1343,6 +1343,7 @@ static struct file_operations stv680_fops = {
 	.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 4bd113325ef9b1441d7b244a7cb2ea8b106a69e1..63a72e550a1bd049d0346d10d1ea440554d5354f 100644
--- a/drivers/usb/media/usbvideo.c
+++ b/drivers/usb/media/usbvideo.c
@@ -953,6 +953,7 @@ static struct file_operations usbvideo_fops = {
 	.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 1c73155c8d772cda08a5ca0934021161488563bd..5df1440738712622a3570ccbe154f4816c2258c1 100644
--- a/drivers/usb/media/vicam.c
+++ b/drivers/usb/media/vicam.c
@@ -1236,6 +1236,7 @@ static struct file_operations vicam_fops = {
 	.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 3605a6f3067b0b7602fff8f4fac14402287d1c47..bff9434c8e5578fcf0648dc6c6e09356e61613aa 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -3490,6 +3490,7 @@ static struct file_operations w9968cf_fops = {
 	.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 43a2508ac69670d972516a0f5d2ad96f8e7bfa02..55d9a3a954cfe7fc35a5ccdc4eb7b6f1afbcff72 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -207,244 +207,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 	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 @@ COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD)
 #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 119f9d064cc6100a1671af7e127bdab31e9cce64..339878952f12f7fe4e3b81ff86691a6923344a34 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -218,32 +218,6 @@ COMPATIBLE_IOCTL(VT_RESIZE)
 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 d41df7047ed72065473f938cb63ac137b047154b..c8cbd90ba3757ace87522db09dc63ff36fbea0a0 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -240,6 +240,15 @@ struct dvb_frontend_event {
 };
 
 
+/**
+ * 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 @@ struct dvb_frontend_event {
 
 #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 fb46f8d56999108036ef1378f8525332b92a0fe3..6ff2d365895f550e72fc6e94a54696d3467573ea 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 0e9e48b83e3b72dff430fcb3550e9f73e8833767..121e26da2c1869b6447423649d38af8591389060 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 1cded681eb6d2a1041270441f99dd4473e7c6c96..ce40675324bd5edb738c339bc56f61b01f1212bf 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -642,6 +642,12 @@ typedef __u64 v4l2_std_id;
 #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 @@ typedef __u64 v4l2_std_id;
 				 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 @@ struct v4l2_audio
 
 /*  Flags for the 'mode' field */
 #define V4L2_AUDMODE_AVL		0x00001
-#define V4L2_AUDMODE_32BITS		0x00002
 
 struct v4l2_audioout
 {
@@ -1110,7 +1116,6 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
 /* 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 @@ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
 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 b7d4b0930408c3e366e28de0a196387bd03a743d..295d256ee811c63f5b533906851926d63a2ab1e8 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -23,11 +23,6 @@ enum audiochip {
 
 /* ---------------------------------------------------------------------- */
 
-/* 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 @@ enum audiochip {
 #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 16af9299315f3da06ba07a722fb9bdaa7627e520..e5e749e984ee7baf4864ac0ceea926130ec72c75 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -178,6 +178,8 @@ struct saa7146_ext_vv
 
 	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 b37cde6066929ea5481857462c2a919831800148..7674b121ce8bb4c4005f601ea867d4584b0f24c5 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 @@ enum tuner_mode {
 	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 @@ struct tuner {
 	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 @@ extern int tea5767_autodetection(struct i2c_client *c);
 
 #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 d3fd48157eb8bb87205e41fd82abdb9d8f89afd9..3cc3132f391ec967839f39ff8423f1d8502b2b6b 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 @@ enum v4l2_chip_ident {
 	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 @@ enum v4l2_chip_ident {
 /* 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 @@ enum v4l2_chip_ident {
    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_ */