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

* master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (180 commits)
  V4L/DVB (4641): Trivial: use lowercase letters in hex subsystem ids
  V4L/DVB (4639): Cx88: add autodetection for alternate revision of Leadtek PVR
  V4L/DVB (4638): Basic DVB-T and analog TV support for the HVR1300.
  V4L/DVB (4637): Add a default method for VIDIOC_G_PARM
  V4L/DVB (4635): Extend bttv and saa7134 to check for both AGP and PCI PCI failure case
  V4L/DVB (4634): Zr36120: implement pcipci checks
  V4L/DVB (4632): Zoran: Implement pcipci failure check
  V4L/DVB (4631): Av7110: remove V4L2_CAP_VBI_CAPTURE flag
  V4L/DVB (4630): Av7110: FW_LOADER depemdency fixed
  V4L/DVB (4629): Saa7134: add card support for Proteus Pro 2309
  V4L/DVB (4628): Fix VIDIOC_ENUMSTD ioctl in videodev.c
  V4L/DVB (4627): Vivi crashes with mplayer
  V4L/DVB (4626): On saa7111/7113, LUMA_CTRL need a different value
  V4L/DVB (4624): Tvaudio: Replaced kernel_thread() with kthread_run()
  V4L/DVB (4622): Copy-paste bug in videodev.c
  V4L/DVB (4620): Fix AGC configuration for MOD3000P-based boards
  V4L/DVB (4619): Fixes some I2C dependencies on V4L devices
  V4L/DVB (4617): Problem with dibusb-mb.c USB IDs
  V4L/DVB (4616): [PATCH] Nebula DigiTV USB RC support
  V4L/DVB (4614): Export symbol saa7134_tvaudio_setmute from saa7134 for saa7134-alsa
  ...
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 4ab4c42..9364f47 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -47,7 +47,7 @@
 ---------------------------
 
 What:	Video4Linux API 1 ioctls and video_decoder.h from Video devices.
-When:	July 2006
+When:	December 2006
 Why:	V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
 	series. The old API have lots of drawbacks and don't provide enough
 	means to work with all video and audio standards. The newer API is
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 00d9a1f..669a09a 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -7,10 +7,10 @@
   6 -> AverTV Studio 303 (M126)                            [1461:000b]
   7 -> MSI TV-@nywhere Master                              [1462:8606]
   8 -> Leadtek Winfast DV2000                              [107d:6620]
-  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663C]
+  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663c,107d:6632]
  10 -> IODATA GV-VCP3/PCI                                  [10fc:d003]
  11 -> Prolink PlayTV PVR
- 12 -> ASUS PVR-416                                        [1043:4823]
+ 12 -> ASUS PVR-416                                        [1043:4823,1461:c111]
  13 -> MSI TV-@nywhere
  14 -> KWorld/VStream XPert DVB-T                          [17de:08a6]
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
@@ -51,3 +51,7 @@
  50 -> NPG Tech Real TV FM Top 10                          [14f1:0842]
  51 -> WinFast DTV2000 H                                   [107d:665e]
  52 -> Geniatech DVB-S                                     [14f1:0084]
+ 53 -> Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T  [0070:1404]
+ 54 -> Norwood Micro TV Tuner
+ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM  [c180:c980]
+ 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 9068b66..94cf695 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -58,7 +58,7 @@
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
  58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0351,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
- 60 -> LifeView/Typhoon FlyDVB-T Duo Cardbus    [5168:0502,4e42:0502]
+ 60 -> LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus [5168:0502,4e42:0502,1489:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
  62 -> Compro VideoMate TV Gold+II
  63 -> Kworld Xpert TV PVR7134
@@ -83,7 +83,7 @@
  82 -> MSI TV@Anywhere plus                     [1462:6231]
  83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
  84 -> LifeView FlyDVB Trio                     [5168:0319]
- 85 -> AverTV DVB-T 777                         [1461:2c05]
+ 85 -> AverTV DVB-T 777                         [1461:2c05,1461:2c05]
  86 -> LifeView FlyDVB-T / Genius VideoWonder DVB-T [5168:0301,1489:0301]
  87 -> ADS Instant TV Duo Cardbus PTV331        [0331:1421]
  88 -> Tevion/KWorld DVB-T 220RF                [17de:7201]
@@ -94,3 +94,6 @@
  93 -> Medion 7134 Bridge #2                    [16be:0005]
  94 -> LifeView FlyDVB-T Hybrid Cardbus         [5168:3306,5168:3502]
  95 -> LifeView FlyVIDEO3000 (NTSC)             [5169:0138]
+ 96 -> Medion Md8800 Quadro                     [16be:0007,16be:0008]
+ 97 -> LifeView FlyDVB-S /Acorp TV134DS         [5168:0300,4e42:0300]
+ 98 -> Proteus Pro 2309                         [0919:2003]
diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
index fc94ff2..bb7c2ca 100644
--- a/Documentation/video4linux/bttv/Insmod-options
+++ b/Documentation/video4linux/bttv/Insmod-options
@@ -54,6 +54,12 @@
 				dropouts.
 		chroma_agc=0/1	AGC of chroma signal, off by default.
 		adc_crush=0/1	Luminance ADC crush, on by default.
+		i2c_udelay=     Allow reduce I2C speed. Default is 5 usecs
+				(meaning 66,67 Kbps). The default is the
+				maximum supported speed by kernel bitbang
+				algoritm. You may use lower numbers, if I2C
+				messages are lost (16 is known to work on
+				all supported cards).
 
 		bttv_gpio=0/1
 		gpiomask=
diff --git a/Documentation/video4linux/cx2341x/README.hm12 b/Documentation/video4linux/cx2341x/README.hm12
new file mode 100644
index 0000000..0e213ed
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/README.hm12
@@ -0,0 +1,116 @@
+The cx23416 can produce (and the cx23415 can also read) raw YUV output. The
+format of a YUV frame is specific to this chip and is called HM12. 'HM' stands
+for 'Hauppauge Macroblock', which is a misnomer as 'Conexant Macroblock' would
+be more accurate.
+
+The format is YUV 4:2:0 which uses 1 Y byte per pixel and 1 U and V byte per
+four pixels.
+
+The data is encoded as two macroblock planes, the first containing the Y
+values, the second containing UV macroblocks.
+
+The Y plane is divided into blocks of 16x16 pixels from left to right
+and from top to bottom. Each block is transmitted in turn, line-by-line.
+
+So the first 16 bytes are the first line of the top-left block, the
+second 16 bytes are the second line of the top-left block, etc. After
+transmitting this block the first line of the block on the right to the
+first block is transmitted, etc.
+
+The UV plane is divided into blocks of 16x8 UV values going from left
+to right, top to bottom. Each block is transmitted in turn, line-by-line.
+
+So the first 16 bytes are the first line of the top-left block and
+contain 8 UV value pairs (16 bytes in total). The second 16 bytes are the
+second line of 8 UV pairs of the top-left block, etc. After transmitting
+this block the first line of the block on the right to the first block is
+transmitted, etc.
+
+The code below is given as an example on how to convert HM12 to separate
+Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels.
+
+The width of a frame is always 720 pixels, regardless of the actual specified
+width.
+
+--------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static unsigned char frame[576*720*3/2];
+static unsigned char framey[576*720];
+static unsigned char frameu[576*720 / 4];
+static unsigned char framev[576*720 / 4];
+
+static void de_macro_y(unsigned char* dst, unsigned char *src, int dstride, int w, int h)
+{
+    unsigned int y, x, i;
+
+    // descramble Y plane
+    // dstride = 720 = w
+    // The Y plane is divided into blocks of 16x16 pixels
+    // Each block in transmitted in turn, line-by-line.
+    for (y = 0; y < h; y += 16) {
+	for (x = 0; x < w; x += 16) {
+	    for (i = 0; i < 16; i++) {
+		memcpy(dst + x + (y + i) * dstride, src, 16);
+		src += 16;
+	    }
+	}
+    }
+}
+
+static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, unsigned char *src, int dstride, int w, int h)
+{
+    unsigned int y, x, i;
+
+    // descramble U/V plane
+    // dstride = 720 / 2 = w
+    // The U/V values are interlaced (UVUV...).
+    // Again, the UV plane is divided into blocks of 16x16 UV values.
+    // Each block in transmitted in turn, line-by-line.
+    for (y = 0; y < h; y += 16) {
+	for (x = 0; x < w; x += 8) {
+	    for (i = 0; i < 16; i++) {
+		int idx = x + (y + i) * dstride;
+
+		dstu[idx+0] = src[0];  dstv[idx+0] = src[1];
+		dstu[idx+1] = src[2];  dstv[idx+1] = src[3];
+		dstu[idx+2] = src[4];  dstv[idx+2] = src[5];
+		dstu[idx+3] = src[6];  dstv[idx+3] = src[7];
+		dstu[idx+4] = src[8];  dstv[idx+4] = src[9];
+		dstu[idx+5] = src[10]; dstv[idx+5] = src[11];
+		dstu[idx+6] = src[12]; dstv[idx+6] = src[13];
+		dstu[idx+7] = src[14]; dstv[idx+7] = src[15];
+		src += 16;
+	    }
+	}
+    }
+}
+
+/*************************************************************************/
+int main(int argc, char **argv)
+{
+    FILE *fin;
+    int i;
+
+    if (argc == 1) fin = stdin;
+    else fin = fopen(argv[1], "r");
+
+    if (fin == NULL) {
+	fprintf(stderr, "cannot open input\n");
+	exit(-1);
+    }
+    while (fread(frame, sizeof(frame), 1, fin) == 1) {
+	de_macro_y(framey, frame, 720, 720, 576);
+	de_macro_uv(frameu, framev, frame + 720 * 576, 720 / 2, 720 / 2, 576 / 2);
+	fwrite(framey, sizeof(framey), 1, stdout);
+	fwrite(framev, sizeof(framev), 1, stdout);
+	fwrite(frameu, sizeof(frameu), 1, stdout);
+    }
+    fclose(fin);
+    return 0;
+}
+
+--------------------------------------------------------------------------
diff --git a/Documentation/video4linux/cx2341x/README.vbi b/Documentation/video4linux/cx2341x/README.vbi
new file mode 100644
index 0000000..5807cf1
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/README.vbi
@@ -0,0 +1,45 @@
+
+Format of embedded V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data
+=========================================================
+
+This document describes the V4L2_MPEG_STREAM_VBI_FMT_IVTV format of the VBI data
+embedded in an MPEG-2 program stream. This format is in part dictated by some
+hardware limitations of the ivtv driver (the driver for the Conexant cx23415/6
+chips), in particular a maximum size for the VBI data. Anything longer is cut
+off when the MPEG stream is played back through the cx23415.
+
+The advantage of this format is it is very compact and that all VBI data for
+all lines can be stored while still fitting within the maximum allowed size.
+
+The stream ID of the VBI data is 0xBD. The maximum size of the embedded data is
+4 + 43 * 36, which is 4 bytes for a header and 2 * 18 VBI lines with a 1 byte
+header and a 42 bytes payload each. Anything beyond this limit is cut off by
+the cx23415/6 firmware. Besides the data for the VBI lines we also need 36 bits
+for a bitmask determining which lines are captured and 4 bytes for a magic cookie,
+signifying that this data package contains V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data.
+If all lines are used, then there is no longer room for the bitmask. To solve this
+two different magic numbers were introduced:
+
+'itv0': After this magic number two unsigned longs follow. Bits 0-17 of the first
+unsigned long denote which lines of the first field are captured. Bits 18-31 of
+the first unsigned long and bits 0-3 of the second unsigned long are used for the
+second field.
+
+'ITV0': This magic number assumes all VBI lines are captured, i.e. it implicitly
+implies that the bitmasks are 0xffffffff and 0xf.
+
+After these magic cookies (and the 8 byte bitmask in case of cookie 'itv0') the
+captured VBI lines start:
+
+For each line the least significant 4 bits of the first byte contain the data type.
+Possible values are shown in the table below. The payload is in the following 42
+bytes.
+
+Here is the list of possible data types:
+
+#define IVTV_SLICED_TYPE_TELETEXT       0x1     // Teletext (uses lines 6-22 for PAL)
+#define IVTV_SLICED_TYPE_CC             0x4     // Closed Captions (line 21 NTSC)
+#define IVTV_SLICED_TYPE_WSS            0x5     // Wide Screen Signal (line 23 PAL)
+#define IVTV_SLICED_TYPE_VPS            0x7     // Video Programming System (PAL) (line 16)
+
+Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 1a04db4..f33e5d9 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -4,7 +4,6 @@
 
 config VIDEO_SAA7146_VV
 	tristate
-	select VIDEO_V4L2
 	select VIDEO_BUF
 	select VIDEO_VIDEOBUF
 	select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index ca98d94..db75344 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -32,6 +32,37 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_empty);
 
+/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
+IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = {
+	/* numeric */
+	[ 0x00 ] = KEY_0,
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	[ 0x5c ] = KEY_POWER,     /* power       */
+	[ 0x20 ] = KEY_F,         /* full screen */
+	[ 0x0f ] = KEY_BACKSPACE, /* recall      */
+	[ 0x1b ] = KEY_ENTER,     /* mute        */
+	[ 0x41 ] = KEY_RECORD,    /* record      */
+	[ 0x43 ] = KEY_STOP,      /* stop        */
+	[ 0x16 ] = KEY_S,
+	[ 0x1a ] = KEY_Q,         /* off         */
+	[ 0x2e ] = KEY_RED,
+	[ 0x1f ] = KEY_DOWN,      /* channel -   */
+	[ 0x1c ] = KEY_UP,        /* channel +   */
+	[ 0x10 ] = KEY_LEFT,      /* volume -    */
+	[ 0x1e ] = KEY_RIGHT,     /* volume +    */
+	[ 0x14 ] = KEY_F1,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_proteus_2309);
 /* Matt Jesson <dvb@jesson.eclipse.co.uk */
 IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
 	[ 0x28 ] = KEY_0,         //'0' / 'enter'
@@ -1473,3 +1504,51 @@
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_npgtech);
+
+/* Norwood Micro (non-Pro) TV Tuner
+   By Peter Naulls <peter@chocky.org>
+   Key comments are the functions given in the manual */
+IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
+	/* Keys 0 to 9 */
+	[ 0x20 ] = KEY_0,
+	[ 0x21 ] = KEY_1,
+	[ 0x22 ] = KEY_2,
+	[ 0x23 ] = KEY_3,
+	[ 0x24 ] = KEY_4,
+	[ 0x25 ] = KEY_5,
+	[ 0x26 ] = KEY_6,
+	[ 0x27 ] = KEY_7,
+	[ 0x28 ] = KEY_8,
+	[ 0x29 ] = KEY_9,
+
+	[ 0x78 ] = KEY_TUNER,             /* Video Source        */
+	[ 0x2c ] = KEY_EXIT,              /* Open/Close software */
+	[ 0x2a ] = KEY_SELECT,            /* 2 Digit Select      */
+	[ 0x69 ] = KEY_AGAIN,             /* Recall              */
+
+	[ 0x32 ] = KEY_BRIGHTNESSUP,      /* Brightness increase */
+	[ 0x33 ] = KEY_BRIGHTNESSDOWN,    /* Brightness decrease */
+	[ 0x6b ] = KEY_KPPLUS,            /* (not named >>>>>)   */
+	[ 0x6c ] = KEY_KPMINUS,           /* (not named <<<<<)   */
+
+	[ 0x2d ] = KEY_MUTE,              /* Mute                */
+	[ 0x30 ] = KEY_VOLUMEUP,          /* Volume up           */
+	[ 0x31 ] = KEY_VOLUMEDOWN,        /* Volume down         */
+	[ 0x60 ] = KEY_CHANNELUP,         /* Channel up          */
+	[ 0x61 ] = KEY_CHANNELDOWN,       /* Channel down        */
+
+	[ 0x3f ] = KEY_RECORD,            /* Record              */
+	[ 0x37 ] = KEY_PLAY,              /* Play                */
+	[ 0x36 ] = KEY_PAUSE,             /* Pause               */
+	[ 0x2b ] = KEY_STOP,              /* Stop                */
+	[ 0x67 ] = KEY_FASTFORWARD,       /* Foward              */
+	[ 0x66 ] = KEY_REWIND,            /* Rewind              */
+	[ 0x3e ] = KEY_SEARCH,            /* Auto Scan           */
+	[ 0x2e ] = KEY_CAMERA,            /* Capture Video       */
+	[ 0x6d ] = KEY_MENU,              /* Show/Hide Control   */
+	[ 0x2f ] = KEY_ZOOM,              /* Full Screen         */
+	[ 0x34 ] = KEY_RADIO,             /* FM                  */
+	[ 0x65 ] = KEY_POWER,             /* Computer power      */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_norwood);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 0027acc..d867a6a 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -455,7 +455,6 @@
 
 static struct video_device device_template =
 {
-	.hardware	= VID_HARDWARE_SAA7146,
 	.fops		= &video_fops,
 	.minor		= -1,
 };
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 49a06fc..a0dcd59 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -2,13 +2,13 @@
 	tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
 	depends on DVB_CORE && I2C
 	select DVB_PLL
-	select DVB_STV0299
-	select DVB_MT352
-	select DVB_MT312
-	select DVB_NXT200X
-	select DVB_STV0297
-	select DVB_BCM3510
-	select DVB_LGDT330X
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_MT312 if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	help
 	  Support for the digital TV receiver chip made by B2C2 Inc. included in
 	  Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 3be87c7..b8ba878 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -505,7 +505,7 @@
 	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) {
+	if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
 		ops = &fc->fe->ops;
 
 		ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
@@ -519,36 +519,36 @@
 		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
 	} else
 	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
-	if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
+	if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
 		fc->dev_type          = FC_AIR_DVB;
 		fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
 		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
 	} else
 	/* try the air atsc 2nd generation (nxt2002) */
-	if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
+	if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC2;
-		dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
+		dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
 		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
 	} else
 	/* try the air atsc 3nd generation (lgdt3303) */
-	if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+	if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC3;
 		fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
 		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
 	} else
 	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
-	if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
+	if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC1;
 		info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
 	} else
 	/* try the cable dvb (stv0297) */
-	if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
+	if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type                        = FC_CABLE;
 		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
 		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
 	} else
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
-	if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+	if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
 		ops = &fc->fe->ops;
 
 		ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
@@ -571,9 +571,7 @@
 	} else {
 		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
 			err("frontend registration failed!");
-			ops = &fc->fe->ops;
-			if (ops->release != NULL)
-				ops->release(fc->fe);
+			dvb_frontend_detach(fc->fe);
 			fc->fe = NULL;
 			return -EINVAL;
 		}
@@ -584,8 +582,10 @@
 
 void flexcop_frontend_exit(struct flexcop_device *fc)
 {
-	if (fc->init_state & FC_STATE_FE_INIT)
+	if (fc->init_state & FC_STATE_FE_INIT) {
 		dvb_unregister_frontend(fc->fe);
+		dvb_frontend_detach(fc->fe);
+	}
 
 	fc->init_state &= ~FC_STATE_FE_INIT;
 }
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 7d0ee1a..ae2ff5d 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -2,13 +2,13 @@
 	tristate "BT8xx based PCI cards"
 	depends on DVB_CORE && PCI && I2C && VIDEO_BT848
 	select DVB_PLL
-	select DVB_MT352
-	select DVB_SP887X
-	select DVB_NXT6000
-	select DVB_CX24110
-	select DVB_OR51211
-	select DVB_LGDT330X
-	select DVB_ZL10353
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_SP887X if !DVB_FE_CUSTOMISE
+	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+	select DVB_CX24110 if !DVB_FE_CUSTOMISE
+	select DVB_OR51211 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 06ac899..9f72b70 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1715,6 +1715,15 @@
 static void dst_release(struct dvb_frontend *fe)
 {
 	struct dst_state *state = fe->demodulator_priv;
+	if (state->dst_ca) {
+		dvb_unregister_device(state->dst_ca);
+#ifdef CONFIG_DVB_CORE_ATTACH
+		symbol_put(dst_ca_attach);
+#endif
+	}
+#ifdef CONFIG_DVB_CORE_ATTACH
+	symbol_put(dst_attach);
+#endif
 	kfree(state);
 }
 
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index fa923b9..240ad08 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -699,12 +699,17 @@
 	.fops = &dst_ca_fops
 };
 
-int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
 {
 	struct dvb_device *dvbdev;
+
 	dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
-	dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
-	return 0;
+	if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
+		dst->dst_ca = dvbdev;
+		return dst->dst_ca;
+	}
+
+	return NULL;
 }
 
 EXPORT_SYMBOL(dst_ca_attach);
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 0677b04..3bf084f 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -140,6 +140,7 @@
 	char *tuner_name;
 	struct mutex dst_mutex;
 	u8 fw_name[8];
+	struct dvb_device *dst_ca;
 };
 
 struct tuner_types {
@@ -178,7 +179,7 @@
 int read_dst(struct dst_state *state, u8 * ret, u8 len);
 u8 dst_check_sum(u8 * buf, u32 len);
 struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
-int dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
 int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
 
 int dst_command(struct dst_state* state, u8 * data, u8 len);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index b715b97..fb6c4cc 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -67,7 +67,7 @@
 
 static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
-	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
 	struct dvb_bt8xx_card *card = dvbdmx->priv;
 	int rc;
 
@@ -595,15 +595,14 @@
 
 static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 {
-	int ret;
 	struct dst_state* state = NULL;
 
 	switch(type) {
 	case BTTV_BOARD_DVICO_DVBT_LITE:
-		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+		card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
 
 		if (card->fe == NULL)
-			card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+			card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
 						  card->i2c_adapter);
 
 		if (card->fe != NULL) {
@@ -615,7 +614,7 @@
 
 	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
 		lgdt330x_reset(card);
-		card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
+		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
@@ -630,7 +629,7 @@
 
 		/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
 		digitv_alps_tded4_reset(card);
-		card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
+		card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
 			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
@@ -639,7 +638,7 @@
 
 		/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
 		digitv_alps_tded4_reset(card);
-		card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
+		card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
 
 		if (card->fe != NULL) {
 			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
@@ -648,14 +647,14 @@
 		break;
 
 	case BTTV_BOARD_AVDVBT_761:
-		card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+		card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
 		if (card->fe) {
 			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
 		}
 		break;
 
 	case BTTV_BOARD_AVDVBT_771:
-		card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
+		card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
 			card->fe->ops.info.frequency_min = 174000000;
@@ -670,22 +669,21 @@
 		state->config = &dst_config;
 		state->i2c = card->i2c_adapter;
 		state->bt = card->bt;
-
+		state->dst_ca = NULL;
 		/*	DST is not a frontend, attaching the ASIC	*/
-		if ((dst_attach(state, &card->dvb_adapter)) == NULL) {
+		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
 			printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
 			break;
 		}
-		card->fe = &state->frontend;
-
 		/*	Attach other DST peripherals if any		*/
 		/*	Conditional Access device			*/
+		card->fe = &state->frontend;
 		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
-			ret = dst_ca_attach(state, &card->dvb_adapter);
+			dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
 		break;
 
 	case BTTV_BOARD_PINNACLESAT:
-		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+		card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
 		if (card->fe) {
 			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
 			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
@@ -694,7 +692,7 @@
 		break;
 
 	case BTTV_BOARD_PC_HDTV:
-		card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
+		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
 		break;
 	}
 
@@ -707,8 +705,7 @@
 	else
 		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
 			printk("dvb-bt8xx: Frontend registration failed!\n");
-			if (card->fe->ops.release)
-				card->fe->ops.release(card->fe);
+			dvb_frontend_detach(card->fe);
 			card->fe = NULL;
 		}
 }
@@ -925,8 +922,10 @@
 	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 	dvb_dmxdev_release(&card->dmxdev);
 	dvb_dmx_release(&card->demux);
-	if (card->fe)
+	if (card->fe) {
 		dvb_unregister_frontend(card->fe);
+		dvb_frontend_detach(card->fe);
+	}
 	dvb_unregister_adapter(&card->dvb_adapter);
 
 	kfree(card);
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
index 12ee912..e46eae3 100644
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ b/drivers/media/dvb/dvb-core/Kconfig
@@ -9,3 +9,16 @@
 	  in-kernel drivers will select this automatically if needed.
 	  If unsure say N.
 
+config DVB_CORE_ATTACH
+	bool "Load and attach frontend modules as needed"
+	depends on DVB_CORE
+	depends on MODULES
+	help
+	  Remove the static dependency of DVB card drivers on all
+	  frontend modules for all possible card variants. Instead,
+	  allow the card drivers to only load the frontend modules
+	  they require. This saves several KBytes of memory.
+
+	  Note: You will need moudule-init-tools v3.2 or later for this feature.
+
+	  If unsure say Y.
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 57b34cd..3dd5dbaf 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1105,18 +1105,42 @@
 	mutex_lock(&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
-	if (fe->ops.tuner_ops.release) {
-		fe->ops.tuner_ops.release(fe);
-		if (fe->ops.i2c_gate_ctrl)
-			fe->ops.i2c_gate_ctrl(fe, 0);
-	}
-	if (fe->ops.release)
-		fe->ops.release(fe);
-	else
-		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
+
 	/* fe is invalid now */
 	kfree(fepriv);
 	mutex_unlock(&frontend_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(dvb_unregister_frontend);
+
+#ifdef CONFIG_DVB_CORE_ATTACH
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+	void *ptr;
+
+	if (fe->ops.release_sec) {
+		fe->ops.release_sec(fe);
+		symbol_put_addr(fe->ops.release_sec);
+	}
+	if (fe->ops.tuner_ops.release) {
+		fe->ops.tuner_ops.release(fe);
+		symbol_put_addr(fe->ops.tuner_ops.release);
+	}
+	ptr = (void*)fe->ops.release;
+	if (ptr) {
+		fe->ops.release(fe);
+		symbol_put_addr(ptr);
+	}
+}
+#else
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+	if (fe->ops.release_sec)
+		fe->ops.release_sec(fe);
+	if (fe->ops.tuner_ops.release)
+		fe->ops.tuner_ops.release(fe);
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+#endif
+EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 2887e2b..e5d5028 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -92,10 +92,13 @@
 	struct dvb_frontend_info info;
 
 	void (*release)(struct dvb_frontend* fe);
+	void (*release_sec)(struct dvb_frontend* fe);
 
 	int (*init)(struct dvb_frontend* fe);
 	int (*sleep)(struct dvb_frontend* fe);
 
+	int (*write)(struct dvb_frontend* fe, u8* buf, int len);
+
 	/* if this is set, it overrides the default swzigzag */
 	int (*tune)(struct dvb_frontend* fe,
 		    struct dvb_frontend_parameters* params,
@@ -147,7 +150,7 @@
 	void* demodulator_priv;
 	void* tuner_priv;
 	void* frontend_priv;
-	void* misc_priv;
+	void* sec_priv;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter* dvb,
@@ -155,6 +158,8 @@
 
 extern int dvb_unregister_frontend(struct dvb_frontend* fe);
 
+extern void dvb_frontend_detach(struct dvb_frontend* fe);
+
 extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
 
 extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 7a7f75f..620e788 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -102,4 +102,26 @@
 			    int (*func)(struct inode *inode, struct file *file,
 			    unsigned int cmd, void *arg));
 
+/** generic DVB attach function. */
+#ifdef CONFIG_DVB_CORE_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+	void *__r = NULL; \
+	typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+	if (__a) { \
+		__r = (void *) __a(ARGS); \
+		if (__r == NULL) \
+			symbol_put(FUNCTION); \
+	} else { \
+		printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+	} \
+	__r; \
+})
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+	FUNCTION(ARGS); \
+})
+
+#endif
+
 #endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 75824b7..0a3c353 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -26,6 +26,7 @@
 	tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
 	depends on DVB_USB
 	select DVB_DIB3000MC
+	select DVB_TUNER_MT2060
 	help
 	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
@@ -33,6 +34,7 @@
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
 	depends on DVB_USB
 	select DVB_DIB3000MB
+	select DVB_TUNER_MT2060
 	help
 	  Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -65,6 +67,7 @@
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
 	depends on DVB_USB
 	select DVB_DIB3000MC
+	select DVB_TUNER_MT2060
 	help
 	  Support for 2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -80,16 +83,17 @@
 	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
 	depends on DVB_USB
 	select DVB_DIB3000MC
+	select DVB_TUNER_MT2060
 	help
 	  Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
 
 config DVB_USB_CXUSB
 	tristate "Conexant USB2.0 hybrid reference design support"
 	depends on DVB_USB
-	select DVB_CX22702
-	select DVB_LGDT330X
-	select DVB_MT352
-	select DVB_ZL10353
+	select DVB_CX22702 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -101,8 +105,8 @@
 config DVB_USB_DIGITV
 	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
 	depends on DVB_USB
-	select DVB_NXT6000
-	select DVB_MT352
+	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
 
@@ -145,6 +149,7 @@
 	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
 	depends on DVB_USB
 	select DVB_DIB3000MC
+	select DVB_TUNER_MT2060
 	help
 	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index ce44aa6..df0c384 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -26,6 +26,13 @@
 	return 0;
 }
 
+/* assure to put cold to 0 for iManufacturer == 1 */
+static int a800_identify_state(struct usb_device *udev, struct dvb_usb_properties *props,struct dvb_usb_device_description **desc, int *cold)
+{
+	*cold = udev->descriptor.iManufacturer != 1;
+	return 0;
+}
+
 static struct dvb_usb_rc_key a800_rc_keys[] = {
 	{ 0x02, 0x01, KEY_PROG1 },       /* SOURCE */
 	{ 0x02, 0x00, KEY_POWER },       /* POWER */
@@ -113,6 +120,7 @@
 	.power_ctrl       = a800_power_ctrl,
 	.frontend_attach  = dibusb_dib3000mc_frontend_attach,
 	.tuner_attach     = dibusb_dib3000mc_tuner_attach,
+	.identify_state   = a800_identify_state,
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = a800_rc_keys,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index ae23bdd..c710c01 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -349,6 +349,7 @@
 
 static struct zl10353_config cxusb_zl10353_dee1601_config = {
 	.demod_address = 0x0f,
+	.parallel_ts = 1,
 };
 
 static struct mt352_config cxusb_mt352_config = {
@@ -409,7 +410,7 @@
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1);
 
-	if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
+	if ((d->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &d->i2c_adap)) != NULL)
 		return 0;
 
 	return -EIO;
@@ -422,7 +423,7 @@
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-	if ((d->fe = lgdt330x_attach(&cxusb_lgdt3303_config, &d->i2c_adap)) != NULL)
+	if ((d->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &d->i2c_adap)) != NULL)
 		return 0;
 
 	return -EIO;
@@ -435,7 +436,7 @@
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-	if ((d->fe = mt352_attach(&cxusb_mt352_config, &d->i2c_adap)) != NULL)
+	if ((d->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &d->i2c_adap)) != NULL)
 		return 0;
 
 	return -EIO;
@@ -448,8 +449,8 @@
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-	if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
-	    ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
+	if (((d->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+		((d->fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
 		return 0;
 
 	return -EIO;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index abd75b4..124e25a 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -131,9 +131,6 @@
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	if (num > 2)
-		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
@@ -168,31 +165,137 @@
 }
 EXPORT_SYMBOL(dibusb_read_eeprom_byte);
 
+/* 3000MC/P stuff */
+// Config Adjacent channels  Perf -cal22
+static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
+	.band_caps = BAND_VHF | BAND_UHF,
+	.setup     = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0),
+
+	.agc1_max = 48497,
+	.agc1_min = 23593,
+	.agc2_max = 46531,
+	.agc2_min = 24904,
+
+	.agc1_pt1 = 0x65,
+	.agc1_pt2 = 0x69,
+
+	.agc1_slope1 = 0x51,
+	.agc1_slope2 = 0x27,
+
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 0x33,
+
+	.agc2_slope1 = 0x35,
+	.agc2_slope2 = 0x37,
+};
+
+static struct dib3000mc_config stk3000p_dib3000p_config = {
+	&dib3000p_mt2060_agc_config,
+
+	.max_time     = 0x196,
+	.ln_adc_level = 0x1cc7,
+
+	.output_mpeg2_in_188_bytes = 1,
+};
+
+static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
+	.setup    = (0 << 15) | (0 << 14) | (1 << 13) | (1 << 12) | (29 << 0),
+
+	.agc1_max = 56361,
+	.agc1_min = 22282,
+	.agc2_max = 47841,
+	.agc2_min = 36045,
+
+	.agc1_pt1 = 0x3b,
+	.agc1_pt2 = 0x6b,
+
+	.agc1_slope1 = 0x55,
+	.agc1_slope2 = 0x1d,
+
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 0x0a,
+
+	.agc2_slope1 = 0x95,
+	.agc2_slope2 = 0x1e,
+};
+
+static struct dib3000mc_config mod3000p_dib3000p_config = {
+	&dib3000p_panasonic_agc_config,
+
+	.max_time     = 0x51,
+	.ln_adc_level = 0x1cc7,
+
+	.output_mpeg2_in_188_bytes = 1,
+};
+
 int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
 {
-	struct dib3000_config demod_cfg;
-	struct dibusb_state *st = d->priv;
-
-	for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
-		if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
-			d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-			d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-			d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
-			return 0;
+	if (dib3000mc_attach(&d->i2c_adap, 1, DEFAULT_DIB3000P_I2C_ADDRESS, 0, &mod3000p_dib3000p_config, &d->fe) == 0 ||
+		dib3000mc_attach(&d->i2c_adap, 1, DEFAULT_DIB3000MC_I2C_ADDRESS, 0, &mod3000p_dib3000p_config, &d->fe) == 0) {
+		if (d->priv != NULL) {
+			struct dibusb_state *st = d->priv;
+			st->ops.pid_parse = dib3000mc_pid_parse;
+			st->ops.pid_ctrl  = dib3000mc_pid_control;
 		}
-
+		return 0;
+	}
 	return -ENODEV;
 }
 EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
 
+static struct mt2060_config stk3000p_mt2060_config = {
+	0x60
+};
+
 int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
 {
-	d->pll_addr = 0x60;
-	d->pll_desc = &dvb_pll_env57h1xd5;
+	struct dibusb_state *st = d->priv;
+	int ret;
+	u8 a,b;
+	u16 if1 = 1220;
+	struct i2c_adapter *tun_i2c;
 
-	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+	// First IF calibration for Liteon Sticks
+	if (d->udev->descriptor.idVendor == USB_VID_LITEON &&
+		d->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
 
+		dibusb_read_eeprom_byte(d,0x7E,&a);
+		dibusb_read_eeprom_byte(d,0x7F,&b);
+
+		if (a == 0x00)
+			if1 += b;
+		else if (a == 0x80)
+			if1 -= b;
+		else
+			warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
+
+	} else if (d->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
+		   d->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+		u8 desc;
+		dibusb_read_eeprom_byte(d, 7, &desc);
+		if (desc == 2) {
+			a = 127;
+			do {
+				dibusb_read_eeprom_byte(d, a, &desc);
+				a--;
+			} while (a > 7 && (desc == 0xff || desc == 0x00));
+			if (desc & 0x80)
+				if1 -= (0xff - desc);
+			else
+				if1 += desc;
+		}
+	}
+
+	tun_i2c = dib3000mc_get_tuner_i2c_master(d->fe, 1);
+	if ((ret = mt2060_attach(d->fe, tun_i2c, &stk3000p_mt2060_config, if1)) != 0) {
+		/* not found - use panasonic pll parameters */
+		if (dvb_pll_attach(d->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+			return -ENOMEM;
+	} else {
+		st->mt2060_present = 1;
+		/* set the correct parameters for the dib3000p */
+		dib3000mc_set_config(d->fe, &stk3000p_dib3000p_config);
+	}
 	return 0;
 }
 EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
@@ -267,6 +370,67 @@
 	{ 0x86, 0x1e, KEY_DOWN },
 	{ 0x86, 0x1f, KEY_LEFT },
 	{ 0x86, 0x1b, KEY_RIGHT },
+
+	/* Key codes for the DiBcom MOD3000 remote. */
+	{ 0x80, 0x00, KEY_MUTE },
+	{ 0x80, 0x01, KEY_TEXT },
+	{ 0x80, 0x02, KEY_HOME },
+	{ 0x80, 0x03, KEY_POWER },
+
+	{ 0x80, 0x04, KEY_RED },
+	{ 0x80, 0x05, KEY_GREEN },
+	{ 0x80, 0x06, KEY_YELLOW },
+	{ 0x80, 0x07, KEY_BLUE },
+
+	{ 0x80, 0x08, KEY_DVD },
+	{ 0x80, 0x09, KEY_AUDIO },
+	{ 0x80, 0x0a, KEY_MEDIA },      /* Pictures */
+	{ 0x80, 0x0b, KEY_VIDEO },
+
+	{ 0x80, 0x0c, KEY_BACK },
+	{ 0x80, 0x0d, KEY_UP },
+	{ 0x80, 0x0e, KEY_RADIO },
+	{ 0x80, 0x0f, KEY_EPG },
+
+	{ 0x80, 0x10, KEY_LEFT },
+	{ 0x80, 0x11, KEY_OK },
+	{ 0x80, 0x12, KEY_RIGHT },
+	{ 0x80, 0x13, KEY_UNKNOWN },    /* SAP */
+
+	{ 0x80, 0x14, KEY_TV },
+	{ 0x80, 0x15, KEY_DOWN },
+	{ 0x80, 0x16, KEY_MENU },       /* DVD Menu */
+	{ 0x80, 0x17, KEY_LAST },
+
+	{ 0x80, 0x18, KEY_RECORD },
+	{ 0x80, 0x19, KEY_STOP },
+	{ 0x80, 0x1a, KEY_PAUSE },
+	{ 0x80, 0x1b, KEY_PLAY },
+
+	{ 0x80, 0x1c, KEY_PREVIOUS },
+	{ 0x80, 0x1d, KEY_REWIND },
+	{ 0x80, 0x1e, KEY_FASTFORWARD },
+	{ 0x80, 0x1f, KEY_NEXT},
+
+	{ 0x80, 0x40, KEY_1 },
+	{ 0x80, 0x41, KEY_2 },
+	{ 0x80, 0x42, KEY_3 },
+	{ 0x80, 0x43, KEY_CHANNELUP },
+
+	{ 0x80, 0x44, KEY_4 },
+	{ 0x80, 0x45, KEY_5 },
+	{ 0x80, 0x46, KEY_6 },
+	{ 0x80, 0x47, KEY_CHANNELDOWN },
+
+	{ 0x80, 0x48, KEY_7 },
+	{ 0x80, 0x49, KEY_8 },
+	{ 0x80, 0x4a, KEY_9 },
+	{ 0x80, 0x4b, KEY_VOLUMEUP },
+
+	{ 0x80, 0x4c, KEY_CLEAR },
+	{ 0x80, 0x4d, KEY_0 },
+	{ 0x80, 0x4e, KEY_ENTER },
+	{ 0x80, 0x4f, KEY_VOLUMEDOWN },
 };
 EXPORT_SYMBOL(dibusb_rc_keys);
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index f4c45f3..effd34c 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -21,11 +21,11 @@
 
 	demod_cfg.demod_address = 0x8;
 
-	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
-		d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-		d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
 		return -ENODEV;
-	}
+
+	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
 
 	d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 
@@ -169,7 +169,7 @@
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
-	.rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
@@ -247,7 +247,7 @@
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
-	.rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
@@ -272,8 +272,8 @@
 #endif
 	.devices = {
 		{	"Artec T1 USB1.1 TVBOX with AN2235",
-			{ &dibusb_dib3000mb_table[20], NULL },
 			{ &dibusb_dib3000mb_table[21], NULL },
+			{ &dibusb_dib3000mb_table[22], NULL },
 		},
 #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
@@ -304,7 +304,7 @@
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
-	.rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
@@ -355,7 +355,7 @@
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
-	.rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+	.rc_key_map_size  = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
 	.rc_query         = dibusb_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 55802fb..eca4082 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -28,6 +28,17 @@
 /* 00 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_COLD) },
 /* 01 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_WARM) },
 /* 02 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 03 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
+/* 04 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_COLD) },
+/* 05 */	{ USB_DEVICE(USB_VID_LITEON,		USB_PID_LITEON_DVB_T_WARM) },
+/* 06 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_COLD) },
+/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_DIGIVOX_MINI_SL_WARM) },
+/* 08 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_COLD) },
+/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB2_WARM) },
+/* 10 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_COLD) },
+/* 11 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ARTEC_T14_WARM) },
+/* 12 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_COLD) },
+/* 13 */	{ USB_DEVICE(USB_VID_LEADTEK,		USB_PID_WINFAST_DTV_DONGLE_WARM) },
 			{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
@@ -50,7 +61,7 @@
 
 	.rc_interval      = DEFAULT_RC_INTERVAL,
 	.rc_key_map       = dibusb_rc_keys,
-	.rc_key_map_size  = 63, /* FIXME */
+	.rc_key_map_size  = 111, /* FIXME */
 	.rc_query         = dibusb_rc_query,
 
 	.i2c_algo         = &dibusb_i2c_algo,
@@ -68,16 +79,38 @@
 		}
 	},
 
-	.num_device_descs = 2,
+	.num_device_descs = 7,
 	.devices = {
 		{   "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
 			{ &dibusb_dib3000mc_table[0], NULL },
 			{ &dibusb_dib3000mc_table[1], NULL },
 		},
-		{   "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+		{   "Artec T1 USB2.0 TVBOX (please check the warm ID)",
 			{ &dibusb_dib3000mc_table[2], NULL },
-			{ NULL },
+			{ &dibusb_dib3000mc_table[3], NULL },
 		},
+		{   "LITE-ON USB2.0 DVB-T Tuner",
+		    /* Also rebranded as Intuix S800, Toshiba */
+			{ &dibusb_dib3000mc_table[4], NULL },
+			{ &dibusb_dib3000mc_table[5], NULL },
+		},
+		{   "MSI Digivox Mini SL",
+			{ &dibusb_dib3000mc_table[6], NULL },
+			{ &dibusb_dib3000mc_table[7], NULL },
+		},
+		{   "GRAND - USB2.0 DVB-T adapter",
+			{ &dibusb_dib3000mc_table[8], NULL },
+			{ &dibusb_dib3000mc_table[9], NULL },
+		},
+		{   "Artec T14 - USB2.0 DVB-T",
+			{ &dibusb_dib3000mc_table[10], NULL },
+			{ &dibusb_dib3000mc_table[11], NULL },
+		},
+		{   "Leadtek - USB2.0 Winfast DTV dongle",
+			{ &dibusb_dib3000mc_table[12], NULL },
+			{ &dibusb_dib3000mc_table[13], NULL },
+		},
+		{ NULL },
 	}
 };
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 2d99d05..a43f874 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -17,6 +17,8 @@
 #include "dvb-usb.h"
 
 #include "dib3000.h"
+#include "dib3000mc.h"
+#include "mt2060.h"
 
 /*
  * protocol of all dibusb related devices
@@ -96,6 +98,7 @@
 
 struct dibusb_state {
 	struct dib_fe_xfer_ops ops;
+	int mt2060_present;
 
 	/* for RC5 remote control */
 	int old_toggle;
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index c14d9ef..0158544 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -128,11 +128,11 @@
 
 static int digitv_frontend_attach(struct dvb_usb_device *d)
 {
-	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+	if ((d->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &d->i2c_adap)) != NULL) {
 		d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 		return 0;
 	}
-	if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+	if ((d->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
 		d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
 		return 0;
 	}
@@ -147,21 +147,91 @@
 }
 
 static struct dvb_usb_rc_key digitv_rc_keys[] = {
-	{ 0x00, 0x16, KEY_POWER }, /* dummy key */
+	{ 0x5f, 0x55, KEY_0 },
+	{ 0x6f, 0x55, KEY_1 },
+	{ 0x9f, 0x55, KEY_2 },
+	{ 0xaf, 0x55, KEY_3 },
+	{ 0x5f, 0x56, KEY_4 },
+	{ 0x6f, 0x56, KEY_5 },
+	{ 0x9f, 0x56, KEY_6 },
+	{ 0xaf, 0x56, KEY_7 },
+	{ 0x5f, 0x59, KEY_8 },
+	{ 0x6f, 0x59, KEY_9 },
+	{ 0x9f, 0x59, KEY_TV },
+	{ 0xaf, 0x59, KEY_AUX },
+	{ 0x5f, 0x5a, KEY_DVD },
+	{ 0x6f, 0x5a, KEY_POWER },
+	{ 0x9f, 0x5a, KEY_MHP },     /* labelled 'Picture' */
+	{ 0xaf, 0x5a, KEY_AUDIO },
+	{ 0x5f, 0x65, KEY_INFO },
+	{ 0x6f, 0x65, KEY_F13 },     /* 16:9 */
+	{ 0x9f, 0x65, KEY_F14 },     /* 14:9 */
+	{ 0xaf, 0x65, KEY_EPG },
+	{ 0x5f, 0x66, KEY_EXIT },
+	{ 0x6f, 0x66, KEY_MENU },
+	{ 0x9f, 0x66, KEY_UP },
+	{ 0xaf, 0x66, KEY_DOWN },
+	{ 0x5f, 0x69, KEY_LEFT },
+	{ 0x6f, 0x69, KEY_RIGHT },
+	{ 0x9f, 0x69, KEY_ENTER },
+	{ 0xaf, 0x69, KEY_CHANNELUP },
+	{ 0x5f, 0x6a, KEY_CHANNELDOWN },
+	{ 0x6f, 0x6a, KEY_VOLUMEUP },
+	{ 0x9f, 0x6a, KEY_VOLUMEDOWN },
+	{ 0xaf, 0x6a, KEY_RED },
+	{ 0x5f, 0x95, KEY_GREEN },
+	{ 0x6f, 0x95, KEY_YELLOW },
+	{ 0x9f, 0x95, KEY_BLUE },
+	{ 0xaf, 0x95, KEY_SUBTITLE },
+	{ 0x5f, 0x96, KEY_F15 },     /* AD */
+	{ 0x6f, 0x96, KEY_TEXT },
+	{ 0x9f, 0x96, KEY_MUTE },
+	{ 0xaf, 0x96, KEY_REWIND },
+	{ 0x5f, 0x99, KEY_STOP },
+	{ 0x6f, 0x99, KEY_PLAY },
+	{ 0x9f, 0x99, KEY_FASTFORWARD },
+	{ 0xaf, 0x99, KEY_F16 },     /* chapter */
+	{ 0x5f, 0x9a, KEY_PAUSE },
+	{ 0x6f, 0x9a, KEY_PLAY },
+	{ 0x9f, 0x9a, KEY_RECORD },
+	{ 0xaf, 0x9a, KEY_F17 },     /* picture in picture */
+	{ 0x5f, 0xa5, KEY_KPPLUS },  /* zoom in */
+	{ 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
+	{ 0x9f, 0xa5, KEY_F18 },     /* capture */
+	{ 0xaf, 0xa5, KEY_F19 },     /* web */
+	{ 0x5f, 0xa6, KEY_EMAIL },
+	{ 0x6f, 0xa6, KEY_PHONE },
+	{ 0x9f, 0xa6, KEY_PC },
 };
 
-/* TODO is it really the NEC protocol ? */
 static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
+	int i;
 	u8 key[5];
+	u8 b[4] = { 0 };
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
 
 	digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
-	/* TODO state, maybe it is VV ? */
-	if (key[1] != 0)
-		key[0] = 0x01; /* if something is inside the buffer, simulate key press */
 
-	/* call the universal NEC remote processor, to find out the key's state and event */
-	dvb_usb_nec_rc_key_to_event(d,key,event,state);
+	/* Tell the device we've read the remote. Not sure how necessary
+	   this is, but the Nebula SDK does it. */
+	digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
+
+	/* if something is inside the buffer, simulate key press */
+	if (key[1] != 0)
+	{
+		  for (i = 0; i < d->props.rc_key_map_size; i++) {
+			if (d->props.rc_key_map[i].custom == key[1] &&
+			    d->props.rc_key_map[i].data == key[2]) {
+				*event = d->props.rc_key_map[i].event;
+				*state = REMOTE_KEY_PRESSED;
+				return 0;
+			}
+		}
+	}
+
 	if (key[0] != 0)
 		deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
 	return 0;
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 70afcfd..27af4e4 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -93,6 +93,7 @@
 }
 
 static struct dvb_usb_properties dtt200u_properties;
+static struct dvb_usb_properties wt220u_fc_properties;
 static struct dvb_usb_properties wt220u_properties;
 static struct dvb_usb_properties wt220u_zl0353_properties;
 
@@ -101,6 +102,7 @@
 {
 	if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
 		return 0;
 
@@ -114,6 +116,9 @@
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
+	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
@@ -193,13 +198,54 @@
 	.num_device_descs = 1,
 	.devices = {
 		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
-		  .cold_ids = { &dtt200u_usb_table[2], NULL },
+		  .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
 		  .warm_ids = { &dtt200u_usb_table[3], NULL },
 		},
 		{ NULL },
 	}
 };
 
+static struct dvb_usb_properties wt220u_fc_properties = {
+	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+	.pid_filter_count = 15,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-fc03.fw",
+
+	.power_ctrl      = dtt200u_power_ctrl,
+	.streaming_ctrl  = dtt200u_streaming_ctrl,
+	.pid_filter      = dtt200u_pid_filter,
+	.frontend_attach = dtt200u_frontend_attach,
+
+	.rc_interval     = 300,
+	.rc_key_map      = dtt200u_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+	.rc_query        = dtt200u_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 7,
+		.endpoint = 0x86,
+		.u = {
+			.bulk = {
+				.buffersize = 4096,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
+		  .cold_ids = { &dtt200u_usb_table[6], NULL },
+		  .warm_ids = { &dtt200u_usb_table[7], NULL },
+		},
+		{ NULL },
+	}
+};
+
 static struct dvb_usb_properties wt220u_zl0353_properties = {
 	.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
 	.pid_filter_count = 15,
@@ -271,6 +317,6 @@
 module_exit(dtt200u_usb_module_exit);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
 MODULE_VERSION("1.0");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index ec63170..fe6208a 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -175,36 +175,36 @@
 int dvb_usb_fe_init(struct dvb_usb_device* d)
 {
 	if (d->props.frontend_attach == NULL) {
-		err("strange '%s' doesn't want to attach a frontend.",d->desc->name);
+		err("strange: '%s' doesn't want to attach a frontend.",d->desc->name);
 		return 0;
 	}
 
-	d->props.frontend_attach(d);
-
 	/* re-assign sleep and wakeup functions */
-	if (d->fe != NULL) {
+	if (d->props.frontend_attach(d) == 0 && d->fe != NULL) {
 		d->fe_init = d->fe->ops.init;   d->fe->ops.init  = dvb_usb_fe_wakeup;
 		d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
 
 		if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
 			err("Frontend registration failed.");
-			if (d->fe->ops.release)
-				d->fe->ops.release(d->fe);
+			dvb_frontend_detach(d->fe);
 			d->fe = NULL;
 			return -ENODEV;
 		}
+
+		/* only attach the tuner if the demod is there */
+		if (d->props.tuner_attach != NULL)
+			d->props.tuner_attach(d);
 	} else
 		err("no frontend was attached by '%s'",d->desc->name);
 
-	if (d->props.tuner_attach != NULL)
-		d->props.tuner_attach(d);
-
 	return 0;
 }
 
 int dvb_usb_fe_exit(struct dvb_usb_device *d)
 {
-	if (d->fe != NULL)
+	if (d->fe != NULL) {
 		dvb_unregister_frontend(d->fe);
+		dvb_frontend_detach(d->fe);
+	}
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 9569891..57a10de 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -10,51 +10,53 @@
 #define _DVB_USB_IDS_H_
 
 /* Vendor IDs */
-#define USB_VID_ADSTECH						0x06e1
-#define USB_VID_ANCHOR						0x0547
-#define USB_VID_WIDEVIEW					0x14aa
-#define USB_VID_AVERMEDIA					0x07ca
-#define USB_VID_COMPRO						0x185b
-#define USB_VID_COMPRO_UNK					0x145f
-#define USB_VID_CYPRESS						0x04b4
-#define USB_VID_DIBCOM						0x10b8
-#define USB_VID_DVICO						0x0fe9
-#define USB_VID_EMPIA						0xeb1a
-#define USB_VID_GRANDTEC					0x5032
-#define USB_VID_HANFTEK						0x15f4
-#define USB_VID_HAUPPAUGE					0x2040
-#define USB_VID_HYPER_PALTEK				0x1025
-#define USB_VID_KWORLD						0xeb2a
-#define USB_VID_KYE							0x0458
-#define USB_VID_MEDION						0x1660
-#define USB_VID_PINNACLE					0x2304
-#define USB_VID_VISIONPLUS					0x13d3
-#define USB_VID_TWINHAN						0x1822
-#define USB_VID_ULTIMA_ELECTRONIC			0x05d8
-#define USB_VID_GENPIX					0x09c0
+#define USB_VID_ADSTECH				0x06e1
+#define USB_VID_ANCHOR				0x0547
+#define USB_VID_AVERMEDIA			0x07ca
+#define USB_VID_COMPRO				0x185b
+#define USB_VID_COMPRO_UNK			0x145f
+#define USB_VID_CYPRESS				0x04b4
+#define USB_VID_DIBCOM				0x10b8
+#define USB_VID_DVICO				0x0fe9
+#define USB_VID_EMPIA				0xeb1a
+#define USB_VID_GENPIX				0x09c0
+#define USB_VID_GRANDTEC			0x5032
+#define USB_VID_HANFTEK				0x15f4
+#define USB_VID_HAUPPAUGE			0x2040
+#define USB_VID_HYPER_PALTEK			0x1025
+#define USB_VID_KWORLD				0xeb2a
+#define USB_VID_KYE				0x0458
+#define USB_VID_LEADTEK				0x0413
+#define USB_VID_LITEON				0x04ca
+#define USB_VID_MEDION				0x1660
+#define USB_VID_PINNACLE			0x2304
+#define USB_VID_VISIONPLUS			0x13d3
+#define USB_VID_TWINHAN				0x1822
+#define USB_VID_ULTIMA_ELECTRONIC		0x05d8
+#define USB_VID_WIDEVIEW			0x14aa
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
 #define USB_PID_ADSTECH_USB2_WARM			0xa334
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD		0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM		0x0002
-#define USB_PID_AVERMEDIA_DVBT_USB2_COLD	0xa800
-#define USB_PID_AVERMEDIA_DVBT_USB2_WARM	0xa801
-#define USB_PID_COMPRO_DVBU2000_COLD		0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM		0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD	0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM	0x010d
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM		0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD			0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM			0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD		0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
-#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM	0x0065
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
 #define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
 #define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
 #define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
 #define USB_PID_DIBCOM_STK7700				0x1e14
-#define USB_PID_DIBCOM_STK7700_REENUM		0x1e15
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD		0x2131
-#define USB_PID_GRANDTEC_DVBT_USB_COLD		0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM		0x0fa1
+#define USB_PID_DIBCOM_STK7700_REENUM			0x1e15
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_TWINHAN_VP7041_COLD			0x3201
@@ -69,25 +71,30 @@
 #define USB_PID_DNTV_TINYUSB2_WARM			0x3224
 #define USB_PID_ULTIMA_TVBOX_COLD			0x8105
 #define USB_PID_ULTIMA_TVBOX_WARM			0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD	0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM	0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD	0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD		0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_WARM		0x810a
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD	0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM	0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD		0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM		0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD		0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM		0x0015
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD		0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM		0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD		0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD			0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
+#define USB_PID_ARTEC_T14_COLD				0x810b
+#define USB_PID_ARTEC_T14_WARM				0x810c
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM			0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD			0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM			0x0015
 #define USB_PID_DTT200U_COLD				0x0201
 #define USB_PID_DTT200U_WARM				0x0301
-#define USB_PID_WT220U_COLD					0x0222
-#define USB_PID_WT220U_WARM					0x0221
+#define USB_PID_WT220U_ZAP250_COLD			0x0220
+#define USB_PID_WT220U_COLD				0x0222
+#define USB_PID_WT220U_WARM				0x0221
+#define USB_PID_WT220U_FC_COLD				0x0225
+#define USB_PID_WT220U_FC_WARM				0x0226
 #define USB_PID_WT220U_ZL0353_COLD			0x022a
 #define USB_PID_WT220U_ZL0353_WARM			0x022b
-#define USB_PID_WINTV_NOVA_T_USB2_COLD		0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM		0x9301
+#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_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
@@ -103,8 +110,17 @@
 #define USB_PID_MEDION_MD95700				0x0932
 #define USB_PID_KYE_DVB_T_COLD				0x701e
 #define USB_PID_KYE_DVB_T_WARM				0x701f
-#define USB_PID_PCTV_200E					0x020e
-#define USB_PID_PCTV_400E					0x020f
-#define USB_PID_GENPIX_8PSK_COLD				0x0200
-#define USB_PID_GENPIX_8PSK_WARM				0x0201
+#define USB_PID_PCTV_200E				0x020e
+#define USB_PID_PCTV_400E				0x020f
+#define USB_PID_LITEON_DVB_T_COLD			0xf000
+#define USB_PID_LITEON_DVB_T_WARM			0xf001
+#define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
+#define USB_PID_DIGIVOX_MINI_SL_WARM			0xe361
+#define USB_PID_GRANDTEC_DVBT_USB2_COLD			0x0bc6
+#define USB_PID_GRANDTEC_DVBT_USB2_WARM			0x0bc7
+#define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
+#define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
+#define USB_PID_GENPIX_8PSK_COLD			0x0200
+#define USB_PID_GENPIX_8PSK_WARM			0x0201
+
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index e5c6d98..380b2a4 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -6,6 +6,7 @@
  * This file contains functions for initializing the the input-device and for handling remote-control-queries.
  */
 #include "dvb-usb-common.h"
+#include <linux/usb/input.h>
 
 /* Remote-control poll function - called every dib->rc_query_interval ms to see
  * whether the remote control has received anything.
@@ -96,7 +97,7 @@
 		return 0;
 
 	usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
-	strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+	strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
 
 	d->rc_input_dev = input_allocate_device();
 	if (!d->rc_input_dev)
@@ -107,6 +108,8 @@
 	d->rc_input_dev->keycodemax = KEY_MAX;
 	d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver";
 	d->rc_input_dev->phys = d->rc_phys;
+	usb_to_input_id(d->udev, &d->rc_input_dev->id);
+	d->rc_input_dev->cdev.dev = &d->udev->dev;
 
 	/* set the bits for the keys */
 	deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 412039d..79f0a02 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -156,7 +156,7 @@
 	.pid_filter_count = 32,
 
 	.usb_ctrl = CYPRESS_FX2,
-	.firmware = "dvb-usb-nova-t-usb2-01.fw",
+	.firmware = "dvb-usb-nova-t-usb2-02.fw",
 
 	.size_of_priv     = sizeof(struct dibusb_state),
 
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 97d74da..418a0b7 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -58,7 +58,7 @@
 	umt_config.demod_init = umt_mt352_demod_init;
 	umt_config.demod_address = 0xf;
 
-	d->fe = mt352_attach(&umt_config, &d->i2c_adap);
+	d->fe = dvb_attach(mt352_attach, &umt_config, &d->i2c_adap);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index db97855..080fa25 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -1,48 +1,73 @@
 menu "Customise DVB Frontends"
 	depends on DVB_CORE
 
+config DVB_FE_CUSTOMISE
+	bool "Customise the frontend modules to build"
+	default N
+	help
+	  This allows the user to deselect frontend drivers unnecessary
+	  for their hardware from the build. Use this option with care
+	  as deselecting frontends which are in fact necessary will result
+	  in DVB devices which cannot be tuned due to lack of driver support.
+
+	  If unsure say N.
+
 comment "DVB-S (satellite) frontends"
 	depends on DVB_CORE
 
 config DVB_STV0299
 	tristate "ST STV0299 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 config DVB_CX24110
 	tristate "Conexant CX24110 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	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 && I2C
+	default m if DVB_FE_CUSTOMISE
 	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 && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 config DVB_MT312
 	tristate "Zarlink VP310/MT312 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 config DVB_VES1X93
 	tristate "VLSI VES1893 or VES1993 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 config DVB_S5H1420
 	tristate "Samsung S5H1420 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10086
+	tristate "Philips TDA10086 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
@@ -52,6 +77,7 @@
 config DVB_SP8870
 	tristate "Spase sp8870 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -64,6 +90,7 @@
 config DVB_SP887X
 	tristate "Spase sp887x based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -76,24 +103,28 @@
 config DVB_CX22700
 	tristate "Conexant CX22700 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  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 && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_L64781
 	tristate "LSI L64781"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_TDA1004X
 	tristate "Philips TDA10045H/TDA10046H based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -107,24 +138,28 @@
 config DVB_NXT6000
 	tristate "NxtWave Communications NXT6000 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_MT352
 	tristate "Zarlink MT352 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_ZL10353
 	tristate "Zarlink ZL10353 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_DIB3000MB
 	tristate "DiBcom 3000M-B"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
 	  to support this frontend.
@@ -132,6 +167,7 @@
 config DVB_DIB3000MC
 	tristate "DiBcom 3000P/M-C"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
 	  to support this frontend.
@@ -142,18 +178,21 @@
 config DVB_VES1820
 	tristate "VLSI VES1820 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  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 && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_STV0297
 	tristate "ST STV0297 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
@@ -163,6 +202,7 @@
 config DVB_NXT200X
 	tristate "NxtWave Communications NXT2002/NXT2004 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -177,6 +217,7 @@
 config DVB_OR51211
 	tristate "Oren OR51211 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -189,6 +230,7 @@
 config DVB_OR51132
 	tristate "Oren OR51132 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -204,6 +246,7 @@
 config DVB_BCM3510
 	tristate "Broadcom BCM3510"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
@@ -212,28 +255,52 @@
 config DVB_LGDT330X
 	tristate "LG Electronics LGDT3302/LGDT3303 based"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
-
-comment "Miscellaneous devices"
+comment "Tuners/PLL support"
 	depends on DVB_CORE
 
 config DVB_PLL
 	tristate
 	depends on DVB_CORE && I2C
 
+config DVB_TDA826X
+	tristate "Philips TDA826X silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUNER_MT2060
+	tristate "Microtune MT2060 silicon IF tuner"
+	help
+	  A driver for the silicon IF tuner MT2060 from Microtune.
+
+comment "Miscellaneous devices"
+	depends on DVB_CORE
+
 config DVB_LNBP21
 	tristate "LNBP21 SEC controller"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  An SEC control chip.
 
 config DVB_ISL6421
 	tristate "ISL6421 SEC controller"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
 	help
 	  An SEC control chip.
 
+config DVB_TUA6100
+	tristate "TUA6100 PLL"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVBS PLL chip.
+
 endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 0e4880b..dce9cf0 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -11,8 +11,8 @@
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
 obj-$(CONFIG_DVB_TDA8083) += tda8083.o
 obj-$(CONFIG_DVB_L64781) += l64781.o
-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
-obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -33,3 +33,7 @@
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
+obj-$(CONFIG_DVB_TDA10086) += tda10086.o
+obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUA6100) += tua6100.o
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
index 80f5d09..6dfa839 100644
--- a/drivers/media/dvb/frontends/bcm3510.h
+++ b/drivers/media/dvb/frontends/bcm3510.h
@@ -34,7 +34,16 @@
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
+#if defined(CONFIG_DVB_BCM3510) || defined(CONFIG_DVB_BCM3510_MODULE)
 extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_BCM3510
 
 #endif
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index dcd8979..10286cc 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -31,7 +31,16 @@
 	u8 demod_address;
 };
 
+#if defined(CONFIG_DVB_CX22700) || defined(CONFIG_DVB_CX22700_MODULE)
 extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX22700
 
 #endif // CX22700_H
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 4106d46..335219e 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -399,7 +399,9 @@
 {
 	struct cx22702_state* state = fe->demodulator_priv;
 
-	*signal_strength = cx22702_readreg (state, 0x23);
+	u16 rs_ber = 0;
+	rs_ber = cx22702_readreg (state, 0x23);
+	*signal_strength = (rs_ber << 8) | rs_ber;
 
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 7f2f241..bc217dd 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -41,7 +41,16 @@
 	u8 output_mode;
 };
 
+#if defined(CONFIG_DVB_CX22702) || defined(CONFIG_DVB_CX22702_MODULE)
 extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX22702
 
 #endif // CX22702_H
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index ce3c739..ae96395 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -1,4 +1,4 @@
-/*
+	/*
     cx24110 - Single Chip Satellite Channel Receiver driver module
 
     Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
@@ -311,16 +311,17 @@
 
 }
 
-int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
+static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
 {
 	struct cx24110_state *state = fe->demodulator_priv;
 
+	if (len != 3)
+		return -EINVAL;
+
 /* tuner data is 21 bits long, must be left-aligned in data */
 /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
 /* FIXME (low): add error handling, avoid infinite loops if HW fails... */
 
-	dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
-
 	cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
 	cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
 
@@ -329,19 +330,19 @@
 		cx24110_writereg(state,0x72,0);
 
 	/* write the topmost 8 bits */
-	cx24110_writereg(state,0x72,(data>>24)&0xff);
+	cx24110_writereg(state,0x72,buf[0]);
 
 	/* wait for the send to be completed */
 	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 		;
 
 	/* send another 8 bytes */
-	cx24110_writereg(state,0x72,(data>>16)&0xff);
+	cx24110_writereg(state,0x72,buf[1]);
 	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 		;
 
 	/* and the topmost 5 bits of this byte */
-	cx24110_writereg(state,0x72,(data>>8)&0xff);
+	cx24110_writereg(state,0x72,buf[2]);
 	while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
 		;
 
@@ -642,6 +643,7 @@
 	.release = cx24110_release,
 
 	.init = cx24110_initfe,
+	.write = _cx24110_pll_write,
 	.set_frontend = cx24110_set_frontend,
 	.get_frontend = cx24110_get_frontend,
 	.read_status = cx24110_read_status,
@@ -664,4 +666,3 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(cx24110_attach);
-EXPORT_SYMBOL(cx24110_pll_write);
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index b354a64..c9d5ae2 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -33,9 +33,24 @@
 	u8 demod_address;
 };
 
+static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
+	int r = 0;
+	u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 3);
+	return r;
+}
+
+#if defined(CONFIG_DVB_CX24110) || defined(CONFIG_DVB_CX24110_MODULE)
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
 					   struct i2c_adapter* i2c);
-
-extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data);
+#else
+static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX24110
 
 #endif // CX24110_H
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 274a87b..62d69a6 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -45,9 +45,6 @@
 
 	struct dvb_frontend frontend;
 
-	u32 lastber;
-	u16 snr;
-
 	/* Some PLL specifics for tuning */
 	u32 VCAarg;
 	u32 VGAarg;
@@ -194,7 +191,7 @@
 	{0x06, 0x31}, /* MPEG (default) */
 	{0x0b, 0x00}, /* Freq search start point (default) */
 	{0x0c, 0x00}, /* Demodulator sample gain (default) */
-	{0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */
+	{0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */
 	{0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
 	{0x0f, 0xfe}, /* FEC search mask (all supported codes) */
 	{0x10, 0x01}, /* Default search inversion, no repeat (default) */
@@ -223,8 +220,9 @@
 	{0x44, 0x00}, /* Constellation (default) */
 	{0x45, 0x00}, /* Symbol count (default) */
 	{0x46, 0x0d}, /* Symbol rate estimator on (default) */
-	{0x56, 0x41}, /* Various (default) */
+	{0x56, 0xc1}, /* Error Counter = Viterbi BER */
 	{0x57, 0xff}, /* Error Counter Window (default) */
+	{0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */
 	{0x67, 0x83}, /* Non-DCII symbol clock */
 };
 
@@ -321,6 +319,12 @@
 	if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
 		fec = FEC_AUTO;
 
+	/* Set the soft decision threshold */
+	if(fec == FEC_1_2)
+		cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01);
+	else
+		cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01);
+
 	switch (fec) {
 	case FEC_1_2:
 		dprintk("%s:  set FEC to 1/2\n",__FUNCTION__);
@@ -657,6 +661,10 @@
 	for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
 		cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
+	/* Set the LNB polarity */
+	if(state->config->lnb_polarity)
+		cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
+
 	return 0;
 }
 
@@ -674,6 +682,9 @@
 	case SEC_VOLTAGE_18:
 		dprintk("%s: setting voltage 18V\n", __FUNCTION__);
 		return cx24123_writereg(state, 0x29, val | 0x80);
+	case SEC_VOLTAGE_OFF:
+		/* already handled in cx88-dvb */
+		return 0;
 	default:
 		return -EINVAL;
 	};
@@ -776,13 +787,15 @@
 	if (lock & 0x01)
 		*status |= FE_HAS_SIGNAL;
 	if (sync & 0x02)
-		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_CARRIER;	/* Phase locked */
 	if (sync & 0x04)
 		*status |= FE_HAS_VITERBI;
+
+	/* Reed-Solomon Status */
 	if (sync & 0x08)
 		*status |= FE_HAS_SYNC;
 	if (sync & 0x80)
-		*status |= FE_HAS_LOCK;
+		*status |= FE_HAS_LOCK;		/*Full Sync */
 
 	return 0;
 }
@@ -795,29 +808,13 @@
 {
 	struct cx24123_state *state = fe->demodulator_priv;
 
-	state->lastber =
-		((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+	/* The true bit error rate is this value divided by
+	   the window size (set as 256 * 255) */
+	*ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
 		(cx24123_readreg(state, 0x1d) << 8 |
-		cx24123_readreg(state, 0x1e));
+		 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;
-
-	dprintk("%s:  BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
-
-	*ber = state->lastber;
+	dprintk("%s:  BER = %d\n",__FUNCTION__,*ber);
 
 	return 0;
 }
@@ -825,6 +822,7 @@
 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 */
 
 	dprintk("%s:  Signal strength = %d\n",__FUNCTION__,*signal_strength);
@@ -835,23 +833,17 @@
 static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	*snr = state->snr;
+
+	/* Inverted raw Es/N0 count, totally bogus but better than the
+	   BER threshold. */
+	*snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
+			 (u16)cx24123_readreg(state, 0x19));
 
 	dprintk("%s:  read S/N index = %d\n",__FUNCTION__,*snr);
 
 	return 0;
 }
 
-static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
-	struct cx24123_state *state = fe->demodulator_priv;
-	*ucblocks = state->lastber;
-
-	dprintk("%s:  ucblocks (ber) = %d\n",__FUNCTION__,*ucblocks);
-
-	return 0;
-}
-
 static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
@@ -922,6 +914,29 @@
 	return 0;
 }
 
+static int cx24123_tune(struct dvb_frontend* fe,
+			struct dvb_frontend_parameters* params,
+			unsigned int mode_flags,
+			int *delay,
+			fe_status_t *status)
+{
+	int retval = 0;
+
+	if (params != NULL)
+		retval = cx24123_set_frontend(fe, params);
+
+	if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+		cx24123_read_status(fe, status);
+	*delay = HZ/10;
+
+	return retval;
+}
+
+static int cx24123_get_algo(struct dvb_frontend *fe)
+{
+	return 1; //FE_ALGO_HW
+}
+
 static void cx24123_release(struct dvb_frontend* fe)
 {
 	struct cx24123_state* state = fe->demodulator_priv;
@@ -949,8 +964,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	state->lastber = 0;
-	state->snr = 0;
 	state->VCAarg = 0;
 	state->VGAarg = 0;
 	state->bandselectarg = 0;
@@ -1003,11 +1016,12 @@
 	.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,
 	.diseqc_send_burst = cx24123_diseqc_send_burst,
 	.set_tone = cx24123_set_tone,
 	.set_voltage = cx24123_set_voltage,
+	.tune = cx24123_tune,
+	.get_frontend_algo = cx24123_get_algo,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 9606f82..57a1dae 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -30,9 +30,21 @@
 
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+	/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
+	int lnb_polarity;
 };
 
+#if defined(CONFIG_DVB_CX24123) || defined(CONFIG_DVB_CX24123_MODULE)
 extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_CX24123
 
 #endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
deleted file mode 100644
index 1a4f1f7..0000000
--- a/drivers/media/dvb/frontends/dib3000-common.c
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "dib3000-common.h"
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_i2c(args...) dprintk(0x02,args)
-#define deb_srch(args...) dprintk(0x04,args)
-
-
-int dib3000_read_reg(struct dib3000_state *state, u16 reg)
-{
-	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
-	u8 rb[2];
-	struct i2c_msg msg[] = {
-		{ .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
-		{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
-	};
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2)
-		deb_i2c("i2c read error\n");
-
-	deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
-			(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
-
-	return (rb[0] << 8) | rb[1];
-}
-
-int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
-{
-	u8 b[] = {
-		(reg >> 8) & 0xff, reg & 0xff,
-		(val >> 8) & 0xff, val & 0xff,
-	};
-	struct i2c_msg msg[] = {
-		{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
-	};
-	deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
-
-	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-int dib3000_search_status(u16 irq,u16 lock)
-{
-	if (irq & 0x02) {
-		if (lock & 0x01) {
-			deb_srch("auto search succeeded\n");
-			return 1; // auto search succeeded
-		} else {
-			deb_srch("auto search not successful\n");
-			return 0; // auto search failed
-		}
-	} else if (irq & 0x01)  {
-		deb_srch("auto search failed\n");
-		return 0; // auto search failed
-	}
-	return -1; // try again
-}
-
-/* for auto search */
-u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
-	{ /* fft */
-		{ /* gua */
-			{ 0, 1 },                   /*  0   0   { 0,1 } */
-			{ 3, 9 },                   /*  0   1   { 0,1 } */
-		},
-		{
-			{ 2, 5 },                   /*  1   0   { 0,1 } */
-			{ 6, 11 },                  /*  1   1   { 0,1 } */
-		}
-	};
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000_seq);
-
-EXPORT_SYMBOL(dib3000_read_reg);
-EXPORT_SYMBOL(dib3000_write_reg);
-EXPORT_SYMBOL(dib3000_search_status);
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
deleted file mode 100644
index be1c0d3..0000000
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * .h-files for the common use of the frontend drivers made by DiBcom
- * DiBcom 3000M-B/C, 3000P
- *
- * DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DibCom, which has
- *
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- * Acknowledgements
- *
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dibusb for more information
- *
- */
-
-#ifndef DIB3000_COMMON_H
-#define DIB3000_COMMON_H
-
-#include "dvb_frontend.h"
-#include "dib3000.h"
-
-/* info and err, taken from usb.h, if there is anything available like by default. */
-#define err(format, arg...)  printk(KERN_ERR     "dib3000: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO    "dib3000: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
-
-/* frontend state */
-struct dib3000_state {
-	struct i2c_adapter* i2c;
-
-/* configuration settings */
-	struct dib3000_config config;
-
-	struct dvb_frontend frontend;
-	int timing_offset;
-	int timing_offset_comp_done;
-
-	fe_bandwidth_t last_tuned_bw;
-	u32 last_tuned_freq;
-};
-
-/* commonly used methods by the dib3000mb/mc/p frontend */
-extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
-extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
-
-extern int dib3000_search_status(u16 irq,u16 lock);
-
-/* handy shortcuts */
-#define rd(reg) dib3000_read_reg(state,reg)
-
-#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
-	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
-
-#define wr_foreach(a,v) { int i; \
-	if (sizeof(a) != sizeof(v)) \
-		err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
-	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
-		wr(a[i],v[i]); \
-	}
-
-#define set_or(reg,val) wr(reg,rd(reg) | val)
-
-#define set_and(reg,val) wr(reg,rd(reg) & val)
-
-
-/* debug */
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(level,args...) \
-    do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
-
-/* mask for enabling a specific pid for the pid_filter */
-#define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
-
-/* common values for tuning */
-#define DIB3000_ALPHA_0					(     0)
-#define DIB3000_ALPHA_1					(     1)
-#define DIB3000_ALPHA_2					(     2)
-#define DIB3000_ALPHA_4					(     4)
-
-#define DIB3000_CONSTELLATION_QPSK		(     0)
-#define DIB3000_CONSTELLATION_16QAM		(     1)
-#define DIB3000_CONSTELLATION_64QAM		(     2)
-
-#define DIB3000_GUARD_TIME_1_32			(     0)
-#define DIB3000_GUARD_TIME_1_16			(     1)
-#define DIB3000_GUARD_TIME_1_8			(     2)
-#define DIB3000_GUARD_TIME_1_4			(     3)
-
-#define DIB3000_TRANSMISSION_MODE_2K	(     0)
-#define DIB3000_TRANSMISSION_MODE_8K	(     1)
-
-#define DIB3000_SELECT_LP				(     0)
-#define DIB3000_SELECT_HP				(     1)
-
-#define DIB3000_FEC_1_2					(     1)
-#define DIB3000_FEC_2_3					(     2)
-#define DIB3000_FEC_3_4					(     3)
-#define DIB3000_FEC_5_6					(     5)
-#define DIB3000_FEC_7_8					(     7)
-
-#define DIB3000_HRCH_OFF				(     0)
-#define DIB3000_HRCH_ON					(     1)
-
-#define DIB3000_DDS_INVERSION_OFF		(     0)
-#define DIB3000_DDS_INVERSION_ON		(     1)
-
-#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 8))
-#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 8) | (1 << 7)))
-
-/* for auto search */
-extern u16 dib3000_seq[2][2][2];
-
-#define DIB3000_REG_MANUFACTOR_ID		(  1025)
-#define DIB3000_I2C_ID_DIBCOM			(0x01b3)
-
-#define DIB3000_REG_DEVICE_ID			(  1026)
-#define DIB3000MB_DEVICE_ID				(0x3000)
-#define DIB3000MC_DEVICE_ID				(0x3001)
-#define DIB3000P_DEVICE_ID				(0x3002)
-
-#endif // DIB3000_COMMON_H
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index ec92762..0caac3f 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -41,9 +41,16 @@
 	int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
 };
 
+#if defined(CONFIG_DVB_DIB3000MB) || defined(CONFIG_DVB_DIB3000MB_MODULE)
 extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
+#else
+static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MB
 
-extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
-					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
 #endif // DIB3000_H
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 5302e11..adbabfd 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -29,9 +29,10 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
-#include "dib3000-common.h"
-#include "dib3000mb_priv.h"
+#include "dvb_frontend.h"
+
 #include "dib3000.h"
+#include "dib3000mb_priv.h"
 
 /* Version information */
 #define DRIVER_VERSION "0.1"
@@ -44,10 +45,81 @@
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
 #endif
 #define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...)  dprintk(0x02,args)
+#define deb_srch(args...) dprintk(0x04,args)
+#define deb_info(args...) dprintk(0x01,args)
 #define deb_xfer(args...) dprintk(0x02,args)
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
 
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
+#endif
+
+static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+{
+	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+	u8 rb[2];
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2)
+		deb_i2c("i2c read error\n");
+
+	deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+			(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+
+	return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+{
+	u8 b[] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+	};
+	deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+
+	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static int dib3000_search_status(u16 irq,u16 lock)
+{
+	if (irq & 0x02) {
+		if (lock & 0x01) {
+			deb_srch("auto search succeeded\n");
+			return 1; // auto search succeeded
+		} else {
+			deb_srch("auto search not successful\n");
+			return 0; // auto search failed
+		}
+	} else if (irq & 0x01)  {
+		deb_srch("auto search failed\n");
+		return 0; // auto search failed
+	}
+	return -1; // try again
+}
+
+/* for auto search */
+static u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
+	{ /* fft */
+		{ /* gua */
+			{ 0, 1 },                   /*  0   0   { 0,1 } */
+			{ 3, 9 },                   /*  0   1   { 0,1 } */
+		},
+		{
+			{ 2, 5 },                   /*  1   0   { 0,1 } */
+			{ 6, 11 },                  /*  1   1   { 0,1 } */
+		}
+	};
+
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep);
 
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 999b190..1a12747 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -13,6 +13,99 @@
 #ifndef __DIB3000MB_PRIV_H_INCLUDED__
 #define __DIB3000MB_PRIV_H_INCLUDED__
 
+/* info and err, taken from usb.h, if there is anything available like by default. */
+#define err(format, arg...)  printk(KERN_ERR     "dib3000: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO    "dib3000: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
+
+/* handy shortcuts */
+#define rd(reg) dib3000_read_reg(state,reg)
+
+#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+
+#define wr_foreach(a,v) { int i; \
+	if (sizeof(a) != sizeof(v)) \
+		err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
+	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+		wr(a[i],v[i]); \
+	}
+
+#define set_or(reg,val) wr(reg,rd(reg) | val)
+
+#define set_and(reg,val) wr(reg,rd(reg) & val)
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(level,args...) \
+    do { if ((debug & level)) { printk(args); } } while (0)
+#else
+#define dprintk(args...) do { } while (0)
+#endif
+
+/* mask for enabling a specific pid for the pid_filter */
+#define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
+
+/* common values for tuning */
+#define DIB3000_ALPHA_0					(     0)
+#define DIB3000_ALPHA_1					(     1)
+#define DIB3000_ALPHA_2					(     2)
+#define DIB3000_ALPHA_4					(     4)
+
+#define DIB3000_CONSTELLATION_QPSK		(     0)
+#define DIB3000_CONSTELLATION_16QAM		(     1)
+#define DIB3000_CONSTELLATION_64QAM		(     2)
+
+#define DIB3000_GUARD_TIME_1_32			(     0)
+#define DIB3000_GUARD_TIME_1_16			(     1)
+#define DIB3000_GUARD_TIME_1_8			(     2)
+#define DIB3000_GUARD_TIME_1_4			(     3)
+
+#define DIB3000_TRANSMISSION_MODE_2K	(     0)
+#define DIB3000_TRANSMISSION_MODE_8K	(     1)
+
+#define DIB3000_SELECT_LP				(     0)
+#define DIB3000_SELECT_HP				(     1)
+
+#define DIB3000_FEC_1_2					(     1)
+#define DIB3000_FEC_2_3					(     2)
+#define DIB3000_FEC_3_4					(     3)
+#define DIB3000_FEC_5_6					(     5)
+#define DIB3000_FEC_7_8					(     7)
+
+#define DIB3000_HRCH_OFF				(     0)
+#define DIB3000_HRCH_ON					(     1)
+
+#define DIB3000_DDS_INVERSION_OFF		(     0)
+#define DIB3000_DDS_INVERSION_ON		(     1)
+
+#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 8))
+#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 8) | (1 << 7)))
+
+#define DIB3000_REG_MANUFACTOR_ID		(  1025)
+#define DIB3000_I2C_ID_DIBCOM			(0x01b3)
+
+#define DIB3000_REG_DEVICE_ID			(  1026)
+#define DIB3000MB_DEVICE_ID				(0x3000)
+#define DIB3000MC_DEVICE_ID				(0x3001)
+#define DIB3000P_DEVICE_ID				(0x3002)
+
+/* frontend state */
+struct dib3000_state {
+	struct i2c_adapter* i2c;
+
+/* configuration settings */
+	struct dib3000_config config;
+
+	struct dvb_frontend frontend;
+	int timing_offset;
+	int timing_offset_comp_done;
+
+	fe_bandwidth_t last_tuned_bw;
+	u32 last_tuned_freq;
+};
+
 /* register addresses and some of their default values */
 
 /* restart subsystems */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 9867347..cc28417 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,725 +1,791 @@
 /*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C
- * DiBcom (http://www.dibcom.fr/)
+ * Driver for DiBcom DiB3000MC/P-demodulator.
  *
+ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
- * based on GPL code from DiBCom, which has
+ * This code is partially based on the previous dib3000mc.c .
  *
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- *	This program is free software; you can redistribute it and/or
+ * This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License as
  *	published by the Free Software Foundation, version 2.
- *
- * Acknowledgements
- *
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dibusb for more information
- *
  */
+
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
+#include <linux/i2c.h>
+//#include <linux/init.h>
+//#include <linux/delay.h>
+//#include <linux/string.h>
+//#include <linux/slab.h>
 
-#include "dib3000-common.h"
-#include "dib3000mc_priv.h"
-#include "dib3000.h"
+#include "dvb_frontend.h"
 
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+#include "dib3000mc.h"
 
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able)).");
-#endif
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_setf(args...) dprintk(0x04,args)
-#define deb_getf(args...) dprintk(0x08,args)
-#define deb_stat(args...) dprintk(0x10,args)
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
-	fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+
+struct dib3000mc_state {
+	struct dvb_frontend demod;
+	struct dib3000mc_config *cfg;
+
+	u8 i2c_addr;
+	struct i2c_adapter *i2c_adap;
+
+	struct dibx000_i2c_master i2c_master;
+
+	fe_bandwidth_t current_bandwidth;
+
+	u16 dev_id;
+};
+
+static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
 {
-	switch (transmission_mode) {
-		case TRANSMISSION_MODE_2K:
-			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
-			break;
-		case TRANSMISSION_MODE_8K:
-			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
-			break;
-		default:
-			break;
+	u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
+	u8 rb[2];
+	struct i2c_msg msg[2] = {
+		{ .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+
+	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+		dprintk("i2c read error on %d\n",reg);
+
+	return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
+{
+	u8 b[4] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg = {
+		.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+	};
+	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+
+static int dib3000mc_identify(struct dib3000mc_state *state)
+{
+	u16 value;
+	if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
+		dprintk("-E-  DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
+		return -EREMOTEIO;
 	}
 
-	switch (bandwidth) {
-/*		case BANDWIDTH_5_MHZ:
-			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
-			break; */
-		case BANDWIDTH_6_MHZ:
-			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
-			break;
-		case BANDWIDTH_7_MHZ:
-			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
-			break;
-		case BANDWIDTH_8_MHZ:
-			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
-			break;
-		default:
-			break;
+	value = dib3000mc_read_word(state, 1026);
+	if (value != 0x3001 && value != 0x3002) {
+		dprintk("-E-  DiB3000MC/P: wrong Device ID (%x)\n",value);
+		return -EREMOTEIO;
 	}
+	state->dev_id = value;
 
-	switch (mode) {
-		case 0: /* no impulse */ /* fall through */
-			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
-			break;
-		case 1: /* new algo */
-			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
-			set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
-			break;
-		default: /* old algo */
-			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
-			break;
-	}
+	dprintk("-I-  found DiB3000MC/P: %x\n",state->dev_id);
+
 	return 0;
 }
 
-static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
-		fe_transmit_mode_t fft, fe_bandwidth_t bw)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
 {
-	u16 timf_msb,timf_lsb;
-	s32 tim_offset,tim_sgn;
-	u64 comp1,comp2,comp=0;
-
-	switch (bw) {
-		case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
-		case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
-		case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
-		default: err("unknown bandwidth (%d)",bw); break;
-	}
-	timf_msb = (comp >> 16) & 0xff;
-	timf_lsb = (comp & 0xffff);
+/*
+	u32 timf_msb, timf_lsb, i;
+	int tim_sgn ;
+	LUInt comp1, comp2, comp ;
+//	u32 tim_offset ;
+	comp = 27700 * BW_INDEX_TO_KHZ(bw) / 1000;
+	timf_msb = (comp >> 16) & 0x00FF;
+	timf_lsb =  comp        & 0xFFFF;
 
 	// Update the timing offset ;
-	if (upd_offset > 0) {
-		if (!state->timing_offset_comp_done) {
-			msleep(200);
+	if (update_offset) {
+		if (state->timing_offset_comp_done == 0) {
+			usleep(200000);
 			state->timing_offset_comp_done = 1;
 		}
-		tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
+		tim_offset = dib3000mc_read_word(state, 416);
 		if ((tim_offset & 0x2000) == 0x2000)
-			tim_offset |= 0xC000;
-		if (fft == TRANSMISSION_MODE_2K)
-			tim_offset <<= 2;
+			tim_offset |= 0xC000; // PB: This only works if tim_offset is s16 - weird
+
+		if (nfft == 0)
+			tim_offset = tim_offset << 2; // PB: Do not store the offset for different things in one variable
 		state->timing_offset += tim_offset;
 	}
-
 	tim_offset = state->timing_offset;
+
 	if (tim_offset < 0) {
 		tim_sgn = 1;
 		tim_offset = -tim_offset;
 	} else
 		tim_sgn = 0;
 
-	comp1 =  (u32)tim_offset * (u32)timf_lsb ;
-	comp2 =  (u32)tim_offset * (u32)timf_msb ;
+	comp1 = tim_offset * timf_lsb;
+	comp2 = tim_offset * timf_msb;
 	comp  = ((comp1 >> 16) + comp2) >> 7;
 
 	if (tim_sgn == 0)
-		comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
+		comp = timf_msb * (1<<16) + timf_lsb + comp;
 	else
-		comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
+		comp = timf_msb * (1<<16) + timf_lsb - comp;
 
-	timf_msb = (comp >> 16) & 0xff;
-	timf_lsb = comp & 0xffff;
+	timf_msb = (comp>>16)&0xFF ;
+	timf_lsb = comp&0xFFFF;
+*/
+	u32 timf = 1384402 * (BW_INDEX_TO_KHZ(bw) / 1000);
 
-	wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
-	wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
+	dib3000mc_write_word(state, 23, timf >> 16);
+	dib3000mc_write_word(state, 24, timf & 0xffff);
+
 	return 0;
 }
 
-static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
+static int dib3000mc_setup_pwm3_state(struct dib3000mc_state *state)
 {
-	if (boost) {
-		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
+    if (state->cfg->pwm3_inversion) {
+		dib3000mc_write_word(state, 51, (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
+		dib3000mc_write_word(state, 52, (0 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (2 << 0));
 	} else {
-		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
+		dib3000mc_write_word(state, 51, (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0));
+		dib3000mc_write_word(state, 52, (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0));
 	}
+
+    if (state->cfg->use_pwm3)
+		dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
+	else
+		dib3000mc_write_word(state, 245, 0);
+
+    dib3000mc_write_word(state, 1040, 0x3);
+	return 0;
+}
+
+static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
+{
+	int    ret = 0;
+	u16 fifo_threshold = 1792;
+	u16 outreg = 0;
+	u16 outmode = 0;
+	u16 elecout = 1;
+	u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
+
+	dprintk("-I-  Setting output mode for demod %p to %d\n",
+			&state->demod, mode);
+
+	switch (mode) {
+		case OUTMODE_HIGH_Z:  // disable
+			elecout = 0;
+			break;
+		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
+			outmode = 0;
+			break;
+		case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
+			outmode = 1;
+			break;
+		case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
+			outmode = 2;
+			break;
+		case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
+			elecout = 3;
+			/*ADDR @ 206 :
+			P_smo_error_discard  [1;6:6] = 0
+			P_smo_rs_discard     [1;5:5] = 0
+			P_smo_pid_parse      [1;4:4] = 0
+			P_smo_fifo_flush     [1;3:3] = 0
+			P_smo_mode           [2;2:1] = 11
+			P_smo_ovf_prot       [1;0:0] = 0
+			*/
+			smo_reg |= 3 << 1;
+			fifo_threshold = 512;
+			outmode = 5;
+			break;
+		case OUTMODE_DIVERSITY:
+			outmode = 4;
+			elecout = 1;
+			break;
+		default:
+			dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+			outmode = 0;
+			break;
+	}
+
+	if ((state->cfg->output_mpeg2_in_188_bytes))
+		smo_reg |= (1 << 5); // P_smo_rs_discard     [1;5:5] = 1
+
+	outreg = dib3000mc_read_word(state, 244) & 0x07FF;
+	outreg |= (outmode << 11);
+	ret |= dib3000mc_write_word(state,  244, outreg);
+	ret |= dib3000mc_write_word(state,  206, smo_reg);   /*smo_ mode*/
+	ret |= dib3000mc_write_word(state,  207, fifo_threshold); /* synchronous fread */
+	ret |= dib3000mc_write_word(state, 1040, elecout);         /* P_out_cfg */
+	return ret;
+}
+
+static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	u16 bw_cfg[6] = { 0 };
+	u16 imp_bw_cfg[3] = { 0 };
+	u16 reg;
+
+/* settings here are for 27.7MHz */
 	switch (bw) {
 		case BANDWIDTH_8_MHZ:
-			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+			bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
+			imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
 			break;
+
 		case BANDWIDTH_7_MHZ:
-			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
+			bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
+			imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
 			break;
+
 		case BANDWIDTH_6_MHZ:
-			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
+			bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
+			imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
 			break;
-/*		case BANDWIDTH_5_MHZ:
-			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
-			break;*/
-		case BANDWIDTH_AUTO:
-			return -EOPNOTSUPP;
-		default:
-			err("unknown bandwidth value (%d).",bw);
-			return -EINVAL;
+
+		case 255 /* BANDWIDTH_5_MHZ */:
+			bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
+			imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
+			break;
+
+		default: return -EINVAL;
 	}
-	if (boost) {
-		u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
-			rd(DIB3000MC_REG_BW_TIMOUT_LSB);
-		timeout *= 85; timeout >>= 7;
-		wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
-		wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
-	}
+
+	for (reg = 6; reg < 12; reg++)
+		dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
+	dib3000mc_write_word(state, 12, 0x0000);
+	dib3000mc_write_word(state, 13, 0x03e8);
+	dib3000mc_write_word(state, 14, 0x0000);
+	dib3000mc_write_word(state, 15, 0x03f2);
+	dib3000mc_write_word(state, 16, 0x0001);
+	dib3000mc_write_word(state, 17, 0xb0d0);
+	// P_sec_len
+	dib3000mc_write_word(state, 18, 0x0393);
+	dib3000mc_write_word(state, 19, 0x8700);
+
+	for (reg = 55; reg < 58; reg++)
+		dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
+
+	// Timing configuration
+	dib3000mc_set_timing(state, 0, bw, 0);
+
 	return 0;
 }
 
-static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con)
+static u16 impulse_noise_val[29] =
+
 {
-	switch (con) {
-		case QAM_64:
-			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]);
-			break;
-		case QAM_16:
-			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
-			break;
-		case QPSK:
-			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]);
-			break;
-		case QAM_AUTO:
-			break;
-		default:
-			warn("unkown constellation.");
-			break;
-	}
-	return 0;
-}
+	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
+	0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
+	0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
+};
 
-static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val)
+static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
 {
-	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
-	fe_code_rate_t fe_cr = FEC_NONE;
-	u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
-	int seq;
+	u16 i;
+	for (i = 58; i < 87; i++)
+		dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
 
-	switch (ofdm->transmission_mode) {
-		case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
-		case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
-		case TRANSMISSION_MODE_AUTO: break;
-		default: return -EINVAL;
-	}
-	switch (ofdm->guard_interval) {
-		case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
-		case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
-		case GUARD_INTERVAL_1_8:  guard = DIB3000_GUARD_TIME_1_8; break;
-		case GUARD_INTERVAL_1_4:  guard = DIB3000_GUARD_TIME_1_4; break;
-		case GUARD_INTERVAL_AUTO: break;
-		default: return -EINVAL;
-	}
-	switch (ofdm->constellation) {
-		case QPSK:   qam = DIB3000_CONSTELLATION_QPSK; break;
-		case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
-		case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
-		case QAM_AUTO: break;
-		default: return -EINVAL;
-	}
-	switch (ofdm->hierarchy_information) {
-		case HIERARCHY_NONE: /* fall through */
-		case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
-		case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
-		case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
-		case HIERARCHY_AUTO: break;
-		default: return -EINVAL;
-	}
-	if (ofdm->hierarchy_information == HIERARCHY_NONE) {
-		hrch   = DIB3000_HRCH_OFF;
-		sel_hp = DIB3000_SELECT_HP;
-		fe_cr  = ofdm->code_rate_HP;
-	} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
-		hrch   = DIB3000_HRCH_ON;
-		sel_hp = DIB3000_SELECT_LP;
-		fe_cr  = ofdm->code_rate_LP;
-	}
-	switch (fe_cr) {
-		case FEC_1_2: cr = DIB3000_FEC_1_2; break;
-		case FEC_2_3: cr = DIB3000_FEC_2_3; break;
-		case FEC_3_4: cr = DIB3000_FEC_3_4; break;
-		case FEC_5_6: cr = DIB3000_FEC_5_6; break;
-		case FEC_7_8: cr = DIB3000_FEC_7_8; break;
-		case FEC_NONE: break;
-		case FEC_AUTO: break;
-		default: return -EINVAL;
+	if (nfft == 1) {
+		dib3000mc_write_word(state, 58, 0x3b);
+		dib3000mc_write_word(state, 84, 0x00);
+		dib3000mc_write_word(state, 85, 0x8200);
 	}
 
-	wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
-	wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
+	dib3000mc_write_word(state, 34, 0x1294);
+	dib3000mc_write_word(state, 35, 0x1ff8);
+	if (mode == 1)
+		dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
+}
 
-	switch (fep->inversion) {
-		case INVERSION_OFF:
-			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
-			break;
-		case INVERSION_AUTO: /* fall through */
-		case INVERSION_ON:
-			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
-			break;
-		default:
-			return -EINVAL;
+static int dib3000mc_init(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	struct dibx000_agc_config *agc = state->cfg->agc;
+
+	// Restart Configuration
+	dib3000mc_write_word(state, 1027, 0x8000);
+	dib3000mc_write_word(state, 1027, 0x0000);
+
+	// power up the demod + mobility configuration
+	dib3000mc_write_word(state, 140, 0x0000);
+	dib3000mc_write_word(state, 1031, 0);
+
+	if (state->cfg->mobile_mode) {
+		dib3000mc_write_word(state, 139,  0x0000);
+		dib3000mc_write_word(state, 141,  0x0000);
+		dib3000mc_write_word(state, 175,  0x0002);
+		dib3000mc_write_word(state, 1032, 0x0000);
+	} else {
+		dib3000mc_write_word(state, 139,  0x0001);
+		dib3000mc_write_word(state, 141,  0x0000);
+		dib3000mc_write_word(state, 175,  0x0000);
+		dib3000mc_write_word(state, 1032, 0x012C);
 	}
+	dib3000mc_write_word(state, 1033, 0);
 
-	seq = dib3000_seq
-		[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
-		[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
-		[fep->inversion == INVERSION_AUTO];
+	// P_clk_cfg
+	dib3000mc_write_word(state, 1037, 12592);
 
-	deb_setf("seq? %d\n", seq);
-	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
-	*auto_val = ofdm->constellation == QAM_AUTO ||
-			ofdm->hierarchy_information == HIERARCHY_AUTO ||
-			ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
-			ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
-			fe_cr == FEC_AUTO ||
-			fep->inversion == INVERSION_AUTO;
+	// other configurations
+
+	// P_ctrl_sfreq
+	dib3000mc_write_word(state, 33, (5 << 0));
+	dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
+
+	// Phase noise control
+	// P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
+	dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
+
+	if (state->cfg->phase_noise_mode == 0)
+		dib3000mc_write_word(state, 111, 0x00);
+	else
+		dib3000mc_write_word(state, 111, 0x02);
+
+	// P_agc_global
+	dib3000mc_write_word(state, 50, 0x8000);
+
+	// agc setup misc
+	dib3000mc_setup_pwm3_state(state);
+
+	// P_agc_counter_lock
+	dib3000mc_write_word(state, 53, 0x87);
+	// P_agc_counter_unlock
+	dib3000mc_write_word(state, 54, 0x87);
+
+	/* agc */
+	dib3000mc_write_word(state, 36, state->cfg->max_time);
+	dib3000mc_write_word(state, 37, agc->setup);
+	dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
+	dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
+
+	// set_agc_loop_Bw
+	dib3000mc_write_word(state, 40, 0x0179);
+	dib3000mc_write_word(state, 41, 0x03f0);
+
+	dib3000mc_write_word(state, 42, agc->agc1_max);
+	dib3000mc_write_word(state, 43, agc->agc1_min);
+	dib3000mc_write_word(state, 44, agc->agc2_max);
+	dib3000mc_write_word(state, 45, agc->agc2_min);
+	dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+	dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+	dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+// Begin: TimeOut registers
+	// P_pha3_thres
+	dib3000mc_write_word(state, 110, 3277);
+	// P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
+	dib3000mc_write_word(state,  26, 0x6680);
+	// lock_mask0
+	dib3000mc_write_word(state, 1, 4);
+	// lock_mask1
+	dib3000mc_write_word(state, 2, 4);
+	// lock_mask2
+	dib3000mc_write_word(state, 3, 0x1000);
+	// P_search_maxtrial=1
+	dib3000mc_write_word(state, 5, 1);
+
+	dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+
+	// div_lock_mask
+	dib3000mc_write_word(state,  4, 0x814);
+
+	dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
+	dib3000mc_write_word(state, 22, 0x463d);
+
+	// Spurious rm cfg
+	// P_cspu_regul, P_cspu_win_cut
+	dib3000mc_write_word(state, 120, 0x200f);
+	// P_adp_selec_monit
+	dib3000mc_write_word(state, 134, 0);
+
+	// Fec cfg
+	dib3000mc_write_word(state, 195, 0x10);
+
+	// diversity register: P_dvsy_sync_wait..
+	dib3000mc_write_word(state, 180, 0x2FF0);
+
+	// Impulse noise configuration
+	dib3000mc_set_impulse_noise(state, 0, 1);
+
+	// output mode set-up
+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
+
+	/* close the i2c-gate */
+	dib3000mc_write_word(state, 769, (1 << 7) );
+
 	return 0;
 }
 
+static int dib3000mc_sleep(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+
+	dib3000mc_write_word(state, 1037, dib3000mc_read_word(state, 1037) | 0x0003);
+	dib3000mc_write_word(state, 1031, 0xFFFF);
+	dib3000mc_write_word(state, 1032, 0xFFFF);
+	dib3000mc_write_word(state, 1033, 0xFFF4);   // ****  Bin2
+
+    return 0;
+}
+
+static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
+{
+	u16 cfg[4] = { 0 },reg;
+	switch (qam) {
+		case 0:
+			cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
+			break;
+		case 1:
+			cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
+			break;
+		case 2:
+			cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
+			break;
+	}
+	for (reg = 129; reg < 133; reg++)
+		dib3000mc_write_word(state, reg, cfg[reg - 129]);
+}
+
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+{
+	u16 tmp;
+
+	dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+
+//	if (boost)
+//		dib3000mc_write_word(state, 100, (11 << 6) + 6);
+//	else
+		dib3000mc_write_word(state, 100, (16 << 6) + 9);
+
+	dib3000mc_write_word(state, 1027, 0x0800);
+	dib3000mc_write_word(state, 1027, 0x0000);
+
+	//Default cfg isi offset adp
+	dib3000mc_write_word(state, 26,  0x6680);
+	dib3000mc_write_word(state, 29,  0x1273);
+	dib3000mc_write_word(state, 33,       5);
+	dib3000mc_set_adp_cfg(state, 1);
+	dib3000mc_write_word(state, 133,  15564);
+
+	dib3000mc_write_word(state, 12 , 0x0);
+	dib3000mc_write_word(state, 13 , 0x3e8);
+	dib3000mc_write_word(state, 14 , 0x0);
+	dib3000mc_write_word(state, 15 , 0x3f2);
+
+	dib3000mc_write_word(state, 93,0);
+	dib3000mc_write_word(state, 94,0);
+	dib3000mc_write_word(state, 95,0);
+	dib3000mc_write_word(state, 96,0);
+	dib3000mc_write_word(state, 97,0);
+	dib3000mc_write_word(state, 98,0);
+
+	dib3000mc_set_impulse_noise(state, 0, chan->nfft);
+
+	tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
+	dib3000mc_write_word(state, 0, tmp);
+
+	dib3000mc_write_word(state, 5, seq);
+
+	tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
+	if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
+		tmp |= chan->vit_code_rate_hp << 1;
+	else
+		tmp |= chan->vit_code_rate_lp << 1;
+	dib3000mc_write_word(state, 181, tmp);
+
+	// diversity synchro delay
+	tmp = dib3000mc_read_word(state, 180) & 0x000f;
+	tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
+	dib3000mc_write_word(state, 180, tmp);
+
+	// restart demod
+	tmp = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, tmp | (1 << 9));
+	dib3000mc_write_word(state, 0, tmp);
+
+	msleep(30);
+
+	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+}
+
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	u16 reg;
+//	u32 val;
+	struct dibx000_ofdm_channel fchan;
+
+	INIT_OFDM_CHANNEL(&fchan);
+	fchan = *chan;
+
+
+	/* a channel for autosearch */
+	reg = 0;
+	if (chan->nfft == -1 && chan->guard == -1) reg = 7;
+	if (chan->nfft == -1 && chan->guard != -1) reg = 2;
+	if (chan->nfft != -1 && chan->guard == -1) reg = 3;
+
+	fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
+	fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
+	fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+
+	dib3000mc_set_channel_cfg(state, &fchan, reg);
+
+	reg = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, reg | (1 << 8));
+	dib3000mc_write_word(state, 0, reg);
+
+	return 0;
+}
+
+static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	u16 irq_pending = dib3000mc_read_word(state, 511);
+
+	if (irq_pending & 0x1) // failed
+		return 1;
+
+	if (irq_pending & 0x2) // succeeded
+		return 2;
+
+	return 0; // still pending
+}
+
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+
+	// ** configure demod **
+	dib3000mc_set_channel_cfg(state, ch, 0);
+
+	// activates isi
+	dib3000mc_write_word(state, 29, 0x1073);
+
+	dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+
+	if (ch->nfft == 1) {
+		dib3000mc_write_word(state, 26, 38528);
+		dib3000mc_write_word(state, 33, 8);
+	} else {
+		dib3000mc_write_word(state, 26, 30336);
+		dib3000mc_write_word(state, 33, 6);
+	}
+
+	// if (lock)
+	//	dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+
+	return 0;
+}
+
+static int dib3000mc_demod_output_mode(struct dvb_frontend *demod, int mode)
+{
+	struct dib3000mc_state *state = demod->demodulator_priv;
+	return dib3000mc_set_output_mode(state, mode);
+}
+
+static int dib3000mc_i2c_enumeration(struct dvb_frontend *demod[], int no_of_demods, u8 default_addr)
+{
+	struct dib3000mc_state *st;
+	int k,ret=0;
+	u8 new_addr;
+
+	static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
+
+	for (k = no_of_demods-1; k >= 0; k--) {
+		st = demod[k]->demodulator_priv;
+
+		/* designated i2c address */
+		new_addr          = DIB3000MC_I2C_ADDRESS[k];
+
+		st->i2c_addr = new_addr;
+		if (dib3000mc_identify(st) != 0) {
+			st->i2c_addr = default_addr;
+			if (dib3000mc_identify(st) != 0) {
+				dprintk("-E-  DiB3000P/MC #%d: not identified\n", k);
+				return -EINVAL;
+			}
+		}
+
+		/* turn on div_out */
+		dib3000mc_demod_output_mode(demod[k], OUTMODE_MPEG2_PAR_CONT_CLK);
+
+		// set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
+		ret |= dib3000mc_write_word(st, 1024, (new_addr << 3) | 0x1);
+		st->i2c_addr = new_addr;
+	}
+
+	for (k = 0; k < no_of_demods; k++) {
+		st = demod[k]->demodulator_priv;
+
+		ret |= dib3000mc_write_word(st, 1024, st->i2c_addr << 3);
+
+		/* turn off data output */
+		dib3000mc_demod_output_mode(demod[k],OUTMODE_HIGH_Z);
+		dib3000mc_write_word(st, 769, (1 << 7) );
+
+	}
+	return 0;
+}
+
+struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
+{
+	struct dib3000mc_state *st = demod->demodulator_priv;
+	return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
+}
+
+EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
+
 static int dib3000mc_get_frontend(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters *fep)
+				struct dvb_frontend_parameters *fep)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
-	fe_code_rate_t *cr;
-	u16 tps_val,cr_val;
-	int inv_test1,inv_test2;
-	u32 dds_val, threshold = 0x1000000;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 tps = dib3000mc_read_word(state,458);
 
-	if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
-		return 0;
+	fep->inversion = INVERSION_AUTO;
 
-	dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
-	deb_getf("DDS_FREQ: %6x\n",dds_val);
-	if (dds_val < threshold)
-		inv_test1 = 0;
-	else if (dds_val == threshold)
-		inv_test1 = 1;
-	else
-		inv_test1 = 2;
+	fep->u.ofdm.bandwidth = state->current_bandwidth;
 
-	dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
-	deb_getf("DDS_SET_FREQ: %6x\n",dds_val);
-	if (dds_val < threshold)
-		inv_test2 = 0;
-	else if (dds_val == threshold)
-		inv_test2 = 1;
-	else
-		inv_test2 = 2;
-
-	fep->inversion =
-		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
-		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
-		INVERSION_ON : INVERSION_OFF;
-
-	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
-
-	fep->frequency = state->last_tuned_freq;
-	fep->u.ofdm.bandwidth= state->last_tuned_bw;
-
-	tps_val = rd(DIB3000MC_REG_TUNING_PARM);
-
-	switch (DIB3000MC_TP_QAM(tps_val)) {
-		case DIB3000_CONSTELLATION_QPSK:
-			deb_getf("QPSK ");
-			ofdm->constellation = QPSK;
-			break;
-		case DIB3000_CONSTELLATION_16QAM:
-			deb_getf("QAM16 ");
-			ofdm->constellation = QAM_16;
-			break;
-		case DIB3000_CONSTELLATION_64QAM:
-			deb_getf("QAM64 ");
-			ofdm->constellation = QAM_64;
-			break;
-		default:
-			err("Unexpected constellation returned by TPS (%d)", tps_val);
-			break;
+	switch ((tps >> 8) & 0x1) {
+		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+		case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
 	}
 
-	if (DIB3000MC_TP_HRCH(tps_val)) {
-		deb_getf("HRCH ON ");
-		cr = &ofdm->code_rate_LP;
-		ofdm->code_rate_HP = FEC_NONE;
-		switch (DIB3000MC_TP_ALPHA(tps_val)) {
-			case DIB3000_ALPHA_0:
-				deb_getf("HIERARCHY_NONE ");
-				ofdm->hierarchy_information = HIERARCHY_NONE;
-				break;
-			case DIB3000_ALPHA_1:
-				deb_getf("HIERARCHY_1 ");
-				ofdm->hierarchy_information = HIERARCHY_1;
-				break;
-			case DIB3000_ALPHA_2:
-				deb_getf("HIERARCHY_2 ");
-				ofdm->hierarchy_information = HIERARCHY_2;
-				break;
-			case DIB3000_ALPHA_4:
-				deb_getf("HIERARCHY_4 ");
-				ofdm->hierarchy_information = HIERARCHY_4;
-				break;
-			default:
-				err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
-				break;
-		}
-		cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
-	} else {
-		deb_getf("HRCH OFF ");
-		cr = &ofdm->code_rate_HP;
-		ofdm->code_rate_LP = FEC_NONE;
-		ofdm->hierarchy_information = HIERARCHY_NONE;
-		cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
+	switch (tps & 0x3) {
+		case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
+		case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
+		case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
+		case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
 	}
 
-	switch (cr_val) {
-		case DIB3000_FEC_1_2:
-			deb_getf("FEC_1_2 ");
-			*cr = FEC_1_2;
-			break;
-		case DIB3000_FEC_2_3:
-			deb_getf("FEC_2_3 ");
-			*cr = FEC_2_3;
-			break;
-		case DIB3000_FEC_3_4:
-			deb_getf("FEC_3_4 ");
-			*cr = FEC_3_4;
-			break;
-		case DIB3000_FEC_5_6:
-			deb_getf("FEC_5_6 ");
-			*cr = FEC_4_5;
-			break;
-		case DIB3000_FEC_7_8:
-			deb_getf("FEC_7_8 ");
-			*cr = FEC_7_8;
-			break;
-		default:
-			err("Unexpected FEC returned by TPS (%d)", tps_val);
-			break;
+	switch ((tps >> 13) & 0x3) {
+		case 0: fep->u.ofdm.constellation = QPSK; break;
+		case 1: fep->u.ofdm.constellation = QAM_16; break;
+		case 2:
+		default: fep->u.ofdm.constellation = QAM_64; break;
 	}
 
-	switch (DIB3000MC_TP_GUARD(tps_val)) {
-		case DIB3000_GUARD_TIME_1_32:
-			deb_getf("GUARD_INTERVAL_1_32 ");
-			ofdm->guard_interval = GUARD_INTERVAL_1_32;
-			break;
-		case DIB3000_GUARD_TIME_1_16:
-			deb_getf("GUARD_INTERVAL_1_16 ");
-			ofdm->guard_interval = GUARD_INTERVAL_1_16;
-			break;
-		case DIB3000_GUARD_TIME_1_8:
-			deb_getf("GUARD_INTERVAL_1_8 ");
-			ofdm->guard_interval = GUARD_INTERVAL_1_8;
-			break;
-		case DIB3000_GUARD_TIME_1_4:
-			deb_getf("GUARD_INTERVAL_1_4 ");
-			ofdm->guard_interval = GUARD_INTERVAL_1_4;
-			break;
-		default:
-			err("Unexpected Guard Time returned by TPS (%d)", tps_val);
-			break;
+	/* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+	/* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
+
+	fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+	switch ((tps >> 5) & 0x7) {
+		case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
+		case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
+		case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
+		case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+		case 7:
+		default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+
 	}
 
-	switch (DIB3000MC_TP_FFT(tps_val)) {
-		case DIB3000_TRANSMISSION_MODE_2K:
-			deb_getf("TRANSMISSION_MODE_2K ");
-			ofdm->transmission_mode = TRANSMISSION_MODE_2K;
-			break;
-		case DIB3000_TRANSMISSION_MODE_8K:
-			deb_getf("TRANSMISSION_MODE_8K ");
-			ofdm->transmission_mode = TRANSMISSION_MODE_8K;
-			break;
-		default:
-			err("unexpected transmission mode return by TPS (%d)", tps_val);
-			break;
+	switch ((tps >> 2) & 0x7) {
+		case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
+		case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
+		case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
+		case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+		case 7:
+		default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
 	}
-	deb_getf("\n");
 
 	return 0;
 }
 
 static int dib3000mc_set_frontend(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters *fep, int tuner)
+				struct dvb_frontend_parameters *fep)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
-	int search_state,auto_val;
-	u16 val;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	struct dibx000_ofdm_channel ch;
 
-	if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+	INIT_OFDM_CHANNEL(&ch);
+	FEP2DIB(fep,&ch);
+
+	state->current_bandwidth = fep->u.ofdm.bandwidth;
+	dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, fep);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-
-		state->last_tuned_freq = fep->frequency;
-	//	if (!scanboost) {
-			dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
-			dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
-			state->last_tuned_bw = ofdm->bandwidth;
-
-			wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
-			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
-			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-
-			/* Default cfg isi offset adp */
-			wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
-
-			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
-			dib3000mc_set_adp_cfg(state,ofdm->constellation);
-			wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
-
-			wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
-			/* power smoothing */
-			if (ofdm->bandwidth != BANDWIDTH_8_MHZ) {
-				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
-			} else {
-				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
-			}
-			auto_val = 0;
-			dib3000mc_set_general_cfg(state,fep,&auto_val);
-			dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-
-			val = rd(DIB3000MC_REG_DEMOD_PARM);
-			wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
-			wr(DIB3000MC_REG_DEMOD_PARM,val);
-	//	}
-		msleep(70);
-
-		/* something has to be auto searched */
-		if (auto_val) {
-			int as_count=0;
-
-			deb_setf("autosearch enabled.\n");
-
-			val = rd(DIB3000MC_REG_DEMOD_PARM);
-			wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
-			wr(DIB3000MC_REG_DEMOD_PARM,val);
-
-			while ((search_state = dib3000_search_status(
-						rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
-				msleep(10);
-
-			deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
-
-			if (search_state == 1) {
-				struct dvb_frontend_parameters feps;
-				if (dib3000mc_get_frontend(fe, &feps) == 0) {
-					deb_setf("reading tuning data from frontend succeeded.\n");
-					return dib3000mc_set_frontend(fe, &feps, 0);
-				}
-			}
-		} else {
-			dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth);
-			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
-			dib3000mc_set_adp_cfg(state,ofdm->constellation);
-
-			/* set_offset_cfg */
-			wr_foreach(dib3000mc_reg_offset,
-					dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
-		}
-	} else { /* second call, after autosearch (fka: set_WithKnownParams) */
-//		dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
-
-		auto_val = 0;
-		dib3000mc_set_general_cfg(state,fep,&auto_val);
-		if (auto_val)
-			deb_info("auto_val is true, even though an auto search was already performed.\n");
-
-		dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-
-		val = rd(DIB3000MC_REG_DEMOD_PARM);
-		wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
-		wr(DIB3000MC_REG_DEMOD_PARM,val);
-
-		msleep(30);
-
-		wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
-			dib3000mc_set_adp_cfg(state,ofdm->constellation);
-		wr_foreach(dib3000mc_reg_offset,
-				dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
+		msleep(100);
 	}
-	return 0;
+
+	if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
+		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
+		fep->u.ofdm.constellation     == QAM_AUTO ||
+		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+		int i = 100, found;
+
+		dib3000mc_autosearch_start(fe, &ch);
+		do {
+			msleep(1);
+			found = dib3000mc_autosearch_is_irq(fe);
+		} while (found == 0 && i--);
+
+		dprintk("autosearch returns: %d\n",found);
+		if (found == 0 || found == 1)
+			return 0; // no channel found
+
+		dib3000mc_get_frontend(fe, fep);
+		FEP2DIB(fep,&ch);
+	}
+
+	/* make this a config parameter */
+	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+	return dib3000mc_tune(fe, &ch);
 }
 
-static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
+static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
-	struct dib3000_state *state = fe->demodulator_priv;
-	deb_info("init start\n");
-
-	state->timing_offset = 0;
-	state->timing_offset_comp_done = 0;
-
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
-	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
-	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
-	wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
-
-	wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
-	wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
-
-	wr(33,5);
-	wr(36,81);
-	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
-
-	wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
-	wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
-
-	/* mobile mode - portable reception */
-	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
-
-/* TUNER_PANASONIC_ENV57H12D5: */
-	wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
-	wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
-	wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
-
-	wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
-	wr(26,0x6680);
-	wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
-	wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
-	wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
-	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
-
-	wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
-	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
-
-	wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
-
-	wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
-	wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
-
-	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
-//	wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
-
-	wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
-	wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
-	wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
-
-	wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
-
-	dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
-
-/* output mode control, just the MPEG2_SLAVE */
-//	set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
-	wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
-	wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
-	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
-	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
-
-/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
-	wr(DIB3000MC_REG_OUTMODE,
-		DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
-			rd(DIB3000MC_REG_OUTMODE)));
-
-	wr(DIB3000MC_REG_SMO_MODE,
-			DIB3000MC_SMO_MODE_DEFAULT |
-			DIB3000MC_SMO_MODE_188);
-
-	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
-	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
-*/
-
-/* diversity */
-	wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
-	wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
-
-	set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
-
-	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
-
-	deb_info("init end\n");
-	return 0;
-}
-static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-	u16 lock = rd(DIB3000MC_REG_LOCKING);
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 lock = dib3000mc_read_word(state, 509);
 
 	*stat = 0;
-	if (DIB3000MC_AGC_LOCK(lock))
+
+	if (lock & 0x8000)
 		*stat |= FE_HAS_SIGNAL;
-	if (DIB3000MC_CARRIER_LOCK(lock))
+	if (lock & 0x3000)
 		*stat |= FE_HAS_CARRIER;
-	if (DIB3000MC_TPS_LOCK(lock))
+	if (lock & 0x0100)
 		*stat |= FE_HAS_VITERBI;
-	if (DIB3000MC_MPEG_SYNC_LOCK(lock))
-		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
-
-	deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040));
+	if (lock & 0x0010)
+		*stat |= FE_HAS_SYNC;
+	if (lock & 0x0008)
+		*stat |= FE_HAS_LOCK;
 
 	return 0;
 }
 
-static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
+static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-	*ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	*ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
 	return 0;
 }
 
-static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	*unc = rd(DIB3000MC_REG_PACKET_ERRORS);
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	*unc = dib3000mc_read_word(state, 508);
 	return 0;
 }
 
-/* see dib3000mb.c for calculation comments */
-static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
-	*strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
-
-	deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 val = dib3000mc_read_word(state, 392);
+	*strength = 65535 - val;
 	return 0;
 }
 
-/* see dib3000mb.c for calculation comments */
 static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
-	struct dib3000_state* state = fe->demodulator_priv;
-	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB),
-		val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB);
-	u16 sig,noise;
-
-	sig =   (((val >> 6) & 0xff) << 8) + (val & 0x3f);
-	noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
-	if (noise == 0)
-		*snr = 0xffff;
-	else
-		*snr = (u16) sig/noise;
-
-	deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
-	deb_stat("noise:  mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
-	deb_stat("snr: %d\n",*snr);
-	return 0;
-}
-
-static int dib3000mc_sleep(struct dvb_frontend* fe)
-{
-	struct dib3000_state* state = fe->demodulator_priv;
-
-	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
-	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
-	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
-	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
+	*snr = 0x0000;
 	return 0;
 }
 
@@ -729,185 +795,127 @@
 	return 0;
 }
 
-static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
+static void dib3000mc_release(struct dvb_frontend *fe)
 {
-	return dib3000mc_fe_init(fe, 0);
-}
-
-static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
-{
-	return dib3000mc_set_frontend(fe, fep, 1);
-}
-
-static void dib3000mc_release(struct dvb_frontend* fe)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	dibx000_exit_i2c_master(&state->i2c_master);
 	kfree(state);
 }
 
-/* pid filter and transfer stuff */
-static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
+int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
 {
-	struct dib3000_state *state = fe->demodulator_priv;
-	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-	wr(index+DIB3000MC_REG_FIRST_PID,pid);
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	dib3000mc_write_word(state, 212 + index,  onoff ? (1 << 13) | pid : 0);
 	return 0;
 }
+EXPORT_SYMBOL(dib3000mc_pid_control);
 
-static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
+int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
 {
-	struct dib3000_state *state = fe->demodulator_priv;
-	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-
-	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
-
-	if (onoff) {
-		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
-		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
-	} else {
-		deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
-		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
-	}
-	return 0;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
+	tmp |= (onoff << 4);
+	return dib3000mc_write_word(state, 206, tmp);
 }
+EXPORT_SYMBOL(dib3000mc_pid_parse);
 
-static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
 {
-	struct dib3000_state *state = fe->demodulator_priv;
-	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-
-	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
-
-	if (onoff) {
-		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
-	} else {
-		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
-	}
-	return 0;
+	struct dib3000mc_state *state = fe->demodulator_priv;
+	state->cfg = cfg;
 }
-
-static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
-{
-	struct dib3000_state *state = fe->demodulator_priv;
-	if (onoff) {
-		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
-	} else {
-		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
-	}
-	return 0;
-}
-
-static int dib3000mc_demod_init(struct dib3000_state *state)
-{
-	u16 default_addr = 0x0a;
-	/* first init */
-	if (state->config.demod_address != default_addr) {
-		deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr);
-		wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
-		wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
-
-		wr(DIB3000MC_REG_RST_I2C_ADDR,
-			DIB3000MC_DEMOD_ADDR(default_addr) |
-			DIB3000MC_DEMOD_ADDR_ON);
-
-		state->config.demod_address = default_addr;
-
-		wr(DIB3000MC_REG_RST_I2C_ADDR,
-			DIB3000MC_DEMOD_ADDR(default_addr));
-	} else
-		deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address);
-	return 0;
-}
-
+EXPORT_SYMBOL(dib3000mc_set_config);
 
 static struct dvb_frontend_ops dib3000mc_ops;
 
-struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
-				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+int dib3000mc_attach(struct i2c_adapter *i2c_adap, int no_of_demods, u8	default_addr,				u8 do_i2c_enum, struct dib3000mc_config cfg[], struct dvb_frontend *demod[])
 {
-	struct dib3000_state* state = NULL;
-	u16 devid;
+	struct dib3000mc_state *st;
+	int k, num=0;
 
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL);
-	if (state == NULL)
-		goto error;
+	if (no_of_demods < 1)
+		return -EINVAL;
 
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->config,config,sizeof(struct dib3000_config));
+	for (k = 0; k < no_of_demods; k++) {
+		st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
+		if (st == NULL)
+			goto error;
 
-	/* check for the correct demod */
-	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
-		goto error;
+		num++;
 
-	devid = rd(DIB3000_REG_DEVICE_ID);
-	if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
-		goto error;
+		st->cfg = &cfg[k];
+	//	st->gpio_val = cfg[k].gpio_val;
+	//	st->gpio_dir = cfg[k].gpio_dir;
+		st->i2c_adap = i2c_adap;
 
-	switch (devid) {
-		case DIB3000MC_DEVICE_ID:
-			info("Found a DiBcom 3000M-C, interesting...");
-			break;
-		case DIB3000P_DEVICE_ID:
-			info("Found a DiBcom 3000P.");
-			break;
+		demod[k]           = &st->demod;
+		demod[k]->demodulator_priv     = st;
+		memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+
+//		INIT_COMPONENT_REGISTER_ACCESS(&st->register_access, 12, 16, dib7000p_register_read, dib7000p_register_write, st);
+//		demod[k]->register_access = &st->register_access;
 	}
 
-	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
-	state->frontend.demodulator_priv = state;
+	if (do_i2c_enum) {
+		if (dib3000mc_i2c_enumeration(demod,no_of_demods,default_addr) != 0)
+			goto error;
+	} else {
+		st = demod[0]->demodulator_priv;
+		st->i2c_addr = default_addr;
+		if (dib3000mc_identify(st) != 0)
+			goto error;
+	}
 
-	/* set the xfer operations */
-	xfer_ops->pid_parse = dib3000mc_pid_parse;
-	xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
-	xfer_ops->pid_ctrl = dib3000mc_pid_control;
-	xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl;
+	for (k = 0; k < num; k++) {
+		st = demod[k]->demodulator_priv;
+		dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
+	}
 
-	dib3000mc_demod_init(state);
-
-	return &state->frontend;
+	return 0;
 
 error:
-	kfree(state);
-	return NULL;
+	for (k = 0; k < num; k++) {
+		kfree(demod[k]->demodulator_priv);
+		demod[k] = NULL;
+	}
+	return -EINVAL;
 }
+
 EXPORT_SYMBOL(dib3000mc_attach);
 
 static struct dvb_frontend_ops dib3000mc_ops = {
-
 	.info = {
-		.name			= "DiBcom 3000P/M-C DVB-T",
-		.type			= FE_OFDM,
-		.frequency_min		= 44250000,
-		.frequency_max		= 867250000,
-		.frequency_stepsize	= 62500,
+		.name = "DiBcom 3000MC/P",
+		.type = FE_OFDM,
+		.frequency_min      = 44250000,
+		.frequency_max      = 867250000,
+		.frequency_stepsize = 62500,
 		.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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-				FE_CAN_TRANSMISSION_MODE_AUTO |
-				FE_CAN_GUARD_INTERVAL_AUTO |
-				FE_CAN_RECOVER |
-				FE_CAN_HIERARCHY_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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
 	},
 
-	.release = dib3000mc_release,
+	.release              = dib3000mc_release,
 
-	.init = dib3000mc_fe_init_nonmobile,
-	.sleep = dib3000mc_sleep,
+	.init                 = dib3000mc_init,
+	.sleep                = dib3000mc_sleep,
 
-	.set_frontend = dib3000mc_set_frontend_and_tuner,
-	.get_frontend = dib3000mc_get_frontend,
-	.get_tune_settings = dib3000mc_fe_get_tune_settings,
+	.set_frontend         = dib3000mc_set_frontend,
+	.get_tune_settings    = dib3000mc_fe_get_tune_settings,
+	.get_frontend         = dib3000mc_get_frontend,
 
-	.read_status = dib3000mc_read_status,
-	.read_ber = dib3000mc_read_ber,
+	.read_status          = dib3000mc_read_status,
+	.read_ber             = dib3000mc_read_ber,
 	.read_signal_strength = dib3000mc_read_signal_strength,
-	.read_snr = dib3000mc_read_snr,
-	.read_ucblocks = dib3000mc_read_unc_blocks,
+	.read_snr             = dib3000mc_read_snr,
+	.read_ucblocks        = dib3000mc_read_unc_blocks,
 };
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
new file mode 100644
index 0000000..fd0b2e7
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib3000mc.h
@@ -0,0 +1,58 @@
+/*
+ * Driver for DiBcom DiB3000MC/P-demodulator.
+ *
+ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
+ *
+ * This code is partially based on the previous dib3000mc.c .
+ *
+ * This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ */
+#ifndef DIB3000MC_H
+#define DIB3000MC_H
+
+#include "dibx000_common.h"
+
+struct dib3000mc_config {
+	struct dibx000_agc_config *agc;
+
+	u8 phase_noise_mode;
+	u8 impulse_noise_mode;
+
+	u8  pwm3_inversion;
+	u8  use_pwm3;
+	u16 pwm3_value;
+
+	u16 max_time;
+	u16 ln_adc_level;
+
+	u8 mobile_mode;
+
+	u8 output_mpeg2_in_188_bytes;
+};
+
+#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
+#define DEFAULT_DIB3000P_I2C_ADDRESS  24
+
+#if defined(CONFIG_DVB_DIB3000MC) || defined(CONFIG_DVB_DIB3000MC_MODULE)
+extern int dib3000mc_attach(struct i2c_adapter *i2c_adap, int no_of_demods, u8 default_addr,
+    u8 do_i2c_enum, struct dib3000mc_config cfg[], struct dvb_frontend *demod[]);
+#else
+static inline struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MC
+
+extern struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating);
+
+extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
+extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
+
+extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
deleted file mode 100644
index 2930aac..0000000
--- a/drivers/media/dvb/frontends/dib3000mc_priv.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * dib3000mc_priv.h
- *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- * for more information see dib3000mc.c .
- */
-
-#ifndef __DIB3000MC_PRIV_H__
-#define __DIB3000MC_PRIV_H__
-
-/*
- * Demodulator parameters
- * reg: 0  1 1  1 11 11 111
- *         | |  |  |  |  |
- *         | |  |  |  |  +-- alpha (000=0, 001=1, 010=2, 100=4)
- *         | |  |  |  +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
- *         | |  |  +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
- *         | |  +----------- transmission mode (0=2k, 1=8k)
- *         | |
- *         | +-------------- restart autosearch for parameters
- *         +---------------- restart the demodulator
- * reg: 181      1 111 1
- *               |  |  |
- *               |  |  +- FEC applies for HP or LP (0=LP, 1=HP)
- *               |  +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
- *               +------- hierarchy on (0=no, 1=yes)
- */
-
-/* demodulator tuning parameter and restart options */
-#define DIB3000MC_REG_DEMOD_PARM		(     0)
-#define DIB3000MC_DEMOD_PARM(a,c,g,t)	( \
-		 (0x7 & a) | \
-		((0x3 & c) << 3) | \
-		((0x3 & g) << 5) | \
-		((0x1 & t) << 7) )
-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON	(1 << 8)
-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF	(0 << 8)
-#define DIB3000MC_DEMOD_RST_DEMOD_ON		(1 << 9)
-#define DIB3000MC_DEMOD_RST_DEMOD_OFF		(0 << 9)
-
-/* register for hierarchy parameters */
-#define DIB3000MC_REG_HRCH_PARM			(   181)
-#define DIB3000MC_HRCH_PARM(s,f,h)		( \
-		 (0x1 & s) | \
-		((0x7 & f) << 1) | \
-		((0x1 & h) << 4) )
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_1				(     1)
-#define DIB3000MC_UNK_1					(  0x04)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_2				(     2)
-#define DIB3000MC_UNK_2					(  0x04)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_3				(     3)
-#define DIB3000MC_UNK_3					(0x1000)
-
-#define DIB3000MC_REG_UNK_4				(     4)
-#define DIB3000MC_UNK_4					(0x0814)
-
-/* timeout ??? */
-#define DIB3000MC_REG_SEQ_TPS			(     5)
-#define DIB3000MC_SEQ_TPS_DEFAULT		(     1)
-#define DIB3000MC_SEQ_TPS(s,t)			( \
-		((s & 0x0f) << 4) | \
-		((t & 0x01) << 8) )
-#define DIB3000MC_IS_TPS(v)				((v << 8) & 0x1)
-#define DIB3000MC_IS_AS(v)				((v >> 4) & 0xf)
-
-/* parameters for the bandwidth */
-#define DIB3000MC_REG_BW_TIMOUT_MSB		(     6)
-#define DIB3000MC_REG_BW_TIMOUT_LSB		(     7)
-
-static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
-
-/*static u16 dib3000mc_bandwidth_5mhz[] =
-	{ 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
-
-static u16 dib3000mc_bandwidth_6mhz[] =
-	{ 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_bandwidth_7mhz[] =
-	{ 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_bandwidth_8mhz[] =
-	{ 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
-static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
-
-/* lock mask */
-#define DIB3000MC_REG_LOCK_MASK			(    15)
-#define DIB3000MC_ACTIVATE_LOCK_MASK	(0x0800)
-
-/* reset the uncorrected packet count (??? do it 5 times) */
-#define DIB3000MC_REG_RST_UNC			(    18)
-#define DIB3000MC_RST_UNC_ON			(     1)
-#define DIB3000MC_RST_UNC_OFF			(     0)
-
-#define DIB3000MC_REG_UNK_19			(    19)
-#define DIB3000MC_UNK_19				(     0)
-
-/* DDS frequency value (IF position) and inversion bit */
-#define DIB3000MC_REG_INVERSION			(    21)
-#define DIB3000MC_REG_SET_DDS_FREQ_MSB	(    21)
-#define DIB3000MC_DDS_FREQ_MSB_INV_OFF	(0x0164)
-#define DIB3000MC_DDS_FREQ_MSB_INV_ON	(0x0364)
-
-#define DIB3000MC_REG_SET_DDS_FREQ_LSB	(    22)
-#define DIB3000MC_DDS_FREQ_LSB			(0x463d)
-
-/* timing frequencies setting */
-#define DIB3000MC_REG_TIMING_FREQ_MSB	(    23)
-#define DIB3000MC_REG_TIMING_FREQ_LSB	(    24)
-#define DIB3000MC_CLOCK_REF				(0x151fd1)
-
-//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
-
-//static u16 dib3000mc_timing_freq[][2] = {
-//	{ 0x69, 0x9f18 }, /* 5 MHz */
-//	{ 0x7e ,0xbee9 }, /* 6 MHz */
-//	{ 0x93 ,0xdebb }, /* 7 MHz */
-//	{ 0xa8 ,0xfe8c }, /* 8 MHz */
-//};
-
-/* timeout ??? */
-static u16 dib3000mc_reg_offset[] = { 26,33 };
-
-static u16 dib3000mc_offset[][2] = {
-	{ 26240, 5 }, /* default */
-	{ 30336, 6 }, /* 8K */
-	{ 38528, 8 }, /* 2K */
-};
-
-#define DIB3000MC_REG_ISI				(    29)
-#define DIB3000MC_ISI_DEFAULT			(0x1073)
-#define DIB3000MC_ISI_ACTIVATE			(0x0000)
-#define DIB3000MC_ISI_INHIBIT			(0x0200)
-
-/* impulse noise control */
-static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
-
-static u16 dib3000mc_imp_noise_ctl[][2] = {
-	{ 0x1294, 0x1ff8 }, /* mode 0 */
-	{ 0x1294, 0x1ff8 }, /* mode 1 */
-	{ 0x1294, 0x1ff8 }, /* mode 2 */
-	{ 0x1294, 0x1ff8 }, /* mode 3 */
-	{ 0x1294, 0x1ff8 }, /* mode 4 */
-};
-
-/* AGC registers */
-static u16 dib3000mc_reg_agc[] = {
-	36,37,38,39,42,43,44,45,46,47,48,49
-};
-
-static u16 dib3000mc_agc_tuner[][12] = {
-	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
-		0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
-	}, /* TUNER_PANASONIC_ENV77H04D5, */
-
-	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
-		0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
-	}, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
-
-	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
-		0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
-	}, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
-
-	{	0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
-		0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
-	}, /* TUNER_PROVIDER_X */
-	/* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
-};
-
-/* AGC loop bandwidth */
-static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
-static u16 dib3000mc_agc_bandwidth[]  = { 0x119,0x330 };
-
-static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
-static u16 dib3000mc_agc_bandwidth_general[] =
-	{ 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
-
-#define DIB3000MC_REG_IMP_NOISE_55		(    55)
-#define DIB3000MC_IMP_NEW_ALGO(w)		(w | (1<<10))
-
-/* Impulse noise params */
-static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
-static u16 dib3000mc_impluse_noise[][3] = {
-	{ 0x489, 0x89, 0x72 }, /* 5 MHz */
-	{ 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
-	{ 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
-	{ 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
-};
-
-static u16 dib3000mc_reg_fft[] = {
-	58,59,60,61,62,63,64,65,66,67,68,69,
-	70,71,72,73,74,75,76,77,78,79,80,81,
-	82,83,84,85,86
-};
-
-static u16 dib3000mc_fft_modes[][29] = {
-	{	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
-		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
-		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
-		0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
-		0x3ffe, 0x5b3, 0x3feb, 0x76,   0x0, 0xd
-	}, /* fft mode 0 */
-	{	0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
-		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
-		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
-		0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
-		0x3ffe, 0x5b3, 0x3feb, 0x0,  0x8200, 0xd
-	}, /* fft mode 1 */
-};
-
-#define DIB3000MC_REG_UNK_88			(    88)
-#define DIB3000MC_UNK_88				(0x0410)
-
-static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
-static u16 dib3000mc_bw[][6] = {
-	{ 0,0,0,0,0,0 }, /* 5 MHz */
-	{ 0,0,0,0,0,0 }, /* 6 MHz */
-	{ 0,0,0,0,0,0 }, /* 7 MHz */
-	{ 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
-};
-
-
-/* phase noise control */
-#define DIB3000MC_REG_UNK_99			(    99)
-#define DIB3000MC_UNK_99				(0x0220)
-
-#define DIB3000MC_REG_SCAN_BOOST		(   100)
-#define DIB3000MC_SCAN_BOOST_ON			((11 << 6) + 6)
-#define DIB3000MC_SCAN_BOOST_OFF		((16 << 6) + 9)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_110			(   110)
-#define DIB3000MC_UNK_110				(  3277)
-
-#define DIB3000MC_REG_UNK_111			(   111)
-#define DIB3000MC_UNK_111_PH_N_MODE_0	(     0)
-#define DIB3000MC_UNK_111_PH_N_MODE_1	(1 << 1)
-
-/* superious rm config */
-#define DIB3000MC_REG_UNK_120			(   120)
-#define DIB3000MC_UNK_120				(  8207)
-
-#define DIB3000MC_REG_UNK_133			(   133)
-#define DIB3000MC_UNK_133				( 15564)
-
-#define DIB3000MC_REG_UNK_134			(   134)
-#define DIB3000MC_UNK_134				(     0)
-
-/* adapter config for constellation */
-static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
-
-static u16 dib3000mc_adp_cfg[][4] = {
-	{ 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK  */
-	{ 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
-	{ 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
-};
-
-static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
-
-static u16 dib3000mc_mobile_mode[][5] = {
-	{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
-	{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
-	{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
-	{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
-};
-
-#define DIB3000MC_REG_DIVERSITY1		(   177)
-#define DIB3000MC_DIVERSITY1_DEFAULT	(     1)
-
-#define DIB3000MC_REG_DIVERSITY2		(   178)
-#define DIB3000MC_DIVERSITY2_DEFAULT	(     1)
-
-#define DIB3000MC_REG_DIVERSITY3		(   180)
-#define DIB3000MC_DIVERSITY3_IN_OFF		(0xfff0)
-#define DIB3000MC_DIVERSITY3_IN_ON		(0xfff6)
-
-#define DIB3000MC_REG_FEC_CFG			(   195)
-#define DIB3000MC_FEC_CFG				(  0x10)
-
-/*
- * reg 206, output mode
- *              1111 1111
- *              |||| ||||
- *              |||| |||+- unk
- *              |||| ||+-- unk
- *              |||| |+--- unk (on by default)
- *              |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
- *              |||+------ pid_parse (1 = enabled, 0 = disabled)
- *              ||+------- outp_188  (1 = TS packet size 188, 0 = packet size 204)
- *              |+-------- unk
- *              +--------- unk
- */
-
-#define DIB3000MC_REG_SMO_MODE			(   206)
-#define DIB3000MC_SMO_MODE_DEFAULT		(1 << 2)
-#define DIB3000MC_SMO_MODE_FIFO_FLUSH	(1 << 3)
-#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH	(0xfff7)
-#define DIB3000MC_SMO_MODE_PID_PARSE	(1 << 4)
-#define DIB3000MC_SMO_MODE_NO_PID_PARSE	(0xffef)
-#define DIB3000MC_SMO_MODE_188			(1 << 5)
-#define DIB3000MC_SMO_MODE_SLAVE		(DIB3000MC_SMO_MODE_DEFAULT | \
-			DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
-
-#define DIB3000MC_REG_FIFO_THRESHOLD	(   207)
-#define DIB3000MC_FIFO_THRESHOLD_DEFAULT	(  1792)
-#define DIB3000MC_FIFO_THRESHOLD_SLAVE	(   512)
-/*
- * pidfilter
- * it is not a hardware pidfilter but a filter which drops all pids
- * except the ones set. When connected to USB1.1 bandwidth this is important.
- * DiB3000P/M-C can filter up to 32 PIDs
- */
-#define DIB3000MC_REG_FIRST_PID			(   212)
-#define DIB3000MC_NUM_PIDS				(    32)
-
-#define DIB3000MC_REG_OUTMODE			(   244)
-#define DIB3000MC_OM_PARALLEL_GATED_CLK	(     0)
-#define DIB3000MC_OM_PAR_CONT_CLK		(1 << 11)
-#define DIB3000MC_OM_SERIAL				(2 << 11)
-#define DIB3000MC_OM_DIVOUT_ON			(4 << 11)
-#define DIB3000MC_OM_SLAVE				(DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
-
-#define DIB3000MC_REG_RF_POWER			(   392)
-
-#define DIB3000MC_REG_FFT_POSITION		(   407)
-
-#define DIB3000MC_REG_DDS_FREQ_MSB		(   414)
-#define DIB3000MC_REG_DDS_FREQ_LSB		(   415)
-
-#define DIB3000MC_REG_TIMING_OFFS_MSB	(   416)
-#define DIB3000MC_REG_TIMING_OFFS_LSB	(   417)
-
-#define DIB3000MC_REG_TUNING_PARM		(   458)
-#define DIB3000MC_TP_QAM(v)				((v >> 13) & 0x03)
-#define DIB3000MC_TP_HRCH(v)			((v >> 12) & 0x01)
-#define DIB3000MC_TP_ALPHA(v)			((v >> 9) & 0x07)
-#define DIB3000MC_TP_FFT(v)				((v >> 8) & 0x01)
-#define DIB3000MC_TP_FEC_CR_HP(v)		((v >> 5) & 0x07)
-#define DIB3000MC_TP_FEC_CR_LP(v)		((v >> 2) & 0x07)
-#define DIB3000MC_TP_GUARD(v)			(v & 0x03)
-
-#define DIB3000MC_REG_SIGNAL_NOISE_MSB	(   483)
-#define DIB3000MC_REG_SIGNAL_NOISE_LSB	(   484)
-
-#define DIB3000MC_REG_MER				(   485)
-
-#define DIB3000MC_REG_BER_MSB			(   500)
-#define DIB3000MC_REG_BER_LSB			(   501)
-
-#define DIB3000MC_REG_PACKET_ERRORS		(   503)
-
-#define DIB3000MC_REG_PACKET_ERROR_COUNT	(   506)
-
-#define DIB3000MC_REG_LOCK_507			(   507)
-#define DIB3000MC_LOCK_507				(0x0002) // ? name correct ?
-
-#define DIB3000MC_REG_LOCKING			(   509)
-#define DIB3000MC_AGC_LOCK(v)			(v & 0x8000)
-#define DIB3000MC_CARRIER_LOCK(v)		(v & 0x2000)
-#define DIB3000MC_MPEG_SYNC_LOCK(v)		(v & 0x0080)
-#define DIB3000MC_MPEG_DATA_LOCK(v)		(v & 0x0040)
-#define DIB3000MC_TPS_LOCK(v)			(v & 0x0004)
-
-#define DIB3000MC_REG_AS_IRQ			(   511)
-#define DIB3000MC_AS_IRQ_SUCCESS		(1 << 1)
-#define DIB3000MC_AS_IRQ_FAIL			(     1)
-
-#define DIB3000MC_REG_TUNER				(   769)
-
-#define DIB3000MC_REG_RST_I2C_ADDR		(  1024)
-#define DIB3000MC_DEMOD_ADDR_ON			(     1)
-#define DIB3000MC_DEMOD_ADDR(a)			((a << 4) & 0x03F0)
-
-#define DIB3000MC_REG_RESTART			(  1027)
-#define DIB3000MC_RESTART_OFF			(0x0000)
-#define DIB3000MC_RESTART_AGC			(0x0800)
-#define DIB3000MC_RESTART_CONFIG		(0x8000)
-
-#define DIB3000MC_REG_RESTART_VIT		(  1028)
-#define DIB3000MC_RESTART_VIT_OFF		(     0)
-#define DIB3000MC_RESTART_VIT_ON		(     1)
-
-#define DIB3000MC_REG_CLK_CFG_1			(  1031)
-#define DIB3000MC_CLK_CFG_1_POWER_UP	(     0)
-#define DIB3000MC_CLK_CFG_1_POWER_DOWN	(0xffff)
-
-#define DIB3000MC_REG_CLK_CFG_2			(  1032)
-#define DIB3000MC_CLK_CFG_2_PUP_FIXED	(0x012c)
-#define DIB3000MC_CLK_CFG_2_PUP_PORT	(0x0104)
-#define DIB3000MC_CLK_CFG_2_PUP_MOBILE  (0x0000)
-#define DIB3000MC_CLK_CFG_2_POWER_DOWN	(0xffff)
-
-#define DIB3000MC_REG_CLK_CFG_3			(  1033)
-#define DIB3000MC_CLK_CFG_3_POWER_UP	(     0)
-#define DIB3000MC_CLK_CFG_3_POWER_DOWN	(0xfff5)
-
-#define DIB3000MC_REG_CLK_CFG_7			(  1037)
-#define DIB3000MC_CLK_CFG_7_INIT		( 12592)
-#define DIB3000MC_CLK_CFG_7_POWER_UP	(~0x0003)
-#define DIB3000MC_CLK_CFG_7_PWR_DOWN	(0x0003)
-#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF	(1 << 8)
-
-/* was commented out ??? */
-#define DIB3000MC_REG_CLK_CFG_8			(  1038)
-#define DIB3000MC_CLK_CFG_8_POWER_UP	(0x160c)
-
-#define DIB3000MC_REG_CLK_CFG_9			(  1039)
-#define DIB3000MC_CLK_CFG_9_POWER_UP	(     0)
-
-/* also clock ??? */
-#define DIB3000MC_REG_ELEC_OUT			(  1040)
-#define DIB3000MC_ELEC_OUT_HIGH_Z		(     0)
-#define DIB3000MC_ELEC_OUT_DIV_OUT_ON	(     1)
-#define DIB3000MC_ELEC_OUT_SLAVE		(     3)
-
-#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
new file mode 100644
index 0000000..a18c8f4
--- /dev/null
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -0,0 +1,152 @@
+#include <linux/i2c.h>
+
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0)
+
+static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+{
+	u8 b[4] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg = {
+		.addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4
+	};
+	return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+
+static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf)
+{
+	if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
+		dprintk("selecting interface: %d\n",intf);
+		mst->selected_interface = intf;
+		return dibx000_write_word(mst, mst->base_reg + 4, intf);
+	}
+	return 0;
+}
+
+static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff)
+{
+	u16 val;
+
+
+	if (onoff)
+		val = addr << 8; // bit 7 = use master or not, if 0, the gate is open
+	else
+		val = 1 << 7;
+
+	if (mst->device_rev > DIB7000)
+		val <<= 1;
+
+	tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
+	tx[1] = ( (mst->base_reg + 1)       & 0xff);
+	tx[2] = val >> 8;
+	tx[3] = val & 0xff;
+
+	return 0;
+}
+
+static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+	struct i2c_msg m[2 + num];
+	u8 tx_open[4], tx_close[4];
+
+	memset(m,0, sizeof(struct i2c_msg) * (2 + num));
+
+	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+
+	dibx000_i2c_gate_ctrl(mst, tx_open,  msg[0].addr, 1);
+	m[0].addr = mst->i2c_addr;
+	m[0].buf  = tx_open;
+	m[0].len  = 4;
+
+	memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+
+	dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
+	m[num+1].addr = mst->i2c_addr;
+	m[num+1].buf  = tx_close;
+	m[num+1].len  = 4;
+
+	return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO;
+}
+
+static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+	.master_xfer   = dibx000_i2c_gated_tuner_xfer,
+	.functionality = dibx000_i2c_func,
+};
+
+struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating)
+{
+	struct i2c_adapter *i2c = NULL;
+
+	switch (intf) {
+		case DIBX000_I2C_INTERFACE_TUNER:
+			if (gating)
+				i2c = &mst->gated_tuner_i2c_adap;
+			break;
+		default:
+			printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
+			break;
+	}
+
+	return i2c;
+}
+EXPORT_SYMBOL(dibx000_get_i2c_adapter);
+
+static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst)
+{
+	strncpy(i2c_adap->name, name, I2C_NAME_SIZE);
+	i2c_adap->class     = I2C_CLASS_TV_DIGITAL,
+	i2c_adap->algo      = algo;
+	i2c_adap->algo_data = NULL;
+	i2c_set_adapdata(i2c_adap, mst);
+	if (i2c_add_adapter(i2c_adap) < 0)
+		return -ENODEV;
+	return 0;
+}
+
+int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr)
+{
+	u8 tx[4];
+	struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 };
+
+	mst->device_rev = device_rev;
+	mst->i2c_adap   = i2c_adap;
+	mst->i2c_addr   = i2c_addr >> 1;
+
+	if (device_rev == DIB7000P)
+		mst->base_reg = 1024;
+	else
+		mst->base_reg = 768;
+
+    if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0)
+		printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n");
+
+	/* initialize the i2c-master by closing the gate */
+	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
+
+	return i2c_transfer(i2c_adap, &m, 1) == 1;
+}
+EXPORT_SYMBOL(dibx000_init_i2c_master);
+
+void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
+{
+	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
+}
+EXPORT_SYMBOL(dibx000_exit_i2c_master);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
new file mode 100644
index 0000000..bb0c65f
--- /dev/null
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -0,0 +1,166 @@
+#ifndef DIBX000_COMMON_H
+#define DIBX000_COMMON_H
+
+enum dibx000_i2c_interface {
+	DIBX000_I2C_INTERFACE_TUNER    = 0,
+	DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
+	DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
+};
+
+struct dibx000_i2c_master {
+#define DIB3000MC 1
+#define DIB7000   2
+#define DIB7000P  11
+#define DIB7000MC 12
+	u16 device_rev;
+
+	enum dibx000_i2c_interface selected_interface;
+
+//	struct i2c_adapter  tuner_i2c_adap;
+	struct i2c_adapter  gated_tuner_i2c_adap;
+
+	struct i2c_adapter *i2c_adap;
+	u8                  i2c_addr;
+
+	u16 base_reg;
+};
+
+extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr);
+extern struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating);
+extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
+
+#define BAND_LBAND 0x01
+#define BAND_UHF   0x02
+#define BAND_VHF   0x04
+
+struct dibx000_agc_config {
+	/* defines the capabilities of this AGC-setting - using the BAND_-defines*/
+	u8  band_caps;
+
+	u16 setup;
+
+	u16 inv_gain;
+	u16 time_stabiliz;
+
+	u8  alpha_level;
+	u16 thlock;
+
+	u8  wbd_inv;
+	u16 wbd_ref;
+	u8 wbd_sel;
+	u8 wbd_alpha;
+
+	u16 agc1_max;
+	u16 agc1_min;
+	u16 agc2_max;
+	u16 agc2_min;
+
+	u8 agc1_pt1;
+	u8 agc1_pt2;
+	u8 agc1_pt3;
+
+	u8 agc1_slope1;
+	u8 agc1_slope2;
+
+	u8 agc2_pt1;
+	u8 agc2_pt2;
+
+	u8 agc2_slope1;
+	u8 agc2_slope2;
+
+	u8 alpha_mant;
+	u8 alpha_exp;
+
+	u8 beta_mant;
+	u8 beta_exp;
+
+	u8 perform_agc_softsplit;
+
+	struct {
+		u16 min;
+		u16 max;
+		u16 min_thres;
+		u16 max_thres;
+	} split;
+};
+
+struct dibx000_bandwidth_config {
+	u32   internal;
+	u32   sampling;
+
+	u8 pll_prediv;
+	u8 pll_ratio;
+	u8 pll_range;
+	u8 pll_reset;
+	u8 pll_bypass;
+
+	u8 enable_refdiv;
+	u8 bypclk_div;
+	u8 IO_CLK_en_core;
+	u8 ADClkSrc;
+	u8 modulo;
+
+	u16 sad_cfg;
+
+	u32 ifreq;
+	u32 timf;
+};
+
+enum dibx000_adc_states {
+	DIBX000_SLOW_ADC_ON = 0,
+	DIBX000_SLOW_ADC_OFF,
+	DIBX000_ADC_ON,
+	DIBX000_ADC_OFF,
+	DIBX000_VBG_ENABLE,
+	DIBX000_VBG_DISABLE,
+};
+
+#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
+			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
+			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
+
+/* Chip output mode. */
+#define OUTMODE_HIGH_Z                      0
+#define OUTMODE_MPEG2_PAR_GATED_CLK         1
+#define OUTMODE_MPEG2_PAR_CONT_CLK          2
+#define OUTMODE_MPEG2_SERIAL                7
+#define OUTMODE_DIVERSITY                   4
+#define OUTMODE_MPEG2_FIFO                  5
+
+/* I hope I can get rid of the following kludge in the near future */
+struct dibx000_ofdm_channel {
+	u8  Bw;
+	s16 nfft;
+	s16 guard;
+	s16 nqam;
+	s16 vit_hrch;
+	s16 vit_select_hp;
+	s16 vit_alpha;
+	s16 vit_code_rate_hp;
+	s16 vit_code_rate_lp;
+};
+
+#define FEP2DIB(fep,ch) \
+	(ch)->Bw               = (fep)->u.ofdm.bandwidth; \
+	(ch)->nfft             = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
+	(ch)->guard            = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
+	(ch)->nqam             = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
+	(ch)->vit_hrch         = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
+	(ch)->vit_select_hp    = 1; \
+	(ch)->vit_alpha        = 1; \
+	(ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
+	(ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP;
+
+#define INIT_OFDM_CHANNEL(ch) do {\
+	(ch)->Bw               = 0;  \
+	(ch)->nfft             = -1; \
+	(ch)->guard            = -1; \
+	(ch)->nqam             = -1; \
+	(ch)->vit_hrch         = -1; \
+	(ch)->vit_select_hp    = -1; \
+	(ch)->vit_alpha        = -1; \
+	(ch)->vit_code_rate_hp = -1; \
+	(ch)->vit_code_rate_lp = -1; \
+} while (0)
+
+#endif
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 2be33f2..b7e7108 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -493,6 +493,9 @@
 	int i;
 	int result;
 
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
 	for (i = 0; i < priv->pll_desc->count; i++) {
 		if (priv->pll_desc->entries[i].limit == 0)
 			break;
@@ -611,7 +614,7 @@
 	.get_bandwidth = dvb_pll_get_bandwidth,
 };
 
-int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
 {
 	u8 b1 [] = { 0 };
 	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
@@ -624,14 +627,14 @@
 
 		ret = i2c_transfer (i2c, &msg, 1);
 		if (ret != 1)
-			return -1;
+			return NULL;
 		if (fe->ops.i2c_gate_ctrl)
 			     fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
 	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
 	if (priv == NULL)
-		return -ENOMEM;
+		return NULL;
 
 	priv->pll_i2c_address = pll_addr;
 	priv->i2c = i2c;
@@ -643,7 +646,7 @@
 	fe->ops.tuner_ops.info.frequency_min = desc->max;
 
 	fe->tuner_priv = priv;
-	return 0;
+	return fe;
 }
 EXPORT_SYMBOL(dvb_pll_attach);
 
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 66361cd..ed5ac5a 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -57,8 +57,8 @@
  * @param pll_addr i2c address of the PLL (if used).
  * @param i2c i2c adapter to use (set to NULL if not used).
  * @param desc dvb_pll_desc to use.
- * @return 0 on success, nonzero on failure.
+ * @return Frontend pointer on success, NULL on failure
  */
-extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
 
 #endif
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
index 58c34db..ef31936 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -42,12 +42,11 @@
 	u8			override_and;
 	struct i2c_adapter	*i2c;
 	u8			i2c_addr;
-	void			(*release_chain)(struct dvb_frontend* fe);
 };
 
 static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
-	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
 	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
 				.buf = &isl6421->config,
 				.len = sizeof(isl6421->config) };
@@ -75,7 +74,7 @@
 
 static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
 {
-	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
 	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
 				.buf = &isl6421->config,
 				.len = sizeof(isl6421->config) };
@@ -93,31 +92,26 @@
 
 static void isl6421_release(struct dvb_frontend *fe)
 {
-	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
-
 	/* power off */
 	isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
 
-	/* free data & call next release routine */
-	fe->ops.release = isl6421->release_chain;
-	kfree(fe->misc_priv);
-	fe->misc_priv = NULL;
-	if (fe->ops.release)
-		fe->ops.release(fe);
+	/* free */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
 }
 
-int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
 		   u8 override_set, u8 override_clear)
 {
 	struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
 	if (!isl6421)
-		return -ENOMEM;
+		return NULL;
 
 	/* default configuration */
 	isl6421->config = ISL6421_ISEL1;
 	isl6421->i2c = i2c;
 	isl6421->i2c_addr = i2c_addr;
-	fe->misc_priv = isl6421;
+	fe->sec_priv = isl6421;
 
 	/* bits which should be forced to '1' */
 	isl6421->override_or = override_set;
@@ -128,19 +122,17 @@
 	/* detect if it is present or not */
 	if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
 		kfree(isl6421);
-		fe->misc_priv = NULL;
-		return -EIO;
+		return NULL;
 	}
 
 	/* install release callback */
-	isl6421->release_chain = fe->ops.release;
-	fe->ops.release = isl6421_release;
+	fe->ops.release_sec = isl6421_release;
 
 	/* override frontend ops */
 	fe->ops.set_voltage = isl6421_set_voltage;
 	fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
 
-	return 0;
+	return fe;
 }
 EXPORT_SYMBOL(isl6421_attach);
 
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
index 675f80a..1916e3e 100644
--- a/drivers/media/dvb/frontends/isl6421.h
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -39,8 +39,17 @@
 #define ISL6421_ISEL1	0x20
 #define ISL6421_DCL	0x40
 
+#if defined(CONFIG_DVB_ISL6421) || defined(CONFIG_DVB_ISL6421_MODULE)
 /* override_set and override_clear control which system register bits (above) to always set & clear */
-extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
 			  u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+						  u8 override_set, u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_ISL6421
 
 #endif
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 83b8bc2..21ba4a2 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -31,8 +31,16 @@
 	u8 demod_address;
 };
 
-
+#if defined(CONFIG_DVB_L64781) || defined(CONFIG_DVB_L64781_MODULE)
 extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
 					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_L64781
 
 #endif // L64781_H
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index bad903c..3f96b48 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -52,8 +52,17 @@
 	int clock_polarity_flip;
 };
 
+#if defined(CONFIG_DVB_LGDT330X) || defined(CONFIG_DVB_LGDT330X_MODULE)
 extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
 					    struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_LGDT330X
 
 #endif /* LGDT330X_H */
 
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index e933edc..2d2f58c 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -40,12 +40,11 @@
 	u8			override_or;
 	u8			override_and;
 	struct i2c_adapter	*i2c;
-	void			(*release_chain)(struct dvb_frontend* fe);
 };
 
 static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
 	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
 				.buf = &lnbp21->config,
 				.len = sizeof(lnbp21->config) };
@@ -73,7 +72,7 @@
 
 static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
 {
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
 	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
 				.buf = &lnbp21->config,
 				.len = sizeof(lnbp21->config) };
@@ -91,29 +90,24 @@
 
 static void lnbp21_release(struct dvb_frontend *fe)
 {
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
 	/* LNBP power off */
 	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
 
-	/* free data & call next release routine */
-	fe->ops.release = lnbp21->release_chain;
-	kfree(fe->misc_priv);
-	fe->misc_priv = NULL;
-	if (fe->ops.release)
-		fe->ops.release(fe);
+	/* free data */
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
 }
 
-int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
 {
 	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
 	if (!lnbp21)
-		return -ENOMEM;
+		return NULL;
 
 	/* default configuration */
 	lnbp21->config = LNBP21_ISEL;
 	lnbp21->i2c = i2c;
-	fe->misc_priv = lnbp21;
+	fe->sec_priv = lnbp21;
 
 	/* bits which should be forced to '1' */
 	lnbp21->override_or = override_set;
@@ -124,19 +118,17 @@
 	/* detect if it is present or not */
 	if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
 		kfree(lnbp21);
-		fe->misc_priv = NULL;
-		return -EIO;
+		return NULL;
 	}
 
 	/* install release callback */
-	lnbp21->release_chain = fe->ops.release;
-	fe->ops.release = lnbp21_release;
+	fe->ops.release_sec = lnbp21_release;
 
 	/* override frontend ops */
 	fe->ops.set_voltage = lnbp21_set_voltage;
 	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
 
-	return 0;
+	return fe;
 }
 EXPORT_SYMBOL(lnbp21_attach);
 
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 047a4ab..1fe1dd1 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -39,7 +39,15 @@
 
 #include <linux/dvb/frontend.h>
 
+#if defined(CONFIG_DVB_LNBP21) || defined(CONFIG_DVB_LNBP21_MODULE)
 /* override_set and override_clear control which system register bits (above) to always set & clear */
-extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
+extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_LNBP21
 
-#endif
+#endif // _LNBP21_H
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
new file mode 100644
index 0000000..508ec1b
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060.c
@@ -0,0 +1,367 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.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.=
+ */
+
+/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2060.h"
+#include "mt2060_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "mt2060 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a single register
+static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+	};
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2060 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Initialisation sequences
+// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
+static u8 mt2060_config1[] = {
+	REG_LO1C1,
+	0x3F,	0x74,	0x00,	0x08,	0x93
+};
+
+// FMCG=2, GP2=0, GP1=0
+static u8 mt2060_config2[] = {
+	REG_MISC_CTRL,
+	0x20,	0x1E,	0x30,	0xff,	0x80,	0xff,	0x00,	0x2c,	0x42
+};
+
+//  VGAG=3, V1CSE=1
+
+#ifdef  MT2060_SPURCHECK
+/* The function below calculates the frequency offset between the output frequency if2
+ and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
+static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
+{
+	int I,J;
+	int dia,diamin,diff;
+	diamin=1000000;
+	for (I = 1; I < 10; I++) {
+		J = ((2*I*lo1)/lo2+1)/2;
+		diff = I*(int)lo1-J*(int)lo2;
+		if (diff < 0) diff=-diff;
+		dia = (diff-(int)if2);
+		if (dia < 0) dia=-dia;
+		if (diamin > dia) diamin=dia;
+	}
+	return diamin;
+}
+
+#define BANDWIDTH 4000 // kHz
+
+/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
+static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
+{
+	u32 Spur,Sp1,Sp2;
+	int I,J;
+	I=0;
+	J=1000;
+
+	Spur=mt2060_spurcalc(lo1,lo2,if2);
+	if (Spur < BANDWIDTH) {
+		/* Potential spurs detected */
+		dprintk("Spurs before : f_lo1: %d  f_lo2: %d  (kHz)",
+			(int)lo1,(int)lo2);
+		I=1000;
+		Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
+		Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
+
+		if (Sp1 < Sp2) {
+			J=-J; I=-I; Spur=Sp2;
+		} else
+			Spur=Sp1;
+
+		while (Spur < BANDWIDTH) {
+			I += J;
+			Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
+		}
+		dprintk("Spurs after  : f_lo1: %d  f_lo2: %d  (kHz)",
+			(int)(lo1+I),(int)(lo2+I));
+	}
+	return I;
+}
+#endif
+
+#define IF2  36150       // IF2 frequency = 36.150 MHz
+#define FREF 16000       // Quartz oscillator 16 MHz
+
+static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct mt2060_priv *priv;
+	int ret=0;
+	int i=0;
+	u32 freq;
+	u8  lnaband;
+	u32 f_lo1,f_lo2;
+	u32 div1,num1,div2,num2;
+	u8  b[8];
+	u32 if1;
+
+	priv = fe->tuner_priv;
+
+	if1 = priv->if1_freq;
+	b[0] = REG_LO1B1;
+	b[1] = 0xFF;
+
+	mt2060_writeregs(priv,b,2);
+
+	freq = params->frequency / 1000; // Hz -> kHz
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+	f_lo1 = freq + if1 * 1000;
+	f_lo1 = (f_lo1 / 250) * 250;
+	f_lo2 = f_lo1 - freq - IF2;
+	// From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
+	f_lo2 = ((f_lo2 + 25) / 50) * 50;
+	priv->frequency =  (f_lo1 - f_lo2 - IF2) * 1000,
+
+#ifdef MT2060_SPURCHECK
+	// LO-related spurs detection and correction
+	num1   = mt2060_spurcheck(f_lo1,f_lo2,IF2);
+	f_lo1 += num1;
+	f_lo2 += num1;
+#endif
+	//Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
+	num1 = f_lo1 / (FREF / 64);
+	div1 = num1 / 64;
+	num1 &= 0x3f;
+
+	// Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
+	num2 = f_lo2 * 64 / (FREF / 128);
+	div2 = num2 / 8192;
+	num2 &= 0x1fff;
+
+	if (freq <=  95000) lnaband = 0xB0; else
+	if (freq <= 180000) lnaband = 0xA0; else
+	if (freq <= 260000) lnaband = 0x90; else
+	if (freq <= 335000) lnaband = 0x80; else
+	if (freq <= 425000) lnaband = 0x70; else
+	if (freq <= 480000) lnaband = 0x60; else
+	if (freq <= 570000) lnaband = 0x50; else
+	if (freq <= 645000) lnaband = 0x40; else
+	if (freq <= 730000) lnaband = 0x30; else
+	if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
+
+	b[0] = REG_LO1C1;
+	b[1] = lnaband | ((num1 >>2) & 0x0F);
+	b[2] = div1;
+	b[3] = (num2 & 0x0F)  | ((num1 & 3) << 4);
+	b[4] = num2 >> 4;
+	b[5] = ((num2 >>12) & 1) | (div2 << 1);
+
+	dprintk("IF1: %dMHz",(int)if1);
+	dprintk("PLL freq=%dkHz  f_lo1=%dkHz  f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
+	dprintk("PLL div1=%d  num1=%d  div2=%d  num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
+	dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
+
+	mt2060_writeregs(priv,b,6);
+
+	//Waits for pll lock or timeout
+	i = 0;
+	do {
+		mt2060_readreg(priv,REG_LO_STATUS,b);
+		if ((b[0] & 0x88)==0x88)
+			break;
+		msleep(4);
+		i++;
+	} while (i<10);
+
+	return ret;
+}
+
+static void mt2060_calibrate(struct mt2060_priv *priv)
+{
+	u8 b = 0;
+	int i = 0;
+
+	if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
+		return;
+	if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
+		return;
+
+	do {
+		b |= (1 << 6); // FM1SS;
+		mt2060_writereg(priv, REG_LO2C1,b);
+		msleep(20);
+
+		if (i == 0) {
+			b |= (1 << 7); // FM1CA;
+			mt2060_writereg(priv, REG_LO2C1,b);
+			b &= ~(1 << 7); // FM1CA;
+			msleep(20);
+		}
+
+		b &= ~(1 << 6); // FM1SS
+		mt2060_writereg(priv, REG_LO2C1,b);
+
+		msleep(20);
+		i++;
+	} while (i < 9);
+
+	i = 0;
+	while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
+		msleep(20);
+
+	if (i < 10) {
+		mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
+		dprintk("calibration was successful: %d", (int)priv->fmfreq);
+	} else
+		dprintk("FMCAL timed out");
+}
+
+static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2060_init(struct dvb_frontend *fe)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	return mt2060_writereg(priv, REG_VGAG,0x33);
+}
+
+static int mt2060_sleep(struct dvb_frontend *fe)
+{
+	struct mt2060_priv *priv = fe->tuner_priv;
+	return mt2060_writereg(priv, REG_VGAG,0x30);
+}
+
+static int mt2060_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2060_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2060",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mt2060_release,
+
+	.init          = mt2060_init,
+	.sleep         = mt2060_sleep,
+
+	.set_params    = mt2060_set_params,
+	.get_frequency = mt2060_get_frequency,
+	.get_bandwidth = mt2060_get_bandwidth
+};
+
+/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
+int mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
+{
+	struct mt2060_priv *priv = NULL;
+	u8 id = 0;
+
+	priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->cfg      = cfg;
+	priv->i2c      = i2c;
+	priv->if1_freq = if1;
+
+	if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
+		kfree(priv);
+		return -ENODEV;
+	}
+
+	if (id != PART_REV) {
+		kfree(priv);
+		return -ENODEV;
+	}
+	printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
+	memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	mt2060_calibrate(priv);
+
+	return 0;
+}
+EXPORT_SYMBOL(mt2060_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h
new file mode 100644
index 0000000..c58b03e
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060.h
@@ -0,0 +1,35 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.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 MT2060_H
+#define MT2060_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2060_config {
+	u8 i2c_address;
+	/* Shall we add settings for the discrete outputs ? */
+};
+
+extern int mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/dvb/frontends/mt2060_priv.h
new file mode 100644
index 0000000..5eaccde
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060_priv.h
@@ -0,0 +1,105 @@
+/*
+ *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ *  Copyright (c) 2006 Olivier DANET <odanet@caramail.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 MT2060_PRIV_H
+#define MT2060_PRIV_H
+
+// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
+// #define MT2060_SPURCHECK
+
+/* This driver is based on the information available in the datasheet of the
+   "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
+
+   I2C Address : 0x60
+
+   Reg.No |   B7   |   B6   |   B5   |   B4   |   B3   |   B2   |   B1   |   B0   | ( defaults )
+   --------------------------------------------------------------------------------
+       00 | [              PART             ] | [              REV              ] | R  = 0x63
+       01 | [             LNABAND           ] | [              NUM1(5:2)        ] | RW = 0x3F
+       02 | [                               DIV1                                ] | RW = 0x74
+       03 | FM1CA  | FM1SS  | [  NUM1(1:0)  ] | [              NUM2(3:0)        ] | RW = 0x00
+       04 |                                 NUM2(11:4)                          ] | RW = 0x08
+       05 | [                               DIV2                       ] |NUM2(12)| RW = 0x93
+       06 | L1LK   | [        TAD1          ] | L2LK   | [         TAD2         ] | R
+       07 | [                               FMF                                 ] | R
+       08 |   ?    | FMCAL  |   ?    |   ?    |   ?    |   ?    |   ?    | TEMP   | R
+       09 |   0    |   0    | [    FMGC     ] |   0    | GP02   | GP01   |   0    | RW = 0x20
+       0A | ??
+       0B |   0    |   0    |   1    |   1    |   0    |   0    | [   VGAG      ] | RW = 0x30
+       0C | V1CSE  |   1    |   1    |   1    |   1    |   1    |   1    |   1    | RW = 0xFF
+       0D |   1    |   0    | [                      V1CS                       ] | RW = 0xB0
+       0E | ??
+       0F | ??
+       10 | ??
+       11 | [             LOTO              ] |   0    |   0    |   1    |   0    | RW = 0x42
+
+       PART    : Part code      : 6 for MT2060
+       REV     : Revision code  : 3 for current revision
+       LNABAND : Input frequency range : ( See code for details )
+       NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
+       FM1CA  : Calibration Start Bit
+       FM1SS  : Calibration Single Step bit
+       L1LK   : LO1 Lock Detect
+       TAD1   : Tune Line ADC ( ? )
+       L2LK   : LO2 Lock Detect
+       TAD2   : Tune Line ADC ( ? )
+       FMF    : Estimated first IF Center frequency Offset ( ? )
+       FM1CAL : Calibration done bit
+       TEMP   : On chip temperature sensor
+       FMCG   : Mixer 1 Cap Gain ( ? )
+       GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
+       V1CSE  : LO1 VCO Automatic Capacitor Select Enable ( ? )
+       V1CS   : LO1 Capacitor Selection Value ( ? )
+       LOTO   : LO Timeout ( ? )
+       VGAG   : Tuner Output gain
+*/
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV   0
+#define REG_LO1C1      1
+#define REG_LO1C2      2
+#define REG_LO2C1      3
+#define REG_LO2C2      4
+#define REG_LO2C3      5
+#define REG_LO_STATUS  6
+#define REG_FM_FREQ    7
+#define REG_MISC_STAT  8
+#define REG_MISC_CTRL  9
+#define REG_RESERVED_A 0x0A
+#define REG_VGAG       0x0B
+#define REG_LO1B1      0x0C
+#define REG_LO1B2      0x0D
+#define REG_LOTO       0x11
+
+#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
+
+struct mt2060_priv {
+	struct mt2060_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+	u16 if1_freq;
+	u8  fmfreq;
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 666a1bd..7112fb4 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -34,8 +34,16 @@
 	u8 demod_address;
 };
 
+#if defined(CONFIG_DVB_MT312) || defined(CONFIG_DVB_MT312_MODULE)
 struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 					struct i2c_adapter* i2c);
-
+#else
+static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+					struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_MT312
 
 #endif // MT312_H
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 5de7376..87e31ca 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -70,7 +70,7 @@
 	return 0;
 }
 
-int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
 {
 	int err,i;
 	for (i=0; i < ilen-1; i++)
@@ -107,7 +107,7 @@
 {
 	static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
 
-	mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
+	_mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
 	return 0;
 }
 
@@ -293,14 +293,14 @@
 				fe->ops.i2c_gate_ctrl(fe, 0);
 		}
 
-		mt352_write(fe, buf, 8);
-		mt352_write(fe, fsm_go, 2);
+		_mt352_write(fe, buf, 8);
+		_mt352_write(fe, fsm_go, 2);
 	} else {
 		if (fe->ops.tuner_ops.calc_regs) {
 			fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
 			buf[8] <<= 1;
-			mt352_write(fe, buf, sizeof(buf));
-			mt352_write(fe, tuner_go, 2);
+			_mt352_write(fe, buf, sizeof(buf));
+			_mt352_write(fe, tuner_go, 2);
 		}
 	}
 
@@ -522,7 +522,7 @@
 	    (mt352_read_register(state, CONFIG) & 0x20) == 0) {
 
 		/* Do a "hard" reset */
-		mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+		_mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
 		return state->config.demod_init(fe);
 	}
 
@@ -585,6 +585,7 @@
 
 	.init = mt352_init,
 	.sleep = mt352_sleep,
+	.write = _mt352_write,
 
 	.set_frontend = mt352_set_parameters,
 	.get_frontend = mt352_get_parameters,
@@ -605,4 +606,3 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(mt352_attach);
-EXPORT_SYMBOL(mt352_write);
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 9e7ff4b..0035c2e 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -51,9 +51,23 @@
 	int (*demod_init)(struct dvb_frontend* fe);
 };
 
+#if defined(CONFIG_DVB_MT352) || defined(CONFIG_DVB_MT352_MODULE)
 extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
 					 struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+					 struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_MT352
 
-extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
+static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
+	int r = 0;
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, len);
+	return r;
+}
 
 #endif // MT352_H
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 34d6173..2eb220e 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -45,8 +45,17 @@
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
 };
 
+#if defined(CONFIG_DVB_NXT200X) || defined(CONFIG_DVB_NXT200X_MODULE)
 extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_NXT200X
 
 #endif /* NXT200X_H */
 
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index 117031d..9397393 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -33,7 +33,16 @@
 	u8 clock_inversion:1;
 };
 
+#if defined(CONFIG_DVB_NXT6000) || defined(CONFIG_DVB_NXT6000_MODULE)
 extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_NXT6000
 
 #endif // NXT6000_H
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 8965888..9718be4 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -34,8 +34,17 @@
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
 };
 
+#if defined(CONFIG_DVB_OR51132) || defined(CONFIG_DVB_OR51132_MODULE)
 extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_OR51132
 
 #endif // OR51132_H
 
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
index 13a5a3a..10a5419 100644
--- a/drivers/media/dvb/frontends/or51211.h
+++ b/drivers/media/dvb/frontends/or51211.h
@@ -37,8 +37,17 @@
 	void (*sleep)(struct dvb_frontend * fe);
 };
 
+#if defined(CONFIG_DVB_OR51211) || defined(CONFIG_DVB_OR51211_MODULE)
 extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_OR51211
 
 #endif // OR51211_H
 
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 4e39015..efc54d7 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -34,7 +34,16 @@
 	u8 invert:1;
 };
 
+#if defined(CONFIG_DVB_S5H1420) || defined(CONFIG_DVB_S5H1420_MODULE)
 extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
 	     struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_S5H1420
 
 #endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index 93afbb9..4cf27d3 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -35,7 +35,16 @@
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
+#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
 extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
 					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_SP8870
 
 #endif // SP8870_H
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index c44b0eb..cab7ea6 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -17,7 +17,16 @@
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
+#if defined(CONFIG_DVB_SP887X) || defined(CONFIG_DVB_SP887X_MODULE)
 extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
 					  struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+					  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_SP887X
 
 #endif // SP887X_H
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 1da5384..760b80d 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -42,7 +42,16 @@
 	u8 stop_during_read:1;
 };
 
+#if defined(CONFIG_DVB_STV0297) || defined(CONFIG_DVB_STV0297_MODULE)
 extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_STV0297
 
 #endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 96648a7..9348376 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,11 +92,14 @@
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
+int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
 {
 	struct stv0299_state* state = fe->demodulator_priv;
 
-	return stv0299_writeregI(state, reg, data);
+	if (len != 2)
+		return -EINVAL;
+
+	return stv0299_writeregI(state, buf[0], buf[1]);
 }
 
 static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
@@ -694,6 +697,7 @@
 
 	.init = stv0299_init,
 	.sleep = stv0299_sleep,
+	.write = stv0299_write,
 	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
 
 	.set_frontend = stv0299_set_frontend,
@@ -724,5 +728,4 @@
 	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
 MODULE_LICENSE("GPL");
 
-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 1504828..7ef2520 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -89,9 +89,24 @@
 	int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
 };
 
-extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-
+#if defined(CONFIG_DVB_STV0299) || defined(CONFIG_DVB_STV0299_MODULE)
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_STV0299
+
+static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
 
 #endif // STV0299_H
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 9cbd164..dca8917 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -72,7 +72,7 @@
 	0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
 };
 
-static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
+static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
 {
 	u8 buf[] = { reg, data };
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
@@ -88,14 +88,6 @@
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	return tda10021_writereg(state, reg, data);
-}
-EXPORT_SYMBOL(tda10021_write_byte);
-
 static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
 {
 	u8 b0 [] = { reg };
@@ -149,8 +141,8 @@
 	else if (INVERSION_OFF == inversion)
 		DISABLE_INVERSION(reg0);
 
-	tda10021_writereg (state, 0x00, reg0 & 0xfe);
-	tda10021_writereg (state, 0x00, reg0 | 0x01);
+	_tda10021_writereg (state, 0x00, reg0 & 0xfe);
+	_tda10021_writereg (state, 0x00, reg0 | 0x01);
 
 	state->reg0 = reg0;
 	return 0;
@@ -198,17 +190,27 @@
 
 	NDEC = (NDEC << 6) | tda10021_inittab[0x03];
 
-	tda10021_writereg (state, 0x03, NDEC);
-	tda10021_writereg (state, 0x0a, BDR&0xff);
-	tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
-	tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+	_tda10021_writereg (state, 0x03, NDEC);
+	_tda10021_writereg (state, 0x0a, BDR&0xff);
+	_tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+	_tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
 
-	tda10021_writereg (state, 0x0d, BDRI);
-	tda10021_writereg (state, 0x0e, SFIL);
+	_tda10021_writereg (state, 0x0d, BDRI);
+	_tda10021_writereg (state, 0x0e, SFIL);
 
 	return 0;
 }
 
+int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return _tda10021_writereg(state, buf[0], buf[1]);
+}
+
 static int tda10021_init (struct dvb_frontend *fe)
 {
 	struct tda10021_state* state = fe->demodulator_priv;
@@ -216,12 +218,12 @@
 
 	dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
 
-	//tda10021_writereg (fe, 0, 0);
+	//_tda10021_writereg (fe, 0, 0);
 
 	for (i=0; i<tda10021_inittab_size; i++)
-		tda10021_writereg (state, i, tda10021_inittab[i]);
+		_tda10021_writereg (state, i, tda10021_inittab[i]);
 
-	tda10021_writereg (state, 0x34, state->pwm);
+	_tda10021_writereg (state, 0x34, state->pwm);
 
 	//Comment by markus
 	//0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
@@ -230,7 +232,7 @@
 	//0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
 
 	//Activate PLL
-	tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+	_tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
 	return 0;
 }
 
@@ -264,12 +266,12 @@
 	}
 
 	tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
-	tda10021_writereg (state, 0x34, state->pwm);
+	_tda10021_writereg (state, 0x34, state->pwm);
 
-	tda10021_writereg (state, 0x01, reg0x01[qam]);
-	tda10021_writereg (state, 0x05, reg0x05[qam]);
-	tda10021_writereg (state, 0x08, reg0x08[qam]);
-	tda10021_writereg (state, 0x09, reg0x09[qam]);
+	_tda10021_writereg (state, 0x01, reg0x01[qam]);
+	_tda10021_writereg (state, 0x05, reg0x05[qam]);
+	_tda10021_writereg (state, 0x08, reg0x08[qam]);
+	_tda10021_writereg (state, 0x09, reg0x09[qam]);
 
 	tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
 
@@ -342,8 +344,8 @@
 		*ucblocks = 0xffffffff;
 
 	/* reset uncorrected block counter */
-	tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
-	tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+	_tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
 
 	return 0;
 }
@@ -392,8 +394,8 @@
 {
 	struct tda10021_state* state = fe->demodulator_priv;
 
-	tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
-	tda10021_writereg (state, 0x00, 0x80);  /* standby */
+	_tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+	_tda10021_writereg (state, 0x00, 0x80);  /* standby */
 
 	return 0;
 }
@@ -459,6 +461,7 @@
 
 	.init = tda10021_init,
 	.sleep = tda10021_sleep,
+	.write = tda10021_write,
 	.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
 
 	.set_frontend = tda10021_set_parameters,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index b1df425..d68ae20 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -32,9 +32,24 @@
 	u8 demod_address;
 };
 
+#if defined(CONFIG_DVB_TDA10021) || defined(CONFIG_DVB_TDA10021_MODULE)
 extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
 					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10021
 
-extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
 
 #endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 59a2ed6..11e0dca 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -579,11 +579,14 @@
 	return -1;
 }
 
-int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
+int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
 
-	return tda1004x_write_byteI(state, reg, data);
+	if (len != 2)
+		return -EINVAL;
+
+	return tda1004x_write_byteI(state, buf[0], buf[1]);
 }
 
 static int tda10045_init(struct dvb_frontend* fe)
@@ -1216,6 +1219,7 @@
 
 	.init = tda10045_init,
 	.sleep = tda1004x_sleep,
+	.write = tda1004x_write,
 	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
 	.set_frontend = tda1004x_set_fe,
@@ -1274,6 +1278,7 @@
 
 	.init = tda10046_init,
 	.sleep = tda1004x_sleep,
+	.write = tda1004x_write,
 	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
 	.set_frontend = tda1004x_set_fe,
@@ -1323,4 +1328,3 @@
 
 EXPORT_SYMBOL(tda10045_attach);
 EXPORT_SYMBOL(tda10046_attach);
-EXPORT_SYMBOL(tda1004x_write_byte);
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index b877b23..e28fca0 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -71,12 +71,33 @@
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
+#if defined(CONFIG_DVB_TDA1004X) || defined(CONFIG_DVB_TDA1004X_MODULE)
 extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
 					    struct i2c_adapter* i2c);
 
 extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
 					    struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+					    struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA1004X
 
-extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data);
+static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+	int r = 0;
+	u8 buf[] = {reg, val};
+	if (fe->ops.write)
+		r = fe->ops.write(fe, buf, 2);
+	return r;
+}
 
 #endif // TDA1004X_H
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
new file mode 100644
index 0000000..7456b0b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -0,0 +1,740 @@
+  /*
+     Driver for Philips tda10086 DVBS Demodulator
+
+     (c) 2006 Andrew de Quincey
+
+     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/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda10086.h"
+
+#define SACLK 96000000
+
+struct tda10086_state {
+	struct i2c_adapter* i2c;
+	const struct tda10086_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demod data */
+	u32 frequency;
+	u32 symbol_rate;
+};
+
+static int debug = 0;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda10086: " args); \
+	} while (0)
+
+static int tda10086_write_byte(struct tda10086_state *state, int reg, int data)
+{
+	int ret;
+	u8 b0[] = { reg, data };
+	struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 };
+
+	msg.addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+			__FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? ret : 0;
+}
+
+static int tda10086_read_byte(struct tda10086_state *state, int reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+				{ .flags = I2C_M_RD, .buf = b1, .len = 1 }};
+
+	msg[0].addr = state->config->demod_address;
+	msg[1].addr = state->config->demod_address;
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+			ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data)
+{
+	int val;
+
+	// read a byte and check
+	val = tda10086_read_byte(state, reg);
+	if (val < 0)
+		return val;
+
+	// mask if off
+	val = val & ~mask;
+	val |= data & 0xff;
+
+	// write it out again
+	return tda10086_write_byte(state, reg, val);
+}
+
+static int tda10086_init(struct dvb_frontend* fe)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	// reset
+	tda10086_write_byte(state, 0x00, 0x00);
+	msleep(10);
+
+	// misc setup
+	tda10086_write_byte(state, 0x01, 0x94);
+	tda10086_write_byte(state, 0x02, 0x35); // NOTE: TT drivers appear to disable CSWP
+	tda10086_write_byte(state, 0x03, 0x64);
+	tda10086_write_byte(state, 0x04, 0x43);
+	tda10086_write_byte(state, 0x0c, 0x0c);
+	tda10086_write_byte(state, 0x1b, 0xb0); // noise threshold
+	tda10086_write_byte(state, 0x20, 0x89); // misc
+	tda10086_write_byte(state, 0x30, 0x04); // acquisition period length
+	tda10086_write_byte(state, 0x32, 0x00); // irq off
+	tda10086_write_byte(state, 0x31, 0x56); // setup AFC
+
+	// setup PLL (assumes 16Mhz XIN)
+	tda10086_write_byte(state, 0x55, 0x2c); // misc PLL setup
+	tda10086_write_byte(state, 0x3a, 0x0b); // M=12
+	tda10086_write_byte(state, 0x3b, 0x01); // P=2
+	tda10086_write_mask(state, 0x55, 0x20, 0x00); // powerup PLL
+
+	// setup TS interface
+	tda10086_write_byte(state, 0x11, 0x81);
+	tda10086_write_byte(state, 0x12, 0x81);
+	tda10086_write_byte(state, 0x19, 0x40); // parallel mode A + MSBFIRST
+	tda10086_write_byte(state, 0x56, 0x80); // powerdown WPLL - unused in the mode we use
+	tda10086_write_byte(state, 0x57, 0x08); // bypass WPLL - unused in the mode we use
+	tda10086_write_byte(state, 0x10, 0x2a);
+
+	// setup ADC
+	tda10086_write_byte(state, 0x58, 0x61); // ADC setup
+	tda10086_write_mask(state, 0x58, 0x01, 0x00); // powerup ADC
+
+	// setup AGC
+	tda10086_write_byte(state, 0x05, 0x0B);
+	tda10086_write_byte(state, 0x37, 0x63);
+	tda10086_write_byte(state, 0x3f, 0x03); // NOTE: flydvb uses 0x0a and varies it
+	tda10086_write_byte(state, 0x40, 0x64);
+	tda10086_write_byte(state, 0x41, 0x4f);
+	tda10086_write_byte(state, 0x42, 0x43);
+
+	// setup viterbi
+	tda10086_write_byte(state, 0x1a, 0x11); // VBER 10^6, DVB, QPSK
+
+	// setup carrier recovery
+	tda10086_write_byte(state, 0x3d, 0x80);
+
+	// setup SEC
+	tda10086_write_byte(state, 0x36, 0x00); // all SEC off
+	tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000)));      // } tone frequency
+	tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // }
+
+	return 0;
+}
+
+static void tda10086_diseqc_wait(struct tda10086_state *state)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(200);
+	while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
+		if(time_after(jiffies, timeout)) {
+			printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+			break;
+		}
+		msleep(10);
+	}
+}
+
+static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch(tone) {
+	case SEC_TONE_OFF:
+		tda10086_write_byte(state, 0x36, 0x00);
+		break;
+
+	case SEC_TONE_ON:
+		tda10086_write_byte(state, 0x36, 0x01);
+		break;
+	}
+
+	return 0;
+}
+
+static int tda10086_send_master_cmd (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd* cmd)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	int i;
+	u8 oldval;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	if (cmd->msg_len > 6)
+		return -EINVAL;
+	oldval = tda10086_read_byte(state, 0x36);
+
+	for(i=0; i< cmd->msg_len; i++) {
+		tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
+	}
+	tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len + 1) << 4));
+
+	tda10086_diseqc_wait(state);
+
+	tda10086_write_byte(state, 0x36, oldval);
+
+	return 0;
+}
+
+static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 oldval = tda10086_read_byte(state, 0x36);
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch(minicmd) {
+	case SEC_MINI_A:
+		tda10086_write_byte(state, 0x36, 0x04);
+		break;
+
+	case SEC_MINI_B:
+		tda10086_write_byte(state, 0x36, 0x06);
+		break;
+	}
+
+	tda10086_diseqc_wait(state);
+
+	tda10086_write_byte(state, 0x36, oldval);
+
+	return 0;
+}
+
+static int tda10086_set_inversion(struct tda10086_state *state,
+				  struct dvb_frontend_parameters *fe_params)
+{
+	u8 invval = 0x80;
+
+	dprintk ("%s %i %i\n", __FUNCTION__, fe_params->inversion, state->config->invert);
+
+	switch(fe_params->inversion) {
+	case INVERSION_OFF:
+		if (state->config->invert)
+			invval = 0x40;
+		break;
+	case INVERSION_ON:
+		if (!state->config->invert)
+			invval = 0x40;
+		break;
+	case INVERSION_AUTO:
+		invval = 0x00;
+		break;
+	}
+	tda10086_write_mask(state, 0x0c, 0xc0, invval);
+
+	return 0;
+}
+
+static int tda10086_set_symbol_rate(struct tda10086_state *state,
+				    struct dvb_frontend_parameters *fe_params)
+{
+	u8 dfn = 0;
+	u8 afs = 0;
+	u8 byp = 0;
+	u8 reg37 = 0x43;
+	u8 reg42 = 0x43;
+	u64 big;
+	u32 tmp;
+	u32 bdr;
+	u32 bdri;
+	u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
+
+	dprintk ("%s %i\n", __FUNCTION__, symbol_rate);
+
+	// setup the decimation and anti-aliasing filters..
+	if (symbol_rate < (u32) (SACLK * 0.0137)) {
+		dfn=4;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0208)) {
+		dfn=4;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.0270)) {
+		dfn=3;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0416)) {
+		dfn=3;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.0550)) {
+		dfn=2;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.0833)) {
+		dfn=2;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.1100)) {
+		dfn=1;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.1666)) {
+		dfn=1;
+		afs=0;
+	} else if (symbol_rate < (u32) (SACLK * 0.2200)) {
+		dfn=0;
+		afs=1;
+	} else if (symbol_rate < (u32) (SACLK * 0.3333)) {
+		dfn=0;
+		afs=0;
+	} else {
+		reg37 = 0x63;
+		reg42 = 0x4f;
+		byp=1;
+	}
+
+	// calculate BDR
+	big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
+	big += ((SACLK/1000ULL)-1ULL);
+	do_div(big, (SACLK/1000ULL));
+	bdr = big & 0xfffff;
+
+	// calculate BDRI
+	tmp = (1<<dfn)*(symbol_rate/1000);
+	bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
+
+	tda10086_write_byte(state, 0x21, (afs << 7) | dfn);
+	tda10086_write_mask(state, 0x20, 0x08, byp << 3);
+	tda10086_write_byte(state, 0x06, bdr);
+	tda10086_write_byte(state, 0x07, bdr >> 8);
+	tda10086_write_byte(state, 0x08, bdr >> 16);
+	tda10086_write_byte(state, 0x09, bdri);
+	tda10086_write_byte(state, 0x37, reg37);
+	tda10086_write_byte(state, 0x42, reg42);
+
+	return 0;
+}
+
+static int tda10086_set_fec(struct tda10086_state *state,
+			    struct dvb_frontend_parameters *fe_params)
+{
+	u8 fecval;
+
+	dprintk ("%s %i\n", __FUNCTION__, fe_params->u.qpsk.fec_inner);
+
+	switch(fe_params->u.qpsk.fec_inner) {
+	case FEC_1_2:
+		fecval = 0x00;
+		break;
+	case FEC_2_3:
+		fecval = 0x01;
+		break;
+	case FEC_3_4:
+		fecval = 0x02;
+		break;
+	case FEC_4_5:
+		fecval = 0x03;
+		break;
+	case FEC_5_6:
+		fecval = 0x04;
+		break;
+	case FEC_6_7:
+		fecval = 0x05;
+		break;
+	case FEC_7_8:
+		fecval = 0x06;
+		break;
+	case FEC_8_9:
+		fecval = 0x07;
+		break;
+	case FEC_AUTO:
+		fecval = 0x08;
+		break;
+	default:
+		return -1;
+	}
+	tda10086_write_byte(state, 0x0d, fecval);
+
+	return 0;
+}
+
+static int tda10086_set_frontend(struct dvb_frontend* fe,
+				 struct dvb_frontend_parameters *fe_params)
+{
+	struct tda10086_state *state = fe->demodulator_priv;
+	int ret;
+	u32 freq = 0;
+	int freqoff;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	// set params
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, fe_params);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+
+		if (fe->ops.tuner_ops.get_frequency)
+			fe->ops.tuner_ops.get_frequency(fe, &freq);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	// calcluate the frequency offset (in *Hz* not kHz)
+	freqoff = fe_params->frequency - freq;
+	freqoff = ((1<<16) * freqoff) / (SACLK/1000);
+	tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
+	tda10086_write_byte(state, 0x3e, freqoff);
+
+	if ((ret = tda10086_set_inversion(state, fe_params)) < 0)
+		return ret;
+	if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0)
+		return ret;
+	if ((ret = tda10086_set_fec(state, fe_params)) < 0)
+		return ret;
+
+	// soft reset + disable TS output until lock
+	tda10086_write_mask(state, 0x10, 0x40, 0x40);
+	tda10086_write_mask(state, 0x00, 0x01, 0x00);
+
+	state->symbol_rate = fe_params->u.qpsk.symbol_rate;
+	state->frequency = fe_params->frequency;
+	return 0;
+}
+
+static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 val;
+	int tmp;
+	u64 tmp64;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	// calculate the updated frequency (note: we convert from Hz->kHz)
+	tmp64 = tda10086_read_byte(state, 0x52);
+	tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
+	if (tmp64 & 0x8000)
+		tmp64 |= 0xffffffffffff0000ULL;
+	tmp64 = (tmp64 * (SACLK/1000ULL));
+	do_div(tmp64, (1ULL<<15) * (1ULL<<1));
+	fe_params->frequency = (int) state->frequency + (int) tmp64;
+
+	// the inversion
+	val = tda10086_read_byte(state, 0x0c);
+	if (val & 0x80) {
+		switch(val & 0x40) {
+		case 0x00:
+			fe_params->inversion = INVERSION_OFF;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_ON;
+			break;
+		default:
+			fe_params->inversion = INVERSION_ON;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_OFF;
+			break;
+		}
+	} else {
+		tda10086_read_byte(state, 0x0f);
+		switch(val & 0x02) {
+		case 0x00:
+			fe_params->inversion = INVERSION_OFF;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_ON;
+			break;
+		default:
+			fe_params->inversion = INVERSION_ON;
+			if (state->config->invert)
+				fe_params->inversion = INVERSION_OFF;
+			break;
+		}
+	}
+
+	// calculate the updated symbol rate
+	tmp = tda10086_read_byte(state, 0x1d);
+	if (tmp & 0x80)
+		tmp |= 0xffffff00;
+	tmp = (tmp * 480 * (1<<1)) / 128;
+	tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
+	fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
+
+	// the FEC
+	val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
+	switch(val) {
+	case 0x00:
+		fe_params->u.qpsk.fec_inner = FEC_1_2;
+		break;
+	case 0x01:
+		fe_params->u.qpsk.fec_inner = FEC_2_3;
+		break;
+	case 0x02:
+		fe_params->u.qpsk.fec_inner = FEC_3_4;
+		break;
+	case 0x03:
+		fe_params->u.qpsk.fec_inner = FEC_4_5;
+		break;
+	case 0x04:
+		fe_params->u.qpsk.fec_inner = FEC_5_6;
+		break;
+	case 0x05:
+		fe_params->u.qpsk.fec_inner = FEC_6_7;
+		break;
+	case 0x06:
+		fe_params->u.qpsk.fec_inner = FEC_7_8;
+		break;
+	case 0x07:
+		fe_params->u.qpsk.fec_inner = FEC_8_9;
+		break;
+	}
+
+	return 0;
+}
+
+static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	val = tda10086_read_byte(state, 0x0e);
+	*fe_status = 0;
+	if (val & 0x01)
+		*fe_status |= FE_HAS_SIGNAL;
+	if (val & 0x02)
+		*fe_status |= FE_HAS_CARRIER;
+	if (val & 0x04)
+		*fe_status |= FE_HAS_VITERBI;
+	if (val & 0x08)
+		*fe_status |= FE_HAS_SYNC;
+	if (val & 0x10)
+		*fe_status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 _str;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	_str = tda10086_read_byte(state, 0x43);
+	*signal = (_str << 8) | _str;
+
+	return 0;
+}
+
+static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+	u8 _snr;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	_snr = tda10086_read_byte(state, 0x1c);
+	*snr = (_snr << 8) | _snr;
+
+	return 0;
+}
+
+static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	// read it
+	*ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
+
+	// reset counter
+	tda10086_write_byte(state, 0x18, 0x00);
+	tda10086_write_byte(state, 0x18, 0x80);
+
+	return 0;
+}
+
+static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	// read it
+	*ber = 0;
+	*ber |= tda10086_read_byte(state, 0x15);
+	*ber |= tda10086_read_byte(state, 0x16) << 8;
+	*ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16;
+
+	return 0;
+}
+
+static int tda10086_sleep(struct dvb_frontend* fe)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	tda10086_write_mask(state, 0x00, 0x08, 0x08);
+
+	return 0;
+}
+
+static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10086_state* state = fe->demodulator_priv;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	if (enable) {
+		tda10086_write_mask(state, 0x00, 0x10, 0x10);
+	} else {
+		tda10086_write_mask(state, 0x00, 0x10, 0x00);
+	}
+
+	return 0;
+}
+
+static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+		fesettings->min_delay_ms = 50;
+		fesettings->step_size = 2000;
+		fesettings->max_drift = 8000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1500;
+		fesettings->max_drift = 9000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 1000;
+		fesettings->max_drift = 8000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+		fesettings->min_delay_ms = 100;
+		fesettings->step_size = 500;
+		fesettings->max_drift = 7000;
+	} else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+		fesettings->max_drift = 14 * fesettings->step_size;
+	} else {
+		fesettings->min_delay_ms = 200;
+		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+		fesettings->max_drift = 18 * fesettings->step_size;
+	}
+
+	return 0;
+}
+
+static void tda10086_release(struct dvb_frontend* fe)
+{
+	struct tda10086_state *state = fe->demodulator_priv;
+	tda10086_sleep(fe);
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10086_ops = {
+
+	.info = {
+		.name     = "Philips TDA10086 DVB-S",
+		.type     = FE_QPSK,
+		.frequency_min    = 950000,
+		.frequency_max    = 2150000,
+		.frequency_stepsize = 125,     /* kHz for QPSK frontends */
+		.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_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK
+	},
+
+	.release = tda10086_release,
+
+	.init = tda10086_init,
+	.sleep = tda10086_sleep,
+	.i2c_gate_ctrl = tda10086_i2c_gate_ctrl,
+
+	.set_frontend = tda10086_set_frontend,
+	.get_frontend = tda10086_get_frontend,
+	.get_tune_settings = tda10086_get_tune_settings,
+
+	.read_status = tda10086_read_status,
+	.read_ber = tda10086_read_ber,
+	.read_signal_strength = tda10086_read_signal_strength,
+	.read_snr = tda10086_read_snr,
+	.read_ucblocks = tda10086_read_ucblocks,
+
+	.diseqc_send_master_cmd = tda10086_send_master_cmd,
+	.diseqc_send_burst = tda10086_send_burst,
+	.set_tone = tda10086_set_tone,
+};
+
+struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+				     struct i2c_adapter* i2c)
+{
+	struct tda10086_state *state;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda10086_state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+
+	/* check if the demod is there */
+	if (tda10086_read_byte(state, 0x1e) != 0xe1) {
+		kfree(state);
+		return NULL;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+}
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10086_attach);
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
new file mode 100644
index 0000000..e8061db
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10086.h
@@ -0,0 +1,41 @@
+  /*
+     Driver for Philips tda10086 DVBS Frontend
+
+     (c) 2006 Andrew de Quincey
+
+     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 TDA10086_H
+#define TDA10086_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda10086_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* does the "inversion" need inverted? */
+	u8 invert;
+};
+
+extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+					    struct i2c_adapter* i2c);
+
+#endif // TDA10086_H
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index e7a48f6..aae15bd 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -35,7 +35,16 @@
 	u8 demod_address;
 };
 
+#if defined(CONFIG_DVB_TDA8083) || defined(CONFIG_DVB_TDA8083_MODULE)
 extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA8083
 
 #endif // TDA8083_H
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
new file mode 100644
index 0000000..eeab26b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -0,0 +1,173 @@
+  /*
+     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+     (c) 2006 Andrew de Quincey
+
+     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/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tda826x.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "tda826x: " args); \
+	} while (0)
+
+struct tda826x_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u8 has_loopthrough:1;
+	u32 frequency;
+};
+
+static int tda826x_release(struct dvb_frontend *fe)
+{
+	if (fe->tuner_priv)
+		kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tda826x_sleep(struct dvb_frontend *fe)
+{
+	struct tda826x_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 buf [] = { 0x00, 0x8d };
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
+
+	dprintk("%s:\n", __FUNCTION__);
+
+	if (!priv->has_loopthrough)
+		buf[1] = 0xad;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		dprintk("%s: i2c error\n", __FUNCTION__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct tda826x_priv *priv = fe->tuner_priv;
+	int ret;
+	u32 div;
+	u8 buf [11];
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
+
+	dprintk("%s:\n", __FUNCTION__);
+
+	div = (params->frequency + (1000-1)) / 1000;
+
+	buf[0] = 0x00; // subaddress
+	buf[1] = 0x09; // powerdown RSSI + the magic value 1
+	if (!priv->has_loopthrough)
+		buf[1] |= 0x20; // power down loopthrough if not needed
+	buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
+	buf[3] = div >> 7;
+	buf[4] = div << 1;
+	buf[5] = 0xff; // basedband filter to max
+	buf[6] = 0xfe; // gains at max + no RF attenuation
+	buf[7] = 0x83; // charge pumps at high, tests off
+	buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
+	buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL
+	buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		dprintk("%s: i2c error\n", __FUNCTION__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	priv->frequency = div * 1000;
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda826x_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tda826x_tuner_ops = {
+	.info = {
+		.name = "Philips TDA826X",
+		.frequency_min = 950000,
+		.frequency_min = 2175000
+	},
+	.release = tda826x_release,
+	.sleep = tda826x_sleep,
+	.set_params = tda826x_set_params,
+	.get_frequency = tda826x_get_frequency,
+};
+
+struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough)
+{
+	struct tda826x_priv *priv = NULL;
+	u8 b1 [] = { 0, 0 };
+	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 };
+	int ret;
+
+	dprintk("%s:\n", __FUNCTION__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 1)
+		return NULL;
+	if (!(b1[1] & 0x80))
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+	priv->has_loopthrough = has_loopthrough;
+
+	memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(tda826x_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB TDA826x driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h
new file mode 100644
index 0000000..3307607
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda826x.h
@@ -0,0 +1,40 @@
+  /*
+     Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+     (c) 2006 Andrew de Quincey
+
+     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 __DVB_TDA826X_H__
+#define __DVB_TDA826X_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a tda826x tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
+ * @return FE pointer on success, NULL on failure.
+ */
+extern struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough);
+
+#endif
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
new file mode 100644
index 0000000..8855439
--- /dev/null
+++ b/drivers/media/dvb/frontends/tua6100.c
@@ -0,0 +1,205 @@
+/**
+ * Driver for Infineon tua6100 pll.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ * 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/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tua6100.h"
+
+struct tua6100_priv {
+	/* i2c details */
+	int i2c_address;
+	struct i2c_adapter *i2c;
+	u32 frequency;
+};
+
+static int tua6100_release(struct dvb_frontend *fe)
+{
+	if (fe->tuner_priv)
+		kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tua6100_sleep(struct dvb_frontend *fe)
+{
+	struct tua6100_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 reg0[] = { 0x00, 0x00 };
+	struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+		printk("%s: i2c error\n", __FUNCTION__);
+	}
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int tua6100_set_params(struct dvb_frontend *fe,
+			      struct dvb_frontend_parameters *params)
+{
+	struct tua6100_priv *priv = fe->tuner_priv;
+	u32 div;
+	u32 prediv;
+	u8 reg0[] = { 0x00, 0x00 };
+	u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
+	u8 reg2[] = { 0x02, 0x00, 0x00 };
+	struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+	struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
+	struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
+
+#define _R 4
+#define _P 32
+#define _ri 4000000
+
+	// setup register 0
+	if (params->frequency < 2000000) {
+		reg0[1] = 0x03;
+	} else {
+		reg0[1] = 0x07;
+	}
+
+	// setup register 1
+	if (params->frequency < 1630000) {
+		reg1[1] = 0x2c;
+	} else {
+		reg1[1] = 0x0c;
+	}
+	if (_P == 64)
+		reg1[1] |= 0x40;
+	if (params->frequency >= 1525000)
+		reg1[1] |= 0x80;
+
+	// register 2
+	reg2[1] = (_R >> 8) & 0x03;
+	reg2[2] = _R;
+	if (params->frequency < 1455000) {
+		reg2[1] |= 0x1c;
+	} else if (params->frequency < 1630000) {
+		reg2[1] |= 0x0c;
+	} else {
+		reg2[1] |= 0x1c;
+	}
+
+	// The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz)
+	prediv = (params->frequency * _R) / (_ri / 1000);
+	div = prediv / _P;
+	reg1[1] |= (div >> 9) & 0x03;
+	reg1[2] = div >> 1;
+	reg1[3] = (div << 7);
+	priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+
+	// Finally, calculate and store the value for A
+	reg1[3] |= (prediv - (div*_P)) & 0x7f;
+
+#undef _R
+#undef _P
+#undef _ri
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
+		return -EIO;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tua6100_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tua6100_tuner_ops = {
+	.info = {
+		.name = "Infineon TUA6100",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_step = 1000,
+	},
+	.release = tua6100_release,
+	.sleep = tua6100_sleep,
+	.set_params = tua6100_set_params,
+	.get_frequency = tua6100_get_frequency,
+};
+
+struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+	struct tua6100_priv *priv = NULL;
+	u8 b1 [] = { 0x80 };
+	u8 b2 [] = { 0x00 };
+	struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
+				  { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
+	int ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	ret = i2c_transfer (i2c, msg, 2);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_address = addr;
+	priv->i2c = i2c;
+
+	memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(tua6100_attach);
+
+MODULE_DESCRIPTION("DVB tua6100 driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h
new file mode 100644
index 0000000..8f98033
--- /dev/null
+++ b/drivers/media/dvb/frontends/tua6100.h
@@ -0,0 +1,47 @@
+/**
+ * Driver for Infineon tua6100 PLL.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ * 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 __DVB_TUA6100_H__
+#define __DVB_TUA6100_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_TUA6100) || defined(CONFIG_DVB_TUA6100_MODULE)
+extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUA6100
+
+#endif
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 520f095..f0c9dde 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -41,7 +41,16 @@
 	u8 selagc:1;
 };
 
+#if defined(CONFIG_DVB_VES1820) || defined(CONFIG_DVB_VES1820_MODULE)
 extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
 					   struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+					   struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_VES1820
 
 #endif // VES1820_H
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index ba88ae0..395fed3 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -40,7 +40,16 @@
 	u8 invert_pwm:1;
 };
 
+#if defined(CONFIG_DVB_VES1X93) || defined(CONFIG_DVB_VES1X93_MODULE)
 extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
 					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+					   struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_VES1X93
 
 #endif // VES1X93_H
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 2b95e8b..0e9b59a 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -140,6 +140,8 @@
 	zl10353_single_write(fe, 0x5E, 0x00);
 	zl10353_single_write(fe, 0x65, 0x5A);
 	zl10353_single_write(fe, 0x66, 0xE9);
+	zl10353_single_write(fe, 0x6C, 0xCD);
+	zl10353_single_write(fe, 0x6D, 0x7E);
 	zl10353_single_write(fe, 0x62, 0x0A);
 
 	// if there is no attached secondary tuner, we call set_params to program
@@ -168,6 +170,7 @@
 	// even if there isn't a PLL attached to the secondary bus
 	zl10353_write(fe, pllbuf, sizeof(pllbuf));
 
+	zl10353_single_write(fe, 0x5F, 0x13);
 	zl10353_single_write(fe, 0x70, 0x01);
 	udelay(250);
 	zl10353_single_write(fe, 0xE4, 0x00);
@@ -243,9 +246,12 @@
 
 	if (debug_regs)
 		zl10353_dump_regs(fe);
+	if (state->config.parallel_ts)
+		zl10353_reset_attach[2] &= ~0x20;
 
 	/* Do a "hard" reset if not already done */
-	if (zl10353_read_register(state, 0x50) != 0x03) {
+	if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
+	    zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
 		rc = zl10353_write(fe, zl10353_reset_attach,
 				   sizeof(zl10353_reset_attach));
 		if (debug_regs)
@@ -258,7 +264,6 @@
 static void zl10353_release(struct dvb_frontend *fe)
 {
 	struct zl10353_state *state = fe->demodulator_priv;
-
 	kfree(state);
 }
 
@@ -314,6 +319,7 @@
 
 	.init = zl10353_init,
 	.sleep = zl10353_sleep,
+	.write = zl10353_write,
 
 	.set_frontend = zl10353_set_parameters,
 	.get_tune_settings = zl10353_get_tune_settings,
@@ -330,4 +336,3 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(zl10353_attach);
-EXPORT_SYMBOL(zl10353_write);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 9770cb8..79a9472 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -31,11 +31,21 @@
 
 	/* set if no pll is connected to the secondary i2c bus */
 	int no_tuner;
+
+	/* set if parallel ts output is required */
+	int parallel_ts;
 };
 
+#if defined(CONFIG_DVB_ZL10353) || defined(CONFIG_DVB_ZL10353_MODULE)
 extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
 					   struct i2c_adapter *i2c);
-
-extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
+#else
+static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+					   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_ZL10353
 
 #endif /* ZL10353_H */
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 5fb0975..95531a6 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -1,17 +1,17 @@
 config DVB_AV7110
 	tristate "AV7110 cards"
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-	select FW_LOADER
+	select FW_LOADER if !DVB_AV7110_FIRMWARE
 	select VIDEO_SAA7146_VV
 	select DVB_PLL
-	select DVB_VES1820
-	select DVB_VES1X93
-	select DVB_STV0299
-	select DVB_TDA8083
-	select DVB_SP8870
-	select DVB_STV0297
-	select DVB_L64781
-	select DVB_LNBP21
+	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	select DVB_SP8870 if !DVB_FE_CUSTOMISE
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_L64781 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
 	  Support for SAA7146 and AV7110 based DVB cards as produced
 	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -63,14 +63,16 @@
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146
 	select DVB_PLL
-	select DVB_STV0299
-	select DVB_VES1X93
-	select DVB_VES1820
-	select DVB_L64781
-	select DVB_TDA8083
-	select DVB_TDA10021
-	select DVB_S5H1420
-	select DVB_LNBP21
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+	select DVB_L64781 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
 	  Support for simple SAA7146 based DVB cards
 	  (so called Budget- or Nova-PCI cards) without onboard
@@ -86,10 +88,10 @@
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146
 	select DVB_PLL
-	select DVB_STV0297
-	select DVB_STV0299
-	select DVB_TDA1004X
-	select DVB_LNBP21
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
 	  Support for simple SAA7146 based DVB cards
 	  (so called Budget- or Nova-PCI cards) without onboard
@@ -108,9 +110,10 @@
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146_VV
 	select DVB_PLL
-	select DVB_STV0299
-	select DVB_TDA1004X
-	select DVB_TDA10021
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TUA6100 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
 	  Support for simple SAA7146 based DVB cards
@@ -127,9 +130,9 @@
 	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
 	select DVB_AV7110
 	select DVB_PLL
-	select DVB_STV0299
-	select DVB_VES1X93
-	select DVB_TDA8083
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
 	help
 	  Support for Budget Patch (full TS) modification on
 	  SAA7146+AV7110 based cards (DVB-S cards). This
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 4506165..bba23bc 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -1383,8 +1383,10 @@
 	dvb_dmxdev_release(&av7110->dmxdev);
 	dvb_dmx_release(&av7110->demux);
 
-	if (av7110->fe != NULL)
+	if (av7110->fe != NULL) {
 		dvb_unregister_frontend(av7110->fe);
+		dvb_frontend_detach(av7110->fe);
+	}
 	dvb_unregister_device(av7110->osd_dev);
 	av7110_av_unregister(av7110);
 	av7110_ca_unregister(av7110);
@@ -1699,9 +1701,13 @@
 
 static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
 {
+#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
 	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 
 	return request_firmware(fw, name, &av7110->dev->pci->dev);
+#else
+	return -EINVAL;
+#endif
 }
 
 static struct sp8870_config alps_tdlb7_config = {
@@ -2077,7 +2083,7 @@
 	if (av7110->dev->pci->subsystem_vendor == 0x110a) {
 		switch(av7110->dev->pci->subsystem_device) {
 		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
-			av7110->fe = ves1820_attach(&philips_cd1516_config,
+			av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
 						    &av7110->i2c_adap, read_pwm(av7110));
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
@@ -2092,7 +2098,7 @@
 		case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
 
 			// try the ALPS BSRV2 first of all
-			av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
 				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2103,7 +2109,7 @@
 			}
 
 			// try the ALPS BSRU6 now
-			av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
 				av7110->fe->tuner_priv = &av7110->i2c_adap;
@@ -2116,7 +2122,7 @@
 			}
 
 			// Try the grundig 29504-451
-			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
 				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2130,7 +2136,7 @@
 			switch(av7110->dev->pci->subsystem_device) {
 			case 0x0000:
 				/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
-				av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
+				av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
 							read_pwm(av7110));
 				if (av7110->fe) {
 					av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
@@ -2138,7 +2144,7 @@
 				break;
 			case 0x0003:
 				/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
-				av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
+				av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
 							read_pwm(av7110));
 				if (av7110->fe) {
 					av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
@@ -2148,17 +2154,24 @@
 			break;
 
 		case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
-
-			// ALPS TDLB7
-			av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+			// try ALPS TDLB7 first, then Grundig 29504-401
+			av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+				break;
 			}
+			/* fall-thru */
+
+		case 0x0008: // Hauppauge/TT DVB-T
+			// Grundig 29504-401
+			av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap);
+			if (av7110->fe)
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
 			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 = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
 			}
@@ -2166,7 +2179,7 @@
 
 		case 0x0004: // Galaxis DVB-S rev1.3
 			/* ALPS BSRV2 */
-			av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
 				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2178,7 +2191,7 @@
 
 		case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
 			/* Grundig 29504-451 */
-			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
 				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2188,17 +2201,9 @@
 			}
 			break;
 
-		case 0x0008: // Hauppauge/TT DVB-T
-
-			av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
-			if (av7110->fe) {
-				av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
-			}
-			break;
-
 		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
 
-			av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
 
@@ -2214,12 +2219,12 @@
 
 		case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
 			/* ALPS BSBE1 */
-			av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
+			av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap);
 			if (av7110->fe) {
 				av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
 				av7110->fe->tuner_priv = &av7110->i2c_adap;
 
-				if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+				if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
 					printk("dvb-ttpci: LNBP21 not found!\n");
 					if (av7110->fe->ops.release)
 						av7110->fe->ops.release(av7110->fe);
@@ -2255,8 +2260,7 @@
 		ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
 		if (ret < 0) {
 			printk("av7110: Frontend registration failed!\n");
-			if (av7110->fe->ops.release)
-				av7110->fe->ops.release(av7110->fe);
+			dvb_frontend_detach(av7110->fe);
 			av7110->fe = NULL;
 		}
 	}
@@ -2823,7 +2827,7 @@
 
 
 static struct saa7146_extension av7110_extension = {
-	.name		= "dvb\0",
+	.name		= "dvb",
 	.flags		= SAA7146_I2C_SHORT_DELAY,
 
 	.module		= THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 0f3a044..8c577cf 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -33,7 +33,6 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 6079e88..dd9aee3 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -35,7 +35,6 @@
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 
 #include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 75736f2..37de2e8 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -34,7 +34,6 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 6ffe53f..10cfe31 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -32,7 +32,6 @@
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 
 #include "av7110.h"
@@ -922,7 +921,7 @@
 static struct saa7146_ext_vv av7110_vv_data_c = {
 	.inputs		= 1,
 	.audios		= 1,
-	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
+	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
 	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
 
 	.stds		= &standard[0],
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 2d21fec..2235ff8 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -37,6 +37,7 @@
 #include "stv0299.h"
 #include "tda10021.h"
 #include "tda1004x.h"
+#include "tua6100.h"
 #include "dvb-pll.h"
 #include <media/saa7146_vv.h>
 #include <linux/module.h>
@@ -235,7 +236,7 @@
 
 	/* set tda10021 back to original clock configuration on reset */
 	if (budget_av->tda10021_poclkp) {
-		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
 		budget_av->tda10021_ts_enabled = 0;
 	}
 
@@ -257,7 +258,7 @@
 
 	/* set tda10021 back to original clock configuration when cam removed */
 	if (budget_av->tda10021_poclkp) {
-		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
 		budget_av->tda10021_ts_enabled = 0;
 	}
 	return 0;
@@ -277,7 +278,7 @@
 
 	/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
 	if (budget_av->tda10021_poclkp) {
-		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
 		budget_av->tda10021_ts_enabled = 1;
 	}
 
@@ -548,144 +549,6 @@
 	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_tuner_set_params(struct dvb_frontend *fe,
-						      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;
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-
-	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 */
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	msg.buf = reg0;
-	msg.len = sizeof(reg0);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	msg.buf = reg1;
-	msg.len = sizeof(reg1);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	msg.buf = reg2;
-	msg.len = sizeof(reg2);
-	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	return 0;
-}
-
 static u8 typhoon_cinergy1200s_inittab[] = {
 	0x01, 0x15,
 	0x02, 0x30,
@@ -1068,9 +931,9 @@
 
 	result = budget_av->tda10021_set_frontend(fe, p);
 	if (budget_av->tda10021_ts_enabled) {
-		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
 	} else {
-		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
 	}
 
 	return result;
@@ -1096,15 +959,16 @@
 	switch (saa->pci->subsystem_device) {
 
 	case SUBID_DVBS_KNC1:
+	case SUBID_DVBS_KNC1_PLUS:
 	case SUBID_DVBS_EASYWATCH_1:
 		if (saa->pci->subsystem_vendor == 0x1894) {
-			fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
+			fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,
 					     &budget_av->budget.i2c_adap);
 			if (fe) {
-				fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+				dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);
 			}
 		} else {
-			fe = stv0299_attach(&typhoon_config,
+			fe = dvb_attach(stv0299_attach, &typhoon_config,
 					     &budget_av->budget.i2c_adap);
 			if (fe) {
 				fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1116,16 +980,15 @@
 	case SUBID_DVBS_TV_STAR_CI:
 	case SUBID_DVBS_CYNERGY1200N:
 	case SUBID_DVBS_EASYWATCH:
-		fe = stv0299_attach(&philips_sd1878_config,
+		fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
 				&budget_av->budget.i2c_adap);
 		if (fe) {
 			fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
 		}
 		break;
 
-	case SUBID_DVBS_KNC1_PLUS:
 	case SUBID_DVBS_TYPHOON:
-		fe = stv0299_attach(&typhoon_config,
+		fe = dvb_attach(stv0299_attach, &typhoon_config,
 				    &budget_av->budget.i2c_adap);
 		if (fe) {
 			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1133,7 +996,7 @@
 		break;
 
 	case SUBID_DVBS_CINERGY1200:
-		fe = stv0299_attach(&cinergy_1200s_config,
+		fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
 				    &budget_av->budget.i2c_adap);
 		if (fe) {
 			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1141,19 +1004,10 @@
 		break;
 
 	case SUBID_DVBC_KNC1:
-		budget_av->reinitialise_demod = 1;
-		fe = tda10021_attach(&philips_cu1216_config,
-				     &budget_av->budget.i2c_adap,
-				     read_pwm(budget_av));
-		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
-		}
-		break;
-
 	case SUBID_DVBC_KNC1_PLUS:
 	case SUBID_DVBC_CINERGY1200:
 		budget_av->reinitialise_demod = 1;
-		fe = tda10021_attach(&philips_cu1216_config,
+		fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
 				     &budget_av->budget.i2c_adap,
 				     read_pwm(budget_av));
 		if (fe) {
@@ -1168,7 +1022,7 @@
 	case SUBID_DVBT_KNC1_PLUS:
 	case SUBID_DVBT_CINERGY1200:
 		budget_av->reinitialise_demod = 1;
-		fe = tda10046_attach(&philips_tu1216_config,
+		fe = dvb_attach(tda10046_attach, &philips_tu1216_config,
 				     &budget_av->budget.i2c_adap);
 		if (fe) {
 			fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
@@ -1192,8 +1046,7 @@
 	if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
 				  budget_av->budget.dvb_frontend)) {
 		printk(KERN_ERR "budget-av: Frontend registration failed!\n");
-		if (budget_av->budget.dvb_frontend->ops.release)
-			budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
+		dvb_frontend_detach(budget_av->budget.dvb_frontend);
 		budget_av->budget.dvb_frontend = NULL;
 	}
 }
@@ -1227,8 +1080,10 @@
 	if (budget_av->budget.ci_present)
 		ciintf_deinit(budget_av);
 
-	if (budget_av->budget.dvb_frontend != NULL)
+	if (budget_av->budget.dvb_frontend != NULL) {
 		dvb_unregister_frontend(budget_av->budget.dvb_frontend);
+		dvb_frontend_detach(budget_av->budget.dvb_frontend);
+	}
 	err = ttpci_budget_deinit(&budget_av->budget);
 
 	kfree(budget_av);
@@ -1400,6 +1255,7 @@
 	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
 	MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
 	MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
+	MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
 	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index ffbbb3e..2a2e9b4 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -749,17 +749,17 @@
 	// setup PLL filter and TDA9889
 	switch (params->u.ofdm.bandwidth) {
 	case BANDWIDTH_6_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0x14);
+		tda1004x_writereg(fe, 0x0C, 0x14);
 		filter = 0;
 		break;
 
 	case BANDWIDTH_7_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0x80);
+		tda1004x_writereg(fe, 0x0C, 0x80);
 		filter = 0;
 		break;
 
 	case BANDWIDTH_8_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0x14);
+		tda1004x_writereg(fe, 0x0C, 0x14);
 		filter = 1;
 		break;
 
@@ -988,7 +988,7 @@
 	switch (budget_ci->budget.dev->pci->subsystem_device) {
 	case 0x100c:		// Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
 		budget_ci->budget.dvb_frontend =
-			stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+			dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
 			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
@@ -998,7 +998,7 @@
 
 	case 0x100f:		// Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
 		budget_ci->budget.dvb_frontend =
-			stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+			dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
 			break;
@@ -1008,7 +1008,7 @@
 	case 0x1010:		// TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
 		budget_ci->tuner_pll_address = 0x61;
 		budget_ci->budget.dvb_frontend =
-			stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+			dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
 			break;
@@ -1018,7 +1018,7 @@
 	case 0x1011:		// Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
 		budget_ci->tuner_pll_address = 0x63;
 		budget_ci->budget.dvb_frontend =
-			tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+			dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1029,7 +1029,7 @@
 	case 0x1012:		// TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
 		budget_ci->tuner_pll_address = 0x60;
 		budget_ci->budget.dvb_frontend =
-			tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+			dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1038,16 +1038,15 @@
 		break;
 
 	case 0x1017:		// TT S-1500 PCI
-		budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+		budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
 			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
 			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
 
 			budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
-			if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+			if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
-				if (budget_ci->budget.dvb_frontend->ops.release)
-					budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
+				dvb_frontend_detach(budget_ci->budget.dvb_frontend);
 				budget_ci->budget.dvb_frontend = NULL;
 			}
 		}
@@ -1065,8 +1064,7 @@
 		if (dvb_register_frontend
 		    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
 			printk("budget-ci: Frontend registration failed!\n");
-			if (budget_ci->budget.dvb_frontend->ops.release)
-				budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
+			dvb_frontend_detach(budget_ci->budget.dvb_frontend);
 			budget_ci->budget.dvb_frontend = NULL;
 		}
 	}
@@ -1114,8 +1112,10 @@
 
 	if (budget_ci->budget.ci_present)
 		ciintf_deinit(budget_ci);
-	if (budget_ci->budget.dvb_frontend)
+	if (budget_ci->budget.dvb_frontend) {
 		dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
+		dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+	}
 	err = ttpci_budget_deinit(&budget_ci->budget);
 
 	tasklet_kill(&budget_ci->msp430_irq_tasklet);
@@ -1153,7 +1153,7 @@
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
-	.name = "budget_ci dvb\0",
+	.name = "budget_ci dvb",
 	.flags = SAA7146_I2C_SHORT_DELAY,
 
 	.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 5722744..fc1267b 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -325,7 +325,7 @@
 	case 0x1013: // SATELCO Multimedia PCI
 
 		// try the ALPS BSRV2 first of all
-		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
 			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
@@ -335,7 +335,7 @@
 		}
 
 		// try the ALPS BSRU6 now
-		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
 			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -347,7 +347,7 @@
 		}
 
 		// Try the grundig 29504-451
-		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
 			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
@@ -367,8 +367,7 @@
 	} else {
 		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
 			printk("budget-av: Frontend registration failed!\n");
-			if (budget->dvb_frontend->ops.release)
-				budget->dvb_frontend->ops.release(budget->dvb_frontend);
+			dvb_frontend_detach(budget->dvb_frontend);
 			budget->dvb_frontend = NULL;
 		}
 	}
@@ -627,8 +626,10 @@
 	struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
 	int err;
 
-	if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
-
+	if (budget->dvb_frontend) {
+		dvb_unregister_frontend(budget->dvb_frontend);
+		dvb_frontend_detach(budget->dvb_frontend);
+	}
 	err = ttpci_budget_deinit (budget);
 
 	kfree (budget);
@@ -647,7 +648,7 @@
 }
 
 static struct saa7146_extension budget_extension = {
-	.name           = "budget_patch dvb\0",
+	.name           = "budget_patch dvb",
 	.flags          = 0,
 
 	.module         = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 863dffb..e58f039 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -41,6 +41,8 @@
 #include "l64781.h"
 #include "tda8083.h"
 #include "s5h1420.h"
+#include "tda10086.h"
+#include "tda826x.h"
 #include "lnbp21.h"
 #include "bsru6.h"
 
@@ -342,6 +344,11 @@
 	.invert = 1,
 };
 
+static struct tda10086_config tda10086_config = {
+	.demod_address = 0x0e,
+	.invert = 0,
+};
+
 static u8 read_pwm(struct budget* budget)
 {
 	u8 b = 0xff;
@@ -361,7 +368,7 @@
 	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
 	case 0x1013:
 		// try the ALPS BSRV2 first of all
-		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
 			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
@@ -371,7 +378,7 @@
 		}
 
 		// try the ALPS BSRU6 now
-		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
 			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -381,7 +388,7 @@
 
 	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
 
-		budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+		budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
 			break;
@@ -390,7 +397,7 @@
 
 	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
 
-		budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
 			break;
@@ -398,7 +405,7 @@
 		break;
 
 	case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
-		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
 			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -408,7 +415,7 @@
 		break;
 
 	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
-		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
 			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
@@ -417,10 +424,28 @@
 		break;
 
 	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
-		budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
+		budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
 			budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
-			if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+				printk("%s: No LNBP21 found!\n", __FUNCTION__);
+				goto error_out;
+			}
+			break;
+		}
+
+	case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
+		// gpio2 is connected to CLB - reset it + leave it high
+		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+		msleep(1);
+		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+		msleep(1);
+
+		budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
+				printk("%s: No tda826x found!\n", __FUNCTION__);
+			if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
 				goto error_out;
 			}
@@ -442,8 +467,7 @@
 
 error_out:
 	printk("budget: Frontend registration failed!\n");
-	if (budget->dvb_frontend->ops.release)
-		budget->dvb_frontend->ops.release(budget->dvb_frontend);
+	dvb_frontend_detach(budget->dvb_frontend);
 	budget->dvb_frontend = NULL;
 	return;
 }
@@ -481,7 +505,10 @@
 	struct budget *budget = (struct budget*) dev->ext_priv;
 	int err;
 
-	if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
+	if (budget->dvb_frontend) {
+		dvb_unregister_frontend(budget->dvb_frontend);
+		dvb_frontend_detach(budget->dvb_frontend);
+	}
 
 	err = ttpci_budget_deinit (budget);
 
@@ -497,6 +524,7 @@
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 
@@ -506,6 +534,7 @@
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
+	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
 	{
@@ -516,7 +545,7 @@
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
-	.name		= "budget dvb\0",
+	.name		= "budget dvb",
 	.flags		= SAA7146_I2C_SHORT_DELAY,
 
 	.module		= THIS_MODULE,
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 46a6a60..e78ea92 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -2,13 +2,13 @@
 	tristate "Technotrend/Hauppauge Nova-USB devices"
 	depends on DVB_CORE && USB && I2C
 	select DVB_PLL
-	select DVB_CX22700
-	select DVB_TDA1004X
-	select DVB_VES1820
-	select DVB_TDA8083
-	select DVB_STV0299
-	select DVB_STV0297
-	select DVB_LNBP21
+	select DVB_CX22700 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_VES1820 if !DVB_FE_CUSTOMISE
+	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_STV0297 if !DVB_FE_CUSTOMISE
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
 	  Support for external USB adapters designed by Technotrend and
 	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 04cef30..2341998 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1107,17 +1107,17 @@
 	// setup PLL filter
 	switch (params->u.ofdm.bandwidth) {
 	case BANDWIDTH_6_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0);
+		tda1004x_writereg(fe, 0x0C, 0);
 		filter = 0;
 		break;
 
 	case BANDWIDTH_7_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0);
+		tda1004x_writereg(fe, 0x0C, 0);
 		filter = 0;
 		break;
 
 	case BANDWIDTH_8_MHZ:
-		tda1004x_write_byte(fe, 0x0C, 0xFF);
+		tda1004x_writereg(fe, 0x0C, 0xFF);
 		filter = 1;
 		break;
 
@@ -1564,13 +1564,13 @@
 	switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
 	case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
 		// try the stv0299 based first
-		ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
+		ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
 
 			if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
 				alps_stv0299_config.inittab = alps_bsbe1_inittab;
-				lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
+				dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0);
 			} else { // ALPS BSRU6
 				ttusb->fe->ops.set_voltage = ttusb_set_voltage;
 			}
@@ -1578,7 +1578,7 @@
 		}
 
 		// Grundig 29504-491
-		ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
+		ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
 			ttusb->fe->ops.set_voltage = ttusb_set_voltage;
@@ -1587,13 +1587,13 @@
 		break;
 
 	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
-		ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+		ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
 			break;
 		}
 
-		ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+		ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
 			break;
@@ -1602,14 +1602,14 @@
 
 	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
 		// try the ALPS TDMB7 first
-		ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
+		ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
 			break;
 		}
 
 		// Philips td1316
-		ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
+		ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
 			ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
 			ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1625,8 +1625,7 @@
 	} else {
 		if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
 			printk("dvb-ttusb-budget: Frontend registration failed!\n");
-			if (ttusb->fe->ops.release)
-				ttusb->fe->ops.release(ttusb->fe);
+			dvb_frontend_detach(ttusb->fe);
 			ttusb->fe = NULL;
 		}
 	}
@@ -1763,7 +1762,10 @@
 	dvb_net_release(&ttusb->dvbnet);
 	dvb_dmxdev_release(&ttusb->dmxdev);
 	dvb_dmx_release(&ttusb->dvb_demux);
-	if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
+	if (ttusb->fe != NULL) {
+		dvb_unregister_frontend(ttusb->fe);
+		dvb_frontend_detach(ttusb->fe);
+	}
 	i2c_del_adapter(&ttusb->i2c_adap);
 	dvb_unregister_adapter(&ttusb->adapter);
 
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index c9d6635..de077a7 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1512,7 +1512,11 @@
 	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
 	dvb_dmxdev_release(&dec->dmxdev);
 	dvb_dmx_release(&dec->demux);
-	if (dec->fe) dvb_unregister_frontend(dec->fe);
+	if (dec->fe) {
+		dvb_unregister_frontend(dec->fe);
+		if (dec->fe->ops.release)
+			dec->fe->ops.release(dec->fe);
+	}
 	dvb_unregister_adapter(&dec->adapter);
 }
 
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 220076b..7015517 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -7,7 +7,7 @@
 
 config RADIO_CADET
 	tristate "ADS Cadet AM/FM Tuner"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these AM/FM radio cards, and then
 	  fill in the port address below.
@@ -25,7 +25,7 @@
 
 config RADIO_RTRACK
 	tristate "AIMSlab RadioTrack (aka RadioReveal) support"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
@@ -59,7 +59,7 @@
 
 config RADIO_RTRACK2
 	tristate "AIMSlab RadioTrack II support"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
 	  port address below.
@@ -82,7 +82,7 @@
 
 config RADIO_AZTECH
 	tristate "Aztech/Packard Bell Radio"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
@@ -106,7 +106,7 @@
 
 config RADIO_GEMTEK
 	tristate "GemTek Radio Card support"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
 	  port address below.
@@ -131,7 +131,7 @@
 
 config RADIO_GEMTEK_PCI
 	tristate "GemTek PCI Radio Card support"
-	depends on VIDEO_V4L1 && PCI
+	depends on VIDEO_V4L2 && PCI
 	---help---
 	  Choose Y here if you have this PCI FM radio card.
 
@@ -145,7 +145,7 @@
 
 config RADIO_MAXIRADIO
 	tristate "Guillemot MAXI Radio FM 2000 radio"
-	depends on VIDEO_V4L1 && PCI
+	depends on VIDEO_V4L2 && PCI
 	---help---
 	  Choose Y here if you have this radio card.  This card may also be
 	  found as Gemtek PCI FM.
@@ -160,7 +160,7 @@
 
 config RADIO_MAESTRO
 	tristate "Maestro on board radio"
-	depends on VIDEO_V4L1
+	depends on VIDEO_V4L2 && PCI
 	---help---
 	  Say Y here to directly support the on-board radio tuner on the
 	  Maestro 2 or 2E sound card.
@@ -208,7 +208,7 @@
 
 config RADIO_SF16FMI
 	tristate "SF16FMI Radio"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards.  If you
 	  compile the driver into the kernel and your card is not PnP one, you
@@ -225,7 +225,7 @@
 
 config RADIO_SF16FMR2
 	tristate "SF16FMR2 Radio"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards.
 
@@ -239,7 +239,7 @@
 
 config RADIO_TERRATEC
 	tristate "TerraTec ActiveRadio ISA Standalone"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
 	  port address below. (TODO)
@@ -268,7 +268,7 @@
 
 config RADIO_TRUST
 	tristate "Trust FM radio card"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	help
 	  This is a driver for the Trust FM radio cards. Say Y if you have
 	  such a card and want to use it under Linux.
@@ -286,7 +286,7 @@
 
 config RADIO_TYPHOON
 	tristate "Typhoon Radio (a.k.a. EcoRadio)"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address and the frequency used for muting below.
@@ -330,7 +330,7 @@
 
 config RADIO_ZOLTRIX
 	tristate "Zoltrix Radio"
-	depends on ISA && VIDEO_V4L1
+	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have one of these FM radio cards, and then fill
 	  in the port address below.
@@ -352,7 +352,7 @@
 
 config USB_DSBR
 	tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-	depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+	depends on USB && VIDEO_V4L2 && EXPERIMENTAL
 	---help---
 	  Say Y here if you want to connect this type of radio to your
 	  computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index f7e33f9..db865a0 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -33,8 +33,14 @@
 
  History:
 
+ Version 0.41-ac1:
+	Alan Cox: Some cleanups and fixes
+
+ Version 0.41:
+	Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+
  Version 0.40:
-  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+	Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
 
  Version 0.30:
 	Markus: Updates for 2.5.x kernel and more ISO compliant source
@@ -65,13 +71,12 @@
 
 */
 
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
@@ -79,7 +84,22 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.40"
+#include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
+
+#define DRIVER_VERSION "v0.41"
+#define RADIO_VERSION KERNEL_VERSION(0,4,1)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
+
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
 
@@ -111,7 +131,7 @@
 module_param(radio_nr, int, 0);
 
 /* Data for one (physical) device */
-typedef struct {
+struct dsbr100_device {
 	struct usb_device *usbdev;
 	struct video_device *videodev;
 	unsigned char transfer_buffer[TB_LEN];
@@ -119,7 +139,8 @@
 	int stereo;
 	int users;
 	int removed;
-} dsbr100_device;
+	int muted;
+};
 
 
 /* File system interface */
@@ -138,7 +159,6 @@
 	.owner =	THIS_MODULE,
 	.name =		"D-Link DSB-R 100",
 	.type =		VID_TYPE_TUNER,
-	.hardware =	VID_HARDWARE_AZTECH,
 	.fops =         &usb_dsbr100_fops,
 	.release = video_device_release,
 };
@@ -161,7 +181,7 @@
 /* Low-level device interface begins here */
 
 /* switch on radio */
-static int dsbr100_start(dsbr100_device *radio)
+static int dsbr100_start(struct dsbr100_device *radio)
 {
 	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
 			USB_REQ_GET_STATUS,
@@ -172,12 +192,13 @@
 			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 			0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
 		return -1;
+	radio->muted=0;
 	return (radio->transfer_buffer)[0];
 }
 
 
 /* switch off radio */
-static int dsbr100_stop(dsbr100_device *radio)
+static int dsbr100_stop(struct dsbr100_device *radio)
 {
 	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
 			USB_REQ_GET_STATUS,
@@ -188,11 +209,12 @@
 			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 			0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
 		return -1;
+	radio->muted=1;
 	return (radio->transfer_buffer)[0];
 }
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
 {
 	freq = (freq/16*80)/1000+856;
 	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
@@ -217,7 +239,7 @@
 
 /* return the device status.  This is, in effect, just whether it
 sees a stereo signal or not.  Pity. */
-static void dsbr100_getstat(dsbr100_device *radio)
+static void dsbr100_getstat(struct dsbr100_device *radio)
 {
 	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
 		USB_REQ_GET_STATUS,
@@ -236,9 +258,9 @@
 static int usb_dsbr100_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
-	dsbr100_device *radio;
+	struct dsbr100_device *radio;
 
-	if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
+	if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
 		return -ENOMEM;
 	if (!(radio->videodev = video_device_alloc())) {
 		kfree(radio);
@@ -271,7 +293,7 @@
 leak here it's tiny (~50 bytes per disconnect) */
 static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
-	dsbr100_device *radio = usb_get_intfdata(intf);
+	struct dsbr100_device *radio = usb_get_intfdata(intf);
 
 	usb_set_intfdata (intf, NULL);
 	if (radio) {
@@ -291,89 +313,121 @@
 static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
 				unsigned int cmd, void *arg)
 {
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
 
 	if (!radio)
 		return -EIO;
 
 	switch(cmd) {
-		case VIDIOCGCAP: {
-			struct video_capability *v = arg;
+		case VIDIOC_QUERYCAP:
+		{
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "dsbr100", sizeof (v->driver));
+			strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
 
-			memset(v, 0, sizeof(*v));
-			v->type = VID_TYPE_TUNER;
-			v->channels = 1;
-			v->audios = 1;
-			strcpy(v->name, "D-Link R-100 USB FM Radio");
 			return 0;
 		}
-		case VIDIOCGTUNER: {
-			struct video_tuner *v = arg;
+		case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
 
 			dsbr100_getstat(radio);
-			if(v->tuner)	/* Only 1 tuner */
-				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
 			v->rangelow = FREQ_MIN*FREQ_MUL;
 			v->rangehigh = FREQ_MAX*FREQ_MUL;
-			v->flags = VIDEO_TUNER_LOW;
-			v->mode = VIDEO_MODE_AUTO;
-			v->signal = radio->stereo*0x7000;
-				/* Don't know how to get signal strength */
-			v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
-			strcpy(v->name, "DSB R-100");
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			if(radio->stereo)
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal = 0xFFFF;     /* We can't get the signal strength */
+
 			return 0;
 		}
-		case VIDIOCSTUNER: {
-			struct video_tuner *v = arg;
+		case VIDIOC_S_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
 
-			if(v->tuner!=0)
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ: {
-			int *freq = arg;
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
 
-			if (radio->curfreq==-1)
-				return -EINVAL;
-			*freq = radio->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ: {
-			int *freq = arg;
-
-			radio->curfreq = *freq;
+			radio->curfreq = f->frequency;
 			if (dsbr100_setfreq(radio, radio->curfreq)==-1)
 				warn("Set frequency failed");
 			return 0;
 		}
-		case VIDIOCGAUDIO: {
-			struct video_audio *v = arg;
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
 
-			memset(v, 0, sizeof(*v));
-			v->flags |= VIDEO_AUDIO_MUTABLE;
-			v->mode = VIDEO_SOUND_STEREO;
-			v->volume = 1;
-			v->step = 1;
-			strcpy(v->name, "Radio");
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = radio->curfreq;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO: {
-			struct video_audio *v = arg;
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
 
-			if (v->audio)
-				return -EINVAL;
-			if (v->flags&VIDEO_AUDIO_MUTE) {
-				if (dsbr100_stop(radio)==-1)
-					warn("Radio did not respond properly");
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return 0;
+				}
 			}
-			else
-				if (dsbr100_start(radio)==-1)
-					warn("Radio did not respond properly");
-			return 0;
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+			case V4L2_CID_AUDIO_MUTE:
+				ctrl->value=radio->muted;
+				return 0;
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+			case V4L2_CID_AUDIO_MUTE:
+				if (ctrl->value) {
+					if (dsbr100_stop(radio)==-1)
+						warn("Radio did not respond properly");
+				} else {
+					if (dsbr100_start(radio)==-1)
+						warn("Radio did not respond properly");
+				}
+				return 0;
+			}
+			return -EINVAL;
 		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  usb_dsbr100_do_ioctl);
 	}
 }
 
@@ -385,9 +439,11 @@
 
 static int usb_dsbr100_open(struct inode *inode, struct file *file)
 {
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
 
 	radio->users = 1;
+	radio->muted = 1;
+
 	if (dsbr100_start(radio)<0) {
 		warn("Radio did not start up properly");
 		radio->users = 0;
@@ -399,7 +455,7 @@
 
 static int usb_dsbr100_close(struct inode *inode, struct file *file)
 {
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+	struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
 
 	if (!radio)
 		return -ENODEV;
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index df22a58..3368a89 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -1,5 +1,6 @@
 /* radiotrack (radioreveal) driver for Linux radio support
  * (c) 1997 M. Kirkwood
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Converted to new API by Alan Cox <Alan.Cox@linux.org>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
@@ -33,11 +34,13 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_RTRACK_PORT 	*/
 #include <asm/semaphore.h>	/* Lock for the I/O 		*/
 
+#include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
 #endif
@@ -209,6 +212,25 @@
 	return 1;		/* signal present		*/
 }
 
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 static int rt_do_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, void *arg)
 {
@@ -217,73 +239,114 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "RadioTrack");
+			strlcpy(v->driver, "radio-aimslab", sizeof (v->driver));
+			strlcpy(v->card, "RadioTrack", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
-			v->flags=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			strcpy(v->name, "FM");
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
 			v->signal=0xFFFF*rt_getsigstr(rt);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = rt->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			rt->curfreq = *freq;
+			struct v4l2_frequency *f = arg;
+
+			rt->curfreq = f->frequency;
 			rt_setfreq(rt, rt->curfreq);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			v->volume=rt->curvol * 6554;
-			v->step=6554;
-			strcpy(v->name, "Radio");
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = rt->curfreq;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				rt_mute(rt);
-			else
-				rt_setvol(rt,v->volume/6554);
-			return 0;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=rt->muted;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=rt->curvol * 6554;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						rt_mute(rt);
+					} else {
+						rt_setvol(rt,rt->curvol);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					rt_setvol(rt,ctrl->value);
+					return (0);
+			}
+			return -EINVAL;
+		}
+
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  rt_do_ioctl);
 	}
 }
 
@@ -309,7 +372,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "RadioTrack radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_RTRACK,
+	.hardware	= 0,
 	.fops           = &rtrack_fops,
 };
 
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 95e6322..3ba5fa8 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,5 +1,6 @@
 /* radio-aztech.c - Aztech radio card driver for Linux 2.2
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  *
@@ -30,9 +31,30 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_AZTECH_PORT 	*/
+
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -166,81 +188,121 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "Aztech Radio");
+			strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+			strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
-			v->flags=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			v->signal=0xFFFF*az_getsigstr(az);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
 			if(az_getstereo(az))
-				v->flags|=VIDEO_TUNER_STEREO_ON;
-			strcpy(v->name, "FM");
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xFFFF*az_getsigstr(az);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = az->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			az->curfreq = *freq;
+			struct v4l2_frequency *f = arg;
+
+			az->curfreq = f->frequency;
 			az_setfreq(az, az->curfreq);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			if(az->stereo)
-				v->mode=VIDEO_SOUND_STEREO;
-			else
-				v->mode=VIDEO_SOUND_MONO;
-			v->volume=az->curvol;
-			v->step=16384;
-			strcpy(v->name, "Radio");
-			return 0;
-		}
-		case VIDIOCSAUDIO:
-		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			az->curvol=v->volume;
+			struct v4l2_frequency *f = arg;
 
-			az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				az_setvol(az,0);
-			else
-				az_setvol(az,az->curvol);
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = az->curfreq;
+
 			return 0;
 		}
+
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (az->curvol==0)
+						ctrl->value=1;
+					else
+						ctrl->value=0;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=az->curvol * 6554;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						az_setvol(az,0);
+					} else {
+						az_setvol(az,az->curvol);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					az_setvol(az,ctrl->value);
+					return (0);
+			}
+			return -EINVAL;
+		}
+
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  az_do_ioctl);
 	}
 }
 
@@ -266,7 +328,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "Aztech radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_AZTECH,
+	.hardware	= 0,
 	.fops           = &aztech_fops,
 };
 
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8641aec..69d4b79 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -25,20 +25,28 @@
  *
  * 2003-01-31	Alan Cox <alan@redhat.com>
  *		Cleaned up locking, delay code, general odds and ends
+ *
+ * 2006-07-30	Hans J. Koch <koch@hjk-az.de>
+ *		Changed API to V4L2
  */
 
+#include <linux/version.h>
 #include <linux/module.h>	/* Modules 			*/
 #include <linux/init.h>		/* Initdata			*/
 #include <linux/ioport.h>	/* request_region		*/
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* V4L2 API defs		*/
 #include <media/v4l2-common.h>
 #include <linux/param.h>
 #include <linux/pnp.h>
 
 #define RDS_BUFFER 256
+#define RDS_RX_FLAG 1
+#define MBS_RX_FLAG 2
+
+#define CADET_VERSION KERNEL_VERSION(0,3,3)
 
 static int io=-1;		/* default to isapnp activation */
 static int radio_nr = -1;
@@ -61,44 +69,24 @@
  */
 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
 
-static int cadet_getrds(void)
+
+static int
+cadet_getstereo(void)
 {
-	int rdsstat=0;
-
-	spin_lock(&cadet_io_lock);
-	outb(3,io);                 /* Select Decoder Control/Status */
-	outb(inb(io+1)&0x7f,io+1);  /* Reset RDS detection */
-	spin_unlock(&cadet_io_lock);
-
-	msleep(100);
-
-	spin_lock(&cadet_io_lock);
-	outb(3,io);                 /* Select Decoder Control/Status */
-	if((inb(io+1)&0x80)!=0) {
-		rdsstat|=VIDEO_TUNER_RDS_ON;
-	}
-	if((inb(io+1)&0x10)!=0) {
-		rdsstat|=VIDEO_TUNER_MBS_ON;
-	}
-	spin_unlock(&cadet_io_lock);
-	return rdsstat;
-}
-
-static int cadet_getstereo(void)
-{
-	int ret = 0;
+	int ret = V4L2_TUNER_SUB_MONO;
 	if(curtuner != 0)	/* Only FM has stereo capability! */
-		return 0;
+		return V4L2_TUNER_SUB_MONO;
 
 	spin_lock(&cadet_io_lock);
 	outb(7,io);          /* Select tuner control */
 	if( (inb(io+1) & 0x40) == 0)
-		ret = 1;
+		ret = V4L2_TUNER_SUB_STEREO;
 	spin_unlock(&cadet_io_lock);
 	return ret;
 }
 
-static unsigned cadet_gettune(void)
+static unsigned
+cadet_gettune(void)
 {
 	int curvol,i;
 	unsigned fifo=0;
@@ -135,7 +123,8 @@
 	return fifo;
 }
 
-static unsigned cadet_getfreq(void)
+static unsigned
+cadet_getfreq(void)
 {
 	int i;
 	unsigned freq=0,test,fifo=0;
@@ -167,7 +156,8 @@
 	return freq;
 }
 
-static void cadet_settune(unsigned fifo)
+static void
+cadet_settune(unsigned fifo)
 {
 	int i;
 	unsigned test;
@@ -195,7 +185,8 @@
 	spin_unlock(&cadet_io_lock);
 }
 
-static void cadet_setfreq(unsigned freq)
+static void
+cadet_setfreq(unsigned freq)
 {
 	unsigned fifo;
 	int i,j,test;
@@ -255,7 +246,8 @@
 }
 
 
-static int cadet_getvol(void)
+static int
+cadet_getvol(void)
 {
 	int ret = 0;
 
@@ -270,7 +262,8 @@
 }
 
 
-static void cadet_setvol(int vol)
+static void
+cadet_setvol(int vol)
 {
 	spin_lock(&cadet_io_lock);
 	outb(7,io);                /* Select tuner control */
@@ -281,7 +274,8 @@
 	spin_unlock(&cadet_io_lock);
 }
 
-static void cadet_handler(unsigned long data)
+static void
+cadet_handler(unsigned long data)
 {
 	/*
 	 * Service the RDS fifo
@@ -322,8 +316,8 @@
 
 
 
-static ssize_t cadet_read(struct file *file, char __user *data,
-			  size_t count, loff_t *ppos)
+static ssize_t
+cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
 	int i=0;
 	unsigned char readbuf[RDS_BUFFER];
@@ -359,128 +353,156 @@
 {
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=2;
-			v->audios=1;
-			strcpy(v->name, "ADS Cadet");
+			struct v4l2_capability *cap = arg;
+			memset(cap,0,sizeof(*cap));
+			cap->capabilities =
+				V4L2_CAP_TUNER |
+				V4L2_CAP_READWRITE;
+			cap->version = CADET_VERSION;
+			strcpy(cap->driver, "ADS Cadet");
+			strcpy(cap->card, "ADS Cadet");
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if((v->tuner<0)||(v->tuner>1)) {
+			struct v4l2_tuner *t = arg;
+			memset(t,0,sizeof(*t));
+			t->type = V4L2_TUNER_RADIO;
+			switch (t->index)
+			{
+				case 0: strcpy(t->name, "FM");
+					t->capability = V4L2_TUNER_CAP_STEREO;
+					t->rangelow = 1400;     /* 87.5 MHz */
+					t->rangehigh = 1728;    /* 108.0 MHz */
+					t->rxsubchans=cadet_getstereo();
+					switch (t->rxsubchans){
+						case V4L2_TUNER_SUB_MONO:
+							t->audmode = V4L2_TUNER_MODE_MONO;
+							break;
+						case V4L2_TUNER_SUB_STEREO:
+							t->audmode = V4L2_TUNER_MODE_STEREO;
+							break;
+						default: ;
+					}
+					break;
+				case 1: strcpy(t->name, "AM");
+					t->capability = V4L2_TUNER_CAP_LOW;
+					t->rangelow = 8320;      /* 520 kHz */
+					t->rangehigh = 26400;    /* 1650 kHz */
+					t->rxsubchans = V4L2_TUNER_SUB_MONO;
+					t->audmode = V4L2_TUNER_MODE_MONO;
+					break;
+				default:
+					return -EINVAL;
+			}
+
+			t->signal = sigstrength; /* We might need to modify scaling of this */
+			return 0;
+		}
+		case VIDIOC_S_TUNER:
+		{
+			struct v4l2_tuner *t = arg;
+			if((t->index != 0)&&(t->index != 1))
+				return -EINVAL;
+
+			curtuner = t->index;
+			return 0;
+		}
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+			memset(f,0,sizeof(*f));
+			f->tuner = curtuner;
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = cadet_getfreq();
+			return 0;
+		}
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+			if (f->type != V4L2_TUNER_RADIO){
 				return -EINVAL;
 			}
-			switch(v->tuner) {
-				case 0:
-				strcpy(v->name,"FM");
-				v->rangelow=1400;     /* 87.5 MHz */
-				v->rangehigh=1728;    /* 108.0 MHz */
-				v->flags=0;
-				v->mode=0;
-				v->mode|=VIDEO_MODE_AUTO;
-				v->signal=sigstrength;
-				if(cadet_getstereo()==1) {
-					v->flags|=VIDEO_TUNER_STEREO_ON;
-				}
-				v->flags|=cadet_getrds();
-				break;
-				case 1:
-				strcpy(v->name,"AM");
-				v->rangelow=8320;      /* 520 kHz */
-				v->rangehigh=26400;    /* 1650 kHz */
-				v->flags=0;
-				v->flags|=VIDEO_TUNER_LOW;
-				v->mode=0;
-				v->mode|=VIDEO_MODE_AUTO;
-				v->signal=sigstrength;
-				break;
-			}
-			return 0;
-		}
-		case VIDIOCSTUNER:
-		{
-			struct video_tuner *v = arg;
-			if((v->tuner<0)||(v->tuner>1)) {
+			if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728))) {
 				return -EINVAL;
 			}
-			curtuner=v->tuner;
-			return 0;
-		}
-		case VIDIOCGFREQ:
-		{
-			unsigned long *freq = arg;
-			*freq = cadet_getfreq();
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
+			if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400))) {
 				return -EINVAL;
 			}
-			if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
-				return -EINVAL;
-			}
-			cadet_setfreq(*freq);
+			cadet_setfreq(f->frequency);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_CTRL:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			if(cadet_getstereo()==0) {
-				v->mode=VIDEO_SOUND_MONO;
-			} else {
-				v->mode=VIDEO_SOUND_STEREO;
+			struct v4l2_control *c = arg;
+			switch (c->id){
+				case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+					c->value = (cadet_getvol() == 0);
+					break;
+				case V4L2_CID_AUDIO_VOLUME:
+					c->value = cadet_getvol();
+					break;
+				default:
+					return -EINVAL;
 			}
-			v->volume=cadet_getvol();
-			v->step=0xffff;
-			strcpy(v->name, "Radio");
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_S_CTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			cadet_setvol(v->volume);
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				cadet_setvol(0);
-			else
-				cadet_setvol(0xffff);
+			struct v4l2_control *c = arg;
+			switch (c->id){
+				case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+					if (c->value) cadet_setvol(0);
+						else cadet_setvol(0xffff);
+					break;
+				case V4L2_CID_AUDIO_VOLUME:
+					cadet_setvol(c->value);
+					break;
+				default:
+					return -EINVAL;
+			}
 			return 0;
 		}
+
 		default:
 			return -ENOIOCTLCMD;
 	}
 }
 
-static int cadet_ioctl(struct inode *inode, struct file *file,
+static int
+cadet_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
 	return video_usercopy(inode, file, cmd, arg, cadet_do_ioctl);
 }
 
-static int cadet_open(struct inode *inode, struct file *file)
+static int
+cadet_open(struct inode *inode, struct file *file)
 {
-	if(users)
-		return -EBUSY;
 	users++;
-	init_waitqueue_head(&read_queue);
+	if (1 == users) init_waitqueue_head(&read_queue);
 	return 0;
 }
 
-static int cadet_release(struct inode *inode, struct file *file)
+static int
+cadet_release(struct inode *inode, struct file *file)
 {
-	del_timer_sync(&readtimer);
-	rdsstat=0;
 	users--;
+	if (0 == users){
+		del_timer_sync(&readtimer);
+		rdsstat=0;
+	}
+	return 0;
+}
+
+static unsigned int
+cadet_poll(struct file *file, struct poll_table_struct *wait)
+{
+	poll_wait(file,&read_queue,wait);
+	if(rdsin != rdsout)
+		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
@@ -491,6 +513,7 @@
 	.release       	= cadet_release,
 	.read		= cadet_read,
 	.ioctl		= cadet_ioctl,
+	.poll		= cadet_poll,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -500,7 +523,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "Cadet radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_CADET,
 	.fops           = &cadet_fops,
 };
 
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 4c82956..cfab57d 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -34,6 +34,8 @@
  *
  *     TODO: multiple device support and portability were not tested
  *
+ *     Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
  ***************************************************************************
  */
 
@@ -42,10 +44,32 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/errno.h>
 
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -183,91 +207,117 @@
 	struct gemtek_pci_card *card = dev->priv;
 
 	switch ( cmd ) {
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *c = arg;
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver));
+			strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
 
-			memset(c,0,sizeof(*c));
-			c->type = VID_TYPE_TUNER;
-			c->channels = 1;
-			c->audios = 1;
-			strcpy( c->name, "Gemtek PCI Radio" );
 			return 0;
 		}
-
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *t = arg;
+			struct v4l2_tuner *v = arg;
 
-			if ( t->tuner )
+			if (v->index > 0)
 				return -EINVAL;
 
-			t->rangelow = GEMTEK_PCI_RANGE_LOW;
-			t->rangehigh = GEMTEK_PCI_RANGE_HIGH;
-			t->flags = VIDEO_TUNER_LOW;
-			t->mode = VIDEO_MODE_AUTO;
-			t->signal = 0xFFFF * gemtek_pci_getsignal( card );
-			strcpy( t->name, "FM" );
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow = GEMTEK_PCI_RANGE_LOW;
+			v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xFFFF*gemtek_pci_getsignal( card );
+
 			return 0;
 		}
-
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *t = arg;
-			if ( t->tuner )
-				return -EINVAL;
-			return 0;
-		}
+			struct v4l2_tuner *v = arg;
 
-		case VIDIOCGFREQ:
-		{
-			unsigned long *freq = arg;
-			*freq = card->current_frequency;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-
-			if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
-			     (*freq > GEMTEK_PCI_RANGE_HIGH) )
+			if (v->index > 0)
 				return -EINVAL;
 
-			gemtek_pci_setfrequency( card, *freq );
-			card->current_frequency = *freq;
+			return 0;
+		}
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
+			     (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
+				return -EINVAL;
+
+
+			gemtek_pci_setfrequency( card, f->frequency );
+			card->current_frequency = f->frequency;
 			card->mute = FALSE;
-
 			return 0;
 		}
-
-		case VIDIOCGAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *a = arg;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
 
-			memset( a, 0, sizeof( *a ) );
-			a->flags |= VIDEO_AUDIO_MUTABLE;
-			a->volume = 1;
-			a->step = 65535;
-			strcpy( a->name, "Radio" );
-			return 0;
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
-
-		case VIDIOCSAUDIO:
+		case VIDIOC_G_CTRL:
 		{
-			struct video_audio *a = arg;
+			struct v4l2_control *ctrl= arg;
 
-			if ( a->audio )
-				return -EINVAL;
-
-			if ( a->flags & VIDEO_AUDIO_MUTE )
-				gemtek_pci_mute( card );
-			else
-				gemtek_pci_unmute( card );
-			return 0;
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=card->mute;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (card->mute)
+						ctrl->value=0;
+					else
+						ctrl->value=65535;
+					return (0);
+			}
+			return -EINVAL;
 		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
 
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						gemtek_pci_mute(card);
+					} else {
+						gemtek_pci_unmute(card);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (ctrl->value) {
+						gemtek_pci_unmute(card);
+					} else {
+						gemtek_pci_mute(card);
+					}
+					return (0);
+			}
+			return -EINVAL;
+		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  gemtek_pci_do_ioctl);
 	}
 }
 
@@ -309,7 +359,7 @@
 	.owner         = THIS_MODULE,
 	.name          = "Gemtek PCI Radio",
 	.type          = VID_TYPE_TUNER,
-	.hardware      = VID_HARDWARE_GEMTEK,
+	.hardware      = 0,
 	.fops          = &gemtek_pci_fops,
 };
 
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 162f37d..730fe16 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -13,6 +13,7 @@
  *
  * TODO: Allow for more than one of these foolish entities :-)
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -21,11 +22,32 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_GEMTEK_PORT 	*/
 #include <linux/spinlock.h>
 
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 #ifndef CONFIG_RADIO_GEMTEK_PORT
 #define CONFIG_RADIO_GEMTEK_PORT -1
 #endif
@@ -147,77 +169,122 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "GemTek");
+			strlcpy(v->driver, "radio-gemtek", sizeof (v->driver));
+			strlcpy(v->card, "GemTek", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			v->rangelow=87*16000;
-			v->rangehigh=108*16000;
-			v->flags=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			v->signal=0xFFFF*gemtek_getsigstr(rt);
+
+			memset(v,0,sizeof(*v));
 			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow=(87*16000);
+			v->rangehigh=(108*16000);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xFFFF*gemtek_getsigstr(rt);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = rt->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			rt->curfreq = *freq;
+			struct v4l2_frequency *f = arg;
+
+			rt->curfreq = f->frequency;
 			/* needs to be called twice in order for getsigstr to work */
 			gemtek_setfreq(rt, rt->curfreq);
 			gemtek_setfreq(rt, rt->curfreq);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags|=VIDEO_AUDIO_MUTABLE;
-			v->volume=1;
-			v->step=65535;
-			strcpy(v->name, "Radio");
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = rt->curfreq;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
 
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				gemtek_mute(rt);
-			else
-				gemtek_unmute(rt);
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
 
-			return 0;
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=rt->muted;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (rt->muted)
+						ctrl->value=0;
+					else
+						ctrl->value=65535;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						gemtek_mute(rt);
+					} else {
+						gemtek_unmute(rt);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (ctrl->value) {
+						gemtek_unmute(rt);
+					} else {
+						gemtek_mute(rt);
+					}
+					return (0);
+			}
+			return -EINVAL;
 		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  gemtek_do_ioctl);
 	}
 }
 
@@ -243,7 +310,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "GemTek radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_GEMTEK,
+	.hardware	= 0,
 	.fops           = &gemtek_fops,
 };
 
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index fcfa6c9..e8ce5f7 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -14,6 +14,8 @@
  *  version 0.04
  * + code improvements
  * + VIDEO_TUNER_LOW is permanent
+ *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>
@@ -25,10 +27,23 @@
 #include <asm/uaccess.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 
-#define DRIVER_VERSION	"0.05"
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,6)
+#define DRIVER_VERSION	"0.06"
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
 
 #define GPIO_DATA	0x60   /* port offset from ESS_IO_BASE */
 
@@ -96,7 +111,7 @@
 static struct video_device maestro_radio = {
 	.name		= "Maestro radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_SF16MI,
+	.hardware	= 0,
 	.fops		= &maestro_fops,
 };
 
@@ -130,7 +145,7 @@
 		rdata = inw(io);
 		if(!l)
 			dev->stereo =  rdata & STR_MOST ?
-			0 : VIDEO_TUNER_STEREO_ON;
+			0 : 1;
 		else
 			if(rdata & STR_DATA)
 				data++;
@@ -183,72 +198,120 @@
 	struct radio_device *card = video_get_drvdata(dev);
 
 	switch (cmd) {
-	case VIDIOCGCAP: {
-		struct video_capability *v = arg;
-		memset(v, 0, sizeof(*v));
-		strcpy(v->name, "Maestro radio");
-		v->type = VID_TYPE_TUNER;
-		v->channels = v->audios = 1;
-		return 0;
-	} case VIDIOCGTUNER: {
-		struct video_tuner *v = arg;
-		if (v->tuner)
-			return -EINVAL;
-		(void)radio_bits_get(card);
-		v->flags = VIDEO_TUNER_LOW | card->stereo;
-		v->signal = card->tuned;
-		strcpy(v->name, "FM");
-		v->rangelow = FREQ_LO;
-		v->rangehigh = FREQ_HI;
-		v->mode = VIDEO_MODE_AUTO;
-		return 0;
-	} case VIDIOCSTUNER: {
-		struct video_tuner *v = arg;
-		if (v->tuner != 0)
-			return -EINVAL;
-		return 0;
-	} case VIDIOCGFREQ: {
-		unsigned long *freq = arg;
-		*freq = BITS2FREQ(radio_bits_get(card));
-		return 0;
-	} case VIDIOCSFREQ: {
-		unsigned long *freq = arg;
-		if (*freq < FREQ_LO || *freq > FREQ_HI)
-			return -EINVAL;
-		radio_bits_set(card, FREQ2BITS(*freq));
-		return 0;
-	} case VIDIOCGAUDIO: {
-		struct video_audio *v = arg;
-		memset(v, 0, sizeof(*v));
-		strcpy(v->name, "Radio");
-		v->flags = VIDEO_AUDIO_MUTABLE | card->muted;
-		v->mode = VIDEO_SOUND_STEREO;
-		return 0;
-	} case VIDIOCSAUDIO: {
-		struct video_audio *v = arg;
-		if (v->audio)
-			return -EINVAL;
+		case VIDIOC_QUERYCAP:
 		{
-			register u16 io = card->io;
-			register u16 omask = inw(io + IO_MASK);
-			outw(~STR_WREN, io + IO_MASK);
-			outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ?
-				STR_WREN : 0, io);
-			udelay(4);
-			outw(omask, io + IO_MASK);
-			msleep(125);
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "radio-maestro", sizeof (v->driver));
+			strlcpy(v->card, "Maestro Radio", sizeof (v->card));
+			sprintf(v->bus_info,"PCI");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-	} case VIDIOCGUNIT: {
-		struct video_unit *v = arg;
-		v->video = VIDEO_NO_UNIT;
-		v->vbi = VIDEO_NO_UNIT;
-		v->radio = dev->minor;
-		v->audio = 0;
-		v->teletext = VIDEO_NO_UNIT;
-		return 0;
-	} default:
-		return -ENOIOCTLCMD;
+		case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
+
+			(void)radio_bits_get(card);
+
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow = FREQ_LO;
+			v->rangehigh = FREQ_HI;
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			if(card->stereo)
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=card->tuned;
+
+			return 0;
+		}
+		case VIDIOC_S_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
+
+			return 0;
+		}
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+				return -EINVAL;
+			radio_bits_set(card, FREQ2BITS(f->frequency));
+
+			return 0;
+		}
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = BITS2FREQ(radio_bits_get(card));
+
+			return 0;
+		}
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=card->muted;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+				{
+					register u16 io = card->io;
+					register u16 omask = inw(io + IO_MASK);
+					outw(~STR_WREN, io + IO_MASK);
+					outw((card->muted = ctrl->value ) ?
+						STR_WREN : 0, io);
+					udelay(4);
+					outw(omask, io + IO_MASK);
+					msleep(125);
+
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		default:
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  radio_function);
 	}
 }
 
@@ -275,7 +338,7 @@
 	omask = inw(io + IO_MASK);
 	odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
 	outw(odir & ~STR_WREN, io + IO_DIR);
-	dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE;
+	dev->muted = inw(io) & STR_WREN ? 0 : 1;
 	outw(odir, io + IO_DIR);
 	outw(~(STR_WREN | STR_CLK), io + IO_MASK);
 	outw(dev->muted ? 0 : STR_WREN, io);
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f93d7af..c2eeae7 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -20,13 +20,14 @@
  *   0.75b
  *     - better pci interface thanks to Francois Romieu <romieu@cogenit.fr>
  *
- *   0.75
+ *   0.75      Sun Feb  4 22:51:27 EET 2001
  *     - tiding up
  *     - removed support for multiple devices as it didn't work anyway
  *
  * BUGS:
  *   - card unmutes if you change frequency
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 
@@ -40,11 +41,24 @@
 #include <linux/mutex.h>
 
 #include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 
-/* version 0.75      Sun Feb  4 22:51:27 EET 2001 */
-#define DRIVER_VERSION	"0.75"
+#define DRIVER_VERSION	"0.76"
+
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,7,6)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
 
 #ifndef PCI_VENDOR_ID_GUILLEMOT
 #define PCI_VENDOR_ID_GUILLEMOT 0x5046
@@ -90,7 +104,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "Maxi Radio FM2000 radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_SF16MI,
 	.fops           = &maxiradio_fops,
 };
 
@@ -176,89 +189,116 @@
 	struct radio_device *card=dev->priv;
 
 	switch(cmd) {
-		case VIDIOCGCAP: {
-			struct video_capability *v = arg;
+		case VIDIOC_QUERYCAP:
+		{
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+			strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
+			return 0;
+		}
+		case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
 
 			memset(v,0,sizeof(*v));
-			strcpy(v->name, "Maxi Radio FM2000 radio");
-			v->type=VID_TYPE_TUNER;
-			v->channels=v->audios=1;
-			return 0;
-		}
-		case VIDIOCGTUNER: {
-			struct video_tuner *v = arg;
-
-			if(v->tuner)
-				return -EINVAL;
-
-			card->stereo = 0xffff * get_stereo(card->io);
-			card->tuned = 0xffff * get_tune(card->io);
-
-			v->flags = VIDEO_TUNER_LOW | card->stereo;
-			v->signal = card->tuned;
-
 			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
 
-			v->rangelow = FREQ_LO;
-			v->rangehigh = FREQ_HI;
-			v->mode = VIDEO_MODE_AUTO;
+			v->rangelow=FREQ_LO;
+			v->rangehigh=FREQ_HI;
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			if(get_stereo(card->io))
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xffff*get_tune(card->io);
 
 			return 0;
 		}
-		case VIDIOCSTUNER: {
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+		case VIDIOC_S_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
+
 			return 0;
 		}
-		case VIDIOCGFREQ: {
-			unsigned long *freq = arg;
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
 
-			*freq = card->freq;
-			return 0;
-		}
-		case VIDIOCSFREQ: {
-			unsigned long *freq = arg;
-
-			if (*freq < FREQ_LO || *freq > FREQ_HI)
+			if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 				return -EINVAL;
-			card->freq = *freq;
+
+			card->freq = f->frequency;
 			set_freq(card->io, FREQ2BITS(card->freq));
 			msleep(125);
 			return 0;
 		}
-		case VIDIOCGAUDIO: {
-			struct video_audio *v = arg;
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "Radio");
-			v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
-			v->mode=VIDEO_SOUND_STEREO;
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = card->freq;
+
 			return 0;
 		}
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
 
-		case VIDIOCSAUDIO: {
-			struct video_audio *v = arg;
-
-			if(v->audio)
-				return -EINVAL;
-			card->muted = v->flags & VIDEO_AUDIO_MUTE;
-			if(card->muted)
-				turn_power(card->io, 0);
-			else
-				set_freq(card->io, FREQ2BITS(card->freq));
-			return 0;
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
-		case VIDIOCGUNIT: {
-			struct video_unit *v = arg;
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
 
-			v->video=VIDEO_NO_UNIT;
-			v->vbi=VIDEO_NO_UNIT;
-			v->radio=dev->minor;
-			v->audio=0;
-			v->teletext=VIDEO_NO_UNIT;
-			return 0;
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=card->muted;
+					return (0);
+			}
+			return -EINVAL;
 		}
-		default: return -ENOIOCTLCMD;
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					card->muted = ctrl->value;
+					if(card->muted)
+						turn_power(card->io, 0);
+					else
+						set_freq(card->io, FREQ2BITS(card->freq));
+					return 0;
+			}
+			return -EINVAL;
+		}
+
+		default:
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  radio_function);
+
 	}
 }
 
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 5b68ac4..b9e9848 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -6,6 +6,7 @@
  *
  * TODO: Allow for more than one of these foolish entities :-)
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -14,11 +15,32 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_RTRACK2_PORT 	*/
 #include <linux/spinlock.h>
 
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 65535,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
 #endif
@@ -115,75 +137,120 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "RadioTrack II");
+			strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver));
+			strlcpy(v->card, "RadioTrack II", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			v->rangelow=88*16000;
-			v->rangehigh=108*16000;
-			v->flags=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			v->signal=0xFFFF*rt_getsigstr(rt);
+
+			memset(v,0,sizeof(*v));
 			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow=(88*16000);
+			v->rangehigh=(108*16000);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xFFFF*rt_getsigstr(rt);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = rt->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			rt->curfreq = *freq;
+			struct v4l2_frequency *f = arg;
+
+			rt->curfreq = f->frequency;
 			rt_setfreq(rt, rt->curfreq);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags|=VIDEO_AUDIO_MUTABLE;
-			v->volume=1;
-			v->step=65535;
-			strcpy(v->name, "Radio");
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = rt->curfreq;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
 
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				rt_mute(rt);
-			else
-				rt_unmute(rt);
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
 
-			return 0;
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=rt->muted;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (rt->muted)
+						ctrl->value=0;
+					else
+						ctrl->value=65535;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						rt_mute(rt);
+					} else {
+						rt_unmute(rt);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					if (ctrl->value) {
+						rt_unmute(rt);
+					} else {
+						rt_mute(rt);
+					}
+					return (0);
+			}
+			return -EINVAL;
 		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  rt_do_ioctl);
 	}
 }
 
@@ -209,7 +276,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "RadioTrack II radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_RTRACK2,
+	.hardware	= 0,
 	.fops           = &rtrack2_fops,
 };
 
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index efee6e3..ecc854b 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -13,20 +13,35 @@
  *  No volume control - only mute/unmute - you have to use line volume
  *  control on SB-part of SF16FMI
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
+#include <linux/version.h>
 #include <linux/kernel.h>	/* __setup			*/
 #include <linux/module.h>	/* Modules 			*/
 #include <linux/init.h>		/* Initdata			*/
 #include <linux/ioport.h>	/* request_region		*/
 #include <linux/delay.h>	/* udelay			*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
 #include <linux/isapnp.h>
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/mutex.h>
 
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	}
+};
+
 struct fmi_device
 {
 	int port;
@@ -123,93 +138,122 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			strcpy(v->name, "SF16-FMx radio");
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
+			strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver));
+			strlcpy(v->card, "SF16-FMx radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
+			struct v4l2_tuner *v = arg;
 			int mult;
 
-			if(v->tuner)	/* Only 1 tuner */
+			if (v->index > 0)
 				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
 			strcpy(v->name, "FM");
-			mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v->type = V4L2_TUNER_RADIO;
+
+			mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
 			v->rangelow = RSF16_MINFREQ/mult;
 			v->rangehigh = RSF16_MAXFREQ/mult;
-			v->flags=fmi->flags;
-			v->mode=VIDEO_MODE_AUTO;
+			v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+			v->capability=fmi->flags&V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_STEREO;
 			v->signal = fmi_getsigstr(fmi);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			fmi->flags = v->flags & VIDEO_TUNER_LOW;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = fmi->curfreq;
-			if (!(fmi->flags & VIDEO_TUNER_LOW))
-			    *freq /= 1000;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			if (!(fmi->flags & VIDEO_TUNER_LOW))
-				*freq *= 1000;
-			if (*freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
+			struct v4l2_frequency *f = arg;
+
+			if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+				f->frequency *= 1000;
+			if (f->frequency < RSF16_MINFREQ ||
+					f->frequency > RSF16_MAXFREQ )
 				return -EINVAL;
 			/*rounding in steps of 800 to match th freq
 			  that will be used */
-			fmi->curfreq = (*freq/800)*800;
+			fmi->curfreq = (f->frequency/800)*800;
 			fmi_setfreq(fmi);
+
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0,sizeof(*v));
-			v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
-			strcpy(v->name, "Radio");
-			v->mode=VIDEO_SOUND_STEREO;
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = fmi->curfreq;
+			if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+				f->frequency /= 1000;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
-			fmi->curvol ?
-				fmi_unmute(fmi->port) : fmi_mute(fmi->port);
-			return 0;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
-		case VIDIOCGUNIT:
+		case VIDIOC_G_CTRL:
 		{
-			struct video_unit *v = arg;
-			v->video=VIDEO_NO_UNIT;
-			v->vbi=VIDEO_NO_UNIT;
-			v->radio=dev->minor;
-			v->audio=0; /* How do we find out this??? */
-			v->teletext=VIDEO_NO_UNIT;
-			return 0;
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=fmi->curvol;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+				{
+					if (ctrl->value)
+						fmi_mute(fmi->port);
+					else
+						fmi_unmute(fmi->port);
+
+					fmi->curvol=ctrl->value;
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  fmi_do_ioctl);
 	}
 }
 
@@ -235,7 +279,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "SF16FMx radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_SF16MI,
+	.hardware	= 0,
 	.fops           = &fmi_fops,
 };
 
@@ -294,7 +338,7 @@
 	fmi_unit.port = io;
 	fmi_unit.curvol = 0;
 	fmi_unit.curfreq = 0;
-	fmi_unit.flags = VIDEO_TUNER_LOW;
+	fmi_unit.flags = V4L2_TUNER_CAP_LOW;
 	fmi_radio.priv = &fmi_unit;
 
 	mutex_init(&lock);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 3483b2c..4444dce 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -10,6 +10,8 @@
  *  For read stereo/mono you must wait 0.1 sec after set frequency and
  *  card unmuted so I set frequency on unmute
  *  Signal handling seem to work only on autoscanning (not implemented)
+ *
+ *  Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -18,12 +20,34 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 static struct mutex lock;
 
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 1<<12,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 #undef DEBUG
 //#define DEBUG 1
 
@@ -214,63 +238,65 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			strcpy(v->name, "SF16-FMR2 radio");
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
+			strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver));
+			strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
+			struct v4l2_tuner *v = arg;
 			int mult;
 
-			if(v->tuner)     /* Only 1 tuner */
+			if (v->index > 0)
 				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
 			strcpy(v->name, "FM");
-			mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v->type = V4L2_TUNER_RADIO;
+
+			mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
 			v->rangelow = RSF16_MINFREQ/mult;
 			v->rangehigh = RSF16_MAXFREQ/mult;
-			v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
-			if (fmr2->mute)
-				v->flags |= VIDEO_AUDIO_MUTE;
-			v->mode=VIDEO_MODE_AUTO;
+			v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+			v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW;
+
+			v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
+						    V4L2_TUNER_MODE_MONO;
 			mutex_lock(&lock);
 			v->signal = fmr2_getsigstr(fmr2);
 			mutex_unlock(&lock);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if (v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			fmr2->flags = v->flags & VIDEO_TUNER_LOW;
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = fmr2->curfreq;
-			if (!(fmr2->flags & VIDEO_TUNER_LOW))
-				*freq /= 1000;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			if (!(fmr2->flags & VIDEO_TUNER_LOW))
-				*freq *= 1000;
-			if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
+			struct v4l2_frequency *f = arg;
+
+			if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+				f->frequency *= 1000;
+			if (f->frequency < RSF16_MINFREQ ||
+					f->frequency > RSF16_MAXFREQ )
 				return -EINVAL;
-			/* rounding in steps of 200 to match th freq
-			 * that will be used
-			 */
-			fmr2->curfreq = (*freq/200)*200;
+			/*rounding in steps of 200 to match th freq
+			  that will be used */
+			fmr2->curfreq = (f->frequency/200)*200;
 
 			/* set card freq (if not muted) */
 			if (fmr2->curvol && !fmr2->mute)
@@ -279,40 +305,81 @@
 				fmr2_setfreq(fmr2);
 				mutex_unlock(&lock);
 			}
+
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0,sizeof(*v));
-			/* !!! do not return VIDEO_AUDIO_MUTE */
-			v->flags = VIDEO_AUDIO_MUTABLE;
-			strcpy(v->name, "Radio");
-			/* get current stereo mode */
-			v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
-			/* volume supported ? */
-			if (fmr2->card_type == 11)
-			{
-				v->flags |= VIDEO_AUDIO_VOLUME;
-				v->step = 1 << 12;
-				v->volume = fmr2->curvol;
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = fmr2->curfreq;
+			if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+				f->frequency /= 1000;
+
+			return 0;
+		}
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if ((fmr2->card_type != 11)
+						&& V4L2_CID_AUDIO_VOLUME)
+					radio_qctrl[i].step=65535;
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
 			}
-			debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume));
-			return 0;
+			return -EINVAL;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_G_CTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume));
-			/* set volume */
-			if (v->flags & VIDEO_AUDIO_VOLUME)
-				fmr2->curvol = v->volume; /* !!! set with precision */
-			if (fmr2->card_type != 11) fmr2->curvol = 65535;
-			fmr2->mute = 0;
-			if (v->flags & VIDEO_AUDIO_MUTE)
-				fmr2->mute = 1;
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=fmr2->mute;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=fmr2->curvol;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					fmr2->mute=ctrl->value;
+					if (fmr2->card_type != 11) {
+						if (!fmr2->mute) {
+							fmr2->curvol = 65535;
+						} else {
+							fmr2->curvol = 0;
+						}
+					}
+					break;
+				case V4L2_CID_AUDIO_VOLUME:
+					fmr2->curvol = ctrl->value;
+					if (fmr2->card_type != 11) {
+						if (fmr2->curvol) {
+							fmr2->curvol = 65535;
+							fmr2->mute = 0;
+						} else {
+							fmr2->curvol = 0;
+							fmr2->mute = 1;
+						}
+					}
+					break;
+				default:
+					return -EINVAL;
+			}
 #ifdef DEBUG
 			if (fmr2->curvol && !fmr2->mute)
 				printk(KERN_DEBUG "unmute\n");
@@ -320,27 +387,18 @@
 				printk(KERN_DEBUG "mute\n");
 #endif
 			mutex_lock(&lock);
-			if (fmr2->curvol && !fmr2->mute)
-			{
+			if (fmr2->curvol && !fmr2->mute) {
 				fmr2_setvolume(fmr2);
 				fmr2_setfreq(fmr2);
-			}
-			else fmr2_mute(fmr2->port);
+			} else
+				fmr2_mute(fmr2->port);
 			mutex_unlock(&lock);
-			return 0;
-		}
-		case VIDIOCGUNIT:
-		{
-			struct video_unit *v = arg;
-			v->video=VIDEO_NO_UNIT;
-			v->vbi=VIDEO_NO_UNIT;
-			v->radio=dev->minor;
-			v->audio=0; /* How do we find out this??? */
-			v->teletext=VIDEO_NO_UNIT;
-			return 0;
+			return (0);
 		}
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  fmr2_do_ioctl);
+
 	}
 }
 
@@ -366,7 +424,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "SF16FMR2 radio",
 	. type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_SF16FMR2,
+	.hardware	= 0,
 	.fops		= &fmr2_fops,
 };
 
@@ -377,7 +435,7 @@
 	fmr2_unit.mute = 0;
 	fmr2_unit.curfreq = 0;
 	fmr2_unit.stereo = 1;
-	fmr2_unit.flags = VIDEO_TUNER_LOW;
+	fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
 	fmr2_unit.card_type = 0;
 	fmr2_radio.priv = &fmr2_unit;
 
@@ -396,7 +454,6 @@
 	}
 
 	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
-	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
 	/* mute card - prevents noisy bootups */
 	mutex_lock(&lock);
 	fmr2_mute(io);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index dfba4ae..f539491 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -21,6 +21,7 @@
  *  If you can help me out with that, please contact me!!
  *
  *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -29,11 +30,32 @@
 #include <linux/delay.h>	/* udelay			*/
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
-#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/videodev2.h>	/* kernel radio structs		*/
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_TERRATEC_PORT 	*/
 #include <linux/spinlock.h>
 
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 0xff,
+		.step          = 1,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 #ifndef CONFIG_RADIO_TERRATEC_PORT
 #define CONFIG_RADIO_TERRATEC_PORT 0x590
 #endif
@@ -194,73 +216,117 @@
 
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "ActiveRadio");
+			strlcpy(v->driver, "radio-terratec", sizeof (v->driver));
+			strlcpy(v->card, "ActiveRadio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-		case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
+
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
-			v->flags=VIDEO_TUNER_LOW;
-			v->mode=VIDEO_MODE_AUTO;
-			strcpy(v->name, "FM");
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
 			v->signal=0xFFFF*tt_getsigstr(tt);
+
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner!=0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-		case VIDIOCGFREQ:
+		case VIDIOC_S_FREQUENCY:
 		{
-			unsigned long *freq = arg;
-			*freq = tt->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			tt->curfreq = *freq;
+			struct v4l2_frequency *f = arg;
+
+			tt->curfreq = f->frequency;
 			tt_setfreq(tt, tt->curfreq);
 			return 0;
 		}
-		case VIDIOCGAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v,0, sizeof(*v));
-			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			v->volume=tt->curvol * 6554;
-			v->step=6554;
-			strcpy(v->name, "Radio");
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = tt->curfreq;
+
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_QUERYCTRL:
 		{
-			struct video_audio *v = arg;
-			if(v->audio)
-				return -EINVAL;
-			if(v->flags&VIDEO_AUDIO_MUTE)
-				tt_mute(tt);
-			else
-				tt_setvol(tt,v->volume/6554);
-			return 0;
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
 		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (tt->muted)
+						ctrl->value=1;
+					else
+						ctrl->value=0;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=tt->curvol * 6554;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						tt_mute(tt);
+					} else {
+						tt_setvol(tt,tt->curvol);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					tt_setvol(tt,ctrl->value);
+					return (0);
+			}
+			return -EINVAL;
+		}
+
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  tt_do_ioctl);
 	}
 }
 
@@ -286,7 +352,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "TerraTec ActiveRadio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_TERRATEC,
+	.hardware	= 0,
 	.fops           = &terratec_fops,
 };
 
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 8da4bad..bb03ad5 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -12,7 +12,7 @@
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <stdarg.h>
@@ -21,9 +21,46 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_TRUST_PORT 	*/
+
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 2048,
+		.default_value = 65535,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_BASS,
+		.name          = "Bass",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 4370,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},{
+		.id            = V4L2_CID_AUDIO_TREBLE,
+		.name          = "Treble",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 4370,
+		.default_value = 32768,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	},
+};
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -160,88 +197,125 @@
 {
 	switch(cmd)
 	{
-		case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "radio-trust", sizeof (v->driver));
+			strlcpy(v->card, "Trust FM Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
+			return 0;
+		}
+		case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
 
 			memset(v,0,sizeof(*v));
-			v->type=VID_TYPE_TUNER;
-			v->channels=1;
-			v->audios=1;
-			strcpy(v->name, "Trust FM Radio");
-
-			return 0;
-		}
-		case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-
-			if(v->tuner)	/* Only 1 tuner */
-				return -EINVAL;
-
-			v->rangelow = 87500 * 16;
-			v->rangehigh = 108000 * 16;
-			v->flags = VIDEO_TUNER_LOW;
-			v->mode = VIDEO_MODE_AUTO;
-
-			v->signal = tr_getsigstr();
-			if(tr_getstereo())
-				v->flags |= VIDEO_TUNER_STEREO_ON;
-
 			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow=(87.5*16000);
+			v->rangehigh=(108*16000);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			if(tr_getstereo())
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=tr_getsigstr();
 
 			return 0;
 		}
-		case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if(v->tuner != 0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			return 0;
-		}
-		case VIDIOCGFREQ:
-		{
-			unsigned long *freq = arg;
-			*freq = curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ:
-		{
-			unsigned long *freq = arg;
-			tr_setfreq(*freq);
-			return 0;
-		}
-		case VIDIOCGAUDIO:
-		{
-			struct video_audio *v = arg;
 
-			memset(v,0, sizeof(*v));
-			v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
-				  VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
-			v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-			v->volume = curvol * 2048;
-			v->step = 2048;
-			v->bass = curbass * 4370;
-			v->treble = curtreble * 4370;
-
-			strcpy(v->name, "Trust FM Radio");
 			return 0;
 		}
-		case VIDIOCSAUDIO:
+		case VIDIOC_S_FREQUENCY:
 		{
-			struct video_audio *v = arg;
+			struct v4l2_frequency *f = arg;
 
-			if(v->audio)
-				return -EINVAL;
-			tr_setvol(v->volume);
-			tr_setbass(v->bass);
-			tr_settreble(v->treble);
-			tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
-			tr_setmute(v->flags & VIDEO_AUDIO_MUTE);
+			curfreq = f->frequency;
+			tr_setfreq(curfreq);
 			return 0;
 		}
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = curfreq;
+
+			return 0;
+		}
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=curmute;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value= curvol * 2048;
+					return (0);
+				case V4L2_CID_AUDIO_BASS:
+					ctrl->value= curbass * 4370;
+					return (0);
+				case V4L2_CID_AUDIO_TREBLE:
+					ctrl->value= curtreble * 4370;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					tr_setmute(ctrl->value);
+					return 0;
+				case V4L2_CID_AUDIO_VOLUME:
+					tr_setvol(ctrl->value);
+					return 0;
+				case V4L2_CID_AUDIO_BASS:
+					tr_setbass(ctrl->value);
+					return 0;
+				case V4L2_CID_AUDIO_TREBLE:
+					tr_settreble(ctrl->value);
+					return (0);
+			}
+			return -EINVAL;
+		}
+
 		default:
-			return -ENOIOCTLCMD;
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  tr_do_ioctl);
 	}
 }
 
@@ -265,7 +339,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "Trust FM Radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_TRUST,
+	.hardware	= 0,
 	.fops           = &trust_fops,
 };
 
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index edd0122..4a72b4d 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -27,6 +27,8 @@
  * value where I do expect just noise and turn the speaker volume down.
  * The frequency change is necessary since the card never seems to be
  * completely silent.
+ *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules                        */
@@ -35,11 +37,32 @@
 #include <linux/proc_fs.h>	/* radio card status report	  */
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
-#include <linux/videodev.h>	/* kernel radio structs           */
+#include <linux/videodev2.h>	/* kernel radio structs           */
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_TYPHOON_*         */
 
-#define BANNER "Typhoon Radio Card driver v0.1\n"
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,1,1)
+#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 1<<14,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
@@ -171,76 +194,114 @@
 	struct typhoon_device *typhoon = dev->priv;
 
 	switch (cmd) {
-	case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
 			memset(v,0,sizeof(*v));
-			v->type = VID_TYPE_TUNER;
-			v->channels = 1;
-			v->audios = 1;
-			strcpy(v->name, "Typhoon Radio");
+			strlcpy(v->driver, "radio-typhoon", sizeof (v->driver));
+			strlcpy(v->card, "Typhoon Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
 			return 0;
 		}
-	case VIDIOCGTUNER:
+		case VIDIOC_G_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if (v->tuner)	/* Only 1 tuner */
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			v->rangelow = 875 * 1600;
-			v->rangehigh = 1080 * 1600;
-			v->flags = VIDEO_TUNER_LOW;
-			v->mode = VIDEO_MODE_AUTO;
-			v->signal = 0xFFFF;	/* We can't get the signal strength */
+
+			memset(v,0,sizeof(*v));
 			strcpy(v->name, "FM");
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow=(87.5*16000);
+			v->rangehigh=(108*16000);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal = 0xFFFF;	/* We can't get the signal strength */
+
 			return 0;
 		}
-	case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if (v->tuner != 0)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
+
 			return 0;
 		}
-	case VIDIOCGFREQ:
-	{
-		unsigned long *freq = arg;
-		*freq = typhoon->curfreq;
-		return 0;
-	}
-	case VIDIOCSFREQ:
-	{
-		unsigned long *freq = arg;
-		typhoon->curfreq = *freq;
-		typhoon_setfreq(typhoon, typhoon->curfreq);
-		return 0;
-	}
-	case VIDIOCGAUDIO:
+		case VIDIOC_S_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			memset(v, 0, sizeof(*v));
-			v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
-			v->mode |= VIDEO_SOUND_MONO;
-			v->volume = typhoon->curvol;
-			v->step = 1 << 14;
-			strcpy(v->name, "Typhoon Radio");
+			struct v4l2_frequency *f = arg;
+
+			typhoon->curfreq = f->frequency;
+			typhoon_setfreq(typhoon, typhoon->curfreq);
 			return 0;
 		}
-	case VIDIOCSAUDIO:
+		case VIDIOC_G_FREQUENCY:
 		{
-			struct video_audio *v = arg;
-			if (v->audio)
-				return -EINVAL;
-			if (v->flags & VIDEO_AUDIO_MUTE)
-				typhoon_mute(typhoon);
-			else
-				typhoon_unmute(typhoon);
-			if (v->flags & VIDEO_AUDIO_VOLUME)
-				typhoon_setvol(typhoon, v->volume);
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = typhoon->curfreq;
+
 			return 0;
 		}
-	default:
-		return -ENOIOCTLCMD;
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=typhoon->muted;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=typhoon->curvol;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						typhoon_mute(typhoon);
+					} else {
+						typhoon_unmute(typhoon);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					typhoon_setvol(typhoon, ctrl->value);
+					return (0);
+			}
+			return -EINVAL;
+		}
+
+		default:
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  typhoon_do_ioctl);
 	}
 }
 
@@ -271,7 +332,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "Typhoon Radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_TYPHOON,
+	.hardware	= 0,
 	.fops           = &typhoon_fops,
 };
 
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 59b86a6..671fe1b 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -24,6 +24,9 @@
  *	      - Added unmute function
  *	      - Reworked ioctl functions
  * 2002-07-15 - Fix Stereo typo
+ *
+ * 2006-07-24 - Converted to V4L2 API
+ *		by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/module.h>	/* Modules                        */
@@ -32,9 +35,30 @@
 #include <linux/delay.h>	/* udelay, msleep                 */
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
-#include <linux/videodev.h>	/* kernel radio structs           */
+#include <linux/videodev2.h>	/* kernel radio structs           */
 #include <media/v4l2-common.h>
-#include <linux/config.h>	/* CONFIG_RADIO_ZOLTRIX_PORT      */
+
+#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id            = V4L2_CID_AUDIO_MUTE,
+		.name          = "Mute",
+		.minimum       = 0,
+		.maximum       = 1,
+		.default_value = 1,
+		.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	},{
+		.id            = V4L2_CID_AUDIO_VOLUME,
+		.name          = "Volume",
+		.minimum       = 0,
+		.maximum       = 65535,
+		.step          = 4096,
+		.default_value = 0xff,
+		.type          = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -213,78 +237,116 @@
 	struct zol_device *zol = dev->priv;
 
 	switch (cmd) {
-	case VIDIOCGCAP:
+		case VIDIOC_QUERYCAP:
 		{
-			struct video_capability *v = arg;
+			struct v4l2_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver));
+			strlcpy(v->card, "Zoltrix Radio", sizeof (v->card));
+			sprintf(v->bus_info,"ISA");
+			v->version = RADIO_VERSION;
+			v->capabilities = V4L2_CAP_TUNER;
+
+			return 0;
+		}
+		case VIDIOC_G_TUNER:
+		{
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
+				return -EINVAL;
 
 			memset(v,0,sizeof(*v));
-			v->type = VID_TYPE_TUNER;
-			v->channels = 1 + zol->stereo;
-			v->audios = 1;
-			strcpy(v->name, "Zoltrix Radio");
-			return 0;
-		}
-	case VIDIOCGTUNER:
-		{
-			struct video_tuner *v = arg;
-			if (v->tuner)
-				return -EINVAL;
 			strcpy(v->name, "FM");
-			v->rangelow = (int) (88.0 * 16000);
-			v->rangehigh = (int) (108.0 * 16000);
-			v->flags = zol_is_stereo(zol)
-					? VIDEO_TUNER_STEREO_ON : 0;
-			v->flags |= VIDEO_TUNER_LOW;
-			v->mode = VIDEO_MODE_AUTO;
-			v->signal = 0xFFFF * zol_getsigstr(zol);
+			v->type = V4L2_TUNER_RADIO;
+
+			v->rangelow=(88*16000);
+			v->rangehigh=(108*16000);
+			v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+			v->capability=V4L2_TUNER_CAP_LOW;
+			if(zol_is_stereo(zol))
+				v->audmode = V4L2_TUNER_MODE_STEREO;
+			else
+				v->audmode = V4L2_TUNER_MODE_MONO;
+			v->signal=0xFFFF*zol_getsigstr(zol);
+
 			return 0;
 		}
-	case VIDIOCSTUNER:
+		case VIDIOC_S_TUNER:
 		{
-			struct video_tuner *v = arg;
-			if (v->tuner != 0)
-				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
-			return 0;
-		}
-	case VIDIOCGFREQ:
-	{
-		unsigned long *freq = arg;
-		*freq = zol->curfreq;
-		return 0;
-	}
-	case VIDIOCSFREQ:
-	{
-		unsigned long *freq = arg;
-		zol->curfreq = *freq;
-		zol_setfreq(zol, zol->curfreq);
-		return 0;
-	}
-	case VIDIOCGAUDIO:
-		{
-			struct video_audio *v = arg;
-			memset(v, 0, sizeof(*v));
-			v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
-			v->mode |= zol_is_stereo(zol)
-				? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-			v->volume = zol->curvol * 4096;
-			v->step = 4096;
-			strcpy(v->name, "Zoltrix Radio");
-			return 0;
-		}
-	case VIDIOCSAUDIO:
-		{
-			struct video_audio *v = arg;
-			if (v->audio)
+			struct v4l2_tuner *v = arg;
+
+			if (v->index > 0)
 				return -EINVAL;
 
-			if (v->flags & VIDEO_AUDIO_MUTE)
-				zol_mute(zol);
-			else {
-				zol_unmute(zol);
-				zol_setvol(zol, v->volume / 4096);
+			return 0;
+		}
+		case VIDIOC_S_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			zol->curfreq = f->frequency;
+			zol_setfreq(zol, zol->curfreq);
+			return 0;
+		}
+		case VIDIOC_G_FREQUENCY:
+		{
+			struct v4l2_frequency *f = arg;
+
+			f->type = V4L2_TUNER_RADIO;
+			f->frequency = zol->curfreq;
+
+			return 0;
+		}
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *qc = arg;
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+				if (qc->id && qc->id == radio_qctrl[i].id) {
+					memcpy(qc, &(radio_qctrl[i]),
+								sizeof(*qc));
+					return (0);
+				}
 			}
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
 
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					ctrl->value=zol->muted;
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					ctrl->value=zol->curvol * 4096;
+					return (0);
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *ctrl= arg;
+
+			switch (ctrl->id) {
+				case V4L2_CID_AUDIO_MUTE:
+					if (ctrl->value) {
+						zol_mute(zol);
+					} else {
+						zol_unmute(zol);
+						zol_setvol(zol,zol->curvol);
+					}
+					return (0);
+				case V4L2_CID_AUDIO_VOLUME:
+					zol_setvol(zol,ctrl->value/4096);
+					return (0);
+			}
+			zol->stereo = 1;
+			zol_setfreq(zol, zol->curfreq);
+#if 0
+/* FIXME: Implement stereo/mono switch on V4L2 */
 			if (v->mode & VIDEO_SOUND_STEREO) {
 				zol->stereo = 1;
 				zol_setfreq(zol, zol->curfreq);
@@ -293,10 +355,13 @@
 				zol->stereo = 0;
 				zol_setfreq(zol, zol->curfreq);
 			}
-			return 0;
+#endif
+			return -EINVAL;
 		}
-	default:
-		return -ENOIOCTLCMD;
+
+		default:
+			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+							  zol_do_ioctl);
 	}
 }
 
@@ -323,7 +388,7 @@
 	.owner		= THIS_MODULE,
 	.name		= "Zoltrix Radio Plus",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= VID_HARDWARE_ZOLTRIX,
+	.hardware	= 0,
 	.fops           = &zoltrix_fops,
 };
 
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 94d078b..d1183c9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -16,6 +16,320 @@
 	  V4L devices.
 	  In doubt, say N.
 
+config VIDEO_HELPER_CHIPS_AUTO
+	bool "Autoselect pertinent encoders/decoders and other helper chips"
+	default y
+	---help---
+	  Most video cards may require additional modules to encode or
+	  decode audio/video standards. This option will autoselect
+	  all pertinent modules to each selected video module.
+
+	  Unselect this only if you know exaclty what you are doing, since
+	  it may break support on some boards.
+
+	  In doubt, say Y.
+
+#
+# Encoder / Decoder module configuration
+#
+
+menu "Encoders/decoders and other helper chips"
+	depends on VIDEO_DEV && !VIDEO_HELPER_CHIPS_AUTO
+
+comment "Audio Decoders"
+
+config VIDEO_TVAUDIO
+	tristate "Simple audio decoder chips"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for several audio decoder chips found on some bt8xx boards:
+	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
+		   tea6320, tea6420, tda8425, ta8874z.
+	  Microchip: pic16c54 based design on ProVideo PV951 board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvaudio.
+
+config VIDEO_TDA7432
+	tristate "Philips TDA7432 audio processor chip"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for tda7432 audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tda7432.
+
+config VIDEO_TDA9840
+	tristate "Philips TDA9840 audio processor chip"
+	depends on VIDEO_DEV && I2C
+	---help---
+	  Support for tda9840 audio decoder chip found on some Zoran boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tda9840.
+
+config VIDEO_TDA9875
+	tristate "Philips TDA9875 audio processor chip"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for tda9875 audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tda9875.
+
+config VIDEO_TEA6415C
+	tristate "Philips TEA6415C audio processor chip"
+	depends on VIDEO_DEV && I2C
+	---help---
+	  Support for tea6415c audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tea6415c.
+
+config VIDEO_TEA6420
+	tristate "Philips TEA6420 audio processor chip"
+	depends on VIDEO_DEV && I2C
+	---help---
+	  Support for tea6420 audio decoder chip found on some bt8xx boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tea6420.
+
+config VIDEO_MSP3400
+	tristate "Micronas MSP34xx audio decoders"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Micronas MSP34xx series of audio decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called msp3400.
+
+config VIDEO_CS53L32A
+	tristate "Cirrus Logic CS53L32A audio ADC"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Cirrus Logic CS53L32A low voltage
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs53l32a.
+
+config VIDEO_TLV320AIC23B
+	tristate "Texas Instruments TLV320AIC23B audio codec"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Texas Instruments TLV320AIC23B audio codec.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tlv320aic23b.
+
+config VIDEO_WM8775
+	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Wolfson Microelectronics WM8775 high
+	  performance stereo A/D Converter with a 4 channel input mixer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm8775.
+
+config VIDEO_WM8739
+	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Wolfson Microelectronics WM8739
+	  stereo A/D Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm8739.
+
+comment "MPEG video encoders"
+
+config VIDEO_CX2341X
+	tristate "Conexant CX2341x MPEG encoders"
+	depends on VIDEO_V4L2 && EXPERIMENTAL
+	---help---
+	  Support for the Conexant CX23416 MPEG encoders
+	  and CX23415 MPEG encoder/decoders.
+
+	  This module currently supports the encoding functions only.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx2341x.
+
+source "drivers/media/video/cx25840/Kconfig"
+
+comment "Video encoders"
+
+config VIDEO_SAA7127
+	tristate "Philips SAA7127/9 digital video encoders"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Philips SAA7127/9 digital video encoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7127.
+
+config VIDEO_SAA7185
+	tristate "Philips SAA7185 video encoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Philips SAA7185 video encoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7185.
+
+config VIDEO_ADV7170
+	tristate "Analog Devices ADV7170 video encoder driver"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Analog Devices ADV7170 video encoder driver
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7170.
+
+config VIDEO_ADV7175
+	tristate "Analog Devices ADV7175 video encoder driver"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Analog Devices ADV7175 video encoder driver
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7175.
+
+comment "Video decoders"
+
+config VIDEO_BT819
+	tristate "BT819A VideoStream Decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for BT819A video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt819.
+
+config VIDEO_BT856
+	tristate "BT856 VideoStream Decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for BT856 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt856.
+
+config VIDEO_BT866
+	tristate "BT866 VideoStream Decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for BT866 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bt866.
+
+config VIDEO_KS0127
+	tristate "KS0127 video decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for KS0127 video decoder.
+
+	  This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
+	  cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ks0127.
+
+config VIDEO_SAA7110
+	tristate "Philips SAA7110 video decoder"
+	depends on VIDEO_V4L1
+	---help---
+	  Support for the Philips SAA7110 video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7110.
+
+config VIDEO_SAA7111
+	tristate "Philips SAA7111 video decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Philips SAA711 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7111.
+
+config VIDEO_SAA7114
+	tristate "Philips SAA7114 video decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Philips SAA7114 video decoder. This driver
+	  is used only on Zoran driver and should be moved soon to
+	  SAA711x module.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7114.
+
+config VIDEO_SAA711X
+	tristate "Philips SAA7113/4/5 video decoders"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Philips SAA7113/4/5 video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7115.
+
+config VIDEO_SAA7191
+	tristate "Philips SAA7191 video decoder"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for the Philips SAA7191 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called saa7191.
+
+config VIDEO_TVP5150
+	tristate "Texas Instruments TVP5150 video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Texas Instruments TVP5150 video decoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tvp5150.
+
+config VIDEO_VPX3220
+	tristate "vpx3220a, vpx3216b & vpx3214c video decoder driver"
+	depends on VIDEO_V4L1 && I2C
+	---help---
+	  Support for VPX322x video decoders.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vpx3220.
+
+comment "Video improvement chips"
+
+config VIDEO_UPD64031A
+	tristate "NEC Electronics uPD64031A Ghost Reduction"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the NEC Electronics uPD64031A Ghost Reduction
+	  video chip. It is most often found in NTSC TV cards made for
+	  Japan and is used to reduce the 'ghosting' effect that can
+	  be present in analog TV broadcasts.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called upd64031a.
+
+config VIDEO_UPD64083
+	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+	  separation video chip. It is used to improve the quality of
+	  the colors of a composite signal.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called upd64083.
+
+endmenu # encoder / decoder chips
+
 config VIDEO_VIVI
 	tristate "Virtual Video Driver"
 	depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -135,7 +449,7 @@
 
 config VIDEO_SAA5246A
 	tristate "SAA5246A, SAA5281 Teletext processor"
-	depends on I2C && VIDEO_V4L1
+	depends on I2C && VIDEO_V4L2
 	help
 	  Support for I2C bus based teletext using the SAA5246A or SAA5281
 	  chip. Useful only if you live in Europe.
@@ -145,7 +459,7 @@
 
 config VIDEO_SAA5249
 	tristate "SAA5249 Teletext processor"
-	depends on VIDEO_DEV && I2C && VIDEO_V4L1
+	depends on VIDEO_DEV && I2C && VIDEO_V4L2
 	help
 	  Support for I2C bus based teletext using the SAA5249 chip. At the
 	  moment this is only useful on some European WinTV cards.
@@ -162,8 +476,9 @@
 
 config VIDEO_VINO
 	tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
-	depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L1
+	depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
 	select I2C_ALGO_SGI
+	select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
 	help
 	  Say Y here to build in support for the Vino video input system found
 	  on SGI Indy machines.
@@ -176,6 +491,9 @@
 	  driver for PCI.  There is a product page at
 	  <http://www.stradis.com/>.
 
+config VIDEO_ZORAN_ZR36060
+	tristate
+
 config VIDEO_ZORAN
 	tristate "Zoran ZR36057/36067 Video For Linux"
 	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
@@ -192,12 +510,18 @@
 config VIDEO_ZORAN_BUZ
 	tristate "Iomega Buz support"
 	depends on VIDEO_ZORAN
+	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the Iomega Buz MJPEG capture/playback card.
 
 config VIDEO_ZORAN_DC10
 	tristate "Pinnacle/Miro DC10(+) support"
 	depends on VIDEO_ZORAN
+	select VIDEO_SAA7110
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
 	  card.
@@ -205,6 +529,8 @@
 config VIDEO_ZORAN_DC30
 	tristate "Pinnacle/Miro DC30(+) support"
 	depends on VIDEO_ZORAN
+	select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
 	help
 	  Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
 	  card. This also supports really old DC10 cards based on the
@@ -213,6 +539,9 @@
 config VIDEO_ZORAN_LML33
 	tristate "Linux Media Labs LML33 support"
 	depends on VIDEO_ZORAN
+	select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the Linux Media Labs LML33 MJPEG capture/playback
 	  card.
@@ -220,6 +549,9 @@
 config VIDEO_ZORAN_LML33R10
 	tristate "Linux Media Labs LML33R10 support"
 	depends on VIDEO_ZORAN
+	select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ZORAN_ZR36060
 	help
 	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
 	  card.
@@ -227,6 +559,9 @@
 config VIDEO_ZORAN_AVS6EYES
 	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
 	depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+	select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_ZORAN_ZR36060
 	help
 	  Support for the AverMedia 6 Eyes video surveillance card.
 
@@ -263,6 +598,10 @@
 	depends on PCI && VIDEO_V4L1 && I2C
 	select VIDEO_SAA7146_VV
 	select VIDEO_TUNER
+	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  This is a video4linux driver for the 'Multimedia eXtension Board'
 	  TV card by Siemens-Nixdorf.
@@ -274,7 +613,7 @@
 	tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
 	depends on PCI && VIDEO_V4L1 && I2C
 	select VIDEO_SAA7146_VV
-	select VIDEO_V4L2
+	select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  This is a video4linux driver for the 'dpc7146 demonstration
 	  board' by Philips-Semiconductors. It's the reference design
@@ -287,9 +626,8 @@
 
 config VIDEO_HEXIUM_ORION
 	tristate "Hexium HV-PCI6 and Orion frame grabber"
-	depends on PCI && VIDEO_V4L1 && I2C
+	depends on PCI && VIDEO_V4L2 && I2C
 	select VIDEO_SAA7146_VV
-	select VIDEO_V4L2
 	---help---
 	  This is a video4linux driver for the Hexium HV-PCI6 and
 	  Orion frame grabber cards by Hexium.
@@ -299,9 +637,8 @@
 
 config VIDEO_HEXIUM_GEMINI
 	tristate "Hexium Gemini frame grabber"
-	depends on PCI && VIDEO_V4L1 && I2C
+	depends on PCI && VIDEO_V4L2 && I2C
 	select VIDEO_SAA7146_VV
-	select VIDEO_V4L2
 	---help---
 	  This is a video4linux driver for the Hexium Gemini frame
 	  grabber card by Hexium. Please note that the Gemini Dual
@@ -320,123 +657,16 @@
 	  camera module.
 
 config VIDEO_M32R_AR_M64278
-	tristate "Use Colour AR module M64278(VGA)"
-	depends on VIDEO_M32R_AR && PLAT_M32700UT
+	tristate "AR device with color module M64278(VGA)"
+	depends on PLAT_M32700UT
+	select VIDEO_M32R_AR
 	---help---
-	  Say Y here to use the Renesas M64278E-800 camera module,
-	  which supports VGA(640x480 pixcels) size of images.
-
-#
-# Encoder / Decoder module configuration
-#
-
-menu "Encoders and Decoders"
-	depends on VIDEO_DEV
-
-config VIDEO_MSP3400
-	tristate "Micronas MSP34xx audio decoders"
-	depends on VIDEO_DEV && I2C
-	---help---
-	  Support for the Micronas MSP34xx series of audio decoders.
+	  This is a video4linux driver for the Renesas AR (Artificial
+	  Retina) with M64278E-800 camera module.
+	  This module supports VGA(640x480 pixels) resolutions.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called msp3400.
-
-config VIDEO_CS53L32A
-	tristate "Cirrus Logic CS53L32A audio ADC"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Cirrus Logic CS53L32A low voltage
-	  stereo A/D converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called cs53l32a.
-
-config VIDEO_TLV320AIC23B
-	tristate "Texas Instruments TLV320AIC23B audio codec"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Texas Instruments TLV320AIC23B audio codec.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called tlv320aic23b.
-
-config VIDEO_WM8775
-	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Wolfson Microelectronics WM8775 high
-	  performance stereo A/D Converter with a 4 channel input mixer.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called wm8775.
-
-config VIDEO_WM8739
-	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Wolfson Microelectronics WM8739
-	  stereo A/D Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called wm8739.
-
-config VIDEO_CX2341X
-	tristate "Conexant CX2341x MPEG encoders"
-	depends on VIDEO_V4L2 && EXPERIMENTAL
-	---help---
-	  Support for the Conexant CX23416 MPEG encoders
-	  and CX23415 MPEG encoder/decoders.
-
-	  This module currently supports the encoding functions only.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called cx2341x.
-
-source "drivers/media/video/cx25840/Kconfig"
-
-config VIDEO_SAA711X
-	tristate "Philips SAA7113/4/5 video decoders"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Philips SAA7113/4/5 video decoders.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called saa7115.
-
-config VIDEO_SAA7127
-	tristate "Philips SAA7127/9 digital video encoders"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-	---help---
-	  Support for the Philips SAA7127/9 digital video encoders.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called saa7127.
-
-config VIDEO_UPD64031A
-	tristate "NEC Electronics uPD64031A Ghost Reduction"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-	---help---
-	  Support for the NEC Electronics uPD64031A Ghost Reduction
-	  video chip. It is most often found in NTSC TV cards made for
-	  Japan and is used to reduce the 'ghosting' effect that can
-	  be present in analog TV broadcasts.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called upd64031a.
-
-config VIDEO_UPD64083
-	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
-	---help---
-	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
-	  separation video chip. It is used to improve the quality of
-	  the colors of a composite signal.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called upd64083.
-
-endmenu # encoder / decoder chips
+	  module will be called arv.
 
 #
 # USB Multimedia device configuration
@@ -445,8 +675,6 @@
 menu "V4L USB devices"
 	depends on USB && VIDEO_DEV
 
-source "drivers/media/video/pvrusb2/Kconfig"
-
 source "drivers/media/video/em28xx/Kconfig"
 
 source "drivers/media/video/usbvideo/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e82e511..af57abc 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -17,7 +17,10 @@
 endif
 
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += tvaudio.o tda7432.o tda9875.o ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
+obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
+obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
@@ -27,17 +30,32 @@
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
 obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
 obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
-	zr36016.o
-obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
+
+obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
+obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
+obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
+obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
+obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
+obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
+obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_BT819) += bt819.o
+obj-$(CONFIG_VIDEO_BT856) += bt856.o
+obj-$(CONFIG_VIDEO_BT866) += bt866.o
+obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+
 obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
+
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -46,7 +64,7 @@
 obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
@@ -55,10 +73,10 @@
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
+obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -70,8 +88,6 @@
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
-obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
 obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
@@ -96,4 +112,3 @@
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
-
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 05e42bb..772fd52 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -65,7 +65,7 @@
 struct bt866 {
 	struct i2c_client *i2c;
 	int addr;
-	unsigned char reg[128];
+	unsigned char reg[256];
 
 	int norm;
 	int enable;
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index cdcf556..58eae88 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -8,7 +8,10 @@
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
-	select VIDEO_MSP3400
+	select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  Support for BT848 based frame grabber/overlay boards. This includes
 	  the Miro, Hauppauge and STB boards. Please read the material in
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index de14818..d23a42b 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -4991,7 +4991,7 @@
 	int pcipci_fail = 0;
 	struct pci_dev *dev = NULL;
 
-	if (pci_pci_problems & PCIPCI_FAIL)
+	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) 	/* should check if target is AGP */
 		pcipci_fail = 1;
 	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
 		triton1 = 1;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 20dff7c..50dde82 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2431,6 +2431,14 @@
 		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
 		if (fh->ovfmt)
 			fbuf->depth = fh->ovfmt->depth;
+		else {
+			if (fbuf->width)
+				fbuf->depth   = ((fbuf->bytesperline<<3)
+						  + (fbuf->width-1) )
+						  /fbuf->width;
+			else
+				fbuf->depth = 0;
+		}
 		return 0;
 	}
 	case VIDIOCSFBUF:
@@ -4186,6 +4194,7 @@
 	return;
 }
 
+#ifdef CONFIG_PM
 static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
 	struct bttv *btv = pci_get_drvdata(pci_dev);
@@ -4266,6 +4275,7 @@
 	spin_unlock_irqrestore(&btv->s_lock,flags);
 	return 0;
 }
+#endif
 
 static struct pci_device_id bttv_pci_tbl[] = {
 	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
@@ -4286,8 +4296,10 @@
 	.id_table = bttv_pci_tbl,
 	.probe    = bttv_probe,
 	.remove   = __devexit_p(bttv_remove),
+#ifdef CONFIG_PM
 	.suspend  = bttv_suspend,
 	.resume   = bttv_resume,
+#endif
 };
 
 static int bttv_init_module(void)
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 0dfbcc8..70de6c9 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -8,6 +8,9 @@
 			   & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
+    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+	- Multituner support and i2c address binding
+
     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
@@ -45,10 +48,18 @@
 static int i2c_hw;
 static int i2c_scan;
 module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_hw,"configure i2c debug level");
 module_param(i2c_hw,    int, 0444);
+MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, "
+			"instead of software bitbang");
 module_param(i2c_scan,  int, 0444);
 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0444);
+MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs "
+		"(should be 5 or higher). Lower value means higher bus speed.");
+
 /* ----------------------------------------------------------------------- */
 /* I2C functions - bitbanging adapter (software i2c)                       */
 
@@ -425,6 +436,11 @@
 		       sizeof(bttv_i2c_adap_hw_template));
 	} else {
 		/* bt848 */
+	/* Prevents usage of invalid delay values */
+		if (i2c_udelay<5)
+			i2c_udelay=5;
+		bttv_i2c_algo_bit_template.udelay=i2c_udelay;
+
 		memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
 		       sizeof(bttv_i2c_adap_sw_template));
 		memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index b69ee11..d82a488 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -58,6 +58,7 @@
 	return 0;
 }
 
+
 struct video_buffer32 {
 	compat_caddr_t base;
 	compat_int_t height, width, depth, bytesperline;
@@ -618,6 +619,7 @@
 		struct video_buffer vb;
 		struct video_window vw;
 		struct video_code vc;
+		struct video_audio va;
 #endif
 		struct v4l2_format v2f;
 		struct v4l2_buffer v2b;
@@ -635,31 +637,31 @@
 	/* First, convert the command. */
 	switch(cmd) {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	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 VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
+	case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
+	case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
+	case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
 #endif
-	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_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
+	case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
+	case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
+	case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
+	case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
+	case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
+	case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
+	case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
+	case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
+	case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
 	case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
 	case VIDIOC_ENUMINPUT32: realcmd = 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;
+	case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
+	case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
+	case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
+	case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
 	};
 
 	switch(cmd) {
@@ -676,6 +678,7 @@
 		compatible_arg = 0;
 		break;
 
+
 	case VIDIOCSFREQ:
 #endif
 	case VIDIOC_S_INPUT:
@@ -683,7 +686,7 @@
 	case VIDIOC_STREAMON:
 	case VIDIOC_STREAMOFF:
 		err = get_user(karg.vx, (u32 __user *)up);
-		compatible_arg = 0;
+		compatible_arg = 1;
 		break;
 
 	case VIDIOC_S_FBUF:
@@ -739,6 +742,7 @@
 	case VIDIOC_G_FBUF:
 	case VIDIOC_G_INPUT:
 		compatible_arg = 0;
+		break;
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	case VIDIOCSMICROCODE:
 		err = microcode32(&karg.vc, up);
@@ -755,7 +759,7 @@
 		mm_segment_t old_fs = get_fs();
 
 		set_fs(KERNEL_DS);
-		err = native_ioctl(file, realcmd, (unsigned long)&karg);
+		err = native_ioctl(file, realcmd, (unsigned long) &karg);
 		set_fs(old_fs);
 	}
 	if(err == 0) {
@@ -772,6 +776,7 @@
 		case VIDIOCGFBUF:
 			err = put_video_buffer32(&karg.vb, up);
 			break;
+
 #endif
 		case VIDIOC_G_FBUF:
 			err = put_v4l2_framebuffer32(&karg.v2fb, up);
@@ -841,10 +846,14 @@
 	case VIDIOCSFBUF32:
 	case VIDIOCGFREQ32:
 	case VIDIOCSFREQ32:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
 #endif
 	case VIDIOC_QUERYCAP:
 	case VIDIOC_ENUM_FMT:
 	case VIDIOC_G_FMT32:
+	case VIDIOC_CROPCAP:
+	case VIDIOC_S_CROP:
 	case VIDIOC_S_FMT32:
 	case VIDIOC_REQBUFS:
 	case VIDIOC_QUERYBUF32:
@@ -882,8 +891,6 @@
 	case VIDIOCSPICT:
 	case VIDIOCCAPTURE:
 	case VIDIOCKEY:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
 	case VIDIOCSYNC:
 	case VIDIOCMCAPTURE:
 	case VIDIOCGMBUF:
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 65f00fc..657e0b9 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -691,7 +691,7 @@
 	.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
 	.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
 	.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-	.video_temporal_filter = 0,
+	.video_temporal_filter = 8,
 	.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
 	.video_luma_median_filter_top = 255,
 	.video_luma_median_filter_bottom = 0,
@@ -731,6 +731,7 @@
 	};
 
 	int err = 0;
+	u16 temporal = new->video_temporal_filter;
 
 	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
 
@@ -741,6 +742,7 @@
 
 	if (old == NULL || old->width != new->width || old->height != new->height ||
 			old->video_encoding != new->video_encoding) {
+		int is_scaling;
 		u16 w = new->width;
 		u16 h = new->height;
 
@@ -750,6 +752,20 @@
 		}
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
 		if (err) return err;
+
+		/* Adjust temporal filter if necessary. The problem with the temporal
+		   filter is that it works well with full resolution capturing, but
+		   not when the capture window is scaled (the filter introduces
+		   a ghosting effect). So if the capture window changed, and there is
+		   no updated filter value, then the filter is set depending on whether
+		   the new window is full resolution or not.
+
+		   For full resolution a setting of 8 really improves the video
+		   quality, especially if the original video quality is suboptimal. */
+		is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480);
+		if (old && old->video_temporal_filter == temporal) {
+			temporal = is_scaling ? 0 : 8;
+		}
 	}
 
 	if (old == NULL || old->stream_type != new->stream_type) {
@@ -815,9 +831,9 @@
 	}
 	if (old == NULL ||
 		old->video_spatial_filter != new->video_spatial_filter ||
-		old->video_temporal_filter != new->video_temporal_filter) {
+		old->video_temporal_filter != temporal) {
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
-			new->video_spatial_filter, new->video_temporal_filter);
+			new->video_spatial_filter, temporal);
 		if (err) return err;
 	}
 	if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
@@ -855,6 +871,9 @@
 	printk(KERN_INFO "%s: Stream: %s\n",
 		prefix,
 		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+	printk(KERN_INFO "%s: VBI Format: %s\n",
+		prefix,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
 
 	/* Video */
 	printk(KERN_INFO "%s: Video:  %dx%d, %d fps\n",
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
index 854264e..7cf29a0 100644
--- a/drivers/media/video/cx25840/Kconfig
+++ b/drivers/media/video/cx25840/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_CX25840
 	tristate "Conexant CX2584x audio/video decoders"
-	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
 	select FW_LOADER
 	---help---
 	  Support for the Conexant CX2584x audio/video decoders.
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 6cc8bf2..48014a2 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -111,6 +111,10 @@
 			uv_lpf=0;
 			comb=0;
 			sc=0x0a425f;
+		} else if (std == V4L2_STD_PAL_Nc) {
+			uv_lpf=1;
+			comb=0x20;
+			sc=556453;
 		} else {
 			uv_lpf=1;
 			comb=0x20;
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 7a94e6a..51d68f3 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,7 +1,3 @@
-config VIDEO_CX88_VP3054
-	tristate
-	depends on VIDEO_CX88_DVB && DVB_MT352
-
 config VIDEO_CX88
 	tristate "Conexant 2388x (bt878 successor) support"
 	depends on VIDEO_DEV && PCI && I2C
@@ -52,6 +48,14 @@
 	depends on VIDEO_CX88 && DVB_CORE
 	select VIDEO_BUF_DVB
 	select DVB_PLL
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_OR51132 if !DVB_FE_CUSTOMISE
+	select DVB_CX22702 if !DVB_FE_CUSTOMISE
+	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_CX24123 if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Conexant 2388x chip.
@@ -59,101 +63,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called 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_DVB_ALL_FRONTENDS
-	bool "Build all supported frontends for cx2388x based TV cards"
-	default y
-	depends on VIDEO_CX88_DVB
-	select DVB_MT352
-	select VIDEO_CX88_VP3054
-	select DVB_ZL10353
-	select DVB_OR51132
-	select DVB_CX22702
-	select DVB_LGDT330X
-	select DVB_NXT200X
-	select DVB_CX24123
-	select DVB_ISL6421
-	---help---
-	  This builds cx88-dvb with all currently supported frontend
-	  demodulators.  If you wish to tweak your configuration, and
-	  only include support for the hardware that you need, choose N here.
-
-	  If you are unsure, choose Y.
-
-config VIDEO_CX88_DVB_MT352
-	bool "Zarlink MT352 DVB-T Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select DVB_MT352
-	---help---
-	  This adds DVB-T support for cards based on the
-	  Connexant 2388x chip and the MT352 demodulator.
-
-config VIDEO_CX88_DVB_VP3054
-	bool "VP-3054 Secondary I2C Bus Support"
-	default y
-	depends on VIDEO_CX88_DVB_MT352
-	select VIDEO_CX88_VP3054
+config VIDEO_CX88_VP3054
+	tristate "VP-3054 Secondary I2C Bus Support"
+	default m
+	depends on VIDEO_CX88_DVB && DVB_MT352
 	---help---
 	  This adds DVB-T support for cards based on the
 	  Connexant 2388x chip and the MT352 demodulator,
 	  which also require support for the VP-3054
 	  Secondary I2C bus, such at DNTV Live! DVB-T Pro.
-
-config VIDEO_CX88_DVB_ZL10353
-	bool "Zarlink ZL10353 DVB-T Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select DVB_ZL10353
-	---help---
-	  This adds DVB-T support for cards based on the
-	  Connexant 2388x chip and the ZL10353 demodulator,
-	  successor to the Zarlink MT352.
-
-config VIDEO_CX88_DVB_OR51132
-	bool "OR51132 ATSC Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select DVB_OR51132
-	---help---
-	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
-	  Connexant 2388x chip and the OR51132 demodulator.
-
-config VIDEO_CX88_DVB_CX22702
-	bool "Conexant CX22702 DVB-T Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select DVB_CX22702
-	---help---
-	  This adds DVB-T support for cards based on the
-	  Connexant 2388x chip and the CX22702 demodulator.
-
-config VIDEO_CX88_DVB_LGDT330X
-	bool "LG Electronics DT3302/DT3303 ATSC Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select DVB_LGDT330X
-	---help---
-	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
-	  Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
-
-config VIDEO_CX88_DVB_NXT200X
-	bool "NXT2002/NXT2004 ATSC Support"
-	default y
-	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
-	select 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
-	select DVB_ISL6421
-	---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 352b919..639c3b6 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -14,13 +14,6 @@
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 
 extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_DVB_CX22702)   += -DHAVE_CX22702=1
-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_ZL10353)   += -DHAVE_ZL10353=1
-extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
-extra-cflags-$(CONFIG_DVB_CX24123)   += -DHAVE_CX24123=1
 extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
 
 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index b60177f..a7921f9d 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1160,8 +1160,10 @@
 	.id_table = cx8802_pci_tbl,
 	.probe    = blackbird_probe,
 	.remove   = __devexit_p(blackbird_remove),
+#ifdef CONFIG_PM
 	.suspend  = cx8802_suspend_common,
 	.resume   = cx8802_resume_common,
+#endif
 };
 
 static int blackbird_init(void)
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 14bd486..6214eb8 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1041,11 +1041,11 @@
 		.input          = {{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-			.gpio0  = 0x000027df,
+			.gpio0  = 0x000067df,
 		 },{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-			.gpio0  = 0x000027df,
+			.gpio0  = 0x000067df,
 		}},
 		.dvb            = 1,
 	},
@@ -1209,6 +1209,100 @@
 		}},
 		.dvb      = 1,
 	},
+	[CX88_BOARD_HAUPPAUGE_HVR3000] = {
+		/* FIXME: Add dvb & radio support */
+		.name           = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
+		.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,
+			.gpio0  = 0x84bf,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x84bf,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x84bf,
+		}},
+	},
+	[CX88_BOARD_NORWOOD_MICRO] = {
+		.name           = "Norwood Micro TV Tuner",
+		.tuner_type     = TUNER_TNF_5335MF,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0709,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x070b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x070b,
+		}},
+	},
+       [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
+	       .name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
+	       .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+	       .radio_type     = UNSET,
+	       .tuner_addr     = ADDR_UNSET,
+	       .radio_addr     = ADDR_UNSET,
+	       .input          = {{
+		       .type   = CX88_VMUX_TELEVISION,
+		       .vmux   = 0,
+		       .gpio0  = 0x003fffff,
+		       .gpio1  = 0x00e00000,
+		       .gpio2  = 0x003fffff,
+		       .gpio3  = 0x02000000,
+	       },{
+		       .type   = CX88_VMUX_COMPOSITE1,
+		       .vmux   = 1,
+		       .gpio0  = 0x003fffff,
+		       .gpio1  = 0x00e00000,
+		       .gpio2  = 0x003fffff,
+		       .gpio3  = 0x02000000,
+		},{
+		       .type   = CX88_VMUX_SVIDEO,
+		       .vmux   = 2,
+		       .gpio0  = 0x003fffff,
+		       .gpio1  = 0x00e00000,
+		       .gpio2  = 0x003fffff,
+		       .gpio3  = 0x02000000,
+	       }},
+       },
+	[CX88_BOARD_HAUPPAUGE_HVR1300] = {
+		.name		= "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
+		.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,
+			.gpio0	= 0xe780,
+		},{
+			.type	= CX88_VMUX_COMPOSITE1,
+			.vmux	= 1,
+			.gpio0	= 0xe780,
+		},{
+			.type	= CX88_VMUX_SVIDEO,
+			.vmux	= 2,
+			.gpio0	= 0xe780,
+		}},
+		/* fixme: Add radio support */
+		.dvb		= 1,
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1254,7 +1348,7 @@
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
 	},{
 		.subvendor = 0x107d,
-		.subdevice = 0x663C,
+		.subdevice = 0x663c,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
 	},{
 		.subvendor = 0x1461,
@@ -1458,6 +1552,35 @@
 		.subvendor = 0x14f1,
 		.subdevice = 0x0084,
 		.card      = CX88_BOARD_GENIATECH_DVBS,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x1404,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	},{
+		.subvendor = 0x1461,
+		.subdevice = 0xc111, /* AverMedia M150-D */
+		/* This board is known to work with the ASUS PVR416 config */
+		.card      = CX88_BOARD_ASUS_PVR_416,
+	},{
+		.subvendor = 0xc180,
+		.subdevice = 0xc980,
+		.card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9600,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9601,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x9602,
+		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x6632,
+		.card      = CX88_BOARD_LEADTEK_PVR2000,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1501,6 +1624,7 @@
 	/* Make sure we support the board model */
 	switch (tv.model)
 	{
+	case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */
 	case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
 	case 34519: /* WinTV-PCI-FM */
 	case 90002: /* Nova-T-PCI (9002) */
@@ -1512,6 +1636,11 @@
 	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 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
+	case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */
+	case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */
+	case 96569: /* WinTV-HVR1300 () */
+	case 96659: /* WinTV-HVR1300 () */
 	case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
 		/* known */
 		break;
@@ -1638,6 +1767,22 @@
 		       core->name, i, cx88_boards[i].name);
 }
 
+void cx88_card_setup_pre_i2c(struct cx88_core *core)
+{
+	switch (core->board) {
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		/* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
+		/* We leave here with the 702 on the bus */
+		cx_write(MO_GP0_IO, 0x0000e780);
+		udelay(1000);
+		cx_clear(MO_GP0_IO, 0x00000080);
+		udelay(50);
+		cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+		udelay(1000);
+		break;
+	}
+}
+
 void cx88_card_setup(struct cx88_core *core)
 {
 	static u8 eeprom[256];
@@ -1666,6 +1811,8 @@
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		if (0 == core->i2c_rc)
 			hauppauge_eeprom(core,eeprom);
 		break;
@@ -1673,9 +1820,15 @@
 		cx_write(MO_GP0_IO, 0x000007f8);
 		cx_write(MO_GP1_IO, 0x00000001);
 		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+		/* GPIO0:6 is hooked to FX2 reset pin */
+		cx_set(MO_GP0_IO, 0x00004040);
+		cx_clear(MO_GP0_IO, 0x00000040);
+		msleep(1000);
+		cx_set(MO_GP0_IO, 0x00004040);
+		/* FALLTHROUGH */
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
 		/* GPIO0:0 is hooked to mt352 reset pin */
 		cx_set(MO_GP0_IO, 0x00000101);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 973d3f3..f379ede 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -105,7 +105,7 @@
 			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
 			offset+=bpl;
 		} else {
-			/* scanline needs to be splitted */
+			/* scanline needs to be split */
 			todo = bpl;
 			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
 					    (sg_dma_len(sg)-offset));
@@ -792,6 +792,11 @@
 {
 	/* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
 	int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
+
+	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+	if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+		return 0;
+
 	/* setup fifo + format */
 	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
 	cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
@@ -801,11 +806,16 @@
 
 	/* start dma */
 	cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
+
 	return 0;
 }
 
 int cx88_stop_audio_dma(struct cx88_core *core)
 {
+	/* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+	if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+		return 0;
+
 	/* stop dma */
 	cx_write(MO_AUD_DMACNTRL, 0x0000);
 
@@ -1123,6 +1133,7 @@
 
 	/* init hardware */
 	cx88_reset(core);
+	cx88_card_setup_pre_i2c(core);
 	cx88_i2c_init(core,pci);
 	cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
 	cx88_card_setup(core);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index afde378..c87041d 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -33,32 +33,18 @@
 #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
+#include "mt352.h"
+#include "mt352_priv.h"
+#ifdef HAVE_VP3054_I2C
+# include "cx88-vp3054-i2c.h"
 #endif
-#ifdef HAVE_ZL10353
-# include "zl10353.h"
-#endif
-#ifdef HAVE_CX22702
-# include "cx22702.h"
-#endif
-#ifdef HAVE_OR51132
-# include "or51132.h"
-#endif
-#ifdef HAVE_LGDT330X
-# include "lgdt330x.h"
-# include "lg_h06xf.h"
-#endif
-#ifdef HAVE_NXT200X
-# include "nxt200x.h"
-#endif
-#ifdef HAVE_CX24123
-# include "cx24123.h"
-#endif
+#include "zl10353.h"
+#include "cx22702.h"
+#include "or51132.h"
+#include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "nxt200x.h"
+#include "cx24123.h"
 #include "isl6421.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
@@ -114,8 +100,6 @@
 };
 
 /* ------------------------------------------------------------------ */
-
-#ifdef HAVE_MT352
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
@@ -181,7 +165,7 @@
 }
 
 static struct mt352_config dvico_fusionhdtv = {
-	.demod_address = 0x0F,
+	.demod_address = 0x0f,
 	.demod_init    = dvico_fusionhdtv_demod_init,
 };
 
@@ -191,7 +175,7 @@
 };
 
 static struct mt352_config dvico_fusionhdtv_dual = {
-	.demod_address = 0x0F,
+	.demod_address = 0x0f,
 	.demod_init    = dvico_dual_demod_init,
 };
 
@@ -266,8 +250,8 @@
 	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__, dev->core->pll_addr, buf[0], err);
+		       "(addr %02x <- %02x, err = %i)\n",
+		       __FUNCTION__, dev->core->pll_addr, buf[0], err);
 		if (err < 0)
 			return err;
 		else
@@ -283,9 +267,7 @@
 	.demod_init    = dntv_live_dvbt_pro_demod_init,
 };
 #endif
-#endif
 
-#ifdef HAVE_ZL10353
 static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
 					 struct dvb_frontend_parameters *params)
 {
@@ -304,8 +286,8 @@
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	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);
+		       "(addr %02x <- %02x, err = %i)\n",
+		       __FUNCTION__, pllbuf[0], pllbuf[1], err);
 		if (err < 0)
 			return err;
 		else
@@ -316,16 +298,14 @@
 }
 
 static struct zl10353_config dvico_fusionhdtv_hybrid = {
-	.demod_address = 0x0F,
+	.demod_address = 0x0f,
 	.no_tuner      = 1,
 };
 
 static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
-	.demod_address = 0x0F,
+	.demod_address = 0x0f,
 };
-#endif
 
-#ifdef HAVE_CX22702
 static struct cx22702_config connexant_refboard_config = {
 	.demod_address = 0x43,
 	.output_mode   = CX22702_SERIAL_OUTPUT,
@@ -339,9 +319,11 @@
 	.demod_address = 0x63,
 	.output_mode   = CX22702_SERIAL_OUTPUT,
 };
-#endif
+static struct cx22702_config hauppauge_hvr1300_config = {
+	.demod_address = 0x63,
+	.output_mode   = CX22702_SERIAL_OUTPUT,
+};
 
-#ifdef HAVE_OR51132
 static int or51132_set_ts_param(struct dvb_frontend* fe,
 				int is_punctured)
 {
@@ -351,12 +333,10 @@
 }
 
 static struct or51132_config pchdtv_hd3000 = {
-	.demod_address    = 0x15,
-	.set_ts_params    = or51132_set_ts_param,
+	.demod_address = 0x15,
+	.set_ts_params = or51132_set_ts_param,
 };
-#endif
 
-#ifdef HAVE_LGDT330X
 static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
 				     struct dvb_frontend_parameters* params)
 {
@@ -373,14 +353,14 @@
 
 	dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
 	dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-			__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+		__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
 		printk(KERN_WARNING "cx88-dvb: %s error "
-			   "(addr %02x <- %02x, err = %i)\n",
-			   __FUNCTION__, buf[0], buf[1], err);
+		       "(addr %02x <- %02x, err = %i)\n",
+		       __FUNCTION__, buf[0], buf[1], err);
 		if (err < 0)
 			return err;
 		else
@@ -425,28 +405,26 @@
 }
 
 static struct lgdt330x_config fusionhdtv_3_gold = {
-	.demod_address    = 0x0e,
-	.demod_chip       = LGDT3302,
-	.serial_mpeg      = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
-	.set_ts_params    = lgdt330x_set_ts_param,
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3302,
+	.serial_mpeg   = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
 };
 
 static struct lgdt330x_config fusionhdtv_5_gold = {
-	.demod_address    = 0x0e,
-	.demod_chip       = LGDT3303,
-	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-	.set_ts_params    = lgdt330x_set_ts_param,
+	.demod_address = 0x0e,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
 };
 
 static struct lgdt330x_config pchdtv_hd5500 = {
-	.demod_address    = 0x59,
-	.demod_chip       = LGDT3303,
-	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-	.set_ts_params    = lgdt330x_set_ts_param,
+	.demod_address = 0x59,
+	.demod_chip    = LGDT3303,
+	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+	.set_ts_params = lgdt330x_set_ts_param,
 };
-#endif
 
-#ifdef HAVE_NXT200X
 static int nxt200x_set_ts_param(struct dvb_frontend* fe,
 				int is_punctured)
 {
@@ -465,28 +443,27 @@
 }
 
 static struct nxt200x_config ati_hdtvwonder = {
-	.demod_address    = 0x0a,
-	.set_pll_input    = nxt200x_set_pll_input,
-	.set_ts_params    = nxt200x_set_ts_param,
+	.demod_address = 0x0a,
+	.set_pll_input = nxt200x_set_pll_input,
+	.set_ts_params = nxt200x_set_ts_param,
 };
-#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;
+	dev->ts_gen_cntrl = 0x02;
 	return 0;
 }
 
-static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
+				       fe_sec_voltage_t voltage)
 {
 	struct cx8802_dev *dev= fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
 	if (voltage == SEC_VOLTAGE_OFF) {
-		cx_write(MO_GP0_IO, 0x000006fB);
+		cx_write(MO_GP0_IO, 0x000006fb);
 	} else {
 		cx_write(MO_GP0_IO, 0x000006f9);
 	}
@@ -496,7 +473,8 @@
 	return 0;
 }
 
-static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
 {
 	struct cx8802_dev *dev= fe->dvb->priv;
 	struct cx88_core *core = dev->core;
@@ -512,20 +490,20 @@
 }
 
 static struct cx24123_config geniatech_dvbs_config = {
-	.demod_address  = 0x55,
-	.set_ts_params  = cx24123_set_ts_param,
+	.demod_address = 0x55,
+	.set_ts_params = cx24123_set_ts_param,
 };
 
 static struct cx24123_config hauppauge_novas_config = {
-	.demod_address		= 0x55,
-	.set_ts_params		= cx24123_set_ts_param,
+	.demod_address = 0x55,
+	.set_ts_params = cx24123_set_ts_param,
 };
 
 static struct cx24123_config kworld_dvbs_100_config = {
-	.demod_address		= 0x15,
-	.set_ts_params		= cx24123_set_ts_param,
+	.demod_address = 0x15,
+	.set_ts_params = cx24123_set_ts_param,
+	.lnb_polarity  = 1,
 };
-#endif
 
 static int dvb_register(struct cx8802_dev *dev)
 {
@@ -535,114 +513,114 @@
 
 	/* init frontend */
 	switch (dev->core->board) {
-#ifdef HAVE_CX22702
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
-		dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(cx22702_attach,
+					       &hauppauge_novat_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt759x);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_thomson_dtt759x);
 		}
 		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);
+		dev->dvb.frontend = dvb_attach(cx22702_attach,
+					       &connexant_refboard_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x60,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt7579);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_thomson_dtt7579);
 		}
 		break;
 	case CX88_BOARD_WINFAST_DTV2000H:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
-		dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(cx22702_attach,
+					       &hauppauge_hvr1100_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_fmd1216me);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_fmd1216me);
 		}
 		break;
-#endif
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-#ifdef HAVE_MT352
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
-						 &dev->core->i2c_adap);
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+		dev->dvb.frontend = dvb_attach(cx22702_attach,
+					       &hauppauge_hvr1300_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x60,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt7579);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_fmd1216me);
+		}
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv,
+					       &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+				   NULL, &dvb_pll_thomson_dtt7579);
 			break;
 		}
-#endif
-#ifdef HAVE_ZL10353
 		/* ZL10353 replaces MT352 on later cards */
-		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_plus_v1_1,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x60,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt7579);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+				   NULL, &dvb_pll_thomson_dtt7579);
 		}
-#endif
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
-#ifdef HAVE_MT352
 		/* The tin box says DEE1601, but it seems to be DTT7579
 		 * compatible, with a slightly different MT352 AGC gain. */
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
-						 &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv_dual,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt7579);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_thomson_dtt7579);
 			break;
 		}
-#endif
-#ifdef HAVE_ZL10353
 		/* ZL10353 replaces MT352 on later cards */
-		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_plus_v1_1,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt7579);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_thomson_dtt7579);
 		}
-#endif
 		break;
-#endif /* HAVE_MT352 || HAVE_ZL10353 */
-#ifdef HAVE_MT352
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
-						 &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+					       &dvico_fusionhdtv,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_lg_z201);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_lg_z201);
 		}
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
-		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
-						 &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+					       &dntv_live_dvbt_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_unknown_1);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_unknown_1);
 		}
 		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,
+		dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
 			&((struct vp3054_i2c_state *)dev->card_priv)->adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
@@ -651,30 +629,26 @@
 		printk("%s: built without vp3054 support\n", dev->core->name);
 #endif
 		break;
-#endif
-#ifdef HAVE_ZL10353
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
 		dev->core->pll_addr = 0x61;
 		dev->core->pll_desc = &dvb_pll_thomson_fe6600;
-		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &dvico_fusionhdtv_hybrid,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
 		}
 		break;
-#endif
-#ifdef HAVE_OR51132
 	case CX88_BOARD_PCHDTV_HD3000:
-		dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
-						 &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(or51132_attach,
+					       &pchdtv_hd3000,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_thomson_dtt761x);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_thomson_dtt761x);
 		}
 		break;
-#endif
-#ifdef HAVE_LGDT330X
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
 		dev->ts_gen_cntrl = 0x08;
 		{
@@ -690,8 +664,9 @@
 		fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
 		dev->core->pll_addr = 0x61;
 		dev->core->pll_desc = &dvb_pll_microtune_4042;
-		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
-						    &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_3_gold,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
 		}
@@ -709,8 +684,9 @@
 		mdelay(200);
 		dev->core->pll_addr = 0x61;
 		dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
-		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
-						    &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_3_gold,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
 		}
@@ -726,8 +702,9 @@
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
 		mdelay(200);
-		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
-						    &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &fusionhdtv_5_gold,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
 		}
@@ -743,52 +720,51 @@
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
 		mdelay(200);
-		dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
-						    &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+					       &pchdtv_hd5500,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
 		}
 		}
 		break;
-#endif
-#ifdef HAVE_NXT200X
 	case CX88_BOARD_ATI_HDTVWONDER:
-		dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
-						 &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(nxt200x_attach,
+					       &ati_hdtvwonder,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61,
-				       &dev->core->i2c_adap,
-				       &dvb_pll_tuv1236d);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_tuv1236d);
 		}
 		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);
+		dev->dvb.frontend = dvb_attach(cx24123_attach,
+					       &hauppauge_novas_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend) {
-			isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
-				       0x08, 0x00, 0x00);
+			dvb_attach(isl6421_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap, 0x08, 0x00, 0x00);
 		}
 		break;
 	case CX88_BOARD_KWORLD_DVBS_100:
-		dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
-			&dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(cx24123_attach,
+					       &kworld_dvbs_100_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
 			dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
 		}
 		break;
 	case CX88_BOARD_GENIATECH_DVBS:
-		dev->dvb.frontend = cx24123_attach(&geniatech_dvbs_config,
-						   &dev->core->i2c_adap);
+		dev->dvb.frontend = dvb_attach(cx24123_attach,
+					       &geniatech_dvbs_config,
+					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
 		}
 		break;
-#endif
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
@@ -908,8 +884,10 @@
 	.id_table = cx8802_pci_tbl,
 	.probe    = dvb_probe,
 	.remove   = __devexit_p(dvb_remove),
+#ifdef CONFIG_PM
 	.suspend  = cx8802_suspend_common,
 	.resume   = cx8802_resume_common,
+#endif
 };
 
 static int dvb_init(void)
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 7bea347..27b5dbb 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -7,6 +7,9 @@
     (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
+    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+	- Multituner support and i2c address binding
+
     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
@@ -40,6 +43,11 @@
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
 
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0644);
+MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs "
+		"(should be 5 or higher). Lower value means higher bus speed.");
+
 #define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
 	printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
 
@@ -198,6 +206,11 @@
 /* init + register i2c algo-bit adapter */
 int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 {
+	/* Prevents usage of invalid delay values */
+	if (i2c_udelay<5)
+		i2c_udelay=5;
+	cx8800_i2c_algo_template.udelay=i2c_udelay;
+
 	memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
 	       sizeof(core->i2c_adap));
 	memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c255646..83ebf7a 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -107,7 +107,15 @@
 		   (gpio & ir->mask_keydown) ? " down" : "",
 		   (gpio & ir->mask_keyup) ? " up" : "");
 
-	if (ir->mask_keydown) {
+	if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
+		u32 gpio_key = cx_read(MO_GP0_IO);
+
+		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
+
+		ir_input_keydown(ir->input, &ir->ir, data, data);
+		ir_input_nokey(ir->input, &ir->ir);
+
+	} else if (ir->mask_keydown) {
 		/* bit set on keydown */
 		if (gpio & ir->mask_keydown) {
 			ir_input_keydown(ir->input, &ir->ir, data, data);
@@ -187,6 +195,7 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		ir_codes = ir_codes_hauppauge_new;
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
@@ -248,6 +257,13 @@
 		ir_type = IR_TYPE_PD;
 		ir->sampling = 0xff00; /* address */
 		break;
+	case CX88_BOARD_NORWOOD_MICRO:
+		ir_codes         = ir_codes_norwood;
+		ir->gpio_addr    = MO_GP1_IO;
+		ir->mask_keycode = 0x0e;
+		ir->mask_keyup   = 0x80;
+		ir->polling      = 50; /* ms */
+		break;
 	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
 		ir_codes = ir_codes_npgtech;
 		ir->gpio_addr = MO_GP0_IO;
@@ -402,6 +418,7 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		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-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 5785c34..741e7c5e 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -52,7 +52,6 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
-#include <linux/config.h>
 #include <linux/kthread.h>
 
 #include "cx88.h"
@@ -138,14 +137,10 @@
 {
 	u32 volume;
 
-#ifndef CONFIG_VIDEO_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 CONFIG_VIDEO_CX88_ALSA
 	cx88_start_audio_dma(core);
-#endif
 
 	if (cx88_boards[core->board].blackbird) {
 		/* sets sound input from external adc */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 94c92ba..fbc79e9 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -497,6 +497,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
 static int stop_video_dma(struct cx8800_dev    *dev)
 {
 	struct cx88_core *core = dev->core;
@@ -512,6 +513,7 @@
 	cx_clear(MO_VID_INTMSK, 0x0f0011);
 	return 0;
 }
+#endif
 
 static int restart_video_queue(struct cx8800_dev    *dev,
 			       struct cx88_dmaqueue *q)
@@ -2017,6 +2019,7 @@
 	kfree(dev);
 }
 
+#ifdef CONFIG_PM
 static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
 	struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
@@ -2092,6 +2095,7 @@
 
 	return 0;
 }
+#endif
 
 /* ----------------------------------------------------------- */
 
@@ -2112,9 +2116,10 @@
 	.id_table = cx8800_pci_tbl,
 	.probe    = cx8800_initdev,
 	.remove   = __devexit_p(cx8800_finidev),
-
+#ifdef CONFIG_PM
 	.suspend  = cx8800_suspend,
 	.resume   = cx8800_resume,
+#endif
 };
 
 static int cx8800_init(void)
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e781095..89f12e2 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -197,6 +197,10 @@
 #define CX88_BOARD_NPGTECH_REALTV_TOP10FM  50
 #define CX88_BOARD_WINFAST_DTV2000H        51
 #define CX88_BOARD_GENIATECH_DVBS          52
+#define CX88_BOARD_HAUPPAUGE_HVR3000       53
+#define CX88_BOARD_NORWOOD_MICRO           54
+#define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
+#define CX88_BOARD_HAUPPAUGE_HVR1300       56
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -545,6 +549,7 @@
 
 extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
 extern void cx88_card_setup(struct cx88_core *core);
+extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
 
 /* ----------------------------------------------------------- */
 /* cx88-tvaudio.c                                              */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index dfb15bf..9285a58 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -5,7 +5,8 @@
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
-	select VIDEO_SAA711X
+	select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+	select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  This is a video4linux driver for Empia 28xx based TV cards.
 
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 2a461dde4..20df657 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -174,7 +174,7 @@
 
 	route.input = INPUT(dev->ctl_input)->vmux;
 	route.output = 0;
-	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0);
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 3bf7ac4..c1a377f 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -832,8 +832,7 @@
 static int __devinit ks0127_init_module(void)
 {
 	init_reg_defaults();
-	i2c_add_driver(&i2c_driver_ks0127);
-	return 0;
+	return i2c_add_driver(&i2c_driver_ks0127);
 }
 
 static void __devexit ks0127_cleanup_module(void)
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 7e727fe..a52171e 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -5,8 +5,6 @@
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
-	select VIDEO_SAA711X
-	select VIDEO_MSP3400
 	---help---
 	  This is a video4linux driver for Conexant 23416 based
 	  usb2 personal video recorder devices.
@@ -14,6 +12,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called pvrusb2
 
+config VIDEO_PVRUSB2_29XXX
+	bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
+	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+	select VIDEO_SAA711X
+	select VIDEO_MSP3400
+	---help---
+	  This option enables support for WinTV-PVR USB2 devices whose 
+	  model number is of the form "29xxx" (leading prefix of "29" 
+	  followed by 3 digits).
+	  To see if you may need this option, examine the white
+	  sticker on the underside of your device.
+
+	  If you are in doubt, say Y.
+
 config VIDEO_PVRUSB2_24XXX
 	bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
@@ -60,3 +72,5 @@
 	  You do not need to select this option unless you plan
 	  on debugging the driver or performing a manual firmware
 	  extraction.
+
+	  If you are in doubt, say N.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 02e4142..69b3e43 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -1,10 +1,6 @@
 obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
 obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
 
-obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
-		   pvrusb2-cx2584x-v4l.o \
-		   pvrusb2-wm8775.o
-
 pvrusb2-objs	:= pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
 		   pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
 		   pvrusb2-encoder.o pvrusb2-video-v4l.o \
@@ -12,7 +8,7 @@
 		   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
 		   pvrusb2-ctrl.o pvrusb2-std.o \
 		   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
-		   $(obj-pvrusb2-24xxx-y) \
+		   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
 		   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
 
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index fb6198f..c77de85 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -43,12 +43,17 @@
 			if (cptr->info->type == pvr2_ctl_bitmask) {
 				mask &= cptr->info->def.type_bitmask.valid_bits;
 			} else if (cptr->info->type == pvr2_ctl_int) {
-				if (val < cptr->info->def.type_int.min_value) {
-					break;
+				int lim;
+				lim = cptr->info->def.type_int.min_value;
+				if (cptr->info->get_min_value) {
+					cptr->info->get_min_value(cptr,&lim);
 				}
-				if (val > cptr->info->def.type_int.max_value) {
-					break;
+				if (val < lim) break;
+				lim = cptr->info->def.type_int.max_value;
+				if (cptr->info->get_max_value) {
+					cptr->info->get_max_value(cptr,&lim);
 				}
+				if (val > lim) break;
 			} else if (cptr->info->type == pvr2_ctl_enum) {
 				if (val >= cptr->info->def.type_enum.count) {
 					break;
@@ -91,7 +96,9 @@
 	int ret = 0;
 	if (!cptr) return 0;
 	LOCK_TAKE(cptr->hdw->big_lock); do {
-		if (cptr->info->type == pvr2_ctl_int) {
+		if (cptr->info->get_max_value) {
+			cptr->info->get_max_value(cptr,&ret);
+		} else if (cptr->info->type == pvr2_ctl_int) {
 			ret = cptr->info->def.type_int.max_value;
 		}
 	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
@@ -105,7 +112,9 @@
 	int ret = 0;
 	if (!cptr) return 0;
 	LOCK_TAKE(cptr->hdw->big_lock); do {
-		if (cptr->info->type == pvr2_ctl_int) {
+		if (cptr->info->get_min_value) {
+			cptr->info->get_min_value(cptr,&ret);
+		} else if (cptr->info->type == pvr2_ctl_int) {
 			ret = cptr->info->def.type_int.min_value;
 		}
 	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index c80c26b..df8feac 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -221,7 +221,7 @@
 static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
 {
 	int ret;
-	ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
+	ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0);
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 18a7073..c94f97b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -317,7 +317,7 @@
 
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Failed to configure cx32416");
+			   "Failed to configure cx23416");
 		return ret;
 	}
 
@@ -337,7 +337,7 @@
 
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Failed to initialize cx32416 video input");
+			   "Failed to initialize cx23416 video input");
 		return ret;
 	}
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 0d6dc33..34b08fb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -33,7 +33,6 @@
 
 */
 
-#include <linux/config.h>
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
@@ -41,32 +40,6 @@
 #include "pvrusb2-io.h"
 #include <media/cx2341x.h>
 
-/* Legal values for the SRATE state variable */
-#define PVR2_CVAL_SRATE_48 0
-#define PVR2_CVAL_SRATE_44_1 1
-
-/* Legal values for the AUDIOBITRATE state variable */
-#define PVR2_CVAL_AUDIOBITRATE_384 0
-#define PVR2_CVAL_AUDIOBITRATE_320 1
-#define PVR2_CVAL_AUDIOBITRATE_256 2
-#define PVR2_CVAL_AUDIOBITRATE_224 3
-#define PVR2_CVAL_AUDIOBITRATE_192 4
-#define PVR2_CVAL_AUDIOBITRATE_160 5
-#define PVR2_CVAL_AUDIOBITRATE_128 6
-#define PVR2_CVAL_AUDIOBITRATE_112 7
-#define PVR2_CVAL_AUDIOBITRATE_96 8
-#define PVR2_CVAL_AUDIOBITRATE_80 9
-#define PVR2_CVAL_AUDIOBITRATE_64 10
-#define PVR2_CVAL_AUDIOBITRATE_56 11
-#define PVR2_CVAL_AUDIOBITRATE_48 12
-#define PVR2_CVAL_AUDIOBITRATE_32 13
-#define PVR2_CVAL_AUDIOBITRATE_VBR 14
-
-/* Legal values for the AUDIOEMPHASIS state variable */
-#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
-#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
-#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
-
 /* Legal values for PVR2_CID_HSM */
 #define PVR2_CVAL_HSM_FAIL 0
 #define PVR2_CVAL_HSM_FULL 1
@@ -107,6 +80,8 @@
 
 	/* Control's implementation */
 	pvr2_ctlf_get_value get_value;      /* Get its value */
+	pvr2_ctlf_get_value get_min_value;  /* Get minimum allowed value */
+	pvr2_ctlf_get_value get_max_value;  /* Get maximum allowed value */
 	pvr2_ctlf_set_value set_value;      /* Set its value */
 	pvr2_ctlf_val_to_sym val_to_sym;    /* Custom convert value->symbol */
 	pvr2_ctlf_sym_to_val sym_to_val;    /* Custom convert symbol->value */
@@ -193,9 +168,7 @@
 
 /* Known major hardware variants, keyed from device ID */
 #define PVR2_HDW_TYPE_29XXX 0
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 #define PVR2_HDW_TYPE_24XXX 1
-#endif
 
 typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
 #define PVR2_I2C_FUNC_CNT 128
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index be1e5cc..8860436 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -38,9 +38,7 @@
 
 struct usb_device_id pvr2_device_table[] = {
 	[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
-#endif
 	{ }
 };
 
@@ -48,9 +46,7 @@
 
 static const char *pvr2_device_names[] = {
 	[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
-#endif
 };
 
 struct pvr2_string_table {
@@ -58,14 +54,12 @@
 	unsigned int cnt;
 };
 
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 // Names of other client modules to request for 24xxx model hardware
 static const char *pvr2_client_24xxx[] = {
 	"cx25840",
 	"tuner",
 	"wm8775",
 };
-#endif
 
 // Names of other client modules to request for 29xxx model hardware
 static const char *pvr2_client_29xxx[] = {
@@ -79,12 +73,10 @@
 		pvr2_client_29xxx,
 		sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
 	},
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	[PVR2_HDW_TYPE_24XXX] = {
 		pvr2_client_24xxx,
 		sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
 	},
-#endif
 };
 
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
@@ -221,11 +213,12 @@
 };
 #define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
 
-static const char *control_values_srate[] = {
-	[PVR2_CVAL_SRATE_48]   = "48KHz",
-	[PVR2_CVAL_SRATE_44_1] = "44.1KHz",
-};
 
+static const char *control_values_srate[] = {
+	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100]   = "44.1 kHz",
+	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000]   = "48 kHz",
+	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000]   = "32 kHz",
+};
 
 
 
@@ -362,6 +355,50 @@
 	return 0;
 }
 
+static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp)
+{
+	/* If we're dealing with a 24xxx device, force the horizontal
+	   maximum to be 720 no matter what, since we can't get the device
+	   to work properly with any other value.  Otherwise just return
+	   the normal value. */
+	*vp = cptr->info->def.type_int.max_value;
+	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
+	return 0;
+}
+
+static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp)
+{
+	/* If we're dealing with a 24xxx device, force the horizontal
+	   minimum to be 720 no matter what, since we can't get the device
+	   to work properly with any other value.  Otherwise just return
+	   the normal value. */
+	*vp = cptr->info->def.type_int.min_value;
+	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
+	return 0;
+}
+
+static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
+{
+	/* Actual maximum depends on the video standard in effect. */
+	if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
+		*vp = 480;
+	} else {
+		*vp = 576;
+	}
+	return 0;
+}
+
+static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
+{
+	/* Actual minimum depends on device type. */
+	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+		*vp = 75;
+	} else {
+		*vp = 17;
+	}
+	return 0;
+}
+
 static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
 {
 	return cptr->hdw->enc_stale != 0;
@@ -719,19 +756,27 @@
 		.internal_id = PVR2_CID_HRES,
 		.default_value = 720,
 		DEFREF(res_hor),
-		DEFINT(320,720),
+		DEFINT(19,720),
+		/* Hook in check for clamp on horizontal resolution in
+		   order to avoid unsolved problem involving cx25840. */
+		.get_max_value = ctrl_hres_max_get,
+		.get_min_value = ctrl_hres_min_get,
 	},{
 		.desc = "Vertical capture resolution",
 		.name = "resolution_ver",
 		.internal_id = PVR2_CID_VRES,
 		.default_value = 480,
 		DEFREF(res_ver),
-		DEFINT(200,625),
+		DEFINT(17,576),
+		/* Hook in check for video standard and adjust maximum
+		   depending on the standard. */
+		.get_max_value = ctrl_vres_max_get,
+		.get_min_value = ctrl_vres_min_get,
 	},{
 		.v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
-		.desc = "Sample rate",
+		.default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+		.desc = "Audio Sampling Frequency",
 		.name = "srate",
-		.default_value = PVR2_CVAL_SRATE_48,
 		DEFREF(srate),
 		DEFENUM(control_values_srate),
 	},{
@@ -935,22 +980,18 @@
 	static const char *fw_files_29xxx[] = {
 		"v4l-pvrusb2-29xxx-01.fw",
 	};
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	static const char *fw_files_24xxx[] = {
 		"v4l-pvrusb2-24xxx-01.fw",
 	};
-#endif
 	static const struct pvr2_string_table fw_file_defs[] = {
 		[PVR2_HDW_TYPE_29XXX] = {
 			fw_files_29xxx,
 			sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
 		},
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 		[PVR2_HDW_TYPE_24XXX] = {
 			fw_files_24xxx,
 			sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
 		},
-#endif
 	};
 	hdw->fw1_state = FW1_STATE_FAILED; // default result
 
@@ -2237,11 +2278,14 @@
 	}
 
 	if (hdw->std_dirty ||
+	    hdw->enc_stale ||
+	    hdw->srate_dirty ||
+	    hdw->res_ver_dirty ||
+	    hdw->res_hor_dirty ||
 	    0) {
 		/* If any of this changes, then the encoder needs to be
 		   reconfigured, and we need to reset the stream. */
 		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-		stale_subsys_mask |= hdw->subsys_stream_mask;
 	}
 
 	if (hdw->srate_dirty) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index fbe6039..ed3e810 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -26,10 +26,8 @@
 #include "pvrusb2-audio.h"
 #include "pvrusb2-tuner.h"
 #include "pvrusb2-video-v4l.h"
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 #include "pvrusb2-cx2584x-v4l.h"
 #include "pvrusb2-wm8775.h"
-#endif
 
 #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
 
@@ -71,7 +69,6 @@
 			return;
 		}
 	}
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	if (id == I2C_DRIVERID_CX25840) {
 		if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
 			return;
@@ -82,7 +79,6 @@
 			return;
 		}
 	}
-#endif
 	if (id == I2C_DRIVERID_SAA711X) {
 		if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
 			return;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 8a9933d..05ea17a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -31,7 +31,7 @@
 	v4l2_std_id vs;
 	vs = hdw->std_mask_cur;
 	pvr2_trace(PVR2_TRACE_CHIPS,
-		   "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+		   "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
 
 	pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
 }
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 7fca479..3b9012f8e3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -185,8 +185,6 @@
 	}
 }
 
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
-
 /* This is a special entry point that is entered if an I2C operation is
    attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
    part doesn't work, but we know it is really there.  So let's look for
@@ -289,8 +287,6 @@
 	return -EIO;
 }
 
-#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
-
 /* This is a very, very limited I2C adapter implementation.  We can only
    support what we actually know will work on the device... */
 static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -897,14 +893,12 @@
 		hdw->i2c_func[idx] = pvr2_i2c_basic_op;
 	}
 
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
 	// If however we're dealing with new hardware, insert some hacks in
 	// the I2C transfer stack to let things work better.
 	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
 		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
 		hdw->i2c_func[0x44] = i2c_hack_cx25840;
 	}
-#endif
 
 	// Configure the adapter and set up everything else related to it.
 	memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 8f1a5af..e976c48 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index d1dda5c..c294f46 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <asm/semaphore.h>
@@ -40,8 +39,6 @@
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 	struct pvr2_sysfs_ctl_item *item_first;
 	struct pvr2_sysfs_ctl_item *item_last;
-	struct sysfs_ops kops;
-	struct kobj_type ktype;
 	struct class_device_attribute attr_v4l_minor_number;
 	struct class_device_attribute attr_unit_number;
 	int v4l_minor_number_created_ok;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 0caf70b..3608c2f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -459,18 +459,26 @@
 		ret = 0;
 		switch(vf->type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+			int lmin,lmax;
+			struct pvr2_ctrl *hcp,*vcp;
 			int h = vf->fmt.pix.height;
 			int w = vf->fmt.pix.width;
+			hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
+			vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
 
-			if (h < 200) {
-				h = 200;
-			} else if (h > 625) {
-				h = 625;
+			lmin = pvr2_ctrl_get_min(hcp);
+			lmax = pvr2_ctrl_get_max(hcp);
+			if (w < lmin) {
+				w = lmin;
+			} else if (w > lmax) {
+				w = lmax;
 			}
-			if (w < 320) {
-				w = 320;
-			} else if (w > 720) {
-				w = 720;
+			lmin = pvr2_ctrl_get_min(vcp);
+			lmax = pvr2_ctrl_get_max(vcp);
+			if (h < lmin) {
+				h = lmin;
+			} else if (h > lmax) {
+				h = lmax;
 			}
 
 			memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
@@ -479,14 +487,8 @@
 			vf->fmt.pix.height = h;
 
 			if (cmd == VIDIOC_S_FMT) {
-				pvr2_ctrl_set_value(
-					pvr2_hdw_get_ctrl_by_id(hdw,
-								PVR2_CID_HRES),
-					vf->fmt.pix.width);
-				pvr2_ctrl_set_value(
-					pvr2_hdw_get_ctrl_by_id(hdw,
-								PVR2_CID_VRES),
-					vf->fmt.pix.height);
+				pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
+				pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
 			}
 		} break;
 		case V4L2_BUF_TYPE_VBI_CAPTURE:
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 59a1872..77bb940 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -830,7 +830,6 @@
 	.owner	  = THIS_MODULE,
 	.name	  = IF_NAME,
 	.type	  = VID_TYPE_TELETEXT,
-	.hardware = VID_HARDWARE_SAA5249,
 	.fops	  = &saa_fops,
 	.release  = video_device_release,
 	.minor    = -1,
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 19a8d65..bb3fb43 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -713,7 +713,6 @@
 	.owner		= THIS_MODULE,
 	.name		= IF_NAME,
 	.type		= VID_TYPE_TELETEXT,	/*| VID_TYPE_TUNER ?? */
-	.hardware	= VID_HARDWARE_SAA5249,
 	.fops           = &saa_fops,
 };
 
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index b59c117..974179d 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1,4 +1,6 @@
-/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
+/* saa711x - Philips SAA711x video decoder driver
+ * This driver can work with saa7111, saa7111a, saa7113, saa7114,
+ *			     saa7115 and saa7118.
  *
  * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
  * the saa7111 driver by Dave Perks.
@@ -16,7 +18,9 @@
  * (2/17/2003)
  *
  * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
- * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *	SAA7111, SAA7113 and SAA7118 support
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -33,6 +37,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include "saa711x_regs.h"
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -43,7 +48,9 @@
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
-MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
+#define VRES_60HZ	(480+16)
+
+MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
 MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
 		"Hans Verkuil, Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
@@ -54,14 +61,14 @@
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 static unsigned short normal_i2c[] = {
-		0x4a >> 1, 0x48 >> 1,	/* SAA7113 */
-		0x42 >> 1, 0x40 >> 1,	/* SAA7114 and SAA7115 */
+		0x4a >> 1, 0x48 >> 1,	/* SAA7111, SAA7111A and SAA7113 */
+		0x42 >> 1, 0x40 >> 1,	/* SAA7114, SAA7115 and SAA7118 */
 		I2C_CLIENT_END };
 
 
 I2C_CLIENT_INSMOD;
 
-struct saa7115_state {
+struct saa711x_state {
 	v4l2_std_id std;
 	int input;
 	int enable;
@@ -70,6 +77,8 @@
 	int contrast;
 	int hue;
 	int sat;
+	int width;
+	int height;
 	enum v4l2_chip_ident ident;
 	u32 audclk_freq;
 	u32 crystal_freq;
@@ -80,420 +89,508 @@
 
 /* ----------------------------------------------------------------------- */
 
-static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
 {
 	return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
+/* Sanity routine to check if a register is present */
+static int saa711x_has_reg(const int id, const u8 reg)
 {
+	if (id == V4L2_IDENT_SAA7111)
+		return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
+		       (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
+
+	/* common for saa7113/4/5/8 */
+	if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
+	    reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
+	    reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
+	    reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
+		return 0;
+
+	switch (id) {
+	case V4L2_IDENT_SAA7113:
+		return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
+		       reg != 0x5d && reg < 0x63;
+	case V4L2_IDENT_SAA7114:
+		return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
+		       (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
+		       reg != 0x81 && reg < 0xf0;
+	case V4L2_IDENT_SAA7115:
+		return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
+	case V4L2_IDENT_SAA7118:
+		return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
+		       (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
+		       (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
+	}
+	return 1;
+}
+
+static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	unsigned char reg, data;
 
 	while (*regs != 0x00) {
 		reg = *(regs++);
 		data = *(regs++);
-		if (saa7115_write(client, reg, data) < 0)
-			return -1;
+
+		/* According with datasheets, reserved regs should be
+		   filled with 0 - seems better not to touch on they */
+		if (saa711x_has_reg(state->ident,reg)) {
+			if (saa711x_write(client, reg, data) < 0)
+				return -1;
+		} else {
+			v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
+		}
 	}
 	return 0;
 }
 
-static inline int saa7115_read(struct i2c_client *client, u8 reg)
+static inline int saa711x_read(struct i2c_client *client, u8 reg)
 {
 	return i2c_smbus_read_byte_data(client, reg);
 }
 
 /* ----------------------------------------------------------------------- */
 
+/* SAA7111 initialization table */
+static const unsigned char saa7111_init[] = {
+	R_01_INC_DELAY, 0x00,		/* reserved */
+
+	/*front end */
+	R_02_INPUT_CNTL_1, 0xd0,	/* FUSE=3, GUDL=2, MODE=0 */
+	R_03_INPUT_CNTL_2, 0x23,	/* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
+					 * GAFIX=0, GAI1=256, GAI2=256 */
+	R_04_INPUT_CNTL_3, 0x00,	/* GAI1=256 */
+	R_05_INPUT_CNTL_4, 0x00,	/* GAI2=256 */
+
+	/* decoder */
+	R_06_H_SYNC_START, 0xf3,	/* HSB at  13(50Hz) /  17(60Hz)
+					 * pixels after end of last line */
+	R_07_H_SYNC_STOP, 0xe8,		/* HSS seems to be needed to
+					 * work with NTSC, too */
+	R_08_SYNC_CNTL, 0xc8,		/* AUFD=1, FSEL=1, EXFIL=0,
+					 * VTRC=1, HPLL=0, VNOI=0 */
+	R_09_LUMA_CNTL, 0x01,		/* BYPS=0, PREF=0, BPSS=0,
+					 * VBLB=0, UPTCV=0, APER=1 */
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,
+	R_0B_LUMA_CONTRAST_CNTL, 0x47,	/* 0b - CONT=1.109 */
+	R_0C_CHROMA_SAT_CNTL, 0x40,
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0E_CHROMA_CNTL_1, 0x01,	/* 0e - CDTO=0, CSTD=0, DCCF=0,
+					 * FCTC=0, CHBW=1 */
+	R_0F_CHROMA_GAIN_CNTL, 0x00,	/* reserved */
+	R_10_CHROMA_CNTL_2, 0x48,	/* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+	R_11_MODE_DELAY_CNTL, 0x1c,	/* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
+					 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+	R_12_RT_SIGNAL_CNTL, 0x00,	/* 12 - output control 2 */
+	R_13_RT_X_PORT_OUT_CNTL, 0x00,	/* 13 - output control 3 */
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_15_VGATE_START_FID_CHG, 0x00,
+	R_16_VGATE_STOP, 0x00,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+	0x00, 0x00
+};
+
+/* SAA7113 init codes */
+static const unsigned char saa7113_init[] = {
+	R_01_INC_DELAY, 0x08,
+	R_02_INPUT_CNTL_1, 0xc2,
+	R_03_INPUT_CNTL_2, 0x30,
+	R_04_INPUT_CNTL_3, 0x00,
+	R_05_INPUT_CNTL_4, 0x00,
+	R_06_H_SYNC_START, 0x89,
+	R_07_H_SYNC_STOP, 0x0d,
+	R_08_SYNC_CNTL, 0x88,
+	R_09_LUMA_CNTL, 0x01,
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,
+	R_0B_LUMA_CONTRAST_CNTL, 0x47,
+	R_0C_CHROMA_SAT_CNTL, 0x40,
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0E_CHROMA_CNTL_1, 0x01,
+	R_0F_CHROMA_GAIN_CNTL, 0x2a,
+	R_10_CHROMA_CNTL_2, 0x08,
+	R_11_MODE_DELAY_CNTL, 0x0c,
+	R_12_RT_SIGNAL_CNTL, 0x07,
+	R_13_RT_X_PORT_OUT_CNTL, 0x00,
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_15_VGATE_START_FID_CHG, 0x00,
+	R_16_VGATE_STOP, 0x00,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+	0x00, 0x00
+};
+
 /* If a value differs from the Hauppauge driver values, then the comment starts with
    'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
    Hauppauge driver sets. */
 
+/* SAA7114 and SAA7115 initialization table */
 static const unsigned char saa7115_init_auto_input[] = {
 		/* Front-End Part */
-	0x01, 0x48,		/* white peak control disabled */
-	0x03, 0x20,		/* was 0x30. 0x20: long vertical blanking */
-	0x04, 0x90,		/* analog gain set to 0 */
-	0x05, 0x90,		/* analog gain set to 0 */
+	R_01_INC_DELAY, 0x48,			/* white peak control disabled */
+	R_03_INPUT_CNTL_2, 0x20,		/* was 0x30. 0x20: long vertical blanking */
+	R_04_INPUT_CNTL_3, 0x90,		/* analog gain set to 0 */
+	R_05_INPUT_CNTL_4, 0x90,		/* analog gain set to 0 */
 		/* Decoder Part */
-	0x06, 0xeb,		/* horiz sync begin = -21 */
-	0x07, 0xe0,		/* horiz sync stop = -17 */
-	0x0a, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
-	0x0b, 0x44,		/* was 0x48. decoder contrast, 0x44 is itu standard */
-	0x0c, 0x40,		/* was 0x47. decoder saturation, 0x40 is itu standard */
-	0x0d, 0x00,		/* chrominance hue control */
-	0x0f, 0x00,		/* chrominance gain control: use automicatic mode */
-	0x10, 0x06,		/* chrominance/luminance control: active adaptive combfilter */
-	0x11, 0x00,		/* delay control */
-	0x12, 0x9d,		/* RTS0 output control: VGATE */
-	0x13, 0x80,		/* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
-	0x14, 0x00,		/* analog/ADC/auto compatibility control */
-	0x18, 0x40,		/* raw data gain 0x00 = nominal */
-	0x19, 0x80,		/* raw data offset 0x80 = 0 LSB */
-	0x1a, 0x77,		/* color killer level control 0x77 = recommended */
-	0x1b, 0x42,		/* misc chroma control 0x42 = recommended */
-	0x1c, 0xa9,		/* combfilter control 0xA9 = recommended */
-	0x1d, 0x01,		/* combfilter control 0x01 = recommended */
+	R_06_H_SYNC_START, 0xeb,		/* horiz sync begin = -21 */
+	R_07_H_SYNC_STOP, 0xe0,			/* horiz sync stop = -17 */
+	R_09_LUMA_CNTL, 0x53,			/* 0x53, was 0x56 for 60hz. luminance control */
+	R_0A_LUMA_BRIGHT_CNTL, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
+	R_0B_LUMA_CONTRAST_CNTL, 0x44,		/* was 0x48. decoder contrast, 0x44 is itu standard */
+	R_0C_CHROMA_SAT_CNTL, 0x40,		/* was 0x47. decoder saturation, 0x40 is itu standard */
+	R_0D_CHROMA_HUE_CNTL, 0x00,
+	R_0F_CHROMA_GAIN_CNTL, 0x00,		/* use automatic gain  */
+	R_10_CHROMA_CNTL_2, 0x06,		/* chroma: active adaptive combfilter */
+	R_11_MODE_DELAY_CNTL, 0x00,
+	R_12_RT_SIGNAL_CNTL, 0x9d,		/* RTS0 output control: VGATE */
+	R_13_RT_X_PORT_OUT_CNTL, 0x80,		/* ITU656 standard mode, RTCO output enable RTCE */
+	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+	R_18_RAW_DATA_GAIN_CNTL, 0x40,		/* gain 0x00 = nominal */
+	R_19_RAW_DATA_OFF_CNTL, 0x80,
+	R_1A_COLOR_KILL_LVL_CNTL, 0x77,		/* recommended value */
+	R_1B_MISC_TVVCRDET, 0x42,		/* recommended value */
+	R_1C_ENHAN_COMB_CTRL1, 0xa9,		/* recommended value */
+	R_1D_ENHAN_COMB_CTRL2, 0x01,		/* recommended value */
+
+
+	R_80_GLOBAL_CNTL_1, 0x0,		/* No tasks enabled at init */
 
 		/* Power Device Control */
-	0x88, 0xd0,		/* reset device */
-	0x88, 0xf0,		/* set device programmed, all in operational mode */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset device */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,	/* set device programmed, all in operational mode */
 	0x00, 0x00
 };
 
+/* Used to reset saa7113, saa7114 and saa7115 */
 static const unsigned char saa7115_cfg_reset_scaler[] = {
-	0x87, 0x00,		/* disable I-port output */
-	0x88, 0xd0,		/* reset scaler */
-	0x88, 0xf0,		/* activate scaler */
-	0x87, 0x01,		/* enable I-port output */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00,	/* disable I-port output */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* enable I-port output */
 	0x00, 0x00
 };
 
 /* ============== SAA7715 VIDEO templates =============  */
 
-static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
-	0xcc, 0xd0,		/* hsize low (output), hor. output window size = 0x2d0 = 720 */
-	0xcd, 0x02,		/* hsize hi (output) */
-
-	/* Why not in 60hz-Land, too? */
-	0xd0, 0x01,		/* downscale = 1 */
-	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
-	0xd9, 0x04,
-	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
-	0xdd, 0x02,		/* H-scaling incr chroma */
-
-	0x00, 0x00
-};
-static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
-	0xce, 0xf8,		/* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
-	0xcf, 0x00,		/* vsize hi (output) */
-
-	/* Why not in 60hz-Land, too? */
-	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
-	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
-
-	0xe0, 0x00,		/* V-scaling incr luma low */
-	0xe1, 0x04,		/* " hi */
-	0xe2, 0x00,		/* V-scaling incr chroma low */
-	0xe3, 0x04,		/* " hi */
-
-	0x00, 0x00
-};
-
 static const unsigned char saa7115_cfg_60hz_video[] = {
-	0x80, 0x00,		/* reset tasks */
-	0x88, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
 
-	0x15, 0x03,		/* VGATE pulse start */
-	0x16, 0x11,		/* VGATE pulse stop */
-	0x17, 0x9c,		/* VGATE MSB and other values */
+	R_15_VGATE_START_FID_CHG, 0x03,
+	R_16_VGATE_STOP, 0x11,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
 
-	0x08, 0x68,		/* 0xBO: auto detection, 0x68 = NTSC */
-	0x0e, 0x07,		/* lots of different stuff... video autodetection is on */
+	R_08_SYNC_CNTL, 0x68,			/* 0xBO: auto detection, 0x68 = NTSC */
+	R_0E_CHROMA_CNTL_1, 0x07,		/* video autodetection is on */
 
-	0x5a, 0x06,		/* Vertical offset, standard 60hz value for ITU656 line counting */
+	R_5A_V_OFF_FOR_SLICER, 0x06,		/* standard 60hz value for ITU656 line counting */
 
 	/* Task A */
-	0x90, 0x80,		/* Task Handling Control */
-	0x91, 0x48,		/* X-port formats/config */
-	0x92, 0x40,		/* Input Ref. signal Def. */
-	0x93, 0x84,		/* I-port config */
-	0x94, 0x01,		/* hoffset low (input), 0x0002 is minimum */
-	0x95, 0x00,		/* hoffset hi (input) */
-	0x96, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
-	0x97, 0x02,		/* hsize hi (input) */
-	0x98, 0x05,		/* voffset low (input) */
-	0x99, 0x00,		/* voffset hi (input) */
-	0x9a, 0x0c,		/* vsize low (input), 0x0c = 12 */
-	0x9b, 0x00,		/* vsize hi (input) */
-	0x9c, 0xa0,		/* hsize low (output), 0x05a0 = 1440 */
-	0x9d, 0x05,		/* hsize hi (output) */
-	0x9e, 0x0c,		/* vsize low (output), 0x0c = 12 */
-	0x9f, 0x00,		/* vsize hi (output) */
+	R_90_A_TASK_HANDLING_CNTL, 0x80,
+	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
+	/* hoffset low (input), 0x0002 is minimum */
+	R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
+	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* hsize low (input), 0x02d0 = 720 */
+	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_98_A_VERT_INPUT_WINDOW_START, 0x05,
+	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
+	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
+
+	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
+	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
 
 	/* Task B */
-	0xc0, 0x00,		/* Task Handling Control */
-	0xc1, 0x08,		/* X-port formats/config */
-	0xc2, 0x00,		/* Input Ref. signal Def. */
-	0xc3, 0x80,		/* I-port config */
-	0xc4, 0x02,		/* hoffset low (input), 0x0002 is minimum */
-	0xc5, 0x00,		/* hoffset hi (input) */
-	0xc6, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
-	0xc7, 0x02,		/* hsize hi (input) */
-	0xc8, 0x12,		/* voffset low (input), 0x12 = 18 */
-	0xc9, 0x00,		/* voffset hi (input) */
-	0xca, 0xf8,		/* vsize low (input), 0xf8 = 248 */
-	0xcb, 0x00,		/* vsize hi (input) */
-	0xcc, 0xd0,		/* hsize low (output), 0x02d0 = 720 */
-	0xcd, 0x02,		/* hsize hi (output) */
+	R_C0_B_TASK_HANDLING_CNTL, 0x00,
+	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
 
-	0xf0, 0xad,		/* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
-	0xf1, 0x05,		/* low bit with 0xF0 */
-	0xf5, 0xad,		/* Set pulse generator register */
-	0xf6, 0x01,
+	/* 0x0002 is minimum */
+	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
+	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
 
-	0x87, 0x00,		/* Disable I-port output */
-	0x88, 0xd0,		/* reset scaler */
-	0x80, 0x20,		/* Activate only task "B", continuous mode (was 0xA0) */
-	0x88, 0xf0,		/* activate scaler */
-	0x87, 0x01,		/* Enable I-port output */
-	0x00, 0x00
-};
+	/* 0x02d0 = 720 */
+	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
 
-static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
-	0xcc, 0xd0,		/* hsize low (output), 720 same as 60hz */
-	0xcd, 0x02,		/* hsize hi (output) */
+	/* vwindow start 0x12 = 18 */
+	R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
+	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
 
-	0xd0, 0x01,		/* down scale = 1 */
-	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
-	0xd9, 0x04,
-	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
-	0xdd, 0x02,		/* H-scaling incr chroma */
+	/* vwindow length 0xf8 = 248 */
+	R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
+	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
 
-	0x00, 0x00
-};
-static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
-	0xce, 0x20,		/* vsize low (output), 0x0120 = 288 */
-	0xcf, 0x01,		/* vsize hi (output) */
+	/* hwindow 0x02d0 = 720 */
+	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
 
-	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
-	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
-
-	0xe0, 0x00,		/* V-scaling incr luma low */
-	0xe1, 0x04,		/* " hi */
-	0xe2, 0x00,		/* V-scaling incr chroma low */
-	0xe3, 0x04,		/* " hi */
+	R_F0_LFCO_PER_LINE, 0xad,		/* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0 */
+	R_F5_PULSGEN_LINE_LENGTH, 0xad,
+	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
 
 	0x00, 0x00
 };
 
 static const unsigned char saa7115_cfg_50hz_video[] = {
-	0x80, 0x00,		/* reset tasks */
-	0x88, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x00,
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset scaler */
 
-	0x15, 0x37,		/* VGATE start */
-	0x16, 0x16,		/* VGATE stop */
-	0x17, 0x99,		/* VGATE MSB and other values */
+	R_15_VGATE_START_FID_CHG, 0x37,		/* VGATE start */
+	R_16_VGATE_STOP, 0x16,
+	R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
 
-	0x08, 0x28,		/* 0x28 = PAL */
-	0x0e, 0x07,		/* chrominance control 1 */
+	R_08_SYNC_CNTL, 0x28,			/* 0x28 = PAL */
+	R_0E_CHROMA_CNTL_1, 0x07,
 
-	0x5a, 0x03,		/* Vertical offset, standard 50hz value */
+	R_5A_V_OFF_FOR_SLICER, 0x03,		/* standard 50hz value */
 
 	/* Task A */
-	0x90, 0x81,		/* Task Handling Control */
-	0x91, 0x48,		/* X-port formats/config */
-	0x92, 0x40,		/* Input Ref. signal Def. */
-	0x93, 0x84,		/* I-port config */
+	R_90_A_TASK_HANDLING_CNTL, 0x81,
+	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
 	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
 	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
-	0x94, 0x00,		/* hoffset low (input), 0x0002 is minimum */
-	0x95, 0x00,		/* hoffset hi (input) */
-	0x96, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
-	0x97, 0x02,		/* hsize hi (input) */
-	0x98, 0x03,		/* voffset low (input) */
-	0x99, 0x00,		/* voffset hi (input) */
-	0x9a, 0x12,		/* vsize low (input), 0x12 = 18 */
-	0x9b, 0x00,		/* vsize hi (input) */
-	0x9c, 0xa0,		/* hsize low (output), 0x05a0 = 1440 */
-	0x9d, 0x05,		/* hsize hi (output) */
-	0x9e, 0x12,		/* vsize low (output), 0x12 = 18 */
-	0x9f, 0x00,		/* vsize hi (output) */
+	/* hoffset low (input), 0x0002 is minimum */
+	R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
+	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* hsize low (input), 0x02d0 = 720 */
+	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_98_A_VERT_INPUT_WINDOW_START, 0x03,
+	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* vsize 0x12 = 18 */
+	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
+	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+	/* hsize 0x05a0 = 1440 */
+	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,	/* hsize hi (output) */
+	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12,		/* vsize low (output), 0x12 = 18 */
+	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,	/* vsize hi (output) */
 
 	/* Task B */
-	0xc0, 0x00,		/* Task Handling Control */
-	0xc1, 0x08,		/* X-port formats/config */
-	0xc2, 0x00,		/* Input Ref. signal Def. */
-	0xc3, 0x80,		/* I-port config */
-	0xc4, 0x00,		/* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
-	0xc5, 0x00,		/* hoffset hi (input) */
-	0xc6, 0xd0,		/* hsize low (input), 0x02d0 = 720 */
-	0xc7, 0x02,		/* hsize hi (input) */
-	0xc8, 0x16,		/* voffset low (input), 0x16 = 22 */
-	0xc9, 0x00,		/* voffset hi (input) */
-	0xca, 0x20,		/* vsize low (input), 0x0120 = 288 */
-	0xcb, 0x01,		/* vsize hi (input) */
-	0xcc, 0xd0,		/* hsize low (output), 0x02d0 = 720 */
-	0xcd, 0x02,		/* hsize hi (output) */
-	0xce, 0x20,		/* vsize low (output), 0x0120 = 288 */
-	0xcf, 0x01,		/* vsize hi (output) */
+	R_C0_B_TASK_HANDLING_CNTL, 0x00,
+	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
 
-	0xf0, 0xb0,		/* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
-	0xf1, 0x05,		/* low bit with 0xF0, (was 0x05) */
-	0xf5, 0xb0,		/* Set pulse generator register */
-	0xf6, 0x01,
+	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
+	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+	/* hoffset low (input), 0x0002 is minimum. See comment above. */
+	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
+	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
 
-	0x87, 0x00,		/* Disable I-port output */
-	0x88, 0xd0,		/* reset scaler (was 0xD0) */
-	0x80, 0x20,		/* Activate only task "B" */
-	0x88, 0xf0,		/* activate scaler */
-	0x87, 0x01,		/* Enable I-port output */
+	/* hsize 0x02d0 = 720 */
+	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	/* voffset 0x16 = 22 */
+	R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
+	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+	/* vsize 0x0120 = 288 */
+	R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
+	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
+
+	/* hsize 0x02d0 = 720 */
+	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
+
+	R_F0_LFCO_PER_LINE, 0xb0,		/* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0, (was 0x05) */
+	R_F5_PULSGEN_LINE_LENGTH, 0xb0,
+	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
+
 	0x00, 0x00
 };
 
 /* ============== SAA7715 VIDEO templates (end) =======  */
 
 static const unsigned char saa7115_cfg_vbi_on[] = {
-	0x80, 0x00,		/* reset tasks */
-	0x88, 0xd0,		/* reset scaler */
-	0x80, 0x30,		/* Activate both tasks */
-	0x88, 0xf0,		/* activate scaler */
-	0x87, 0x01,		/* Enable I-port output */
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x30,			/* Activate both tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
+
 	0x00, 0x00
 };
 
 static const unsigned char saa7115_cfg_vbi_off[] = {
-	0x80, 0x00,		/* reset tasks */
-	0x88, 0xd0,		/* reset scaler */
-	0x80, 0x20,		/* Activate only task "B" */
-	0x88, 0xf0,		/* activate scaler */
-	0x87, 0x01,		/* Enable I-port output */
+	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
+	R_80_GLOBAL_CNTL_1, 0x20,			/* Activate only task "B" */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
+
 	0x00, 0x00
 };
 
-static const unsigned char saa7113_init_auto_input[] = {
-	0x01, 0x08,	/* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
-	0x02, 0xc2,	/* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
-	0x03, 0x30,	/* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
-	0x04, 0x00,	/* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
-	0x05, 0x00,	/* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
-	0x06, 0x89,	/* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
-	0x07, 0x0d,	/* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
-	0x08, 0x88,	/* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
-	0x09, 0x01,	/* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
-	0x0a, 0x80,	/* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
-	0x0b, 0x47,	/* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
-	0x0c, 0x40,	/* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
-	0x0d, 0x00,	/* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
-	0x0e, 0x01,	/* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
-	0x0f, 0x2a,	/* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
-	0x10, 0x08,	/* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
-	0x11, 0x0c,	/* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
-	0x12, 0x07,	/* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
-	0x13, 0x00,	/* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
-	0x14, 0x00,	/* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
-	0x15, 0x00,	/* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
-	0x16, 0x00,	/* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
-	0x17, 0x00,	/* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
-	0x00, 0x00
-};
 
 static const unsigned char saa7115_init_misc[] = {
-	0x81, 0x01,		/* reg 0x15,0x16 define blanking window */
-	0x82, 0x00,
-	0x83, 0x01,		/* I port settings */
-	0x84, 0x20,
-	0x85, 0x21,
-	0x86, 0xc5,
-	0x87, 0x01,
+	R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
+	R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
+	R_84_I_PORT_SIGNAL_DEF, 0x20,
+	R_85_I_PORT_SIGNAL_POLAR, 0x21,
+	R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
+	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
 
 	/* Task A */
-	0xa0, 0x01,		/* down scale = 1 */
-	0xa1, 0x00,		/* prescale accumulation length = 1 */
-	0xa2, 0x00,		/* dc gain and fir prefilter control */
-	0xa4, 0x80,		/* Lum Brightness, nominal value = 0x80 */
-	0xa5, 0x40,		/* Lum contrast, nominal value = 0x40 */
-	0xa6, 0x40,		/* Chroma satur. nominal value = 0x80 */
-	0xa8, 0x00,		/* hor lum scaling 0x0200 = 2 zoom */
-	0xa9, 0x02,		/* note: 2 x zoom ensures that VBI lines have same length as video lines. */
-	0xaa, 0x00,		/* H-phase offset Luma = 0 */
-	0xac, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
-	0xad, 0x01,		/* H-scaling incr chroma */
-	0xae, 0x00,		/* H-phase offset chroma. must be offset luma / 2 */
+	R_A0_A_HORIZ_PRESCALING, 0x01,
+	R_A1_A_ACCUMULATION_LENGTH, 0x00,
+	R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
 
-	0xb0, 0x00,		/* V-scaling incr luma low */
-	0xb1, 0x04,		/* " hi */
-	0xb2, 0x00,		/* V-scaling incr chroma low */
-	0xb3, 0x04,		/* " hi */
-	0xb4, 0x01,		/* V-scaling mode control */
-	0xb8, 0x00,		/* V-phase offset chroma 00 */
-	0xb9, 0x00,		/* V-phase offset chroma 01 */
-	0xba, 0x00,		/* V-phase offset chroma 10 */
-	0xbb, 0x00,		/* V-phase offset chroma 11 */
-	0xbc, 0x00,		/* V-phase offset luma 00 */
-	0xbd, 0x00,		/* V-phase offset luma 01 */
-	0xbe, 0x00,		/* V-phase offset luma 10 */
-	0xbf, 0x00,		/* V-phase offset luma 11 */
+	/* Configure controls at nominal value*/
+	R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
+	R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
+	R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
+
+	/* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+	R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
+	R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
+
+	R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+	/* must be horiz lum scaling / 2 */
+	R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
+	R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
+
+	/* must be offset luma / 2 */
+	R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
+
+	R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
+	R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
+	R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+	R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
+
+	R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
+	R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
+	R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
+	R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+	R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
+	R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
+	R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
+	R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
 
 	/* Task B */
-	0xd0, 0x01,		/* down scale = 1 */
-	0xd1, 0x00,		/* prescale accumulation length = 1 */
-	0xd2, 0x00,		/* dc gain and fir prefilter control */
-	0xd4, 0x80,		/* Lum Brightness, nominal value = 0x80 */
-	0xd5, 0x40,		/* Lum contrast, nominal value = 0x40 */
-	0xd6, 0x40,		/* Chroma satur. nominal value = 0x80 */
-	0xd8, 0x00,		/* hor lum scaling 0x0400 = 1 */
-	0xd9, 0x04,
-	0xda, 0x00,		/* H-phase offset Luma = 0 */
-	0xdc, 0x00,		/* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
-	0xdd, 0x02,		/* H-scaling incr chroma */
-	0xde, 0x00,		/* H-phase offset chroma. must be offset luma / 2 */
+	R_D0_B_HORIZ_PRESCALING, 0x01,
+	R_D1_B_ACCUMULATION_LENGTH, 0x00,
+	R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
 
-	0xe0, 0x00,		/* V-scaling incr luma low */
-	0xe1, 0x04,		/* " hi */
-	0xe2, 0x00,		/* V-scaling incr chroma low */
-	0xe3, 0x04,		/* " hi */
-	0xe4, 0x01,		/* V-scaling mode control */
-	0xe8, 0x00,		/* V-phase offset chroma 00 */
-	0xe9, 0x00,		/* V-phase offset chroma 01 */
-	0xea, 0x00,		/* V-phase offset chroma 10 */
-	0xeb, 0x00,		/* V-phase offset chroma 11 */
-	0xec, 0x00,		/* V-phase offset luma 00 */
-	0xed, 0x00,		/* V-phase offset luma 01 */
-	0xee, 0x00,		/* V-phase offset luma 10 */
-	0xef, 0x00,		/* V-phase offset luma 11 */
+	/* Configure controls at nominal value*/
+	R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
+	R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
+	R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
 
-	0xf2, 0x50,		/* crystal clock = 24.576 MHz, target = 27MHz */
-	0xf3, 0x46,
-	0xf4, 0x00,
-	0xf7, 0x4b,		/* not the recommended settings! */
-	0xf8, 0x00,
-	0xf9, 0x4b,
-	0xfa, 0x00,
-	0xfb, 0x4b,
-	0xff, 0x88,		/* PLL2 lock detection settings: 71 lines 50% phase error */
+	/* hor lum scaling 0x0400 = 1 */
+	R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
+	R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+	/* must be hor lum scaling / 2 */
+	R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
+	R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
+
+	/* must be offset luma / 2 */
+	R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
+
+	R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
+	R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+	R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
+	R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+	R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
+
+	R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
+	R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
+	R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
+	R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+	R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
+	R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
+	R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
+	R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
+
+	R_F2_NOMINAL_PLL2_DTO, 0x50,		/* crystal clock = 24.576 MHz, target = 27MHz */
+	R_F3_PLL_INCREMENT, 0x46,
+	R_F4_PLL2_STATUS, 0x00,
+	R_F7_PULSE_A_POS_MSB, 0x4b,		/* not the recommended settings! */
+	R_F8_PULSE_B_POS, 0x00,
+	R_F9_PULSE_B_POS_MSB, 0x4b,
+	R_FA_PULSE_C_POS, 0x00,
+	R_FB_PULSE_C_POS_MSB, 0x4b,
+
+	/* PLL2 lock detection settings: 71 lines 50% phase error */
+	R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
 
 	/* Turn off VBI */
-	0x40, 0x20,             /* No framing code errors allowed. */
-	0x41, 0xff,
-	0x42, 0xff,
-	0x43, 0xff,
-	0x44, 0xff,
-	0x45, 0xff,
-	0x46, 0xff,
-	0x47, 0xff,
-	0x48, 0xff,
-	0x49, 0xff,
-	0x4a, 0xff,
-	0x4b, 0xff,
-	0x4c, 0xff,
-	0x4d, 0xff,
-	0x4e, 0xff,
-	0x4f, 0xff,
-	0x50, 0xff,
-	0x51, 0xff,
-	0x52, 0xff,
-	0x53, 0xff,
-	0x54, 0xff,
-	0x55, 0xff,
-	0x56, 0xff,
-	0x57, 0xff,
-	0x58, 0x40,
-	0x59, 0x47,
-	0x5b, 0x83,
-	0x5d, 0xbd,
-	0x5e, 0x35,
+	R_40_SLICER_CNTL_1, 0x20,             /* No framing code errors allowed. */
+	R_41_LCR_BASE, 0xff,
+	R_41_LCR_BASE+1, 0xff,
+	R_41_LCR_BASE+2, 0xff,
+	R_41_LCR_BASE+3, 0xff,
+	R_41_LCR_BASE+4, 0xff,
+	R_41_LCR_BASE+5, 0xff,
+	R_41_LCR_BASE+6, 0xff,
+	R_41_LCR_BASE+7, 0xff,
+	R_41_LCR_BASE+8, 0xff,
+	R_41_LCR_BASE+9, 0xff,
+	R_41_LCR_BASE+10, 0xff,
+	R_41_LCR_BASE+11, 0xff,
+	R_41_LCR_BASE+12, 0xff,
+	R_41_LCR_BASE+13, 0xff,
+	R_41_LCR_BASE+14, 0xff,
+	R_41_LCR_BASE+15, 0xff,
+	R_41_LCR_BASE+16, 0xff,
+	R_41_LCR_BASE+17, 0xff,
+	R_41_LCR_BASE+18, 0xff,
+	R_41_LCR_BASE+19, 0xff,
+	R_41_LCR_BASE+20, 0xff,
+	R_41_LCR_BASE+21, 0xff,
+	R_41_LCR_BASE+22, 0xff,
+	R_58_PROGRAM_FRAMING_CODE, 0x40,
+	R_59_H_OFF_FOR_SLICER, 0x47,
+	R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
+	R_5D_DID, 0xbd,
+	R_5E_SDID, 0x35,
 
-	0x02, 0x84,		/* input tuner -> input 4, amplifier active */
-	0x09, 0x53,		/* 0x53, was 0x56 for 60hz. luminance control */
+	R_02_INPUT_CNTL_1, 0x84,		/* input tuner -> input 4, amplifier active */
 
-	0x80, 0x20,		/* enable task B */
-	0x88, 0xd0,
-	0x88, 0xf0,
+	R_80_GLOBAL_CNTL_1, 0x20,		/* enable task B */
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
+	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
 	0x00, 0x00
 };
 
-static int saa7115_odd_parity(u8 c)
+static int saa711x_odd_parity(u8 c)
 {
 	c ^= (c >> 4);
 	c ^= (c >> 2);
@@ -502,7 +599,7 @@
 	return c & 1;
 }
 
-static int saa7115_decode_vps(u8 * dst, u8 * p)
+static int saa711x_decode_vps(u8 * dst, u8 * p)
 {
 	static const u8 biphase_tbl[] = {
 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
@@ -549,7 +646,7 @@
 	return err & 0xf0;
 }
 
-static int saa7115_decode_wss(u8 * p)
+static int saa711x_decode_wss(u8 * p)
 {
 	static const int wss_bits[8] = {
 		0, 0, 0, 1, 0, 1, 1, 1
@@ -576,26 +673,25 @@
 	return wss;
 }
 
-
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	u32 acpf;
 	u32 acni;
 	u32 hz;
 	u64 f;
 	u8 acc = 0; 	/* reg 0x3a, audio clock control */
 
+	/* Checks for chips that don't have audio clock (saa7111, saa7113) */
+	if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
+		return 0;
+
 	v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
 
 	/* sanity check */
 	if (freq < 32000 || freq > 48000)
 		return -EINVAL;
 
-	/* The saa7113 has no audio clock */
-	if (state->ident == V4L2_IDENT_SAA7113)
-		return 0;
-
 	/* 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 */
@@ -617,22 +713,26 @@
 	if (state->apll)
 		acc |= 0x08;
 
-	saa7115_write(client, 0x38, 0x03);
-	saa7115_write(client, 0x39, 0x10);
-	saa7115_write(client, 0x3a, acc);
-	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);
+	saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
+	saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+	saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
+
+	saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
+	saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
+							(acpf >> 8) & 0xff);
+	saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
+							(acpf >> 16) & 0x03);
+
+	saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
+	saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
+	saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
 	state->audclk_freq = freq;
 	return 0;
 }
 
-static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -642,7 +742,7 @@
 		}
 
 		state->bright = ctrl->value;
-		saa7115_write(client, 0x0a, state->bright);
+		saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
 		break;
 
 	case V4L2_CID_CONTRAST:
@@ -652,7 +752,7 @@
 		}
 
 		state->contrast = ctrl->value;
-		saa7115_write(client, 0x0b, state->contrast);
+		saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
 		break;
 
 	case V4L2_CID_SATURATION:
@@ -662,7 +762,7 @@
 		}
 
 		state->sat = ctrl->value;
-		saa7115_write(client, 0x0c, state->sat);
+		saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
 		break;
 
 	case V4L2_CID_HUE:
@@ -672,7 +772,7 @@
 		}
 
 		state->hue = ctrl->value;
-		saa7115_write(client, 0x0d, state->hue);
+		saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
 		break;
 
 	default:
@@ -682,9 +782,9 @@
 	return 0;
 }
 
-static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
@@ -706,10 +806,115 @@
 	return 0;
 }
 
-static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static int saa711x_set_size(struct i2c_client *client, int width, int height)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
-	int taskb = saa7115_read(client, 0x80) & 0x10;
+	struct saa711x_state *state = i2c_get_clientdata(client);
+	int HPSC, HFSC;
+	int VSCY;
+	int res;
+	int is_50hz = state->std & V4L2_STD_625_50;
+	int Vsrc = is_50hz ? 576 : 480;
+
+	v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
+
+	/* FIXME need better bounds checking here */
+	if ((width < 1) || (width > 1440))
+		return -EINVAL;
+	if ((height < 1) || (height > Vsrc))
+		return -EINVAL;
+
+	if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
+		/* Decoder only supports 720 columns and 480 or 576 lines */
+		if (width != 720)
+			return -EINVAL;
+		if (height != Vsrc)
+			return -EINVAL;
+	}
+
+	state->width = width;
+	state->height = height;
+
+	if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
+		return 0;
+
+	/* probably have a valid size, let's set it */
+	/* Set output width/height */
+	/* width */
+
+	saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
+					(u8) (width & 0xff));
+	saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
+					(u8) ((width >> 8) & 0xff));
+
+	/* Vertical Scaling uses height/2 */
+	res=height/2;
+
+	/* On 60Hz, it is using a higher Vertical Output Size */
+	if (!is_50hz)
+		res+=(VRES_60HZ-480)>>1;
+
+		/* height */
+	saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
+					(u8) (res & 0xff));
+	saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
+					(u8) ((res >> 8) & 0xff));
+
+	/* Scaling settings */
+	/* Hprescaler is floor(inres/outres) */
+	HPSC = (int)(720 / width);
+	/* 0 is not allowed (div. by zero) */
+	HPSC = HPSC ? HPSC : 1;
+	HFSC = (int)((1024 * 720) / (HPSC * width));
+	/* FIXME hardcodes to "Task B"
+	 * write H prescaler integer */
+	saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
+				(u8) (HPSC & 0x3f));
+
+	v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+	/* write H fine-scaling (luminance) */
+	saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
+				(u8) (HFSC & 0xff));
+	saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
+				(u8) ((HFSC >> 8) & 0xff));
+	/* write H fine-scaling (chrominance)
+	 * must be lum/2, so i'll just bitshift :) */
+	saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
+				(u8) ((HFSC >> 1) & 0xff));
+	saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
+				(u8) ((HFSC >> 9) & 0xff));
+
+	VSCY = (int)((1024 * Vsrc) / height);
+	v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+	/* Correct Contrast and Luminance */
+	saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
+					(u8) (64 * 1024 / VSCY));
+	saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
+					(u8) (64 * 1024 / VSCY));
+
+		/* write V fine-scaling (luminance) */
+	saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
+					(u8) (VSCY & 0xff));
+	saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
+					(u8) ((VSCY >> 8) & 0xff));
+		/* write V fine-scaling (chrominance) */
+	saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
+					(u8) (VSCY & 0xff));
+	saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
+					(u8) ((VSCY >> 8) & 0xff));
+
+	saa711x_writeregs(client, saa7115_cfg_reset_scaler);
+
+	/* Activates task "B" */
+	saa711x_write(client, R_80_GLOBAL_CNTL_1,
+				saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20);
+
+	return 0;
+}
+
+static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+	struct saa711x_state *state = i2c_get_clientdata(client);
 
 	/* Prevent unnecessary standard changes. During a standard
 	   change the I-Port is temporarily disabled. Any devices
@@ -721,17 +926,21 @@
 	if (std == state->std)
 		return;
 
+	state->std = std;
+
 	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
 	if (std & V4L2_STD_525_60) {
 		v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
-		saa7115_writeregs(client, saa7115_cfg_60hz_video);
+		saa711x_writeregs(client, saa7115_cfg_60hz_video);
+		saa711x_set_size(client,720,480);
 	} else {
 		v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
-		saa7115_writeregs(client, saa7115_cfg_50hz_video);
+		saa711x_writeregs(client, saa7115_cfg_50hz_video);
+		saa711x_set_size(client,720,576);
 	}
 
 	/* Register 0E - Bits D6-D4 on NO-AUTO mode
-		(SAA7113 doesn't have auto mode)
+		(SAA7111 and SAA7113 doesn't have auto mode)
 	    50 Hz / 625 lines           60 Hz / 525 lines
 	000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)
 	001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)
@@ -739,8 +948,9 @@
 	011 NTSC N (3.58MHz)            PAL M (3.58MHz)
 	100 reserved                    NTSC-Japan (3.58MHz)
 	*/
-	if (state->ident == V4L2_IDENT_SAA7113) {
-		u8 reg = saa7115_read(client, 0x0e) & 0x8f;
+	if (state->ident == V4L2_IDENT_SAA7111 ||
+	    state->ident == V4L2_IDENT_SAA7113) {
+		u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
 
 		if (std == V4L2_STD_PAL_M) {
 			reg |= 0x30;
@@ -751,31 +961,30 @@
 		} else if (std == V4L2_STD_NTSC_M_JP) {
 			reg |= 0x40;
 		}
-		saa7115_write(client, 0x0e, reg);
+		saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
+	} else {
+		/* restart task B if needed */
+		int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
+
+		if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+			saa711x_writeregs(client, saa7115_cfg_vbi_on);
+		}
+
+		/* switch audio mode too! */
+		saa711x_set_audio_clock_freq(client, state->audclk_freq);
 	}
-
-
-	state->std = std;
-
-	/* restart task B if needed */
-	if (taskb && state->ident != V4L2_IDENT_SAA7115) {
-		saa7115_writeregs(client, saa7115_cfg_vbi_on);
-	}
-
-	/* switch audio mode too! */
-	saa7115_set_audio_clock_freq(client, state->audclk_freq);
 }
 
-static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
+static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 
 	return state->std;
 }
 
-static void saa7115_log_status(struct i2c_client *client)
+static void saa711x_log_status(struct i2c_client *client)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	int reg1e, reg1f;
 	int signalOk;
 	int vcr;
@@ -783,7 +992,7 @@
 	v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
 	if (state->ident != V4L2_IDENT_SAA7115) {
 		/* status for the saa7114 */
-		reg1f = saa7115_read(client, 0x1f);
+		reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
 		signalOk = (reg1f & 0xc1) == 0x81;
 		v4l_info(client, "Video signal:    %s\n", signalOk ? "ok" : "bad");
 		v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
@@ -791,8 +1000,8 @@
 	}
 
 	/* status for the saa7115 */
-	reg1e = saa7115_read(client, 0x1e);
-	reg1f = saa7115_read(client, 0x1f);
+	reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
+	reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
 
 	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
 	vcr = !(reg1f & 0x10);
@@ -819,19 +1028,27 @@
 			v4l_info(client, "Detected format: BW/No color\n");
 			break;
 	}
+	v4l_info(client, "Width, Height:   %d, %d\n", state->width, state->height);
 }
 
 /* setup the sliced VBI lcr registers according to the sliced VBI format */
-static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	int is_50hz = (state->std & V4L2_STD_625_50);
 	u8 lcr[24];
 	int i, x;
 
-	/* saa7113/7114 doesn't yet support VBI */
+#if 1
+	/* saa7113/7114/7118 VBI support are experimental */
+	if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
+		return;
+
+#else
+	/* SAA7113 and SAA7118 also should support VBI - Need testing */
 	if (state->ident != V4L2_IDENT_SAA7115)
 		return;
+#endif
 
 	for (i = 0; i <= 23; i++)
 		lcr[i] = 0xff;
@@ -888,14 +1105,16 @@
 
 	/* write the lcr registers */
 	for (i = 2; i <= 23; i++) {
-		saa7115_write(client, i - 2 + 0x41, lcr[i]);
+		saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
 	}
 
 	/* enable/disable raw VBI capturing */
-	saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
+	saa711x_writeregs(client, fmt->service_set == 0 ?
+				saa7115_cfg_vbi_on :
+				saa7115_cfg_vbi_off);
 }
 
-static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
 	static u16 lcr2vbi[] = {
 		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
@@ -911,10 +1130,10 @@
 		return -EINVAL;
 	memset(sliced, 0, sizeof(*sliced));
 	/* done if using raw VBI */
-	if (saa7115_read(client, 0x80) & 0x10)
+	if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
 		return 0;
 	for (i = 2; i <= 23; i++) {
-		u8 v = saa7115_read(client, i - 2 + 0x41);
+		u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
 
 		sliced->service_lines[0][i] = lcr2vbi[v >> 4];
 		sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -924,114 +1143,31 @@
 	return 0;
 }
 
-static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
-	struct v4l2_pix_format *pix;
-	int HPSC, HFSC;
-	int VSCY, Vsrc;
-	int is_50hz = state->std & V4L2_STD_625_50;
-
 	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-		saa7115_set_lcr(client, &fmt->fmt.sliced);
+		saa711x_set_lcr(client, &fmt->fmt.sliced);
 		return 0;
 	}
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	pix = &(fmt->fmt.pix);
-
-	v4l_dbg(1, debug, client, "decoder set size\n");
-
-	/* FIXME need better bounds checking here */
-	if ((pix->width < 1) || (pix->width > 1440))
-		return -EINVAL;
-	if ((pix->height < 1) || (pix->height > 960))
-		return -EINVAL;
-
-	/* probably have a valid size, let's set it */
-	/* Set output width/height */
-	/* width */
-	saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
-	saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
-	/* height */
-	saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
-	saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
-
-	/* Scaling settings */
-	/* Hprescaler is floor(inres/outres) */
-	/* FIXME hardcoding input res */
-	if (pix->width != 720) {
-		HPSC = (int)(720 / pix->width);
-		/* 0 is not allowed (div. by zero) */
-		HPSC = HPSC ? HPSC : 1;
-		HFSC = (int)((1024 * 720) / (HPSC * pix->width));
-
-		v4l_dbg(1, debug, 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));
-
-		/* write H fine-scaling (luminance) */
-		saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
-		saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
-		/* write H fine-scaling (chrominance)
-		 * must be lum/2, so i'll just bitshift :) */
-		saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
-		saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
-	} else {
-		if (is_50hz) {
-			v4l_dbg(1, debug, client, "Setting full 50hz width\n");
-			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
-		} else {
-			v4l_dbg(1, debug, client, "Setting full 60hz width\n");
-			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
-		}
-	}
-
-	Vsrc = is_50hz ? 576 : 480;
-
-	if (pix->height != Vsrc) {
-		VSCY = (int)((1024 * Vsrc) / pix->height);
-		v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
-
-		/* Correct Contrast and Luminance */
-		saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
-		saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
-
-		/* write V fine-scaling (luminance) */
-		saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
-		saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
-		/* write V fine-scaling (chrominance) */
-		saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
-		saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
-	} else {
-		if (is_50hz) {
-			v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
-			saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
-		} else {
-			v4l_dbg(1, debug, client, "Setting full 60hz height\n");
-			saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
-		}
-	}
-
-	saa7115_writeregs(client, saa7115_cfg_reset_scaler);
-	return 0;
+	return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
 }
 
 /* Decode the sliced VBI data stream as created by the saa7115.
    The format is described in the saa7115 datasheet in Tables 25 and 26
    and in Figure 33.
    The current implementation uses SAV/EAV codes and not the ancillary data
-   headers. The vbi->p pointer points to the SDID byte right after the SAV
+   headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
    code. */
-static void saa7115_decode_vbi_line(struct i2c_client *client,
+static void saa711x_decode_vbi_line(struct i2c_client *client,
 				    struct v4l2_decode_vbi_line *vbi)
 {
 	static const char vbi_no_data_pattern[] = {
 		0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
 	};
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	u8 *p = vbi->p;
 	u32 wss;
 	int id1, id2;   /* the ID1 and ID2 bytes from the internal header */
@@ -1066,12 +1202,12 @@
 		vbi->type = V4L2_SLICED_TELETEXT_B;
 		break;
 	case 4:
-		if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
+		if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
 			return;
 		vbi->type = V4L2_SLICED_CAPTION_525;
 		break;
 	case 5:
-		wss = saa7115_decode_wss(p);
+		wss = saa711x_decode_wss(p);
 		if (wss == -1)
 			return;
 		p[0] = wss & 0xff;
@@ -1079,7 +1215,7 @@
 		vbi->type = V4L2_SLICED_WSS_625;
 		break;
 	case 7:
-		if (saa7115_decode_vps(p, p) != 0)
+		if (saa711x_decode_vps(p, p) != 0)
 			return;
 		vbi->type = V4L2_SLICED_VPS;
 		break;
@@ -1090,21 +1226,21 @@
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	int *iarg = arg;
 
 	/* ioctls to allow direct access to the saa7115 registers for testing */
 	switch (cmd) {
 	case VIDIOC_S_FMT:
-		return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
+		return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_G_FMT:
-		return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
+		return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
+		return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
 
 	case VIDIOC_G_TUNER:
 	{
@@ -1113,7 +1249,7 @@
 
 		if (state->radio)
 			break;
-		status = saa7115_read(client, 0x1f);
+		status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
 
 		v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
 		vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
@@ -1121,14 +1257,14 @@
 	}
 
 	case VIDIOC_LOG_STATUS:
-		saa7115_log_status(client);
+		saa711x_log_status(client);
 		break;
 
 	case VIDIOC_G_CTRL:
-		return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
+		return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
 
 	case VIDIOC_S_CTRL:
-		return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+		return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
 
 	case VIDIOC_QUERYCTRL:
 	{
@@ -1146,12 +1282,12 @@
 	}
 
 	case VIDIOC_G_STD:
-		*(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
+		*(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
 		break;
 
 	case VIDIOC_S_STD:
 		state->radio = 0;
-		saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
+		saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
 		break;
 
 	case AUDC_SET_RADIO:
@@ -1187,13 +1323,13 @@
 		state->input = route->input;
 
 		/* select mode */
-		saa7115_write(client, 0x02,
-			      (saa7115_read(client, 0x02) & 0xf0) |
+		saa711x_write(client, R_02_INPUT_CNTL_1,
+			      (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
 			       state->input);
 
 		/* bypass chrominance trap for S-Video modes */
-		saa7115_write(client, 0x09,
-			      (saa7115_read(client, 0x09) & 0x7f) |
+		saa711x_write(client, R_09_LUMA_CNTL,
+			      (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
 			       (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
 		break;
 	}
@@ -1205,7 +1341,9 @@
 
 		if (state->enable != (cmd == VIDIOC_STREAMON)) {
 			state->enable = (cmd == VIDIOC_STREAMON);
-			saa7115_write(client, 0x87, state->enable);
+			saa711x_write(client,
+				R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
+				state->enable);
 		}
 		break;
 
@@ -1220,17 +1358,17 @@
 		state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
 		state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
 		state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
-		saa7115_set_audio_clock_freq(client, state->audclk_freq);
+		saa711x_set_audio_clock_freq(client, state->audclk_freq);
 		break;
 	}
 
 	case VIDIOC_INT_DECODE_VBI_LINE:
-		saa7115_decode_vbi_line(client, arg);
+		saa711x_decode_vbi_line(client, arg);
 		break;
 
 	case VIDIOC_INT_RESET:
 		v4l_dbg(1, debug, client, "decoder RESET\n");
-		saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+		saa711x_writeregs(client, saa7115_cfg_reset_scaler);
 		break;
 
 	case VIDIOC_INT_G_VBI_DATA:
@@ -1239,25 +1377,25 @@
 
 		switch (data->id) {
 		case V4L2_SLICED_WSS_625:
-			if (saa7115_read(client, 0x6b) & 0xc0)
+			if (saa711x_read(client, 0x6b) & 0xc0)
 				return -EIO;
-			data->data[0] = saa7115_read(client, 0x6c);
-			data->data[1] = saa7115_read(client, 0x6d);
+			data->data[0] = saa711x_read(client, 0x6c);
+			data->data[1] = saa711x_read(client, 0x6d);
 			return 0;
 		case V4L2_SLICED_CAPTION_525:
 			if (data->field == 0) {
 				/* CC */
-				if (saa7115_read(client, 0x66) & 0xc0)
+				if (saa711x_read(client, 0x66) & 0xc0)
 					return -EIO;
-				data->data[0] = saa7115_read(client, 0x67);
-				data->data[1] = saa7115_read(client, 0x68);
+				data->data[0] = saa711x_read(client, 0x67);
+				data->data[1] = saa711x_read(client, 0x68);
 				return 0;
 			}
 			/* XDS */
-			if (saa7115_read(client, 0x66) & 0x30)
+			if (saa711x_read(client, 0x66) & 0x30)
 				return -EIO;
-			data->data[0] = saa7115_read(client, 0x69);
-			data->data[1] = saa7115_read(client, 0x6a);
+			data->data[0] = saa711x_read(client, 0x69);
+			data->data[1] = saa711x_read(client, 0x6a);
 			return 0;
 		default:
 			return -EINVAL;
@@ -1272,7 +1410,7 @@
 
 		if (reg->i2c_id != I2C_DRIVERID_SAA711X)
 			return -EINVAL;
-		reg->val = saa7115_read(client, reg->reg & 0xff);
+		reg->val = saa711x_read(client, reg->reg & 0xff);
 		break;
 	}
 
@@ -1284,7 +1422,7 @@
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
+		saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
@@ -1302,12 +1440,14 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7115;
+static struct i2c_driver i2c_driver_saa711x;
 
-static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
 {
 	struct i2c_client *client;
-	struct saa7115_state *state;
+	struct saa711x_state *state;
+	int	i;
+	char	name[17];
 	u8 chip_id;
 
 	/* Check if the adapter supports the needed features */
@@ -1319,28 +1459,31 @@
 		return -ENOMEM;
 	client->addr = address;
 	client->adapter = adapter;
-	client->driver = &i2c_driver_saa7115;
+	client->driver = &i2c_driver_saa711x;
 	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
 	v4l_dbg(1, debug, 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 < 3 && chip_id > 5) {
-		v4l_dbg(1, debug, client, "saa7115 not found\n");
-		kfree(client);
-		return 0;
+	for (i=0;i<0x0f;i++) {
+		saa711x_write(client, 0, i);
+		name[i] = (saa711x_read(client, 0) &0x0f) +'0';
+		if (name[i]>'9')
+			name[i]+='a'-'9'-1;
 	}
-	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
-	v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+	name[i]='\0';
 
-	state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
+	saa711x_write(client, 0, 5);
+	chip_id = saa711x_read(client, 0) & 0x0f;
+
+	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
+	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
+
+	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
 	i2c_set_clientdata(client, state);
 	if (state == NULL) {
 		kfree(client);
 		return -ENOMEM;
 	}
-	state->std = V4L2_STD_NTSC;
 	state->input = -1;
 	state->enable = 1;
 	state->radio = 0;
@@ -1349,15 +1492,25 @@
 	state->hue = 0;
 	state->sat = 64;
 	switch (chip_id) {
+	case 1:
+		state->ident = V4L2_IDENT_SAA7111;
+		break;
 	case 3:
 		state->ident = V4L2_IDENT_SAA7113;
 		break;
 	case 4:
 		state->ident = V4L2_IDENT_SAA7114;
 		break;
-	default:
+	case 5:
 		state->ident = V4L2_IDENT_SAA7115;
 		break;
+	case 8:
+		state->ident = V4L2_IDENT_SAA7118;
+		break;
+	default:
+		state->ident = V4L2_IDENT_SAA7111;
+		v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
+
 	}
 
 	state->audclk_freq = 48000;
@@ -1365,38 +1518,39 @@
 	v4l_dbg(1, debug, client, "writing init values\n");
 
 	/* init to 60hz/48khz */
-	if (state->ident == V4L2_IDENT_SAA7113) {
-		state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
-		saa7115_writeregs(client, saa7113_init_auto_input);
-	} else {
+	state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
+	switch (state->ident) {
+	case V4L2_IDENT_SAA7111:
+		saa711x_writeregs(client, saa7111_init);
+		break;
+	case V4L2_IDENT_SAA7113:
+		saa711x_writeregs(client, saa7113_init);
+		break;
+	default:
 		state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
-		saa7115_writeregs(client, saa7115_init_auto_input);
+		saa711x_writeregs(client, saa7115_init_auto_input);
 	}
-	saa7115_writeregs(client, saa7115_init_misc);
-	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
-	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
-	saa7115_writeregs(client, saa7115_cfg_60hz_video);
-	saa7115_set_audio_clock_freq(client, state->audclk_freq);
-	saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+	saa711x_writeregs(client, saa7115_init_misc);
+	saa711x_set_v4lstd(client, V4L2_STD_NTSC);
 
 	i2c_attach_client(client);
 
 	v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
-		saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
+		saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
 
 	return 0;
 }
 
-static int saa7115_probe(struct i2c_adapter *adapter)
+static int saa711x_probe(struct i2c_adapter *adapter)
 {
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, &saa7115_attach);
+		return i2c_probe(adapter, &addr_data, &saa711x_attach);
 	return 0;
 }
 
-static int saa7115_detach(struct i2c_client *client)
+static int saa711x_detach(struct i2c_client *client)
 {
-	struct saa7115_state *state = i2c_get_clientdata(client);
+	struct saa711x_state *state = i2c_get_clientdata(client);
 	int err;
 
 	err = i2c_detach_client(client);
@@ -1412,26 +1566,26 @@
 /* ----------------------------------------------------------------------- */
 
 /* i2c implementation */
-static struct i2c_driver i2c_driver_saa7115 = {
+static struct i2c_driver i2c_driver_saa711x = {
 	.driver = {
 		.name = "saa7115",
 	},
 	.id = I2C_DRIVERID_SAA711X,
-	.attach_adapter = saa7115_probe,
-	.detach_client = saa7115_detach,
-	.command = saa7115_command,
+	.attach_adapter = saa711x_probe,
+	.detach_client = saa711x_detach,
+	.command = saa711x_command,
 };
 
 
-static int __init saa7115_init_module(void)
+static int __init saa711x_init_module(void)
 {
-	return i2c_add_driver(&i2c_driver_saa7115);
+	return i2c_add_driver(&i2c_driver_saa711x);
 }
 
-static void __exit saa7115_cleanup_module(void)
+static void __exit saa711x_cleanup_module(void)
 {
-	i2c_del_driver(&i2c_driver_saa7115);
+	i2c_del_driver(&i2c_driver_saa711x);
 }
 
-module_init(saa7115_init_module);
-module_exit(saa7115_cleanup_module);
+module_init(saa711x_init_module);
+module_exit(saa711x_cleanup_module);
diff --git a/drivers/media/video/saa711x_regs.h b/drivers/media/video/saa711x_regs.h
new file mode 100644
index 0000000..4e5f2eb
--- /dev/null
+++ b/drivers/media/video/saa711x_regs.h
@@ -0,0 +1,549 @@
+/* saa711x - Philips SAA711x video decoder register specifications
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.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.
+ */
+
+#define R_00_CHIP_VERSION                             0x00
+/* Video Decoder */
+	/* Video Decoder - Frontend part */
+#define R_01_INC_DELAY                                0x01
+#define R_02_INPUT_CNTL_1                             0x02
+#define R_03_INPUT_CNTL_2                             0x03
+#define R_04_INPUT_CNTL_3                             0x04
+#define R_05_INPUT_CNTL_4                             0x05
+	/* Video Decoder - Decoder part */
+#define R_06_H_SYNC_START                             0x06
+#define R_07_H_SYNC_STOP                              0x07
+#define R_08_SYNC_CNTL                                0x08
+#define R_09_LUMA_CNTL                                0x09
+#define R_0A_LUMA_BRIGHT_CNTL                         0x0a
+#define R_0B_LUMA_CONTRAST_CNTL                       0x0b
+#define R_0C_CHROMA_SAT_CNTL                          0x0c
+#define R_0D_CHROMA_HUE_CNTL                          0x0d
+#define R_0E_CHROMA_CNTL_1                            0x0e
+#define R_0F_CHROMA_GAIN_CNTL                         0x0f
+#define R_10_CHROMA_CNTL_2                            0x10
+#define R_11_MODE_DELAY_CNTL                          0x11
+#define R_12_RT_SIGNAL_CNTL                           0x12
+#define R_13_RT_X_PORT_OUT_CNTL                       0x13
+#define R_14_ANAL_ADC_COMPAT_CNTL                     0x14
+#define R_15_VGATE_START_FID_CHG                      0x15
+#define R_16_VGATE_STOP                               0x16
+#define R_17_MISC_VGATE_CONF_AND_MSB                  0x17
+#define R_18_RAW_DATA_GAIN_CNTL                       0x18
+#define R_19_RAW_DATA_OFF_CNTL                        0x19
+#define R_1A_COLOR_KILL_LVL_CNTL                      0x1a
+#define R_1B_MISC_TVVCRDET                            0x1b
+#define R_1C_ENHAN_COMB_CTRL1                         0x1c
+#define R_1D_ENHAN_COMB_CTRL2                         0x1d
+#define R_1E_STATUS_BYTE_1_VD_DEC                     0x1e
+#define R_1F_STATUS_BYTE_2_VD_DEC                     0x1f
+
+/* Component processing and interrupt masking part */
+#define R_23_INPUT_CNTL_5                             0x23
+#define R_24_INPUT_CNTL_6                             0x24
+#define R_25_INPUT_CNTL_7                             0x25
+#define R_29_COMP_DELAY                               0x29
+#define R_2A_COMP_BRIGHT_CNTL                         0x2a
+#define R_2B_COMP_CONTRAST_CNTL                       0x2b
+#define R_2C_COMP_SAT_CNTL                            0x2c
+#define R_2D_INTERRUPT_MASK_1                         0x2d
+#define R_2E_INTERRUPT_MASK_2                         0x2e
+#define R_2F_INTERRUPT_MASK_3                         0x2f
+
+/* Audio clock generator part */
+#define R_30_AUD_MAST_CLK_CYCLES_PER_FIELD            0x30
+#define R_34_AUD_MAST_CLK_NOMINAL_INC                 0x34
+#define R_38_CLK_RATIO_AMXCLK_TO_ASCLK                0x38
+#define R_39_CLK_RATIO_ASCLK_TO_ALRCLK                0x39
+#define R_3A_AUD_CLK_GEN_BASIC_SETUP                  0x3a
+
+/* General purpose VBI data slicer part */
+#define R_40_SLICER_CNTL_1                            0x40
+#define R_41_LCR_BASE                                 0x41
+#define R_58_PROGRAM_FRAMING_CODE                     0x58
+#define R_59_H_OFF_FOR_SLICER                         0x59
+#define R_5A_V_OFF_FOR_SLICER                         0x5a
+#define R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF          0x5b
+#define R_5D_DID                                      0x5d
+#define R_5E_SDID                                     0x5e
+#define R_60_SLICER_STATUS_BYTE_0                     0x60
+#define R_61_SLICER_STATUS_BYTE_1                     0x61
+#define R_62_SLICER_STATUS_BYTE_2                     0x62
+
+/* X port, I port and the scaler part */
+	/* Task independent global settings */
+#define R_80_GLOBAL_CNTL_1                            0x80
+#define R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F    0x81
+#define R_83_X_PORT_I_O_ENA_AND_OUT_CLK               0x83
+#define R_84_I_PORT_SIGNAL_DEF                        0x84
+#define R_85_I_PORT_SIGNAL_POLAR                      0x85
+#define R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT          0x86
+#define R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED         0x87
+#define R_88_POWER_SAVE_ADC_PORT_CNTL                 0x88
+#define R_8F_STATUS_INFO_SCALER                       0x8f
+	/* Task A definition */
+		/* Basic settings and acquisition window definition */
+#define R_90_A_TASK_HANDLING_CNTL                     0x90
+#define R_91_A_X_PORT_FORMATS_AND_CONF                0x91
+#define R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL          0x92
+#define R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF         0x93
+#define R_94_A_HORIZ_INPUT_WINDOW_START               0x94
+#define R_95_A_HORIZ_INPUT_WINDOW_START_MSB           0x95
+#define R_96_A_HORIZ_INPUT_WINDOW_LENGTH              0x96
+#define R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB          0x97
+#define R_98_A_VERT_INPUT_WINDOW_START                0x98
+#define R_99_A_VERT_INPUT_WINDOW_START_MSB            0x99
+#define R_9A_A_VERT_INPUT_WINDOW_LENGTH               0x9a
+#define R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB           0x9b
+#define R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH             0x9c
+#define R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB         0x9d
+#define R_9E_A_VERT_OUTPUT_WINDOW_LENGTH              0x9e
+#define R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB          0x9f
+		/* FIR filtering and prescaling */
+#define R_A0_A_HORIZ_PRESCALING                       0xa0
+#define R_A1_A_ACCUMULATION_LENGTH                    0xa1
+#define R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER    0xa2
+#define R_A4_A_LUMA_BRIGHTNESS_CNTL                   0xa4
+#define R_A5_A_LUMA_CONTRAST_CNTL                     0xa5
+#define R_A6_A_CHROMA_SATURATION_CNTL                 0xa6
+		/* Horizontal phase scaling */
+#define R_A8_A_HORIZ_LUMA_SCALING_INC                 0xa8
+#define R_A9_A_HORIZ_LUMA_SCALING_INC_MSB             0xa9
+#define R_AA_A_HORIZ_LUMA_PHASE_OFF                   0xaa
+#define R_AC_A_HORIZ_CHROMA_SCALING_INC               0xac
+#define R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB           0xad
+#define R_AE_A_HORIZ_CHROMA_PHASE_OFF                 0xae
+#define R_AF_A_HORIZ_CHROMA_PHASE_OFF_MSB             0xaf
+		/* Vertical scaling */
+#define R_B0_A_VERT_LUMA_SCALING_INC                  0xb0
+#define R_B1_A_VERT_LUMA_SCALING_INC_MSB              0xb1
+#define R_B2_A_VERT_CHROMA_SCALING_INC                0xb2
+#define R_B3_A_VERT_CHROMA_SCALING_INC_MSB            0xb3
+#define R_B4_A_VERT_SCALING_MODE_CNTL                 0xb4
+#define R_B8_A_VERT_CHROMA_PHASE_OFF_00               0xb8
+#define R_B9_A_VERT_CHROMA_PHASE_OFF_01               0xb9
+#define R_BA_A_VERT_CHROMA_PHASE_OFF_10               0xba
+#define R_BB_A_VERT_CHROMA_PHASE_OFF_11               0xbb
+#define R_BC_A_VERT_LUMA_PHASE_OFF_00                 0xbc
+#define R_BD_A_VERT_LUMA_PHASE_OFF_01                 0xbd
+#define R_BE_A_VERT_LUMA_PHASE_OFF_10                 0xbe
+#define R_BF_A_VERT_LUMA_PHASE_OFF_11                 0xbf
+	/* Task B definition */
+		/* Basic settings and acquisition window definition */
+#define R_C0_B_TASK_HANDLING_CNTL                     0xc0
+#define R_C1_B_X_PORT_FORMATS_AND_CONF                0xc1
+#define R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION      0xc2
+#define R_C3_B_I_PORT_FORMATS_AND_CONF                0xc3
+#define R_C4_B_HORIZ_INPUT_WINDOW_START               0xc4
+#define R_C5_B_HORIZ_INPUT_WINDOW_START_MSB           0xc5
+#define R_C6_B_HORIZ_INPUT_WINDOW_LENGTH              0xc6
+#define R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB          0xc7
+#define R_C8_B_VERT_INPUT_WINDOW_START                0xc8
+#define R_C9_B_VERT_INPUT_WINDOW_START_MSB            0xc9
+#define R_CA_B_VERT_INPUT_WINDOW_LENGTH               0xca
+#define R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB           0xcb
+#define R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH             0xcc
+#define R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB         0xcd
+#define R_CE_B_VERT_OUTPUT_WINDOW_LENGTH              0xce
+#define R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB          0xcf
+		/* FIR filtering and prescaling */
+#define R_D0_B_HORIZ_PRESCALING                       0xd0
+#define R_D1_B_ACCUMULATION_LENGTH                    0xd1
+#define R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER    0xd2
+#define R_D4_B_LUMA_BRIGHTNESS_CNTL                   0xd4
+#define R_D5_B_LUMA_CONTRAST_CNTL                     0xd5
+#define R_D6_B_CHROMA_SATURATION_CNTL                 0xd6
+		/* Horizontal phase scaling */
+#define R_D8_B_HORIZ_LUMA_SCALING_INC                 0xd8
+#define R_D9_B_HORIZ_LUMA_SCALING_INC_MSB             0xd9
+#define R_DA_B_HORIZ_LUMA_PHASE_OFF                   0xda
+#define R_DC_B_HORIZ_CHROMA_SCALING                   0xdc
+#define R_DD_B_HORIZ_CHROMA_SCALING_MSB               0xdd
+#define R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA              0xde
+		/* Vertical scaling */
+#define R_E0_B_VERT_LUMA_SCALING_INC                  0xe0
+#define R_E1_B_VERT_LUMA_SCALING_INC_MSB              0xe1
+#define R_E2_B_VERT_CHROMA_SCALING_INC                0xe2
+#define R_E3_B_VERT_CHROMA_SCALING_INC_MSB            0xe3
+#define R_E4_B_VERT_SCALING_MODE_CNTL                 0xe4
+#define R_E8_B_VERT_CHROMA_PHASE_OFF_00               0xe8
+#define R_E9_B_VERT_CHROMA_PHASE_OFF_01               0xe9
+#define R_EA_B_VERT_CHROMA_PHASE_OFF_10               0xea
+#define R_EB_B_VERT_CHROMA_PHASE_OFF_11               0xeb
+#define R_EC_B_VERT_LUMA_PHASE_OFF_00                 0xec
+#define R_ED_B_VERT_LUMA_PHASE_OFF_01                 0xed
+#define R_EE_B_VERT_LUMA_PHASE_OFF_10                 0xee
+#define R_EF_B_VERT_LUMA_PHASE_OFF_11                 0xef
+
+/* second PLL (PLL2) and Pulsegenerator Programming */
+#define R_F0_LFCO_PER_LINE                            0xf0
+#define R_F1_P_I_PARAM_SELECT                         0xf1
+#define R_F2_NOMINAL_PLL2_DTO                         0xf2
+#define R_F3_PLL_INCREMENT                            0xf3
+#define R_F4_PLL2_STATUS                              0xf4
+#define R_F5_PULSGEN_LINE_LENGTH                      0xf5
+#define R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG      0xf6
+#define R_F7_PULSE_A_POS_MSB                          0xf7
+#define R_F8_PULSE_B_POS                              0xf8
+#define R_F9_PULSE_B_POS_MSB                          0xf9
+#define R_FA_PULSE_C_POS                              0xfa
+#define R_FB_PULSE_C_POS_MSB                          0xfb
+#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES     0xff
+
+#if 0
+/* Those structs will be used in the future for debug purposes */
+struct saa711x_reg_descr {
+	u8 reg;
+	int count;
+	char *name;
+};
+
+struct saa711x_reg_descr saa711x_regs[] = {
+	/* REG COUNT NAME */
+	{R_00_CHIP_VERSION,1,
+	 "Chip version"},
+
+	/* Video Decoder: R_01_INC_DELAY to R_1F_STATUS_BYTE_2_VD_DEC */
+
+	/* Video Decoder - Frontend part: R_01_INC_DELAY to R_05_INPUT_CNTL_4 */
+	{R_01_INC_DELAY,1,
+	 "Increment delay"},
+	{R_02_INPUT_CNTL_1,1,
+	 "Analog input control 1"},
+	{R_03_INPUT_CNTL_2,1,
+	 "Analog input control 2"},
+	{R_04_INPUT_CNTL_3,1,
+	 "Analog input control 3"},
+	{R_05_INPUT_CNTL_4,1,
+	 "Analog input control 4"},
+
+	/* Video Decoder - Decoder part: R_06_H_SYNC_START to R_1F_STATUS_BYTE_2_VD_DEC */
+	{R_06_H_SYNC_START,1,
+	 "Horizontal sync start"},
+	{R_07_H_SYNC_STOP,1,
+	 "Horizontal sync stop"},
+	{R_08_SYNC_CNTL,1,
+	 "Sync control"},
+	{R_09_LUMA_CNTL,1,
+	 "Luminance control"},
+	{R_0A_LUMA_BRIGHT_CNTL,1,
+	 "Luminance brightness control"},
+	{R_0B_LUMA_CONTRAST_CNTL,1,
+	 "Luminance contrast control"},
+	{R_0C_CHROMA_SAT_CNTL,1,
+	 "Chrominance saturation control"},
+	{R_0D_CHROMA_HUE_CNTL,1,
+	 "Chrominance hue control"},
+	{R_0E_CHROMA_CNTL_1,1,
+	 "Chrominance control 1"},
+	{R_0F_CHROMA_GAIN_CNTL,1,
+	 "Chrominance gain control"},
+	{R_10_CHROMA_CNTL_2,1,
+	 "Chrominance control 2"},
+	{R_11_MODE_DELAY_CNTL,1,
+	 "Mode/delay control"},
+	{R_12_RT_SIGNAL_CNTL,1,
+	 "RT signal control"},
+	{R_13_RT_X_PORT_OUT_CNTL,1,
+	 "RT/X port output control"},
+	{R_14_ANAL_ADC_COMPAT_CNTL,1,
+	 "Analog/ADC/compatibility control"},
+	{R_15_VGATE_START_FID_CHG,  1,
+	 "VGATE start FID change"},
+	{R_16_VGATE_STOP,1,
+	 "VGATE stop"},
+	{R_17_MISC_VGATE_CONF_AND_MSB,  1,
+	 "Miscellaneous VGATE configuration and MSBs"},
+	{R_18_RAW_DATA_GAIN_CNTL,1,
+	 "Raw data gain control",},
+	{R_19_RAW_DATA_OFF_CNTL,1,
+	 "Raw data offset control",},
+	{R_1A_COLOR_KILL_LVL_CNTL,1,
+	 "Color Killer Level Control"},
+	{ R_1B_MISC_TVVCRDET, 1,
+	  "MISC /TVVCRDET"},
+	{ R_1C_ENHAN_COMB_CTRL1, 1,
+	 "Enhanced comb ctrl1"},
+	{ R_1D_ENHAN_COMB_CTRL2, 1,
+	 "Enhanced comb ctrl1"},
+	{R_1E_STATUS_BYTE_1_VD_DEC,1,
+	 "Status byte 1 video decoder"},
+	{R_1F_STATUS_BYTE_2_VD_DEC,1,
+	 "Status byte 2 video decoder"},
+
+	/* Component processing and interrupt masking part:  0x20h to R_2F_INTERRUPT_MASK_3 */
+	/* 0x20 to 0x22 - Reserved */
+	{R_23_INPUT_CNTL_5,1,
+	 "Analog input control 5"},
+	{R_24_INPUT_CNTL_6,1,
+	 "Analog input control 6"},
+	{R_25_INPUT_CNTL_7,1,
+	 "Analog input control 7"},
+	/* 0x26 to 0x28 - Reserved */
+	{R_29_COMP_DELAY,1,
+	 "Component delay"},
+	{R_2A_COMP_BRIGHT_CNTL,1,
+	 "Component brightness control"},
+	{R_2B_COMP_CONTRAST_CNTL,1,
+	 "Component contrast control"},
+	{R_2C_COMP_SAT_CNTL,1,
+	 "Component saturation control"},
+	{R_2D_INTERRUPT_MASK_1,1,
+	 "Interrupt mask 1"},
+	{R_2E_INTERRUPT_MASK_2,1,
+	 "Interrupt mask 2"},
+	{R_2F_INTERRUPT_MASK_3,1,
+	 "Interrupt mask 3"},
+
+	/* Audio clock generator part: R_30_AUD_MAST_CLK_CYCLES_PER_FIELD to 0x3f */
+	{R_30_AUD_MAST_CLK_CYCLES_PER_FIELD,3,
+	 "Audio master clock cycles per field"},
+	/* 0x33 - Reserved */
+	{R_34_AUD_MAST_CLK_NOMINAL_INC,3,
+	 "Audio master clock nominal increment"},
+	/* 0x37 - Reserved */
+	{R_38_CLK_RATIO_AMXCLK_TO_ASCLK,1,
+	 "Clock ratio AMXCLK to ASCLK"},
+	{R_39_CLK_RATIO_ASCLK_TO_ALRCLK,1,
+	 "Clock ratio ASCLK to ALRCLK"},
+	{R_3A_AUD_CLK_GEN_BASIC_SETUP,1,
+	 "Audio clock generator basic setup"},
+	/* 0x3b-0x3f - Reserved */
+
+	/* General purpose VBI data slicer part: R_40_SLICER_CNTL_1 to 0x7f */
+	{R_40_SLICER_CNTL_1,1,
+	 "Slicer control 1"},
+	{R_41_LCR,23,
+	 "R_41_LCR"},
+	{R_58_PROGRAM_FRAMING_CODE,1,
+	 "Programmable framing code"},
+	{R_59_H_OFF_FOR_SLICER,1,
+	 "Horizontal offset for slicer"},
+	{R_5A_V_OFF_FOR_SLICER,1,
+	 "Vertical offset for slicer"},
+	{R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF,1,
+	 "Field offset and MSBs for horizontal and vertical offset"},
+	{R_5D_DID,1,
+	 "Header and data identification (R_5D_DID)"},
+	{R_5E_SDID,1,
+	 "Sliced data identification (R_5E_SDID) code"},
+	{R_60_SLICER_STATUS_BYTE_0,1,
+	 "Slicer status byte 0"},
+	{R_61_SLICER_STATUS_BYTE_1,1,
+	 "Slicer status byte 1"},
+	{R_62_SLICER_STATUS_BYTE_2,1,
+	 "Slicer status byte 2"},
+	/* 0x63-0x7f - Reserved */
+
+	/* X port, I port and the scaler part: R_80_GLOBAL_CNTL_1 to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+	/* Task independent global settings: R_80_GLOBAL_CNTL_1 to R_8F_STATUS_INFO_SCALER */
+	{R_80_GLOBAL_CNTL_1,1,
+	 "Global control 1"},
+	{R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F,1,
+	 "Vertical sync and Field ID source selection, retimed V and F signals"},
+	/* 0x82 - Reserved */
+	{R_83_X_PORT_I_O_ENA_AND_OUT_CLK,1,
+	 "X port I/O enable and output clock"},
+	{R_84_I_PORT_SIGNAL_DEF,1,
+	 "I port signal definitions"},
+	{R_85_I_PORT_SIGNAL_POLAR,1,
+	 "I port signal polarities"},
+	{R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT,1,
+	 "I port FIFO flag control and arbitration"},
+	{R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,  1,
+	 "I port I/O enable output clock and gated"},
+	{R_88_POWER_SAVE_ADC_PORT_CNTL,1,
+	 "Power save/ADC port control"},
+	/* 089-0x8e - Reserved */
+	{R_8F_STATUS_INFO_SCALER,1,
+	 "Status information scaler part"},
+
+	/* Task A definition: R_90_A_TASK_HANDLING_CNTL to R_BF_A_VERT_LUMA_PHASE_OFF_11 */
+	/* Task A: Basic settings and acquisition window definition */
+	{R_90_A_TASK_HANDLING_CNTL,1,
+	 "Task A: Task handling control"},
+	{R_91_A_X_PORT_FORMATS_AND_CONF,1,
+	 "Task A: X port formats and configuration"},
+	{R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL,1,
+	 "Task A: X port input reference signal definition"},
+	{R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF,1,
+	 "Task A: I port output formats and configuration"},
+	{R_94_A_HORIZ_INPUT_WINDOW_START,2,
+	 "Task A: Horizontal input window start"},
+	{R_96_A_HORIZ_INPUT_WINDOW_LENGTH,2,
+	 "Task A: Horizontal input window length"},
+	{R_98_A_VERT_INPUT_WINDOW_START,2,
+	 "Task A: Vertical input window start"},
+	{R_9A_A_VERT_INPUT_WINDOW_LENGTH,2,
+	 "Task A: Vertical input window length"},
+	{R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+	 "Task A: Horizontal output window length"},
+	{R_9E_A_VERT_OUTPUT_WINDOW_LENGTH,2,
+	 "Task A: Vertical output window length"},
+
+	/* Task A: FIR filtering and prescaling */
+	{R_A0_A_HORIZ_PRESCALING,1,
+	 "Task A: Horizontal prescaling"},
+	{R_A1_A_ACCUMULATION_LENGTH,1,
+	 "Task A: Accumulation length"},
+	{R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+	 "Task A: Prescaler DC gain and FIR prefilter"},
+	/* 0xa3 - Reserved */
+	{R_A4_A_LUMA_BRIGHTNESS_CNTL,1,
+	 "Task A: Luminance brightness control"},
+	{R_A5_A_LUMA_CONTRAST_CNTL,1,
+	 "Task A: Luminance contrast control"},
+	{R_A6_A_CHROMA_SATURATION_CNTL,1,
+	 "Task A: Chrominance saturation control"},
+	/* 0xa7 - Reserved */
+
+	/* Task A: Horizontal phase scaling */
+	{R_A8_A_HORIZ_LUMA_SCALING_INC,2,
+	 "Task A: Horizontal luminance scaling increment"},
+	{R_AA_A_HORIZ_LUMA_PHASE_OFF,1,
+	 "Task A: Horizontal luminance phase offset"},
+	/* 0xab - Reserved */
+	{R_AC_A_HORIZ_CHROMA_SCALING_INC,2,
+	 "Task A: Horizontal chrominance scaling increment"},
+	{R_AE_A_HORIZ_CHROMA_PHASE_OFF,1,
+	 "Task A: Horizontal chrominance phase offset"},
+	/* 0xaf - Reserved */
+
+	/* Task A: Vertical scaling */
+	{R_B0_A_VERT_LUMA_SCALING_INC,2,
+	 "Task A: Vertical luminance scaling increment"},
+	{R_B2_A_VERT_CHROMA_SCALING_INC,2,
+	 "Task A: Vertical chrominance scaling increment"},
+	{R_B4_A_VERT_SCALING_MODE_CNTL,1,
+	 "Task A: Vertical scaling mode control"},
+	/* 0xb5-0xb7 - Reserved */
+	{R_B8_A_VERT_CHROMA_PHASE_OFF_00,1,
+	 "Task A: Vertical chrominance phase offset '00'"},
+	{R_B9_A_VERT_CHROMA_PHASE_OFF_01,1,
+	 "Task A: Vertical chrominance phase offset '01'"},
+	{R_BA_A_VERT_CHROMA_PHASE_OFF_10,1,
+	 "Task A: Vertical chrominance phase offset '10'"},
+	{R_BB_A_VERT_CHROMA_PHASE_OFF_11,1,
+	 "Task A: Vertical chrominance phase offset '11'"},
+	{R_BC_A_VERT_LUMA_PHASE_OFF_00,1,
+	 "Task A: Vertical luminance phase offset '00'"},
+	{R_BD_A_VERT_LUMA_PHASE_OFF_01,1,
+	 "Task A: Vertical luminance phase offset '01'"},
+	{R_BE_A_VERT_LUMA_PHASE_OFF_10,1,
+	 "Task A: Vertical luminance phase offset '10'"},
+	{R_BF_A_VERT_LUMA_PHASE_OFF_11,1,
+	 "Task A: Vertical luminance phase offset '11'"},
+
+	/* Task B definition: R_C0_B_TASK_HANDLING_CNTL to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+	/* Task B: Basic settings and acquisition window definition */
+	{R_C0_B_TASK_HANDLING_CNTL,1,
+	 "Task B: Task handling control"},
+	{R_C1_B_X_PORT_FORMATS_AND_CONF,1,
+	 "Task B: X port formats and configuration"},
+	{R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION,1,
+	 "Task B: Input reference signal definition"},
+	{R_C3_B_I_PORT_FORMATS_AND_CONF,1,
+	 "Task B: I port formats and configuration"},
+	{R_C4_B_HORIZ_INPUT_WINDOW_START,2,
+	 "Task B: Horizontal input window start"},
+	{R_C6_B_HORIZ_INPUT_WINDOW_LENGTH,2,
+	 "Task B: Horizontal input window length"},
+	{R_C8_B_VERT_INPUT_WINDOW_START,2,
+	 "Task B: Vertical input window start"},
+	{R_CA_B_VERT_INPUT_WINDOW_LENGTH,2,
+	 "Task B: Vertical input window length"},
+	{R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+	 "Task B: Horizontal output window length"},
+	{R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,2,
+	 "Task B: Vertical output window length"},
+
+	/* Task B: FIR filtering and prescaling */
+	{R_D0_B_HORIZ_PRESCALING,1,
+	 "Task B: Horizontal prescaling"},
+	{R_D1_B_ACCUMULATION_LENGTH,1,
+	 "Task B: Accumulation length"},
+	{R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+	 "Task B: Prescaler DC gain and FIR prefilter"},
+	/* 0xd3 - Reserved */
+	{R_D4_B_LUMA_BRIGHTNESS_CNTL,1,
+	 "Task B: Luminance brightness control"},
+	{R_D5_B_LUMA_CONTRAST_CNTL,1,
+	 "Task B: Luminance contrast control"},
+	{R_D6_B_CHROMA_SATURATION_CNTL,1,
+	 "Task B: Chrominance saturation control"},
+	/* 0xd7 - Reserved */
+
+	/* Task B: Horizontal phase scaling */
+	{R_D8_B_HORIZ_LUMA_SCALING_INC,2,
+	 "Task B: Horizontal luminance scaling increment"},
+	{R_DA_B_HORIZ_LUMA_PHASE_OFF,1,
+	 "Task B: Horizontal luminance phase offset"},
+	/* 0xdb - Reserved */
+	{R_DC_B_HORIZ_CHROMA_SCALING,2,
+	 "Task B: Horizontal chrominance scaling"},
+	{R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA,1,
+	 "Task B: Horizontal Phase Offset Chroma"},
+	/* 0xdf - Reserved */
+
+	/* Task B: Vertical scaling */
+	{R_E0_B_VERT_LUMA_SCALING_INC,2,
+	 "Task B: Vertical luminance scaling increment"},
+	{R_E2_B_VERT_CHROMA_SCALING_INC,2,
+	 "Task B: Vertical chrominance scaling increment"},
+	{R_E4_B_VERT_SCALING_MODE_CNTL,1,
+	 "Task B: Vertical scaling mode control"},
+	/* 0xe5-0xe7 - Reserved */
+	{R_E8_B_VERT_CHROMA_PHASE_OFF_00,1,
+	 "Task B: Vertical chrominance phase offset '00'"},
+	{R_E9_B_VERT_CHROMA_PHASE_OFF_01,1,
+	 "Task B: Vertical chrominance phase offset '01'"},
+	{R_EA_B_VERT_CHROMA_PHASE_OFF_10,1,
+	 "Task B: Vertical chrominance phase offset '10'"},
+	{R_EB_B_VERT_CHROMA_PHASE_OFF_11,1,
+	 "Task B: Vertical chrominance phase offset '11'"},
+	{R_EC_B_VERT_LUMA_PHASE_OFF_00,1,
+	 "Task B: Vertical luminance phase offset '00'"},
+	{R_ED_B_VERT_LUMA_PHASE_OFF_01,1,
+	 "Task B: Vertical luminance phase offset '01'"},
+	{R_EE_B_VERT_LUMA_PHASE_OFF_10,1,
+	 "Task B: Vertical luminance phase offset '10'"},
+	{R_EF_B_VERT_LUMA_PHASE_OFF_11,1,
+	 "Task B: Vertical luminance phase offset '11'"},
+
+	/* second PLL (PLL2) and Pulsegenerator Programming */
+	{ R_F0_LFCO_PER_LINE, 1,
+	  "LFCO's per line"},
+	{ R_F1_P_I_PARAM_SELECT,1,
+	  "P-/I- Param. Select., PLL Mode, PLL H-Src., LFCO's per line"},
+	{ R_F2_NOMINAL_PLL2_DTO,1,
+	 "Nominal PLL2 DTO"},
+	{R_F3_PLL_INCREMENT,1,
+	 "PLL2 Increment"},
+	{R_F4_PLL2_STATUS,1,
+	 "PLL2 Status"},
+	{R_F5_PULSGEN_LINE_LENGTH,1,
+	 "Pulsgen. line length"},
+	{R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG,1,
+	 "Pulse A Position, Pulsgen Resync., Pulsgen. H-Src., Pulsgen. line length"},
+	{R_F7_PULSE_A_POS_MSB,1,
+	 "Pulse A Position"},
+	{R_F8_PULSE_B_POS,2,
+	 "Pulse B Position"},
+	{R_FA_PULSE_C_POS,2,
+	 "Pulse C Position"},
+	/* 0xfc to 0xfe - Reserved */
+	{R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES,1,
+	 "S_PLL max. phase, error threshold, PLL2 no. of lines, threshold"},
+};
+#endif
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index f554316..59da79c 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -41,53 +41,15 @@
 	select VIDEO_BUF_DVB
 	select FW_LOADER
 	select DVB_PLL
+	select DVB_MT352 if !DVB_FE_CUSTOMISE
+	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select DVB_NXT200X if !DVB_FE_CUSTOMISE
+	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB cards based on the
 	  Philips saa7134 chip.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7134-dvb.
-
-	  You must also select one or more DVB demodulators.
-	  If you are unsure which you need, choose all of them.
-
-config VIDEO_SAA7134_DVB_ALL_FRONTENDS
-	bool "Build all supported frontends for saa7134 based TV cards"
-	default y
-	depends on VIDEO_SAA7134_DVB
-	select DVB_MT352
-	select DVB_TDA1004X
-	select DVB_NXT200X
-	---help---
-	  This builds saa7134-dvb with all currently supported frontend
-	  demodulators.  If you wish to tweak your configuration, and
-	  only include support for the hardware that you need, choose N here.
-
-	  If you are unsure, choose Y.
-
-config VIDEO_SAA7134_DVB_MT352
-	bool "Zarlink MT352 DVB-T Support"
-	default y
-	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
-	select DVB_MT352
-	---help---
-	  This adds DVB-T support for cards based on the
-	  Philips saa7134 chip and the MT352 demodulator.
-
-config VIDEO_SAA7134_DVB_TDA1004X
-	bool "Phillips TDA10045H/TDA10046H DVB-T Support"
-	default y
-	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
-	select DVB_TDA1004X
-	---help---
-	  This adds DVB-T support for cards based on the
-	  Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
-
-config VIDEO_SAA7134_DVB_NXT200X
-	bool "NXT2002/NXT2004 ATSC Support"
-	default y
-	depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
-	select DVB_NXT200X
-	---help---
-	  This adds ATSC 8VSB and QAM64/256 support for cards based on the
-	  Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index be7b9ee..89a1565 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -16,8 +16,5 @@
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 
 extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_DVB_MT352)     += -DHAVE_MT352=1
-extra-cflags-$(CONFIG_DVB_TDA1004X)  += -DHAVE_TDA1004X=1
-extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
 
 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d73cff1..a39e013 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -590,6 +590,11 @@
 
 static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
 {
+	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+	struct saa7134_dev *dev = saa7134->dev;
+
+	dev->ctl_mute = 1;
+	saa7134_tvaudio_setmute(dev);
 	return 0;
 }
 
@@ -631,6 +636,9 @@
 	runtime->private_free = snd_card_saa7134_runtime_free;
 	runtime->hw = snd_card_saa7134_capture;
 
+	dev->ctl_mute = 0;
+	saa7134_tvaudio_setmute(dev);
+
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
 
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 927413a..aa1db50 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1911,7 +1911,7 @@
 		},
 	},
 	[SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = {
-		.name		= "LifeView/Typhoon FlyDVB-T Duo Cardbus",
+		.name		= "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
 		.radio_type     = UNSET,
@@ -2891,6 +2891,80 @@
 			.gpio = 0x8000,
 		},
 	},
+	[SAA7134_BOARD_MEDION_MD8800_QUADRO] = {
+		.name           = "Medion Md8800 Quadro",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE2,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_FLYDVBS_LR300] = {
+		/* LifeView FlyDVB-s */
+		/* Igor M. Liplianin <liplianin@tut.by> */
+		.name           = "LifeView FlyDVB-S /Acorp TV134DS",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_comp1,	/* Composite input */
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,	/* S-Video signal on S-Video input */
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_PROTEUS_2309] = {
+		.name           = "Proteus Pro 2309",
+		.audio_clock    = 0x00187de7,
+		.tuner_type	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3375,7 +3449,7 @@
 		.driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
-		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,	/* SAA 7131E */
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x1461,
 		.subdevice    = 0x2c05,
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_777,
@@ -3422,6 +3496,18 @@
 		.subdevice    = 0x0005,
 		.driver_data  = SAA7134_BOARD_MD7134_BRIDGE_2,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0300,
+		.driver_data  = SAA7134_BOARD_FLYDVBS_LR300,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x0300,/* LR300 */
+		.driver_data  = SAA7134_BOARD_FLYDVBS_LR300,
+	},{
 		.vendor = PCI_VENDOR_ID_PHILIPS,
 		.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor = 0x1489,
@@ -3446,6 +3532,36 @@
 		.subdevice    = 0x3502,  /* whats the difference to 0x3306 ?*/
 		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0007,
+		.driver_data  = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x16be,
+		.subdevice    = 0x0008,
+		.driver_data  = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461,
+		.subdevice    = 0x2c05,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_777,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1489,
+		.subdevice    = 0x0502,                /* Cardbus version */
+		.driver_data  = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0919, /* Philips Proteus PRO 2309 */
+		.subdevice    = 0x2003,
+		.driver_data  = SAA7134_BOARD_PROTEUS_2309,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3548,6 +3664,12 @@
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
 	case SAA7134_BOARD_FLYDVBT_LR301:
 	case SAA7134_BOARD_FLYDVBTDUO:
+	case SAA7134_BOARD_PROTEUS_2309:
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
+	case SAA7134_BOARD_FLYDVBS_LR300:
+		saa_writeb(SAA7134_GPIO_GPMODE3, 0x80);
+		saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40);
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_MD5044:
@@ -3732,6 +3854,7 @@
 	case SAA7134_BOARD_PHILIPS_TIGER:
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
 		/* this is a hybrid board, initialize to analog mode
 		 * and configure firmware eeprom address
 		 */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index be3a81f..09aa62f 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -843,7 +843,7 @@
 			latency = 0x0A;
 		}
 #endif
-		if (pci_pci_problems & PCIPCI_FAIL) {
+		if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) {
 			printk(KERN_INFO "%s: quirk: this driver and your "
 					"chipset may not work together"
 					" in overlay mode.\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 279828b..b688154 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -34,17 +34,14 @@
 #include <media/v4l2-common.h>
 #include "dvb-pll.h"
 
-#ifdef HAVE_MT352
-# include "mt352.h"
-# include "mt352_priv.h" /* FIXME */
-#endif
-#ifdef HAVE_TDA1004X
-# include "tda1004x.h"
-#endif
-#ifdef HAVE_NXT200X
-# include "nxt200x.h"
-#endif
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+#include "nxt200x.h"
 
+#include "tda10086.h"
+#include "tda826x.h"
+#include "isl6421.h"
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
@@ -54,8 +51,6 @@
 MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
 
 /* ------------------------------------------------------------------ */
-
-#ifdef HAVE_MT352
 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
 	u32 ok;
@@ -185,12 +180,8 @@
 	.demod_address = 0xf,
 	.demod_init    = mt352_aver777_init,
 };
-#endif
 
 /* ------------------------------------------------------------------ */
-
-#ifdef HAVE_TDA1004X
-
 static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
@@ -969,11 +960,58 @@
 	.request_firmware = NULL,
 };
 
-#endif
+/* ------------------------------------------------------------------ */
+
+static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 data[] = { 0x3c, 0x33, 0x68};
+	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+	i2c_transfer(&dev->i2c_adap, &msg, 1);
+	philips_tda827xa_tuner_sleep( 0x61, fe);
+	return 0;
+}
+
+static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	int ret;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	static u8 tda8290_close[] = { 0x21, 0xc0};
+	static u8 tda8290_open[]  = { 0x21, 0x80};
+	struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+	/* close tda8290 i2c bridge */
+	tda8290_msg.buf = tda8290_close;
+	ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+	if (ret != 1)
+		return -EIO;
+	msleep(20);
+	ret = philips_tda827xa_pll_set(0x60, fe, params);
+	if (ret != 0)
+		return ret;
+	/* open tda8290 i2c bridge */
+	tda8290_msg.buf = tda8290_open;
+	i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+	return ret;
+}
+
+static struct tda1004x_config md8800_dvbt_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.if_freq       = TDA10046_FREQ_045,
+	.request_firmware = NULL,
+};
+
+static struct tda10086_config flydvbs = {
+	.demod_address = 0x0e,
+	.invert = 0,
+};
 
 /* ------------------------------------------------------------------ */
 
-#ifdef HAVE_NXT200X
 static struct nxt200x_config avertvhda180 = {
 	.demod_address    = 0x0a,
 };
@@ -991,7 +1029,6 @@
 	.demod_address    = 0x0a,
 	.set_pll_input    = nxt200x_set_pll_input,
 };
-#endif
 
 /* ------------------------------------------------------------------ */
 
@@ -1009,29 +1046,26 @@
 			    dev);
 
 	switch (dev->board) {
-#ifdef HAVE_MT352
 	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
 		printk("%s: pinnacle 300i dvb setup\n",dev->name);
-		dev->dvb.frontend = mt352_attach(&pinnacle_300i,
-						 &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
 		}
 		break;
-
 	case SAA7134_BOARD_AVERMEDIA_777:
 		printk("%s: avertv 777 dvb setup\n",dev->name);
-		dev->dvb.frontend = mt352_attach(&avermedia_777,
-						 &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
 		}
 		break;
-#endif
-#ifdef HAVE_TDA1004X
 	case SAA7134_BOARD_MD7134:
-		dev->dvb.frontend = tda10046_attach(&medion_cardbus,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &medion_cardbus,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
@@ -1039,16 +1073,18 @@
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
-		dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tu1216_60_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
-		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &tda827x_lifeview_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1056,8 +1092,9 @@
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
-		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &tda827x_lifeview_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1065,8 +1102,9 @@
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
-		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_europa_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
 			dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
@@ -1076,8 +1114,9 @@
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
-		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_europa_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
@@ -1085,16 +1124,18 @@
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-		dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tu1216_61_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
 			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
-		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tiger_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
@@ -1102,8 +1143,9 @@
 		}
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &philips_tiger_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
@@ -1111,8 +1153,9 @@
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
-		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &tda827x_lifeview_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1120,16 +1163,18 @@
 		}
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
-		dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &lifeview_trio_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
 		}
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
-		dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &ads_tech_duo_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
@@ -1137,37 +1182,63 @@
 		}
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
-		dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &tevion_dvbt220rf_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-		dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
-						    &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(tda10046_attach,
+					       &ads_tech_duo_config,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
 			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
 			dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
 		}
 		break;
-#endif
-#ifdef HAVE_NXT200X
-	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
-		dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+		dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config,
+						    &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode;
+			dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
+		}
+		break;
+	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+		dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+					       &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_tdhu2);
 		}
 		break;
 	case SAA7134_BOARD_KWORLD_ATSC110:
-		dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+		dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, &dvb_pll_tuv1236d);
 		}
 		break;
-#endif
+	case SAA7134_BOARD_FLYDVBS_LR300:
+		dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+					       &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+				       &dev->i2c_adap, 0) == NULL) {
+				printk("%s: No tda826x found!\n", __FUNCTION__);
+			}
+			if (dvb_attach(isl6421_attach, dev->dvb.frontend,
+				       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+				printk("%s: No ISL6421 found!\n", __FUNCTION__);
+			}
+		}
+		break;
 	default:
 		printk("%s: Huh? unknown DVB card?\n",dev->name);
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 7c59549..f7ea857 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -228,6 +228,12 @@
 		mask_keyup   = 0x400000;
 		polling      = 50; // ms
 		break;
+	case SAA7134_BOARD_PROTEUS_2309:
+		ir_codes     = ir_codes_proteus_2309;
+		mask_keycode = 0x00007F;
+		mask_keyup   = 0x000080;
+		polling      = 50; // ms
+		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
 		ir_codes     = ir_codes_videomate_tv_pvr;
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 0db53d1..d31220d 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -1046,6 +1046,7 @@
 }
 
 EXPORT_SYMBOL(saa_dsp_writel);
+EXPORT_SYMBOL(saa7134_tvaudio_setmute);
 
 /* ----------------------------------------------------------- */
 /*
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index c04ce61..7db7b97 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -223,6 +223,9 @@
 #define SAA7134_BOARD_MD7134_BRIDGE_2     93
 #define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
 #define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
+#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
+#define SAA7134_BOARD_FLYDVBS_LR300 97
+#define SAA7134_BOARD_PROTEUS_2309 98
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 8dab481..87ffb0e 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -480,6 +480,8 @@
 	}
 	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
 		buf[1] &= ~cQSS;
+	if (t->tda9887_config & TDA9887_GATING_18)
+		buf[3] &= ~cGating_36;
 	return 0;
 }
 
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index abe37cf..63db4e9 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -10,7 +10,7 @@
 #include <media/v4l2-common.h>
 
 static int offset = 0;
-module_param(offset, int, 0666);
+module_param(offset, int, 0664);
 MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
 
 /* ---------------------------------------------------------------------- */
@@ -331,6 +331,8 @@
 			else if (params->default_top_high)
 				config |= TDA9887_TOP(params->default_top_high);
 		}
+		if (params->default_pll_gating_18)
+			config |= TDA9887_GATING_18;
 		i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
 	}
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -439,8 +441,6 @@
 		buffer[3] = 0xa4;
 		break;
 	}
-	buffer[0] = (div>>8) & 0x7f;
-	buffer[1] = div      & 0xff;
 	if (params->cb_first_if_lower_freq && div < t->last_div) {
 		buffer[0] = buffer[2];
 		buffer[1] = buffer[3];
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 8b54259..8fff642 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -650,6 +650,7 @@
 		.count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
 		.has_tda9887 = 1,
 		.port1_invert_for_secam_lc = 1,
+		.default_pll_gating_18 = 1,
 	},
 };
 
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 936e3f7..fcaef4b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -28,6 +28,7 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/kthread.h>
 
 #include <media/tvaudio.h>
 #include <media/v4l2-common.h>
@@ -124,11 +125,8 @@
 	int input;
 
 	/* thread */
-	pid_t                tpid;
-	struct completion    texit;
-	wait_queue_head_t    wq;
+	struct task_struct   *thread;
 	struct timer_list    wt;
-	int                  done;
 	int                  watch_stereo;
 	int 		     audmode;
 };
@@ -264,28 +262,23 @@
 static void chip_thread_wake(unsigned long data)
 {
 	struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
-	wake_up_interruptible(&chip->wq);
+	wake_up_process(chip->thread);
 }
 
 static int chip_thread(void *data)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	struct CHIPSTATE *chip = data;
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	daemonize("%s", chip->c.name);
-	allow_signal(SIGTERM);
 	v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
 
 	for (;;) {
-		add_wait_queue(&chip->wq, &wait);
-		if (!chip->done) {
-			set_current_state(TASK_INTERRUPTIBLE);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!kthread_should_stop())
 			schedule();
-		}
-		remove_wait_queue(&chip->wq, &wait);
+		set_current_state(TASK_RUNNING);
 		try_to_freeze();
-		if (chip->done || signal_pending(current))
+		if (kthread_should_stop())
 			break;
 		v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
 
@@ -301,7 +294,6 @@
 	}
 
 	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
-	complete_and_exit(&chip->texit, 0);
 	return 0;
 }
 
@@ -1536,19 +1528,18 @@
 		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
 	}
 
-	chip->tpid = -1;
+	chip->thread = NULL;
 	if (desc->checkmode) {
 		/* start async thread */
 		init_timer(&chip->wt);
 		chip->wt.function = chip_thread_wake;
 		chip->wt.data     = (unsigned long)chip;
-		init_waitqueue_head(&chip->wq);
-		init_completion(&chip->texit);
-		chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
-		if (chip->tpid < 0)
-			v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
+		chip->thread = kthread_run(chip_thread, chip, chip->c.name);
+		if (IS_ERR(chip->thread)) {
+			v4l_warn(&chip->c, "%s: failed to create kthread\n",
 			       chip->c.name);
-		wake_up_interruptible(&chip->wq);
+			chip->thread = NULL;
+		}
 	}
 	return 0;
 }
@@ -1569,11 +1560,10 @@
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 
 	del_timer_sync(&chip->wt);
-	if (chip->tpid >= 0) {
+	if (chip->thread) {
 		/* shutdown async thread */
-		chip->done = 1;
-		wake_up_interruptible(&chip->wq);
-		wait_for_completion(&chip->texit);
+		kthread_stop(chip->thread);
+		chip->thread = NULL;
 	}
 
 	i2c_detach_client(&chip->c);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index d95529e..cd1502a 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -605,6 +605,8 @@
 			tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
 			t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
 		}
+	}
+	for (i = j = 0; i < 8; i++) {
 		if (t_format2 & (1 << i)) {
 			tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
 			t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index b167ffa..bc0a4fc 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -294,7 +294,7 @@
 	if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
 		input = 8;
 
-	switch (input) {
+	switch (decoder->route.input) {
 	case TVP5150_COMPOSITE1:
 		input |= 2;
 		/* fall through */
@@ -308,6 +308,11 @@
 		break;
 	}
 
+	tvp5150_dbg( 1, "Selecting video route: route input=%i, output=%i "
+			"=> tvp5150 input=%i, opmode=%i\n",
+			decoder->route.input,decoder->route.output,
+			input, opmode );
+
 	tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
 	tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
 };
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 6f31ecc..4eee8be 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -222,6 +222,7 @@
 static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
 {
 	struct input_dev *input_dev;
+	int error;
 
 	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
 	strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
@@ -242,7 +243,13 @@
 
 	input_dev->private = cam;
 
-	input_register_device(cam->input);
+	error = input_register_device(cam->input);
+	if (error) {
+		warn("Failed to register camera's input device, err: %d\n",
+		     error);
+		input_free_device(cam->input);
+		cam->input = NULL;
+	}
 }
 
 static void konicawc_unregister_input(struct konicawc *cam)
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 90d48e8..08f9559 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -7,6 +7,7 @@
  *                    Monroe Williams (monroe@pobox.com)
  *
  * Supports 3COM HomeConnect PC Digital WebCam
+ * Supports Compro PS39U WebCam
  *
  * 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
@@ -60,6 +61,8 @@
 /* Define these values to match your device */
 #define USB_VICAM_VENDOR_ID	0x04c1
 #define USB_VICAM_PRODUCT_ID	0x009d
+#define USB_COMPRO_VENDOR_ID	0x0602
+#define USB_COMPRO_PRODUCT_ID	0x1001
 
 #define VICAM_BYTES_PER_PIXEL   3
 #define VICAM_MAX_READ_SIZE     (512*242+128)
@@ -1254,6 +1257,7 @@
 /* table of devices that work with this driver */
 static struct usb_device_id vicam_table[] = {
 	{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+	{USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
 	{}			/* Terminating entry */
 };
 
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d7c3fcb..1d899e2 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -349,6 +349,8 @@
 	{
 		struct video_buffer	*buffer = arg;
 
+		memset(buffer, 0, sizeof(*buffer));
+
 		err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
 		if (err < 0) {
 			dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err);
@@ -361,7 +363,7 @@
 		switch (fbuf2.fmt.pixelformat) {
 		case V4L2_PIX_FMT_RGB332:
 			buffer->depth = 8;
-				break;
+			break;
 		case V4L2_PIX_FMT_RGB555:
 			buffer->depth = 15;
 			break;
@@ -377,9 +379,13 @@
 		default:
 			buffer->depth = 0;
 		}
-		if (0 != fbuf2.fmt.bytesperline)
+		if (fbuf2.fmt.bytesperline) {
 			buffer->bytesperline = fbuf2.fmt.bytesperline;
-		else {
+			if (!buffer->depth && buffer->width)
+				buffer->depth   = ((fbuf2.fmt.bytesperline<<3)
+						  + (buffer->width-1) )
+						  /buffer->width;
+		} else {
 			buffer->bytesperline =
 				(buffer->width * buffer->depth + 7) & 7;
 			buffer->bytesperline >>= 3;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 8d972ff..78d28b0 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -938,6 +938,7 @@
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
 	case VIDIOC_INT_I2S_CLOCK_FREQ:
 	case VIDIOC_INT_S_STANDBY:
+	case VIDIOC_INT_RESET:
 	{
 		u32 *p=arg;
 
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index 7ee8a53..f53edf1 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -223,6 +223,7 @@
 fail_dmx:
 	dvb_unregister_frontend(dvb->frontend);
 fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
 	dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
 	return result;
@@ -236,6 +237,7 @@
 	dvb_dmxdev_release(&dvb->dmxdev);
 	dvb_dmx_release(&dvb->demux);
 	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
 	dvb_unregister_adapter(&dvb->adapter);
 }
 
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index edd7b83..479a067 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -739,13 +739,13 @@
 	case VIDIOC_DQBUF:
 	{
 		struct v4l2_buffer *p=arg;
-		if (!vfd->vidioc_qbuf)
+		if (!vfd->vidioc_dqbuf)
 			break;
 		ret = check_fmt (vfd, p->type);
 		if (ret)
 			break;
 
-		ret=vfd->vidioc_qbuf(file, fh, p);
+		ret=vfd->vidioc_dqbuf(file, fh, p);
 		if (!ret)
 			dbgbuf(cmd,vfd,p);
 		break;
@@ -836,7 +836,7 @@
 			break;
 		}
 
-		if (index < 0 || index >= vfd->tvnormsize) {
+		if (index<0 || index >= vfd->tvnormsize) {
 			ret=-EINVAL;
 			break;
 		}
@@ -1283,9 +1283,29 @@
 	case VIDIOC_G_PARM:
 	{
 		struct v4l2_streamparm *p=arg;
-		if (!vfd->vidioc_g_parm)
-			break;
-		ret=vfd->vidioc_g_parm(file, fh, p);
+		if (vfd->vidioc_g_parm) {
+			ret=vfd->vidioc_g_parm(file, fh, p);
+		} else {
+			struct v4l2_standard s;
+
+			if (!vfd->tvnormsize) {
+				printk (KERN_WARNING "%s: no TV norms defined!\n",
+							vfd->name);
+				break;
+			}
+
+			if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+
+			v4l2_video_std_construct(&s, vfd->tvnorms[vfd->current_norm].id,
+						 vfd->tvnorms[vfd->current_norm].name);
+
+			memset(p,0,sizeof(*p));
+
+			p->parm.capture.timeperframe = s.frameperiod;
+			ret=0;
+		}
+
 		dbgarg (cmd, "type=%d\n", p->type);
 		break;
 	}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 268e69f..d1e04f7 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -4404,7 +4404,6 @@
 	.name		= "NOT SET",
 	//.type		= VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
 	//	VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
-	.hardware	= VID_HARDWARE_VINO,
 	.fops		= &vino_fops,
 	.minor		= -1,
 };
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 841884a..e7c01d5 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -992,7 +992,8 @@
 	struct vivi_fh  *fh=priv;
 	struct videobuf_queue *q=&fh->vb_vidq;
 	struct v4l2_requestbuffers req;
-	unsigned int i, ret;
+	unsigned int i;
+	int ret;
 
 	req.type   = q->type;
 	req.count  = 8;
@@ -1359,6 +1360,8 @@
 	dev->vidq.timeout.data     = (unsigned long)dev;
 	init_timer(&dev->vidq.timeout);
 
+	vivi.current_norm         = tvnorms[0].id;
+
 	ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
 	printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
 	return ret;
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 1eca7e6..8ef31ed 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -744,6 +744,6 @@
 module_init(vpx3220_init);
 module_exit(vpx3220_cleanup);
 
-MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver");
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
 MODULE_AUTHOR("Laurent Pinchart");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 29f59c3..9f21d0b 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -1620,10 +1620,10 @@
 	dprintk(5, KERN_DEBUG "Jotti is een held!\n");
 
 	/* some mainboards might not do PCI-PCI data transfer well */
-	if (pci_pci_problems & PCIPCI_FAIL) {
+	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
 		dprintk(1,
 			KERN_WARNING
-			"%s: chipset may not support reliable PCI-PCI DMA\n",
+			"%s: chipset does not support reliable PCI-PCI DMA\n",
 			ZORAN_NAME);
 	}
 
@@ -1631,7 +1631,7 @@
 	for (i = 0; i < zoran_num; i++) {
 		struct zoran *zr = &zoran[i];
 
-		if (pci_pci_problems & PCIPCI_NATOMA && zr->revision <= 1) {
+		if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
 			zr->jpg_buffers.need_contiguous = 1;
 			dprintk(1,
 				KERN_INFO
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 5f90db2..862a984 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -1512,6 +1512,13 @@
 	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
+	/* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
+	   ALi Magik (that needs very low latency while the card needs a
+	   higher value always) */
+
+	if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
+		return -ENXIO;
+
 	/* we need a bytesperline value, even if not given */
 	if (!bytesperline)
 		bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 5043738..9240638 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -987,6 +987,8 @@
 			 VID_TYPE_SCALES;
 		if (ztv->have_tuner)
 			c.type |= VID_TYPE_TUNER;
+		if (pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
+			c.type &= ~VID_TYPE_OVERLAY;
 		if (ztv->have_decoder) {
 			c.channels = ztv->card->video_inputs;
 			c.audios = ztv->card->audio_inputs;
@@ -1284,6 +1286,8 @@
 		struct video_buffer v;
 		if(!capable(CAP_SYS_ADMIN))
 			return -EPERM;
+		if (pcipci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
+			return -ENXIO;
 		if (copy_from_user(&v, arg,sizeof(v)))
 			return -EFAULT;
 		DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
@@ -2030,7 +2034,7 @@
 		/* free it */
 		free_irq(ztv->dev->irq,ztv);
 
-    		/* unregister i2c_bus */
+		/* unregister i2c_bus */
 		i2c_unregister_bus((&ztv->i2c));
 
 		/* unmap and free memory */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index e3715d7..44c59da 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1135,7 +1135,8 @@
 				 (equals frame lines 313-336 for 625 line video
 				  standards, 263-286 for 525 line standards) */
 	__u16   service_lines[2][24];
-	__u32   reserved[4];    /* must be 0 */
+	enum v4l2_buf_type type;
+	__u32   reserved[3];    /* must be 0 */
 };
 
 struct v4l2_sliced_vbi_data
@@ -1242,7 +1243,7 @@
 #define VIDIOC_G_PRIORITY       _IOR  ('V', 67, enum v4l2_priority)
 #define VIDIOC_S_PRIORITY       _IOW  ('V', 68, enum v4l2_priority)
 #if 1
-#define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
+#define VIDIOC_G_SLICED_VBI_CAP _IOWR ('V', 69, struct v4l2_sliced_vbi_cap)
 #endif
 #define VIDIOC_LOG_STATUS       _IO   ('V', 70)
 #define VIDIOC_G_EXT_CTRLS	_IOWR ('V', 71, struct v4l2_ext_controls)
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 7bab09b..8f58406 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -90,6 +90,8 @@
 extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
 
 #endif
 
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index 3c43b95f4..37dad07 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -72,6 +72,9 @@
 	unsigned int port2_invert_for_secam_lc:1;
 	/* Some cards require PORT1 to be 1 for mono Radio FM and 0 for stereo. */
 	unsigned int port1_set_for_fm_mono:1;
+	/* Select 18% (or according to datasheet 0%) L standard PLL gating,
+	   vs the driver default of 36%. */
+	unsigned int default_pll_gating_18:1;
 	/* Default tda9887 TOP value in dB for the low band. Default is 0.
 	   Range: -16:+15 */
 	signed int default_top_low:5;
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 2f7b00b..3116e75 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -144,6 +144,7 @@
 #define TDA9887_DEEMPHASIS_50 		(2<<16)
 #define TDA9887_DEEMPHASIS_75 		(3<<16)
 #define TDA9887_AUTOMUTE 		(1<<18)
+#define TDA9887_GATING_18		(1<<19)
 
 #ifdef __KERNEL__
 
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 5564db1..aecc946 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -121,10 +121,17 @@
 	/* general idents: reserved range 0-49 */
 	V4L2_IDENT_UNKNOWN = 0,
 
-	/* module saa7115: reserved range 100-149 */
+	/* module saa7110: just ident= 100 */
+	V4L2_IDENT_SAA7110 = 100,
+
+	/* module saa7111: just ident= 101 */
+	V4L2_IDENT_SAA7111 = 101,
+
+	/* module saa7115: reserved range 102-149 */
 	V4L2_IDENT_SAA7113 = 103,
 	V4L2_IDENT_SAA7114 = 104,
 	V4L2_IDENT_SAA7115 = 105,
+	V4L2_IDENT_SAA7118 = 108,
 
 	/* module saa7127: reserved range 150-199 */
 	V4L2_IDENT_SAA7127 = 157,
@@ -166,11 +173,12 @@
 #define VIDIOC_INT_S_STANDBY 	     _IOW('d', 94, u32)
 
 /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
-#define	VIDIOC_INT_S_REGISTER 		_IOR ('d', 100, struct v4l2_register)
+#define	VIDIOC_INT_S_REGISTER 		_IOW ('d', 100, struct v4l2_register)
 #define	VIDIOC_INT_G_REGISTER 		_IOWR('d', 101, struct v4l2_register)
 
-/* Reset the I2C chip */
-#define VIDIOC_INT_RESET            	_IO  ('d', 102)
+/* Generic reset command. The argument selects which subsystems to reset.
+   Passing 0 will always reset the whole chip. */
+#define VIDIOC_INT_RESET            	_IOW ('d', 102, u32)
 
 /* Set the frequency (in Hz) of the audio clock output.
    Used to slave an audio processor to the video decoder, ensuring that audio
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index bb495b7..6a11d77 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -9,7 +9,8 @@
 #ifndef _V4L2_DEV_H
 #define _V4L2_DEV_H
 
-#define OBSOLETE_OWNER 1 /* to be removed soon */
+#define OBSOLETE_OWNER   1 /* to be removed soon */
+#define OBSOLETE_DEVDATA 1 /* to be removed soon */
 
 #include <linux/poll.h>
 #include <linux/fs.h>
@@ -338,8 +339,6 @@
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 #include <linux/mm.h>
 
-extern struct video_device* video_devdata(struct file*);
-
 #define to_video_device(cd) container_of(cd, struct video_device, class_dev)
 static inline int __must_check
 video_device_create_file(struct video_device *vfd,
@@ -370,9 +369,14 @@
 {
 	dev->priv = data;
 }
+
 #endif
 
+#ifdef OBSOLETE_DEVDATA /* to be removed soon */
+/* Obsolete stuff - Still needed for radio devices and obsolete drivers */
+extern struct video_device* video_devdata(struct file*);
 extern int video_exclusive_open(struct inode *inode, struct file *file);
 extern int video_exclusive_release(struct inode *inode, struct file *file);
+#endif
 
 #endif /* _V4L2_DEV_H */