public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch] v4l: cx88 driver update
@ 2004-06-18 10:02 Gerd Knorr
  0 siblings, 0 replies; 2+ messages in thread
From: Gerd Knorr @ 2004-06-18 10:02 UTC (permalink / raw)
  To: Andrew Morton, Kernel List

  Hi,

This is a update for the cx88 tv card driver.  Changes:

  * finally make it build with gcc 2.95 ;)
  * add new tv cards.
  * plenty of fixes for the TV sound code.
  * use v4l2 API for communication with tuner + tda9887
  * misc other minor stuff.

please apply,

  Gerd

diff -up linux-2.6.7/drivers/media/video/cx88/cx88-cards.c linux/drivers/media/video/cx88/cx88-cards.c
--- linux-2.6.7/drivers/media/video/cx88/cx88-cards.c	2004-06-17 10:30:25.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-cards.c	2004-06-17 13:47:59.785272417 +0200
@@ -99,6 +99,10 @@ struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
+                        .gpio0  = 0x000003ff,
+                        .gpio1  = 0x000000ff,
+                        .gpio2  = 0x000000ff,
+                        .gpio3  = 0x00000000,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
@@ -111,6 +115,7 @@ struct cx88_board cx88_boards[] = {
         [CX88_BOARD_WINFAST2000XP] = {
                 .name           = "Leadtek Winfast 2000XP Expert",
                 .tuner_type     = 44,
+		.needs_tda9887  = 1,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
@@ -149,22 +154,33 @@ struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 		}},
 	},
-	[CX88_BOARD_MSI_TVANYWHERE] = {
+	[CX88_BOARD_MSI_TVANYWHERE_MASTER] = {	
+		//added gpio values thanks to Torsten Seeboth
+		//values for PAL from DScaler
 		.name           = "MSI TV-@nywhere Master",
 		.tuner_type     = 33,
+		.needs_tda9887	= 1,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+                   	.gpio3  = 0x00000000,
 		},{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
-		},{
-			 // temporarly for testing ...
-                        .type   = CX88_VMUX_COMPOSITE2,
-                        .vmux   = 2,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+			.gpio3  = 0x00000000,
 		},{
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
+			.gpio0  = 0x000040bf,
+			.gpio1  = 0x000080c0,
+			.gpio2  = 0x0000ff40,
+			.gpio3  = 0x00000000,
                 }},
                 .radio = {
                         .type   = CX88_RADIO,
@@ -199,8 +215,97 @@ struct cx88_board cx88_boards[] = {
                         .type   = CX88_RADIO,
                 },
         },
-
-
+	[CX88_BOARD_IODATA_GVVCP3PCI] = {
+ 		.name		= "IODATA GV-VCP3/PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.needs_tda9887  = 0,
+ 		.input          = {{
+ 			.type   = CX88_VMUX_COMPOSITE1,
+ 			.vmux   = 0,
+ 		},{
+ 			.type   = CX88_VMUX_COMPOSITE2,
+ 			.vmux   = 1,
+ 		},{
+ 			.type   = CX88_VMUX_SVIDEO,
+ 			.vmux   = 2,
+ 		}},
+ 	},
+	[CX88_BOARD_PROLINK_PLAYTVPVR] = {
+                .name           = "Prolink PlayTV PVR",
+                .tuner_type     = 43,
+		.needs_tda9887	= 1,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff03,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff03,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0xff00,
+		},
+	},
+	[CX88_BOARD_ASUS_PVR_416] = {
+		.name		= "ASUS PVR-416",
+		.tuner_type     = 43,
+                .needs_tda9887  = 1,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000fde6,
+			.gpio1  = 0x00000000, // possibly for mpeg data
+			.gpio2  = 0x000000e9,
+                   	.gpio3  = 0x00000000,
+ 		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+			.gpio1  = 0x00000000, // possibly for mpeg data
+			.gpio2  = 0x000000e9,
+                   	.gpio3  = 0x00000000,
+		}},
+                .radio = {
+                        .type   = CX88_RADIO,
+			.gpio0  = 0x0000fde2,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x000000e9,
+                   	.gpio3  = 0x00000000,
+                },
+	},
+	[CX88_BOARD_MSI_TVANYWHERE] = { 
+		.name           = "MSI TV-@nywhere",
+		.tuner_type     = 33,
+		.needs_tda9887  = 1,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00000fbf,
+			.gpio1  = 0x000000c0,
+			.gpio2  = 0x0000fc08,
+			.gpio3  = 0x00000000,
+		},{
+  			.type   = CX88_VMUX_COMPOSITE1,
+  			.vmux   = 1,
+			.gpio0  = 0x00000fbf,
+			.gpio1  = 0x000000c0,
+			.gpio2  = 0x0000fc68,
+			.gpio3  = 0x00000000,
+		},{
+  			.type   = CX88_VMUX_SVIDEO,
+  			.vmux   = 2,
+			.gpio0  = 0x00000fbf,
+			.gpio1  = 0x000000c0,
+			.gpio2  = 0x0000fc68,
+			.gpio3  = 0x00000000,
+  		}},
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -242,6 +347,10 @@ struct cx88_subid cx88_subids[] = {
                 .card      = CX88_BOARD_WINFAST_DV2000,
         },{
                 .subvendor = 0x107d,
+                .subdevice = 0x663b,
+                .card      = CX88_BOARD_LEADTEK_PVR2000,
+        },{
+                .subvendor = 0x107d,
                 .subdevice = 0x663C,
                 .card      = CX88_BOARD_LEADTEK_PVR2000,
         },{
@@ -251,12 +360,19 @@ struct cx88_subid cx88_subids[] = {
 	},{
 		.subvendor = 0x1462,
 		.subdevice = 0x8606,
-		.card      = CX88_BOARD_MSI_TVANYWHERE,
-	}
+		.card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
+	},{
+ 		.subvendor = 0x10fc,
+ 		.subdevice = 0xd003,
+ 		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
+	},{
+ 		.subvendor = 0x1043,
+ 		.subdevice = 0x4823,  /* with mpeg encoder */
+ 		.card      = CX88_BOARD_ASUS_PVR_416,
+ 	}
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
 
-
 /* ----------------------------------------------------------------------- */
 /* some leadtek specific stuff                                             */
 
@@ -269,7 +385,7 @@ static void __devinit leadtek_eeprom(str
 	 */
 
 	if (eeprom_data[4] != 0x7d ||
-	    eeprom_data[5] != 0x10 ||
+	    eeprom_data[5] != 0x10 || 
 	    eeprom_data[7] != 0x66) {
 		printk(KERN_WARNING "%s Leadtek eeprom invalid.\n", dev->name);
 		return;
@@ -277,7 +393,7 @@ static void __devinit leadtek_eeprom(str
 
 	dev->has_radio  = 1;
 	dev->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
-
+	
 	printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: "
 	       "tuner=%d, eeprom[0]=0x%02x\n",
 	       dev->name, dev->tuner_type, eeprom_data[0]);
@@ -386,20 +502,22 @@ static struct {
 	[ 0x02 ] = { .id   = TUNER_ABSENT,
 		     .name = "PAL_B" },
 	[ 0x03 ] = { .id   = TUNER_ABSENT,
-		     .name = "BAL_I" },
+		     .name = "PAL_I" },
 	[ 0x04 ] = { .id   = TUNER_ABSENT,
 		     .name = "PAL_D" },
 	[ 0x05 ] = { .id   = TUNER_ABSENT,
 		     .name = "SECAM" },
 
-	[ 0x10 ] = { .id   = TUNER_ABSENT, .fm = 1, 
+	[ 0x10 ] = { .id   = TUNER_ABSENT,
+		     .fm   = 1, 
 		     .name = "TEMIC_4049" },
 	[ 0x11 ] = { .id   = TUNER_TEMIC_4136FY5,
 		     .name = "TEMIC_4136" },
 	[ 0x12 ] = { .id   = TUNER_ABSENT,
 		     .name = "TEMIC_4146" },
 
-	[ 0x20 ] = { .id   = TUNER_PHILIPS_FQ1216ME, .fm = 1,
+	[ 0x20 ] = { .id   = TUNER_PHILIPS_FQ1216ME,
+		     .fm   = 1,
 		     .name = "PHILIPS_FQ1216_MK3" },
 	[ 0x21 ] = { .id   = TUNER_ABSENT, .fm = 1,
 		     .name = "PHILIPS_FQ1236_MK3" },
@@ -454,7 +572,33 @@ i2c_eeprom(struct i2c_client *c, unsigne
 	return 0;
 }
 
-void __devinit cx88_card_setup(struct cx8800_dev *dev)
+void cx88_card_list(struct cx8800_dev *dev)
+{
+	int i;
+
+	if (0 == dev->pci->subsystem_vendor &&
+	    0 == dev->pci->subsystem_device) {
+		printk("%s: Your board has no valid PCI Subsystem ID and thus can't\n"
+		       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
+		       "%s: workaround that.  Redirect complaints to the vendor of\n"
+		       "%s: the TV card.  Best regards,\n"
+		       "%s:         -- tux\n",
+		       dev->name,dev->name,dev->name,dev->name,dev->name);
+	} else {
+		printk("%s: Your board isn't known (yet) to the driver.  You can\n"
+		       "%s: try to pick one of the existing card configs via\n"
+		       "%s: card=<n> insmod option.  Updating to the latest\n"
+		       "%s: version might help as well.\n",
+		       dev->name,dev->name,dev->name,dev->name);
+	}
+	printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+	       dev->name);
+	for (i = 0; i < cx88_bcount; i++)
+		printk("%s:    card=%d -> %s\n",
+		       dev->name, i, cx88_boards[i].name);
+}
+
+void cx88_card_setup(struct cx8800_dev *dev)
 {
 	static u8 eeprom[128];
 		
@@ -474,6 +618,9 @@ void __devinit cx88_card_setup(struct cx
 			i2c_eeprom(&dev->i2c_client,eeprom,sizeof(eeprom));
 		leadtek_eeprom(dev,eeprom);
 		break;
+        case CX88_BOARD_ASUS_PVR_416:
+		dev->has_radio = 1;
+                break;
 	}
 }
 
@@ -483,6 +630,7 @@ EXPORT_SYMBOL(cx88_boards);
 EXPORT_SYMBOL(cx88_bcount);
 EXPORT_SYMBOL(cx88_subids);
 EXPORT_SYMBOL(cx88_idcount);
+EXPORT_SYMBOL(cx88_card_list);
 EXPORT_SYMBOL(cx88_card_setup);
 
 /*
diff -up linux-2.6.7/drivers/media/video/cx88/cx88-i2c.c linux/drivers/media/video/cx88/cx88-i2c.c
--- linux-2.6.7/drivers/media/video/cx88/cx88-i2c.c	2004-06-17 10:28:38.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-i2c.c	2004-06-17 13:47:59.787272041 +0200
@@ -22,8 +22,6 @@
     
 */
 
-#define __NO_VERSION__ 1
-
 #include <linux/module.h>
 #include <linux/init.h>
 
diff -up linux-2.6.7/drivers/media/video/cx88/cx88-reg.h linux/drivers/media/video/cx88/cx88-reg.h
--- linux-2.6.7/drivers/media/video/cx88/cx88-reg.h	2004-06-17 10:28:53.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-reg.h	2004-06-17 13:47:59.790271476 +0200
@@ -599,10 +599,20 @@
 #define EN_I2SIN_STR2DAC        0x00004000
 #define EN_I2SIN_ENABLE         0x00008000
 
+#if 0
+/* old */
 #define EN_DMTRX_SUMDIFF        0x00000800
 #define EN_DMTRX_SUMR           0x00000880
 #define EN_DMTRX_LR             0x00000900
 #define EN_DMTRX_MONO           0x00000980
+#else
+/* dscaler cvs */
+#define EN_DMTRX_SUMDIFF        (0 << 7)
+#define EN_DMTRX_SUMR           (1 << 7)
+#define EN_DMTRX_LR             (2 << 7)
+#define EN_DMTRX_MONO           (3 << 7)
+#define EN_DMTRX_BYPASS         (1 << 11)
+#endif
 
 // Video 
 #define VID_CAPTURE_CONTROL		0x310180
diff -up linux-2.6.7/drivers/media/video/cx88/cx88-tvaudio.c linux/drivers/media/video/cx88/cx88-tvaudio.c
--- linux-2.6.7/drivers/media/video/cx88/cx88-tvaudio.c	2004-06-17 10:28:49.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-tvaudio.c	2004-06-17 13:47:59.794270724 +0200
@@ -48,6 +48,7 @@
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include "cx88.h"
 
@@ -60,6 +61,33 @@ MODULE_PARM_DESC(audio_debug,"enable deb
 
 /* ----------------------------------------------------------- */
 
+static char *aud_ctl_names[64] =
+{
+	[ EN_BTSC_FORCE_MONO       ] = "BTSC_FORCE_MONO",
+	[ EN_BTSC_FORCE_STEREO     ] = "BTSC_FORCE_STEREO",
+	[ EN_BTSC_FORCE_SAP        ] = "BTSC_FORCE_SAP",
+	[ EN_BTSC_AUTO_STEREO      ] = "BTSC_AUTO_STEREO",
+	[ EN_BTSC_AUTO_SAP         ] = "BTSC_AUTO_SAP",
+	[ EN_A2_FORCE_MONO1        ] = "A2_FORCE_MONO1",
+	[ EN_A2_FORCE_MONO2        ] = "A2_FORCE_MONO2",
+	[ EN_A2_FORCE_STEREO       ] = "A2_FORCE_STEREO",
+	[ EN_A2_AUTO_MONO2         ] = "A2_AUTO_MONO2",
+	[ EN_A2_AUTO_STEREO        ] = "A2_AUTO_STEREO",
+	[ EN_EIAJ_FORCE_MONO1      ] = "EIAJ_FORCE_MONO1",
+	[ EN_EIAJ_FORCE_MONO2      ] = "EIAJ_FORCE_MONO2",
+	[ EN_EIAJ_FORCE_STEREO     ] = "EIAJ_FORCE_STEREO",
+	[ EN_EIAJ_AUTO_MONO2       ] = "EIAJ_AUTO_MONO2",
+	[ EN_EIAJ_AUTO_STEREO      ] = "EIAJ_AUTO_STEREO",
+	[ EN_NICAM_FORCE_MONO1     ] = "NICAM_FORCE_MONO1",
+	[ EN_NICAM_FORCE_MONO2     ] = "NICAM_FORCE_MONO2",
+	[ EN_NICAM_FORCE_STEREO    ] = "NICAM_FORCE_STEREO",
+	[ EN_NICAM_AUTO_MONO2      ] = "NICAM_AUTO_MONO2",
+	[ EN_NICAM_AUTO_STEREO     ] = "NICAM_AUTO_STEREO",
+	[ EN_FMRADIO_FORCE_MONO    ] = "FMRADIO_FORCE_MONO",
+	[ EN_FMRADIO_FORCE_STEREO  ] = "FMRADIO_FORCE_STEREO",
+	[ EN_FMRADIO_AUTO_STEREO   ] = "FMRADIO_AUTO_STEREO",
+};
+
 struct rlist {
 	u32 reg;
 	u32 val;
@@ -125,26 +153,116 @@ static void set_audio_finish(struct cx88
 static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
 {
 	static const struct rlist btsc[] = {
-		/* Magic stuff from leadtek driver + datasheet.*/
-		{ AUD_DBX_IN_GAIN,   0x4734 },
-		{ AUD_DBX_WBE_GAIN,  0x4640 },
-		{ AUD_DBX_SE_GAIN,   0x8D31 },
-		{ AUD_DEEMPH0_G0,    0x1604 },
-		{ AUD_PHASE_FIX_CTL, 0x0020 },
-
+		/* from dscaler */
+		{ AUD_OUT1_SEL,                0x00000013 },
+		{ AUD_OUT1_SHIFT,              0x00000000 },
+		{ AUD_POLY0_DDS_CONSTANT,      0x0012010c },
+		{ AUD_DMD_RA_DDS,              0x00c3e7aa },
+		{ AUD_DBX_IN_GAIN,             0x00004734 },
+		{ AUD_DBX_WBE_GAIN,            0x00004640 },
+		{ AUD_DBX_SE_GAIN,             0x00008d31 },
+		{ AUD_DCOC_0_SRC,              0x0000001a },
+		{ AUD_IIR1_4_SEL,              0x00000021 },
+		{ AUD_DCOC_PASS_IN,            0x00000003 },
+		{ AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
+		{ AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
+		{ AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
+		{ AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
+		{ AUD_DN0_FREQ,                0x0000283b },
+		{ AUD_DN2_SRC_SEL,             0x00000008 },
+		{ AUD_DN2_FREQ,                0x00003000 },
+		{ AUD_DN2_AFC,                 0x00000002 },
+		{ AUD_DN2_SHFT,                0x00000000 },
+		{ AUD_IIR2_2_SEL,              0x00000020 },
+		{ AUD_IIR2_2_SHIFT,            0x00000000 },
+		{ AUD_IIR2_3_SEL,              0x0000001f },
+		{ AUD_IIR2_3_SHIFT,            0x00000000 },
+		{ AUD_CRDC1_SRC_SEL,           0x000003ce },
+		{ AUD_CRDC1_SHIFT,             0x00000000 },
+		{ AUD_CORDIC_SHIFT_1,          0x00000007 },
+		{ AUD_DCOC_1_SRC,              0x0000001b },
+		{ AUD_DCOC1_SHIFT,             0x00000000 },
+		{ AUD_RDSI_SEL,                0x00000008 },
+		{ AUD_RDSQ_SEL,                0x00000008 },
+		{ AUD_RDSI_SHIFT,              0x00000000 },
+		{ AUD_RDSQ_SHIFT,              0x00000000 },
+		{ AUD_POLYPH80SCALEFAC,        0x00000003 },
                 { /* end of list */ },
 	};
-
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
-	set_audio_start(dev, 0x0001,
-			EN_BTSC_AUTO_STEREO);
-        set_audio_registers(dev, btsc);
+	static const struct rlist btsc_sap[] = {
+		{ AUD_DBX_IN_GAIN,             0x00007200 },
+		{ AUD_DBX_WBE_GAIN,            0x00006200 },
+		{ AUD_DBX_SE_GAIN,             0x00006200 },
+		{ AUD_IIR1_1_SEL,              0x00000000 },
+		{ AUD_IIR1_3_SEL,              0x00000001 },
+		{ AUD_DN1_SRC_SEL,             0x00000007 },
+		{ AUD_IIR1_4_SHIFT,            0x00000006 },
+		{ AUD_IIR2_1_SHIFT,            0x00000000 },
+		{ AUD_IIR2_2_SHIFT,            0x00000000 },
+		{ AUD_IIR3_0_SHIFT,            0x00000000 },
+		{ AUD_IIR3_1_SHIFT,            0x00000000 },
+		{ AUD_IIR3_0_SEL,              0x0000000d },
+		{ AUD_IIR3_1_SEL,              0x0000000e },
+		{ AUD_DEEMPH1_SRC_SEL,         0x00000014 },
+		{ AUD_DEEMPH1_SHIFT,           0x00000000 },
+		{ AUD_DEEMPH1_G0,              0x00004000 },
+		{ AUD_DEEMPH1_A0,              0x00000000 },
+		{ AUD_DEEMPH1_B0,              0x00000000 },
+		{ AUD_DEEMPH1_A1,              0x00000000 },
+		{ AUD_DEEMPH1_B1,              0x00000000 },
+		{ AUD_OUT0_SEL,                0x0000003f },
+		{ AUD_OUT1_SEL,                0x0000003f },
+		{ AUD_DN1_AFC,                 0x00000002 },
+		{ AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
+		{ AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
+		{ AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
+		{ AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
+		{ AUD_IIR1_0_SEL,              0x0000001d },
+		{ AUD_IIR1_2_SEL,              0x0000001e },
+		{ AUD_IIR2_1_SEL,              0x00000002 },
+		{ AUD_IIR2_2_SEL,              0x00000004 },
+		{ AUD_IIR3_2_SEL,              0x0000000f },
+		{ AUD_DCOC2_SHIFT,             0x00000001 },
+		{ AUD_IIR3_2_SHIFT,            0x00000001 },
+		{ AUD_DEEMPH0_SRC_SEL,         0x00000014 },
+		{ AUD_CORDIC_SHIFT_1,          0x00000006 },
+		{ AUD_POLY0_DDS_CONSTANT,      0x000e4db2 },
+		{ AUD_DMD_RA_DDS,              0x00f696e6 },
+		{ AUD_IIR2_3_SEL,              0x00000025 },
+		{ AUD_IIR1_4_SEL,              0x00000021 },
+		{ AUD_DN1_FREQ,                0x0000c965 },
+		{ AUD_DCOC_PASS_IN,            0x00000003 },
+		{ AUD_DCOC_0_SRC,              0x0000001a },
+		{ AUD_DCOC_1_SRC,              0x0000001b },
+		{ AUD_DCOC1_SHIFT,             0x00000000 },
+		{ AUD_RDSI_SEL,                0x00000009 },
+		{ AUD_RDSQ_SEL,                0x00000009 },
+		{ AUD_RDSI_SHIFT,              0x00000000 },
+		{ AUD_RDSQ_SHIFT,              0x00000000 },
+		{ AUD_POLYPH80SCALEFAC,        0x00000003 },
+                { /* end of list */ },
+	};
+	
+	// dscaler: exactly taken from driver,
+	// dscaler: don't know why to set EN_FMRADIO_EN_RDS
+	if (sap) {
+		dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
+		set_audio_start(dev, 0x0001,
+				EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP);
+		set_audio_registers(dev, btsc_sap);
+	} else {
+		dprintk("%s (status: known-good)\n",__FUNCTION__);
+		set_audio_start(dev, 0x0001,
+				EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO);
+		set_audio_registers(dev, btsc);
+	}
 	set_audio_finish(dev);
 }
 
 static void set_audio_standard_NICAM(struct cx8800_dev *dev)
 {
-	static const struct rlist nicam[] = {
+	static const struct rlist nicam_common[] = {
+		/* from dscaler */
     		{ AUD_RATE_ADJ1,           0x00000010 },
     		{ AUD_RATE_ADJ2,           0x00000040 },
     		{ AUD_RATE_ADJ3,           0x00000100 },
@@ -152,21 +270,64 @@ static void set_audio_standard_NICAM(str
     		{ AUD_RATE_ADJ5,           0x00001000 },
     //		{ AUD_DMD_RA_DDS,          0x00c0d5ce },
 
+		// Deemphasis 1:
+		{ AUD_DEEMPHGAIN_R,        0x000023c2 },
+		{ AUD_DEEMPHNUMER1_R,      0x0002a7bc },
+		{ AUD_DEEMPHNUMER2_R,      0x0003023e },
+		{ AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
+		{ AUD_DEEMPHDENOM2_R,      0x00000000 },
+		
+#if 0
+		// Deemphasis 2: (other tv norm?)
+		{ AUD_DEEMPHGAIN_R,        0x0000c600 },
+		{ AUD_DEEMPHNUMER1_R,      0x00066738 },
+		{ AUD_DEEMPHNUMER2_R,      0x00066739 },
+		{ AUD_DEEMPHDENOM1_R,      0x0001e88c },
+		{ AUD_DEEMPHDENOM2_R,      0x0001e88c },
+#endif
+
+		{ AUD_DEEMPHDENOM2_R,      0x00000000 },
+		{ AUD_ERRLOGPERIOD_R,      0x00000fff },
+		{ AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
+		{ AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
+		{ AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
+		{ AUD_POLYPH80SCALEFAC,    0x00000003 },
+
 		// setup QAM registers
 		{ AUD_PDF_DDS_CNST_BYTE2,  0x06 },
 		{ AUD_PDF_DDS_CNST_BYTE1,  0x82 },
 		{ AUD_PDF_DDS_CNST_BYTE0,  0x16 },
 		{ AUD_QAM_MODE,            0x05 },
+
+                { /* end of list */ },
+        };
+	static const struct rlist nicam_pal_i[] = {
+		{ AUD_PDF_DDS_CNST_BYTE0,  0x12 },
+		{ AUD_PHACC_FREQ_8MSB,     0x3a },
+		{ AUD_PHACC_FREQ_8LSB,     0x93 },
+
+                { /* end of list */ },
+	};
+	static const struct rlist nicam_default[] = {
+		{ AUD_PDF_DDS_CNST_BYTE0,  0x16 },
 		{ AUD_PHACC_FREQ_8MSB,     0x34 },
 		{ AUD_PHACC_FREQ_8LSB,     0x4c },
 
                 { /* end of list */ },
-        };
+	};
 
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
         set_audio_start(dev, 0x0010,
-			EN_DMTRX_LR | EN_NICAM_FORCE_STEREO);
-        set_audio_registers(dev, nicam);
+			EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
+        set_audio_registers(dev, nicam_common);
+	switch (dev->tvaudio) {
+	case WW_NICAM_I:
+		dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
+		set_audio_registers(dev, nicam_pal_i);
+	case WW_NICAM_BGDKL:
+		dprintk("%s PAL NICAM (status: unknown)\n",__FUNCTION__);
+		set_audio_registers(dev, nicam_default);
+		break;
+	};
         set_audio_finish(dev);
 }
 
@@ -185,104 +346,104 @@ static void set_audio_standard_NICAM_L(s
 		{ AUD_PHACC_FREQ_8LSB,             0x4a },
 
 		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_IIR1_0_SEL,                  0x00000000 },
-		{ AUD_IIR1_1_SEL,                  0x00000002 },
-		{ AUD_IIR1_2_SEL,                  0x00000023 },
-		{ AUD_IIR1_3_SEL,                  0x00000004 },
-		{ AUD_IIR1_4_SEL,                  0x00000005 },
-		{ AUD_IIR1_5_SEL,                  0x00000007 },
-		{ AUD_IIR1_0_SHIFT,                0x00000007 },
-		{ AUD_IIR1_1_SHIFT,                0x00000000 },
-		{ AUD_IIR1_2_SHIFT,                0x00000000 },
-		{ AUD_IIR1_3_SHIFT,                0x00000007 },
-		{ AUD_IIR1_4_SHIFT,                0x00000007 },
-		{ AUD_IIR1_5_SHIFT,                0x00000007 },
-		{ AUD_IIR2_0_SEL,                  0x00000002 },
+		{ AUD_IIR1_0_SEL,                  0x00000000 },                
+		{ AUD_IIR1_1_SEL,                  0x00000002 },                
+		{ AUD_IIR1_2_SEL,                  0x00000023 },                
+		{ AUD_IIR1_3_SEL,                  0x00000004 },                
+		{ AUD_IIR1_4_SEL,                  0x00000005 },                
+		{ AUD_IIR1_5_SEL,                  0x00000007 },                
+		{ AUD_IIR1_0_SHIFT,                0x00000007 },                
+		{ AUD_IIR1_1_SHIFT,                0x00000000 },              
+		{ AUD_IIR1_2_SHIFT,                0x00000000 },                
+		{ AUD_IIR1_3_SHIFT,                0x00000007 },              
+		{ AUD_IIR1_4_SHIFT,                0x00000007 },              
+		{ AUD_IIR1_5_SHIFT,                0x00000007 },              
+		{ AUD_IIR2_0_SEL,                  0x00000002 },              
 		{ AUD_IIR2_1_SEL,                  0x00000003 },
 		{ AUD_IIR2_2_SEL,                  0x00000004 },
-		{ AUD_IIR2_3_SEL,                  0x00000005 },
-		{ AUD_IIR3_0_SEL,                  0x00000007 },
-		{ AUD_IIR3_1_SEL,                  0x00000023 },
-		{ AUD_IIR3_2_SEL,                  0x00000016 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000000 },
-		{ AUD_IIR3_2_SHIFT,                0x00000002 },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_IIR4_1_SEL,                  0x00000019 },
-		{ AUD_IIR4_2_SEL,                  0x00000008 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000007 },
-		{ AUD_IIR4_2_SHIFT,                0x00000007 },
-		{ AUD_IIR4_0_CA0,                  0x0003e57e },
-		{ AUD_IIR4_0_CA1,                  0x00005e11 },
-		{ AUD_IIR4_0_CA2,                  0x0003a7cf },
-		{ AUD_IIR4_0_CB0,                  0x00002368 },
-		{ AUD_IIR4_0_CB1,                  0x0003bf1b },
-		{ AUD_IIR4_1_CA0,                  0x00006349 },
-		{ AUD_IIR4_1_CA1,                  0x00006f27 },
-		{ AUD_IIR4_1_CA2,                  0x0000e7a3 },
+		{ AUD_IIR2_3_SEL,                  0x00000005 },         
+		{ AUD_IIR3_0_SEL,                  0x00000007 },         
+		{ AUD_IIR3_1_SEL,                  0x00000023 },         
+		{ AUD_IIR3_2_SEL,                  0x00000016 },         
+		{ AUD_IIR4_0_SHIFT,                0x00000000 },         
+		{ AUD_IIR4_1_SHIFT,                0x00000000 },         
+		{ AUD_IIR3_2_SHIFT,                0x00000002 },         
+		{ AUD_IIR4_0_SEL,                  0x0000001d },         
+		{ AUD_IIR4_1_SEL,                  0x00000019 },         
+		{ AUD_IIR4_2_SEL,                  0x00000008 },         
+		{ AUD_IIR4_0_SHIFT,                0x00000000 },         
+		{ AUD_IIR4_1_SHIFT,                0x00000007 },         
+		{ AUD_IIR4_2_SHIFT,                0x00000007 },         
+		{ AUD_IIR4_0_CA0,                  0x0003e57e },         
+		{ AUD_IIR4_0_CA1,                  0x00005e11 },         
+		{ AUD_IIR4_0_CA2,                  0x0003a7cf },         
+		{ AUD_IIR4_0_CB0,                  0x00002368 },     
+		{ AUD_IIR4_0_CB1,                  0x0003bf1b },         
+		{ AUD_IIR4_1_CA0,                  0x00006349 },         
+		{ AUD_IIR4_1_CA1,                  0x00006f27 },         
+		{ AUD_IIR4_1_CA2,                  0x0000e7a3 },         
 		{ AUD_IIR4_1_CB0,                  0x00005653 },
-		{ AUD_IIR4_1_CB1,                  0x0000cf97 },
-		{ AUD_IIR4_2_CA0,                  0x00006349 },
-		{ AUD_IIR4_2_CA1,                  0x00006f27 },
-		{ AUD_IIR4_2_CA2,                  0x0000e7a3 },
-		{ AUD_IIR4_2_CB0,                  0x00005653 },
-		{ AUD_IIR4_2_CB1,                  0x0000cf97 },
-		{ AUD_HP_MD_IIR4_1,                0x00000001 },
-		{ AUD_HP_PROG_IIR4_1,              0x0000001a },
+		{ AUD_IIR4_1_CB1,                  0x0000cf97 },         
+		{ AUD_IIR4_2_CA0,                  0x00006349 },         
+		{ AUD_IIR4_2_CA1,                  0x00006f27 },         
+		{ AUD_IIR4_2_CA2,                  0x0000e7a3 },         
+		{ AUD_IIR4_2_CB0,                  0x00005653 },         
+		{ AUD_IIR4_2_CB1,                  0x0000cf97 },         
+		{ AUD_HP_MD_IIR4_1,                0x00000001 },           
+		{ AUD_HP_PROG_IIR4_1,              0x0000001a },         
 		{ AUD_DN0_FREQ,                    0x00000000 },
-		{ AUD_DN1_FREQ,                    0x00003318 },
-		{ AUD_DN1_SRC_SEL,                 0x00000017 },
-		{ AUD_DN1_SHFT,                    0x00000007 },
-		{ AUD_DN1_AFC,                     0x00000000 },
-		{ AUD_DN1_FREQ_SHIFT,              0x00000000 },
-		{ AUD_DN2_FREQ,                    0x00003551 },
-		{ AUD_DN2_SRC_SEL,                 0x00000001 },
-		{ AUD_DN2_SHFT,                    0x00000000 },
-		{ AUD_DN2_AFC,                     0x00000002 },
-		{ AUD_DN2_FREQ_SHIFT,              0x00000000 },
-		{ AUD_PDET_SRC,                    0x00000014 },
-		{ AUD_PDET_SHIFT,                  0x00000000 },
-		{ AUD_DEEMPH0_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH1_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH0_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH1_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH0_G0,                  0x00007000 },
-		{ AUD_DEEMPH0_A0,                  0x00000000 },
-		{ AUD_DEEMPH0_B0,                  0x00000000 },
-		{ AUD_DEEMPH0_A1,                  0x00000000 },
-		{ AUD_DEEMPH0_B1,                  0x00000000 },
-		{ AUD_DEEMPH1_G0,                  0x00007000 },
-		{ AUD_DEEMPH1_A0,                  0x00000000 },
-		{ AUD_DEEMPH1_B0,                  0x00000000 },
-		{ AUD_DEEMPH1_A1,                  0x00000000 },
-		{ AUD_DEEMPH1_B1,                  0x00000000 },
-		{ AUD_DMD_RA_DDS,                  0x00f5c285 },
-		{ AUD_RATE_ADJ1,                   0x00000100 },
-		{ AUD_RATE_ADJ2,                   0x00000200 },
-		{ AUD_RATE_ADJ3,                   0x00000300 },
-		{ AUD_RATE_ADJ4,                   0x00000400 },
-		{ AUD_RATE_ADJ5,                   0x00000500 },
-		{ AUD_C2_UP_THR,                   0x00005400 },
-		{ AUD_C2_LO_THR,                   0x00003000 },
-		{ AUD_C1_UP_THR,                   0x00007000 },
-		{ AUD_C2_LO_THR,                   0x00005400 },
-		{ AUD_CTL,                         0x0000100c },
-		{ AUD_DCOC_0_SRC,                  0x00000021 },
-		{ AUD_DCOC_1_SRC,                  0x00000003 },
-		{ AUD_DCOC1_SHIFT,                 0x00000000 },
-		{ AUD_DCOC_1_SHIFT_IN0,            0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,            0x00000008 },
-		{ AUD_DCOC_PASS_IN,                0x00000000 },
-		{ AUD_DCOC_2_SRC,                  0x0000001b },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_PHASE_FIX_CTL,               0x00000000 },
+		{ AUD_DN1_FREQ,                    0x00003318 },         
+		{ AUD_DN1_SRC_SEL,                 0x00000017 },         
+		{ AUD_DN1_SHFT,                    0x00000007 },         
+		{ AUD_DN1_AFC,                     0x00000000 },         
+		{ AUD_DN1_FREQ_SHIFT,              0x00000000 },         
+		{ AUD_DN2_FREQ,                    0x00003551 },         
+		{ AUD_DN2_SRC_SEL,                 0x00000001 },         
+		{ AUD_DN2_SHFT,                    0x00000000 },         
+		{ AUD_DN2_AFC,                     0x00000002 },         
+		{ AUD_DN2_FREQ_SHIFT,              0x00000000 },         
+		{ AUD_PDET_SRC,                    0x00000014 },         
+		{ AUD_PDET_SHIFT,                  0x00000000 },         
+		{ AUD_DEEMPH0_SRC_SEL,             0x00000011 },         
+		{ AUD_DEEMPH1_SRC_SEL,             0x00000011 },         
+		{ AUD_DEEMPH0_SHIFT,               0x00000000 },         
+		{ AUD_DEEMPH1_SHIFT,               0x00000000 },         
+		{ AUD_DEEMPH0_G0,                  0x00007000 },         
+		{ AUD_DEEMPH0_A0,                  0x00000000 },         
+		{ AUD_DEEMPH0_B0,                  0x00000000 },         
+		{ AUD_DEEMPH0_A1,                  0x00000000 },         
+		{ AUD_DEEMPH0_B1,                  0x00000000 },         
+		{ AUD_DEEMPH1_G0,                  0x00007000 },         
+		{ AUD_DEEMPH1_A0,                  0x00000000 },         
+		{ AUD_DEEMPH1_B0,                  0x00000000 },         
+		{ AUD_DEEMPH1_A1,                  0x00000000 },         
+		{ AUD_DEEMPH1_B1,                  0x00000000 },         
+		{ AUD_DMD_RA_DDS,                  0x00f5c285 },         
+		{ AUD_RATE_ADJ1,                   0x00000100 },         
+		{ AUD_RATE_ADJ2,                   0x00000200 },         
+		{ AUD_RATE_ADJ3,                   0x00000300 },         
+		{ AUD_RATE_ADJ4,                   0x00000400 },         
+		{ AUD_RATE_ADJ5,                   0x00000500 },              
+		{ AUD_C2_UP_THR,                   0x00005400 },              
+		{ AUD_C2_LO_THR,                   0x00003000 },              
+		{ AUD_C1_UP_THR,                   0x00007000 },              
+		{ AUD_C2_LO_THR,                   0x00005400 },              
+		{ AUD_CTL,                         0x0000100c },    
+		{ AUD_DCOC_0_SRC,                  0x00000021 },        
+		{ AUD_DCOC_1_SRC,                  0x00000003 },      
+		{ AUD_DCOC1_SHIFT,                 0x00000000 },      
+		{ AUD_DCOC_1_SHIFT_IN0,            0x0000000a },          
+		{ AUD_DCOC_1_SHIFT_IN1,            0x00000008 },         
+		{ AUD_DCOC_PASS_IN,                0x00000000 },           
+		{ AUD_DCOC_2_SRC,                  0x0000001b },             
+		{ AUD_IIR4_0_SEL,                  0x0000001d },            
+		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },         
+		{ AUD_PHASE_FIX_CTL,               0x00000000 },        
 		{ AUD_CORDIC_SHIFT_1,              0x00000007 },
-		{ AUD_PLL_EN,                      0x00000000 },
+		{ AUD_PLL_EN,                      0x00000000 },        
 		{ AUD_PLL_PRESCALE,                0x00000002 },
-		{ AUD_PLL_INT,                     0x0000001e },
-		{ AUD_OUT1_SHIFT,                  0x00000000 },
+		{ AUD_PLL_INT,                     0x0000001e },            
+		{ AUD_OUT1_SHIFT,                  0x00000000 },          
 
 		{ /* end of list */ },
 	};
@@ -297,14 +458,14 @@ static void set_audio_standard_NICAM_L(s
 static void set_audio_standard_A2(struct cx8800_dev *dev)
 {
 	/* from dscaler cvs */
-	static const struct rlist a2[] = {
+	static const struct rlist a2_common[] = {
 		{ AUD_PDF_DDS_CNST_BYTE2,     0x06 },
 		{ AUD_PDF_DDS_CNST_BYTE1,     0x82 },
 		{ AUD_PDF_DDS_CNST_BYTE0,     0x12 },
 		{ AUD_QAM_MODE,		      0x05 },
 		{ AUD_PHACC_FREQ_8MSB,	      0x34 },
 		{ AUD_PHACC_FREQ_8LSB,	      0x4c },
-
+		
 		{ AUD_RATE_ADJ1,	0x00001000 },
 		{ AUD_RATE_ADJ2,	0x00002000 },
 		{ AUD_RATE_ADJ3,	0x00003000 },
@@ -347,16 +508,20 @@ static void set_audio_standard_A2(struct
 		{ AUD_RDSQ_SHIFT,	0x00000000 },
 		{ AUD_POLYPH80SCALEFAC,	0x00000001 },
 
-		// Table 1
+		{ /* end of list */ },
+	};
+	
+	static const struct rlist a2_table1[] = {
+		// PAL-BG
 		{ AUD_DMD_RA_DDS,	0x002a73bd },
 		{ AUD_C1_UP_THR,	0x00007000 },
 		{ AUD_C1_LO_THR,	0x00005400 },
 		{ AUD_C2_UP_THR,	0x00005400 },
 		{ AUD_C2_LO_THR,	0x00003000 },
-
-#if 0
-		// found this in WDM-driver for A2, must country spec.
-		// Table 2
+		{ /* end of list */ },
+	};
+	static const struct rlist a2_table2[] = {
+		// PAL-DK
 		{ AUD_DMD_RA_DDS,	0x002a73bd },
 		{ AUD_C1_UP_THR,	0x00007000 },
 		{ AUD_C1_LO_THR,	0x00005400 },
@@ -364,8 +529,10 @@ static void set_audio_standard_A2(struct
 		{ AUD_C2_LO_THR,	0x00003000 },
 		{ AUD_DN0_FREQ,		0x00003a1c },
 		{ AUD_DN2_FREQ,		0x0000d2e0 },
-
-		// Table 3
+		{ /* end of list */ },
+	};
+	static const struct rlist a2_table3[] = {
+		// unknown, probably NTSC-M
 		{ AUD_DMD_RA_DDS,	0x002a2873 },
 		{ AUD_C1_UP_THR,	0x00003c00 },
 		{ AUD_C1_LO_THR,	0x00003000 },
@@ -375,140 +542,26 @@ static void set_audio_standard_A2(struct
 		{ AUD_DN1_FREQ,		0x00003418 },
 		{ AUD_DN2_FREQ,		0x000029c7 },
 		{ AUD_POLY0_DDS_CONSTANT, 0x000a7540 },
-#endif
-
 		{ /* end of list */ },
 	};
 
-	static const struct rlist a2_old[] = {
-		{ AUD_DN0_FREQ,            0x0000312b },
-		{ AUD_POLY0_DDS_CONSTANT,  0x000a62b4 },
-		{ AUD_IIR1_0_SEL,          0x00000000 },
-		{ AUD_IIR1_1_SEL,          0x00000001 },
-		{ AUD_IIR1_2_SEL,          0x0000001f },
-		{ AUD_IIR1_3_SEL,          0x00000020 },
-		{ AUD_IIR1_4_SEL,          0x00000023 },
-		{ AUD_IIR1_5_SEL,          0x00000007 },
-		{ AUD_IIR1_0_SHIFT,        0x00000000 },
-		{ AUD_IIR1_1_SHIFT,        0x00000000 },
-		{ AUD_IIR1_2_SHIFT,        0x00000007 },
-		{ AUD_IIR1_3_SHIFT,        0x00000007 },
-		{ AUD_IIR1_4_SHIFT,        0x00000007 },
-		{ AUD_IIR1_5_SHIFT,        0x00000000 },
-		{ AUD_IIR2_0_SEL,          0x00000002 },
-		{ AUD_IIR2_1_SEL,          0x00000003 },
-		{ AUD_IIR2_2_SEL,          0x00000004 },
-		{ AUD_IIR2_3_SEL,          0x00000005 },
-		{ AUD_IIR3_0_SEL,          0x00000021 },
-		{ AUD_IIR3_1_SEL,          0x00000023 },
-		{ AUD_IIR3_2_SEL,          0x00000016 },
-		{ AUD_IIR3_0_SHIFT,        0x00000000 },
-		{ AUD_IIR3_1_SHIFT,        0x00000000 },
-		{ AUD_IIR3_2_SHIFT,        0x00000000 },
-		{ AUD_IIR4_0_SEL,          0x0000001d },
-		{ AUD_IIR4_1_SEL,          0x00000019 },
-		{ AUD_IIR4_2_SEL,          0x00000008 },
-		{ AUD_IIR4_0_SHIFT,        0x00000000 },
-		{ AUD_IIR4_1_SHIFT,        0x00000000 },
-		{ AUD_IIR4_2_SHIFT,        0x00000001 },
-		{ AUD_IIR4_0_CA0,          0x0003e57e },
-		{ AUD_IIR4_0_CA1,          0x00005e11 },
-		{ AUD_IIR4_0_CA2,          0x0003a7cf },
-		{ AUD_IIR4_0_CB0,          0x00002368 },
-		{ AUD_IIR4_0_CB1,          0x0003bf1b },
-		{ AUD_IIR4_1_CA0,          0x00006349 },
-		{ AUD_IIR4_1_CA1,          0x00006f27 },
-		{ AUD_IIR4_1_CA2,          0x0000e7a3 },
-		{ AUD_IIR4_1_CB0,          0x00005653 },
-		{ AUD_IIR4_1_CB1,          0x0000cf97 },
-		{ AUD_IIR4_2_CA0,          0x00006349 },
-		{ AUD_IIR4_2_CA1,          0x00006f27 },
-		{ AUD_IIR4_2_CA2,          0x0000e7a3 },
-		{ AUD_IIR4_2_CB0,          0x00005653 },
-		{ AUD_IIR4_2_CB1,          0x0000cf97 },
-		{ AUD_HP_MD_IIR4_1,        0x00000001 },
-		{ AUD_HP_PROG_IIR4_1,      0x00000017 },
-		{ AUD_DN1_FREQ,            0x00003618 },
-		{ AUD_DN1_SRC_SEL,         0x00000017 },
-		{ AUD_DN1_SHFT,            0x00000007 },
-		{ AUD_DN1_AFC,             0x00000000 },
-		{ AUD_DN1_FREQ_SHIFT,      0x00000000 },
-		{ AUD_DN2_SRC_SEL,         0x00000040 },
-		{ AUD_DN2_SHFT,            0x00000000 },
-		{ AUD_DN2_AFC,             0x00000002 },
-		{ AUD_DN2_FREQ,            0x0000caaf },
-		{ AUD_DN2_FREQ_SHIFT,      0x00000000 },
-		{ AUD_PDET_SRC,            0x00000014 },
-		{ AUD_PDET_SHIFT,          0x00000000 },
-		{ AUD_DEEMPH0_SRC_SEL,     0x00000011 },
-		{ AUD_DEEMPH1_SRC_SEL,     0x00000013 },
-		{ AUD_DEEMPH0_SHIFT,       0x00000000 },
-		{ AUD_DEEMPH1_SHIFT,       0x00000000 },
-		{ AUD_DEEMPH0_G0,          0x000004da },
-		{ AUD_DEEMPH0_A0,          0x0000777a },
-		{ AUD_DEEMPH0_B0,          0x00000000 },
-		{ AUD_DEEMPH0_A1,          0x0003f062 },
-		{ AUD_DEEMPH0_B1,          0x00000000 },
-		{ AUD_DEEMPH1_G0,          0x000004da },
-		{ AUD_DEEMPH1_A0,          0x0000777a },
-		{ AUD_DEEMPH1_B0,          0x00000000 },
-		{ AUD_DEEMPH1_A1,          0x0003f062 },
-		{ AUD_DEEMPH1_B1,          0x00000000 },
-		{ AUD_PLL_EN,              0x00000000 },
-		{ AUD_DMD_RA_DDS,          0x002a4efb },
-		{ AUD_RATE_ADJ1,           0x00001000 },
-		{ AUD_RATE_ADJ2,           0x00002000 },
-		{ AUD_RATE_ADJ3,           0x00003000 },
-		{ AUD_RATE_ADJ4,           0x00004000 },
-		{ AUD_RATE_ADJ5,           0x00005000 },
-		{ AUD_C2_UP_THR,           0x0000ffff },
-		{ AUD_C2_LO_THR,           0x0000e800 },
-		{ AUD_C1_UP_THR,           0x00008c00 },
-		{ AUD_C1_LO_THR,           0x00006c00 },
-
-		//   ; Completely ditch AFC feedback
-		{ AUD_DCOC_0_SRC,          0x00000021 },
-		{ AUD_DCOC_1_SRC,          0x0000001a },
-		{ AUD_DCOC1_SHIFT,         0x00000000 },
-		{ AUD_DCOC_1_SHIFT_IN0,    0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,    0x00000008 },
-		{ AUD_DCOC_PASS_IN,        0x00000000 },
-		{ AUD_IIR4_0_SEL,          0x00000023 },
-
-		//  ; Completely ditc FM-2 AFC feedback
-		{ AUD_DN1_AFC,             0x00000000 },
-		{ AUD_DCOC_2_SRC,          0x0000001b },
-		{ AUD_IIR4_1_SEL,          0x00000025 },
-
-		// ; WARNING!!! THIS CHANGE WAS NOT EXPECTED!!!
-		// ; Swap I & Q inputs into second rotator
-		// ; to reverse frequency and therefor invert
-		// ; phase from the cordic FM demodulator
-		// ; (frequency rotation must also be reversed
-		{ AUD_DN2_SRC_SEL,         0x00000001 },
-		{ AUD_DN2_FREQ,            0x00003551 },
-
-		//  setup Audio PLL
-		{ AUD_PLL_PRESCALE,        0x00000002 },
-		{ AUD_PLL_INT,             0x0000001f },
-
-		{ /* end of list */ },
+	set_audio_start(dev, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
+	set_audio_registers(dev, a2_common);
+	switch (dev->tvaudio) {
+	case WW_A2_BG:
+		dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
+		set_audio_registers(dev, a2_table1);
+		break;
+	case WW_A2_DK:
+		dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
+		set_audio_registers(dev, a2_table2);
+		break;
+	case WW_A2_M:
+		dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
+		set_audio_registers(dev, a2_table3);
+		break;
 	};
-
-
-	dprintk("%s (status: WorksForMe[tm])\n",__FUNCTION__);
-
-	if (0) {
-		/* old code */
-		set_audio_start(dev, 0x0004, EN_DMTRX_SUMR | EN_A2_AUTO_STEREO);
-		set_audio_registers(dev, a2_old);
-		set_audio_finish(dev);
-	} else {
-		/* new code */
-		set_audio_start(dev, 0x0004, EN_DMTRX_LR | EN_A2_AUTO_STEREO);
-		set_audio_registers(dev, a2);
-		set_audio_finish(dev);
-	}
+	set_audio_finish(dev);
 }
 
 static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
@@ -617,9 +670,9 @@ void cx88_get_stereo(struct cx8800_dev *
 	reg   = cx_read(AUD_STATUS);
 	mode  = reg & 0x03;
 	pilot = (reg >> 2) & 0x03;
-	dprintk("AUD_STATUS: %s / %s [status=0x%x,ctl=0x%x,vol=0x%x]\n",
-		m[mode], p[pilot], reg,
-		cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
+	dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
+		reg, m[mode], p[pilot],
+		aud_ctl_names[cx_read(AUD_CTL) & 63]);
 
 	t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
 		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
@@ -628,6 +681,8 @@ void cx88_get_stereo(struct cx8800_dev *
 
 	switch (dev->tvaudio) {
 	case WW_A2_BG:
+	case WW_A2_DK:
+	case WW_A2_M:
  		if (1 == pilot) {
 			/* stereo */
 			t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
@@ -659,6 +714,8 @@ void cx88_set_stereo(struct cx8800_dev *
 
 	switch (dev->tvaudio) {
 	case WW_A2_BG:
+	case WW_A2_DK:
+	case WW_A2_M:
 		switch (mode) {
 		case V4L2_TUNER_MODE_MONO:   
 		case V4L2_TUNER_MODE_LANG1:
@@ -717,6 +774,32 @@ void cx88_set_stereo(struct cx8800_dev *
 	return;
 }
 
+/* just monitor the audio status for now ... */
+int cx88_audio_thread(void *data)
+{
+	struct cx8800_dev *dev = data;
+	struct v4l2_tuner t;
+	
+	daemonize("msp3400");
+	allow_signal(SIGTERM);
+	dprintk("cx88: tvaudio thread started\n");
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ*3);
+		if (signal_pending(current))
+			break;
+		if (dev->shutdown)
+			break;
+
+		memset(&t,0,sizeof(t));
+		cx88_get_stereo(dev,&t);
+	}
+
+	dprintk("cx88: tvaudio thread exiting\n");
+        complete_and_exit(&dev->texit, 0);
+}
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff -up linux-2.6.7/drivers/media/video/cx88/cx88-vbi.c linux/drivers/media/video/cx88/cx88-vbi.c
--- linux-2.6.7/drivers/media/video/cx88/cx88-vbi.c	2004-06-17 10:28:57.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-vbi.c	2004-06-17 13:47:59.797270159 +0200
@@ -28,17 +28,14 @@ void cx8800_vbi_fmt(struct cx8800_dev *d
 	f->fmt.vbi.count[0] = VBI_LINE_COUNT;
 	f->fmt.vbi.count[1] = VBI_LINE_COUNT;
 
-	switch (dev->tvnorm->id) {
-	case V4L2_STD_NTSC_M:
-	case V4L2_STD_NTSC_M_JP:
+	if (dev->tvnorm->id & V4L2_STD_525_60) {
+		/* ntsc */
 		f->fmt.vbi.sampling_rate = 28636363;
 		f->fmt.vbi.start[0] = 10 -1;
 		f->fmt.vbi.start[1] = 273 -1;
-		break;
-	case V4L2_STD_PAL_BG:
-	case V4L2_STD_PAL_DK:
-	case V4L2_STD_PAL_I:
-	case V4L2_STD_SECAM:
+
+	} else if (V4L2_STD_625_50) {
+		/* pal */
 		f->fmt.vbi.sampling_rate = 35468950;
 		f->fmt.vbi.start[0] = 7 -1;
 		f->fmt.vbi.start[1] = 319 -1;
@@ -64,10 +61,10 @@ int cx8800_start_vbi_dma(struct cx8800_d
 	/* enable irqs */
 	cx_set(MO_PCI_INTMSK, 0x00fc01);
 	cx_set(MO_VID_INTMSK, 0x0f0088);
-
+	
 	/* enable capture */
 	cx_set(VID_CAPTURE_CONTROL,0x18);
-
+	
 	/* start dma */
 	cx_set(MO_DEV_CNTRL2, (1<<5));
 	cx_set(MO_VID_DMACNTRL, 0x88);
@@ -80,7 +77,7 @@ int cx8800_restart_vbi_queue(struct cx88
 {
 	struct cx88_buffer *buf;
 	struct list_head *item;
-
+	
 	if (list_empty(&q->active))
 		return 0;
 
@@ -104,7 +101,7 @@ void cx8800_vbi_timeout(unsigned long da
 	unsigned long flags;
 
 	cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH24]);
-
+	
 	cx_clear(MO_VID_DMACNTRL, 0x88);
 	cx_clear(VID_CAPTURE_CONTROL, 0x18);
 
@@ -161,7 +158,7 @@ vbi_prepare(struct file *file, struct vi
 		cx88_risc_buffer(dev->pci, &buf->risc,
 				 buf->vb.dma.sglist,
 				 0, buf->vb.width * buf->vb.height,
-				 buf->vb.width, 0,
+				 buf->vb.width, 0, 
 				 buf->vb.height);
 	}
 	buf->vb.state = STATE_PREPARED;
diff -up linux-2.6.7/drivers/media/video/cx88/cx88-video.c linux/drivers/media/video/cx88/cx88-video.c
--- linux-2.6.7/drivers/media/video/cx88/cx88-video.c	2004-06-17 10:29:27.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88-video.c	2004-06-17 13:47:59.805268654 +0200
@@ -2,7 +2,7 @@
  * device driver for Conexant 2388x based TV cards
  * video4linux video interface
  *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
  *  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
@@ -19,8 +19,6 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define __NO_VERSION__ 1
-
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -32,6 +30,8 @@
 
 #include "cx88.h"
 
+#define V4L2_I2C_CLIENTS 1
+
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -194,8 +194,13 @@ static struct cx8800_tvnorm tvnorms[] = 
 		.cxiformat = VideoFormatPAL60,
 		.cxoformat = 0x181f0008,
 	},{
-		.name      = "SECAM",
-		.id        = V4L2_STD_SECAM,
+		.name      = "SECAM-L",
+		.id        = V4L2_STD_SECAM_L,
+		.cxiformat = VideoFormatSECAM,
+		.cxoformat = 0x181f0008,
+	},{
+		.name      = "SECAM-DK",
+		.id        = V4L2_STD_SECAM_DK,
 		.cxiformat = VideoFormatSECAM,
 		.cxoformat = 0x181f0008,
 	}
@@ -331,7 +336,7 @@ static struct cx88_ctrl cx8800_ctls[] = 
 		 */
 		.v = {
 			.id            = V4L2_CID_SATURATION,
-			.name          = "Saturation",
+			.name          = "Saturation", 
 			.minimum       = 0,
 			.maximum       = 0xff,
 			.step          = 1,
@@ -483,35 +488,38 @@ static int set_tvaudio(struct cx8800_dev
 	if (CX88_VMUX_TELEVISION != INPUT(dev->input)->type)
 		return 0;
 
-	switch (dev->tvnorm->id) {
-	case V4L2_STD_PAL_BG:
+	if (V4L2_STD_PAL_BG & dev->tvnorm->id) {
 		dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
-		break;
-	case V4L2_STD_PAL_DK:
+
+	} else if (V4L2_STD_PAL_DK & dev->tvnorm->id) {
 		dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
-		break;
-	case V4L2_STD_PAL_I:
+
+	} else if (V4L2_STD_PAL_I & dev->tvnorm->id) {
 		dev->tvaudio = WW_NICAM_I;
-		break;
-	case V4L2_STD_SECAM:
-		dev->tvaudio = WW_SYSTEM_L_AM;  /* FIXME: fr != ru */
-		break;
-	case V4L2_STD_NTSC_M:
+
+	} else if (V4L2_STD_SECAM_L & dev->tvnorm->id) {
+		dev->tvaudio = WW_SYSTEM_L_AM;
+
+	} else if (V4L2_STD_SECAM_DK & dev->tvnorm->id) {
+		dev->tvaudio = WW_A2_DK;
+
+	} else if ((V4L2_STD_NTSC_M & dev->tvnorm->id) ||
+		   (V4L2_STD_PAL_M  & dev->tvnorm->id)) {
 		dev->tvaudio = WW_BTSC;
-		break;
-	case V4L2_STD_NTSC_M_JP:
+
+	} else if (V4L2_STD_NTSC_M_JP & dev->tvnorm->id) {
 		dev->tvaudio = WW_EIAJ;
-		break;
-	default:
-		dprintk(1,"tvaudio support needs work for this tv norm [%s], sorry\n",
-			dev->tvnorm->name);
+
+	} else {
+		printk("%s: tvaudio support needs work for this tv norm [%s], sorry\n",
+		       dev->name, dev->tvnorm->name);
 		dev->tvaudio = 0;
 		return 0;
 	}
 
 	cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
 	cx88_set_tvaudio(dev);
-	cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
+	// cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
 
 	cx_write(MO_AUDD_LNGTH, 128/8);  /* fifo size */
 	cx_write(MO_AUDR_LNGTH, 128/8);  /* fifo size */
@@ -526,7 +534,6 @@ static int set_tvnorm(struct cx8800_dev 
 	u32 vdec_clock;
 	u64 tmp64;
 	u32 bdelay,agcdelay,htotal;
-	struct video_channel c;
 	
 	dev->tvnorm = norm;
 	fsc8       = norm_fsc8(norm);
@@ -592,30 +599,43 @@ static int set_tvnorm(struct cx8800_dev 
 	set_tvaudio(dev);
 
 	// tell i2c chips
-	memset(&c,0,sizeof(c));
-	c.channel = dev->input;
-	c.norm = VIDEO_MODE_PAL;
-	if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
-		c.norm = VIDEO_MODE_NTSC;
-	if (norm->id & V4L2_STD_SECAM)
-		c.norm = VIDEO_MODE_SECAM;
-	cx8800_call_i2c_clients(dev,VIDIOCSCHAN,&c);
+#ifdef V4L2_I2C_CLIENTS
+	cx8800_call_i2c_clients(dev,VIDIOC_S_STD,&norm->id);
+#else
+	{
+		struct video_channel c;
+		memset(&c,0,sizeof(c));
+		c.channel = dev->input;
+		c.norm = VIDEO_MODE_PAL;
+		if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
+			c.norm = VIDEO_MODE_NTSC;
+		if (norm->id & V4L2_STD_SECAM)
+			c.norm = VIDEO_MODE_SECAM;
+		cx8800_call_i2c_clients(dev,VIDIOCSCHAN,&c);
+	}
+#endif
 
 	// done
 	return 0;
 }
 
 static int set_scale(struct cx8800_dev *dev, unsigned int width, unsigned int height,
-		     int interlaced)
+		     enum v4l2_field field)
 {
 	unsigned int swidth  = norm_swidth(dev->tvnorm);
 	unsigned int sheight = norm_maxh(dev->tvnorm);
 	u32 value;
 
-	dprintk(1,"set_scale: %dx%d [%s]\n", width, height, dev->tvnorm->name);
+	dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+		V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+		V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+		dev->tvnorm->name);
+	if (!V4L2_FIELD_HAS_BOTH(field))
+		height *= 2;
 
 	// recalc H delay and scale registers
 	value = (width * norm_hdelay(dev->tvnorm)) / swidth;
+	value &= 0x3fe;
 	cx_write(MO_HDELAY_EVEN,  value);
 	cx_write(MO_HDELAY_ODD,   value);
 	dprintk(1,"set_scale: hdelay  0x%04x\n", value);
@@ -646,7 +666,7 @@ static int set_scale(struct cx8800_dev *
 	// setup filters
 	value = 0;
 	value |= (1 << 19);        // CFILT (default)
-	if (interlaced)
+	if (V4L2_FIELD_INTERLACED == field)
 		value |= (1 << 3); // VINT (interlaced vertical scaling)
 	if (width < 385)
 		value |= (1 << 0); // 3-tap interpolation
@@ -675,10 +695,12 @@ static int video_mux(struct cx8800_dev *
 
 	switch (INPUT(input)->type) {
 	case CX88_VMUX_SVIDEO:
-		cx_andor(MO_AFECFG_IO, 0x01, 0x01);
+		cx_set(MO_AFECFG_IO,    0x00000001);
+		cx_set(MO_INPUT_FORMAT, 0x00010010);
 		break;
 	default:
-		cx_andor(MO_AFECFG_IO, 0x01, 0x00);
+		cx_clear(MO_AFECFG_IO,    0x00000001);
+		cx_clear(MO_INPUT_FORMAT, 0x00010010);
 		break;
 	}
 	return 0;
@@ -693,7 +715,7 @@ static int start_video_dma(struct cx8800
 	/* setup fifo + format */
 	cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH21],
 				buf->bpl, buf->risc.dma);
-	set_scale(dev, buf->vb.width, buf->vb.height, 1);
+	set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
 	cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);
 
 	/* reset counter */
@@ -1350,6 +1372,9 @@ static int get_control(struct cx8800_dev
 	case V4L2_CID_AUDIO_BALANCE:
 		ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f));
 		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctl->value = 0x3f - (value & 0x3f);
+		break;
 	default:
 		ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
 		break;
@@ -1378,6 +1403,9 @@ static int set_control(struct cx8800_dev
 	case V4L2_CID_AUDIO_BALANCE:
 		value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
 		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		value = 0x3f - (ctl->value & 0x3f);
+		break;
 	case V4L2_CID_SATURATION:
 		/* special v_sat handling */
 		v_sat_value = ctl->value - (0x7f - 0x5a);
@@ -1409,7 +1437,7 @@ static void init_controls(struct cx8800_
 	};
 	static struct v4l2_control volume = {
 		.id    = V4L2_CID_AUDIO_VOLUME,
-		.value = 0,
+		.value = 0x3f,
 	};
 
 	set_control(dev,&mute);
@@ -1459,15 +1487,12 @@ static int cx8800_try_fmt(struct cx8800_
 		maxw  = norm_maxw(dev->tvnorm);
 		maxh  = norm_maxh(dev->tvnorm);
 
-#if 0
 		if (V4L2_FIELD_ANY == field) {
 			field = (f->fmt.pix.height > maxh/2)
 				? V4L2_FIELD_INTERLACED
 				: V4L2_FIELD_BOTTOM;
 		}
-#else
-		field = V4L2_FIELD_INTERLACED;
-#endif
+
 		switch (field) {
 		case V4L2_FIELD_TOP:
 		case V4L2_FIELD_BOTTOM:
@@ -1480,14 +1505,15 @@ static int cx8800_try_fmt(struct cx8800_
 		}
 
 		f->fmt.pix.field = field;
-		if (f->fmt.pix.width < 48)
-			f->fmt.pix.width = 48;
 		if (f->fmt.pix.height < 32)
 			f->fmt.pix.height = 32;
-		if (f->fmt.pix.width > maxw)
-			f->fmt.pix.width = maxw;
 		if (f->fmt.pix.height > maxh)
 			f->fmt.pix.height = maxh;
+		if (f->fmt.pix.width < 48)
+			f->fmt.pix.width = 48;
+		if (f->fmt.pix.width > maxw)
+			f->fmt.pix.width = maxw;
+		f->fmt.pix.width &= ~0x03;
 		f->fmt.pix.bytesperline =
 			(f->fmt.pix.width * fmt->depth) >> 3;
 		f->fmt.pix.sizeimage =
@@ -1783,7 +1809,11 @@ static int video_do_ioctl(struct inode *
 			return -EINVAL;
 		down(&dev->lock);
 		dev->freq = f->frequency;
+#ifdef V4L2_I2C_CLIENTS
+		cx8800_call_i2c_clients(dev,VIDIOC_S_FREQUENCY,f);
+#else
 		cx8800_call_i2c_clients(dev,VIDIOCSFREQ,&dev->freq);
+#endif
 		up(&dev->lock);
 		return 0;
 	}
@@ -1836,7 +1866,7 @@ static int video_do_ioctl(struct inode *
 	case VIDIOC_STREAMOFF:
 	{
 		int res = get_ressource(fh);
-
+		
 		err = videobuf_streamoff(file, get_queue(fh));
 		if (err < 0)
 			return err;
@@ -1885,7 +1915,6 @@ static int radio_do_ioctl(struct inode *
 	case VIDIOC_G_TUNER:
 	{
 		struct v4l2_tuner *t = arg;
-		struct video_tuner vt;
 
 		if (t->index > 0)
 			return -EINVAL;
@@ -1895,9 +1924,16 @@ static int radio_do_ioctl(struct inode *
                 t->rangelow  = (int)(65*16);
                 t->rangehigh = (int)(108*16);
 		
-		memset(&vt,0,sizeof(vt));
-		cx8800_call_i2c_clients(dev,VIDIOCGTUNER,&vt);
-		t->signal = vt.signal;
+#ifdef V4L2_I2C_CLIENTS
+		cx8800_call_i2c_clients(dev,VIDIOC_G_TUNER,t);
+#else
+		{
+			struct video_tuner vt;
+			memset(&vt,0,sizeof(vt));
+			cx8800_call_i2c_clients(dev,VIDIOCGTUNER,&vt);
+			t->signal = vt.signal;
+		}
+#endif
 		return 0;
 	}
 	case VIDIOC_ENUMINPUT:
@@ -2281,11 +2317,6 @@ static void cx8800_unregister_video(stru
 	}
 }
 
-/* debug that damn oops ... */
-static unsigned int oops = 0;
-MODULE_PARM(oops,"i");
-#define OOPS(msg) if (oops) printk("%s: %s\n",__FUNCTION__,msg);
-
 static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 				    const struct pci_device_id *pci_id)
 {
@@ -2299,7 +2330,6 @@ static int __devinit cx8800_initdev(stru
 	memset(dev,0,sizeof(*dev));
 
 	/* pci init */
-	OOPS("pci init");
 	dev->pci = pci_dev;
 	if (pci_enable_device(pci_dev)) {
 		err = -EIO;
@@ -2308,7 +2338,6 @@ static int __devinit cx8800_initdev(stru
 	sprintf(dev->name,"cx%x[%d]",pci_dev->device,cx8800_devcount);
 
 	/* pci quirks */
-	OOPS("pci quirks");
 	cx88_pci_quirks(dev->name, dev->pci, &latency);
 	if (UNSET != latency) {
 		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
@@ -2317,7 +2346,6 @@ static int __devinit cx8800_initdev(stru
 	}
 
 	/* print pci info */
-	OOPS("pci info");
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
         pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
         printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
@@ -2333,14 +2361,15 @@ static int __devinit cx8800_initdev(stru
 	}
 
 	/* board config */
-	OOPS("board config");
 	dev->board = card[cx8800_devcount];
 	for (i = 0; UNSET == dev->board  &&  i < cx88_idcount; i++) 
 		if (pci_dev->subsystem_vendor == cx88_subids[i].subvendor &&
 		    pci_dev->subsystem_device == cx88_subids[i].subdevice)
 			dev->board = cx88_subids[i].card;
-	if (UNSET == dev->board)
+	if (UNSET == dev->board) {
 		dev->board = CX88_BOARD_UNKNOWN;
+		cx88_card_list(dev);
+	}
         printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
 	       dev->name,pci_dev->subsystem_vendor,
 	       pci_dev->subsystem_device,cx88_boards[dev->board].name,
@@ -2352,7 +2381,6 @@ static int __devinit cx8800_initdev(stru
 		dev->tuner_type = cx88_boards[dev->board].tuner_type;
 
 	/* get mmio */
-	OOPS("get mmio");
 	if (!request_mem_region(pci_resource_start(pci_dev,0),
 				pci_resource_len(pci_dev,0),
 				dev->name)) {
@@ -2366,7 +2394,6 @@ static int __devinit cx8800_initdev(stru
 	dev->bmmio = (u8*)dev->lmmio;
 
 	/* initialize driver struct */
-	OOPS("init structs");
         init_MUTEX(&dev->lock);
 	dev->slock = SPIN_LOCK_UNLOCKED;
 	dev->tvnorm = tvnorms;
@@ -2390,11 +2417,9 @@ static int __devinit cx8800_initdev(stru
 			  MO_VID_DMACNTRL,0x88,0x00);
 
 	/* initialize hardware */
-	OOPS("reset hardware");
 	cx8800_reset(dev);
 
 	/* get irq */
-	OOPS("install irq handler");
 	err = request_irq(pci_dev->irq, cx8800_irq,
 			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
 	if (err < 0) {
@@ -2404,13 +2429,10 @@ static int __devinit cx8800_initdev(stru
 	}
 
 	/* register i2c bus + load i2c helpers */
-	OOPS("i2c setup");
 	cx8800_i2c_init(dev);
-	OOPS("card setup");
 	cx88_card_setup(dev);
 
 	/* load and configure helper modules */
-	OOPS("configure i2c clients");
 	if (TUNER_ABSENT != dev->tuner_type)
 		request_module("tuner");
 	if (cx88_boards[dev->board].needs_tda9887)
@@ -2419,7 +2441,6 @@ static int __devinit cx8800_initdev(stru
 		cx8800_call_i2c_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
 
 	/* register v4l devices */
-	OOPS("register video");
 	dev->video_dev = vdev_init(dev,&cx8800_video_template,"video");
 	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
 				    video_nr[cx8800_devcount]);
@@ -2431,7 +2452,6 @@ static int __devinit cx8800_initdev(stru
 	printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
 	       dev->name,dev->video_dev->minor & 0x1f);
 
-	OOPS("register vbi");
 	dev->vbi_dev = vdev_init(dev,&cx8800_vbi_template,"vbi");
 	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
 				    vbi_nr[cx8800_devcount]);
@@ -2444,7 +2464,6 @@ static int __devinit cx8800_initdev(stru
 	       dev->name,dev->vbi_dev->minor & 0x1f);
 
 	if (dev->has_radio) {
-		OOPS("register radio");
 		dev->radio_dev = vdev_init(dev,&cx8800_radio_template,"radio");
 		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
 					    radio_nr[cx8800_devcount]);
@@ -2458,32 +2477,31 @@ static int __devinit cx8800_initdev(stru
 	}
 
 	/* everything worked */
-	OOPS("finalize");
 	list_add_tail(&dev->devlist,&cx8800_devlist);
 	pci_set_drvdata(pci_dev,dev);
 	cx8800_devcount++;
 
 	/* initial device configuration */
-	OOPS("init device");
 	down(&dev->lock);
 	init_controls(dev);
 	set_tvnorm(dev,tvnorms);
 	video_mux(dev,0);
 	up(&dev->lock);
+
+	/* start tvaudio thread */
+	init_completion(&dev->texit);
+	dev->tpid = kernel_thread(cx88_audio_thread, dev, 0);
 	return 0;
 
  fail3:
-	OOPS("fail3");
 	cx8800_unregister_video(dev);
 	if (0 == dev->i2c_rc)
 		i2c_bit_del_bus(&dev->i2c_adap);
 	free_irq(pci_dev->irq, dev);
  fail2:
-	OOPS("fail2");
 	release_mem_region(pci_resource_start(pci_dev,0),
 			   pci_resource_len(pci_dev,0));
  fail1:
-	OOPS("fail1");
 	kfree(dev);
 	return err;
 }
@@ -2492,6 +2510,11 @@ static void __devexit cx8800_finidev(str
 {
         struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
 
+	/* stop thread */
+	dev->shutdown = 1;
+	if (dev->tpid >= 0)
+		wait_for_completion(&dev->texit);
+
 	cx8800_shutdown(dev);
 	pci_disable_device(pci_dev);
 
diff -up linux-2.6.7/drivers/media/video/cx88/cx88.h linux/drivers/media/video/cx88/cx88.h
--- linux-2.6.7/drivers/media/video/cx88/cx88.h	2004-06-17 10:31:18.000000000 +0200
+++ linux/drivers/media/video/cx88/cx88.h	2004-06-17 13:47:59.807268278 +0200
@@ -32,7 +32,7 @@
 #include "cx88-reg.h"
 
 #include <linux/version.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,3)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,4)
 
 #ifndef TRUE
 # define TRUE (1==1)
@@ -114,17 +114,20 @@ extern struct sram_channel cx88_sram_cha
 /* card configuration                                          */
 
 #define CX88_BOARD_NOAUTO        UNSET
-#define CX88_BOARD_UNKNOWN           0
-#define CX88_BOARD_HAUPPAUGE         1
-#define CX88_BOARD_GDI               2
-#define CX88_BOARD_PIXELVIEW         3
-#define CX88_BOARD_ATI_WONDER_PRO    4
-#define CX88_BOARD_WINFAST2000XP     5
-#define CX88_BOARD_AVERTV_303        6
-#define CX88_BOARD_MSI_TVANYWHERE    7
-#define CX88_BOARD_WINFAST_DV2000    8
-#define CX88_BOARD_LEADTEK_PVR2000   9
-
+#define CX88_BOARD_UNKNOWN               0
+#define CX88_BOARD_HAUPPAUGE             1
+#define CX88_BOARD_GDI                   2
+#define CX88_BOARD_PIXELVIEW             3
+#define CX88_BOARD_ATI_WONDER_PRO        4
+#define CX88_BOARD_WINFAST2000XP         5
+#define CX88_BOARD_AVERTV_303            6
+#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
+#define CX88_BOARD_WINFAST_DV2000        8
+#define CX88_BOARD_LEADTEK_PVR2000       9
+#define CX88_BOARD_IODATA_GVVCP3PCI      10
+#define CX88_BOARD_PROLINK_PLAYTVPVR     11
+#define CX88_BOARD_ASUS_PVR_416          12
+#define CX88_BOARD_MSI_TVANYWHERE        13
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -263,6 +266,9 @@ struct cx8800_dev {
 
 	/* other global state info */
 	u32                         shadow[SHADOW_MAX];
+	int                         shutdown;
+	pid_t                       tpid;
+	struct completion           texit;
 	struct cx8800_suspend_state state;
 };
 
@@ -351,7 +357,8 @@ extern const unsigned int cx88_bcount;
 extern struct cx88_subid cx88_subids[];
 extern const unsigned int cx88_idcount;
 
-extern void __devinit cx88_card_setup(struct cx8800_dev *dev);
+extern void cx88_card_list(struct cx8800_dev *dev);
+extern void cx88_card_setup(struct cx8800_dev *dev);
 
 /* ----------------------------------------------------------- */
 /* cx88-tvaudio.c                                              */
@@ -372,6 +379,7 @@ extern void __devinit cx88_card_setup(st
 void cx88_set_tvaudio(struct cx8800_dev *dev);
 void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t);
 void cx88_set_stereo(struct cx8800_dev *dev, u32 mode);
+int cx88_audio_thread(void *data);
 
 /*
  * Local variables:

-- 
Smoking Crack Organization

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [patch] v4l: cx88 driver update
@ 2005-03-08 11:00 Gerd Knorr
  0 siblings, 0 replies; 2+ messages in thread
From: Gerd Knorr @ 2005-03-08 11:00 UTC (permalink / raw)
  To: Andrew Morton, Linux Kernel Mailing List

  Hi,

Finally the big cx88 driver update which makes the cx88-dvb
driver compile and work for some cards.  A number of changes
accumulated over time ...

 * various new tv cards added / fixed.
 * added support for infrared remote controls.
 * some fixes in the blackbird (mpeg encoder) driver,
   starts working now.
 * configurarion for analog hauppauge cards now uses
   the tveeprom module.
 * kconfig fixups.
 * powermanagement fixups.
 * lot of tweaks for tv audio (make NICAM decoding work).
 * lot of changes in the dvb driver, still not working
   for all cards though as some more changes in the dvb
   subsystem are needed.

Signed-off-by: Gerd Knorr <kraxel@bytesex.org>
---
 drivers/media/video/Kconfig               |   10 
 drivers/media/video/cx88/Makefile         |    3 
 drivers/media/video/cx88/cx88-blackbird.c |   27 -
 drivers/media/video/cx88/cx88-cards.c     |  393 ++++++++++---------
 drivers/media/video/cx88/cx88-core.c      |   42 +-
 drivers/media/video/cx88/cx88-dvb.c       |  185 +++++---
 drivers/media/video/cx88/cx88-i2c.c       |    3 
 drivers/media/video/cx88/cx88-input.c     |  396 +++++++++++++++++++
 drivers/media/video/cx88/cx88-mpeg.c      |   44 +-
 drivers/media/video/cx88/cx88-tvaudio.c   |  455 +++++++++++++++-------
 drivers/media/video/cx88/cx88-vbi.c       |    5 
 drivers/media/video/cx88/cx88-video.c     |   34 -
 drivers/media/video/cx88/cx88.h           |   38 +
 13 files changed, 1189 insertions(+), 446 deletions(-)

Index: linux-2.6.11/drivers/media/video/cx88/cx88-cards.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-cards.c	2005-03-07 10:14:56.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-cards.c	2005-03-08 10:33:15.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-cards.c,v 1.47 2004/11/03 09:04:50 kraxel Exp $
+ * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * card-specific stuff.
@@ -26,14 +26,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
-# define WITH_DVB 1
-#endif
-
 #include "cx88.h"
-#ifdef WITH_DVB
-#include "cx22702.h"
-#endif
 
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
@@ -59,6 +52,7 @@ struct cx88_board cx88_boards[] = {
 	[CX88_BOARD_HAUPPAUGE] = {
 		.name		= "Hauppauge WinTV 34xxx models",
 		.tuner_type     = UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -91,7 +85,7 @@ struct cx88_board cx88_boards[] = {
 	},
 	[CX88_BOARD_PIXELVIEW] = {
 		.name           = "PixelView",
-		.tuner_type     = UNSET,
+		.tuner_type     = 5,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -126,7 +120,7 @@ struct cx88_board cx88_boards[] = {
                         .gpio0  = 0x03fe,
 		}},
 	},
-        [CX88_BOARD_WINFAST2000XP] = {
+        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
                 .name           = "Leadtek Winfast 2000XP Expert",
                 .tuner_type     = 44,
 		.tda9887_conf   = TDA9887_PRESENT,
@@ -217,26 +211,55 @@ struct cx88_board cx88_boards[] = {
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
-                }},
+			.gpio0  = 0x0035e700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035e700,
+			.gpio3  = 0x02000000,
+		},{
+
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x00003004,
+			.gpio2  = 0x0035c700,
+			.gpio3  = 0x02000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0035c700,
+			.gpio1  = 0x0035c700,
+			.gpio2  = 0x02000000,
+			.gpio3  = 0x02000000,
+		}},
                 .radio = {
-                        .type   = CX88_RADIO,
-                },
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0035d700,
+			.gpio1  = 0x00007004,
+			.gpio2  = 0x0035d700,
+			.gpio3  = 0x02000000,
+		 },
         },
         [CX88_BOARD_LEADTEK_PVR2000] = {
+		// gpio values for PAL version from regspy by DScaler
                 .name           = "Leadtek PVR 2000",
                 .tuner_type     = 38,
+		.tda9887_conf   = TDA9887_PRESENT,
                 .input          = {{
                         .type   = CX88_VMUX_TELEVISION,
                         .vmux   = 0,
+                        .gpio0  = 0x0000bde6,
                 },{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
+                        .gpio0  = 0x0000bde6,
                 },{
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
+                        .gpio0  = 0x0000bde6,
                 }},
                 .radio = {
                         .type   = CX88_RADIO,
+                        .gpio0  = 0x0000bd62,
                 },
 		.blackbird = 1,
         },
@@ -320,14 +343,15 @@ struct cx88_board cx88_boards[] = {
                 .name           = "KWorld/VStream XPert DVB-T",
 		.tuner_type     = TUNER_ABSENT,
                 .input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                },{
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
                 },{
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
+			.gpio0  = 0x0700,
+			.gpio2  = 0x0101,
                 }},
 		.dvb            = 1,
 	},
@@ -452,6 +476,131 @@ struct cx88_board cx88_boards[] = {
 		}},
 		.dvb            = 1,
 	},
+	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
+		.name	        = "digitalnow DNTV Live! DVB-T",
+		.tuner_type     = TUNER_ABSENT,
+		.input	        = {{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00000700,
+			.gpio2  = 0x00000101,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_PCHDTV_HD3000] = {
+		.name           = "pcHDTV HD3000 HDTV",
+		.tuner_type     = TUNER_THOMSON_DTT7610,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00008484,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.vmux   = 2,
+			.gpio0  = 0x00008400,
+			.gpio1  = 0x00000000,
+			.gpio2  = 0x00000000,
+			.gpio3  = 0x00000000,
+		},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
+		// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
+		// GPIO values obtained from regspy, courtesy Sean Covel
+		.name        = "Hauppauge WinTV 28xxx (Roslyn) models",
+		.tuner_type  = UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xed12,  // internal decoder
+			.gpio2  = 0x00ff,
+		},{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,  // mono from tuner chip
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xed92,
+			.gpio2  = 0x00ff,
+		}},
+		.radio = {
+			 .type   = CX88_RADIO,
+			 .gpio0  = 0xed96,
+			 .gpio2  = 0x00ff,
+		 },
+		.blackbird = 1,
+	},
+	[CX88_BOARD_DIGITALLOGIC_MEC] = {
+		/* params copied over from Leadtek PVR 2000 */
+		.name           = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
+		/* not sure yet about the tuner type */
+		.tuner_type     = 38,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000bde6,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x0000bde6,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x0000bde6,
+		}},
+		.radio = {
+			.type   = CX88_RADIO,
+			.gpio0  = 0x0000bd62,
+		},
+		.blackbird = 1,
+	},
+	[CX88_BOARD_IODATA_GVBCTV7E] = {
+		.name           = "IODATA GV/BCTV7E",
+		.tuner_type     = TUNER_PHILIPS_FQ1286,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 1,
+			.gpio1  = 0x0000e03f,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 2,
+			.gpio1  = 0x0000e07f,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 3,
+			.gpio1  = 0x0000e07f,
+		}}
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -482,11 +631,11 @@ struct cx88_subid cx88_subids[] = {
 	},{
                 .subvendor = 0x107d,
                 .subdevice = 0x6611,
-                .card      = CX88_BOARD_WINFAST2000XP,
+                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
 	},{
                 .subvendor = 0x107d,
                 .subdevice = 0x6613,	/* NTSC */
-                .card      = CX88_BOARD_WINFAST2000XP,
+                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
 	},{
 		.subvendor = 0x107d,
                 .subdevice = 0x6620,
@@ -543,6 +692,30 @@ struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x18AC,
 		.subdevice = 0xDB10,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
+	},{
+                .subvendor = 0x1554,
+                .subdevice = 0x4811,
+                .card      = CX88_BOARD_PIXELVIEW,
+	},{
+		.subvendor = 0x7063,
+		.subdevice = 0x3000, /* HD-3000 card */
+		.card      = CX88_BOARD_PCHDTV_HD3000,
+	},{
+		.subvendor = 0x17DE,
+		.subdevice = 0xA8A6,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x2801,
+		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
+	},{
+		.subvendor = 0x14F1,
+		.subdevice = 0x0342,
+		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
+	},{
+		.subvendor = 0x10fc,
+		.subdevice = 0xd035,
+		.card      = CX88_BOARD_IODATA_GVBCTV7E,
 	}
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -552,7 +725,7 @@ const unsigned int cx88_idcount = ARRAY_
 
 static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-	/* This is just for the Winfast 2000 XP board ATM; I don't have data on
+	/* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on
 	 * any others.
 	 *
 	 * Byte 0 is 1 on the NTSC board.
@@ -569,108 +742,27 @@ static void __devinit leadtek_eeprom(str
 	core->has_radio  = 1;
 	core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
 
-	printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: "
+	printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
 	       "tuner=%d, eeprom[0]=0x%02x\n",
 	       core->name, core->tuner_type, eeprom_data[0]);
 }
 
 
 /* ----------------------------------------------------------------------- */
-/* some hauppauge specific stuff                                           */
-
-static struct {
-        int  id;
-        char *name;
-} hauppauge_tuner[] __devinitdata = {
-        { TUNER_ABSENT,        "" },
-        { TUNER_ABSENT,        "External" },
-        { TUNER_ABSENT,        "Unspecified" },
-        { TUNER_PHILIPS_PAL,   "Philips FI1216" },
-        { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
-        { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
-        { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
-        { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
-        { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
-        { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
-        { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
-        { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
-        { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
-        { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
-        { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
-        { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
-        { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
-        { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
-        { TUNER_PHILIPS_PAL,   "Philips FM1216" },
-        { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
-        { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
-        { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
-        { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
-        { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
-        { TUNER_ABSENT,        "Samsung TCPN9082D" },
-        { TUNER_ABSENT,        "Samsung TCPM9092P" },
-        { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
-        { TUNER_ABSENT,        "Samsung TCPN9085D" },
-        { TUNER_ABSENT,        "Samsung TCPB9085P" },
-        { TUNER_ABSENT,        "Samsung TCPL9091P" },
-        { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
-        { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
-        { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
-        { TUNER_ABSENT,        "Philips FI1256MP" },
-        { TUNER_ABSENT,        "Samsung TCPQ9091P" },
-        { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
-        { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
-        { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
-	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
-	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
-	{ TUNER_LG_NTSC_FM,    "LG TPI8NSR01F"},
-	{ TUNER_LG_PAL_FM,     "LG TPI8PSB01D"},
-	{ TUNER_LG_PAL,        "LG TPI8PSB11D"},
-	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
-	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
-};
 
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
-	unsigned int blk2,tuner,radio,model;
-
-	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) {
-		printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n",
-		       core->name);
-		return;
-	}
-
-	/* Block 2 starts after len+3 bytes header */
-	blk2 = eeprom_data[1] + 3;
-
-	/* decode + use some config infos */
-	model = eeprom_data[12] << 8 | eeprom_data[11];
-	tuner = eeprom_data[9];
-	radio = eeprom_data[blk2-1] & 0x01;
-
-        if (tuner < ARRAY_SIZE(hauppauge_tuner))
-                core->tuner_type = hauppauge_tuner[tuner].id;
-	if (radio)
-		core->has_radio = 1;
+	struct tveeprom tv;
 
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, "
-	       "tuner=%s (%d), radio=%s\n",
-	       core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner)
-				   ? hauppauge_tuner[tuner].name : "?"),
-	       core->tuner_type, radio ? "yes" : "no");
+	tveeprom_hauppauge_analog(&tv, eeprom_data);
+	core->tuner_type = tv.tuner_type;
+	core->has_radio  = tv.has_radio;
 }
 
-#ifdef WITH_DVB
 static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee)
 {
 	int model;
 	int tuner;
-	char *tname;
 
 	/* Make sure we support the board model */
 	model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c];
@@ -689,26 +781,18 @@ static int hauppauge_eeprom_dvb(struct c
 	/* Make sure we support the tuner */
 	tuner = ee[0x2d];
 	switch(tuner) {
-	case 0x4B:
-		tname = "Thomson DTT 7595";
-		core->pll_type = PLLTYPE_DTT7595;
-		break;
-	case 0x4C:
-		tname = "Thomson DTT 7592";
-		core->pll_type = PLLTYPE_DTT7592;
+	case 0x4B: /* dtt 7595 */
+	case 0x4C: /* dtt 7592 */
 		break;
 	default:
 		printk("%s: error: unknown hauppauge tuner 0x%02x\n",
 		       core->name, tuner);
 		return -ENODEV;
 	}
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%s (%d)\n",
-	       core->name, model, tname, tuner);
-
-	core->pll_addr = 0x61;
-	core->demod_addr = 0x43;
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d\n",
+	       core->name, model, tuner);
+	return 0;
 }
-#endif
 
 /* ----------------------------------------------------------------------- */
 /* some GDI (was: Modular Technology) specific stuff                       */
@@ -763,36 +847,6 @@ static void gdi_eeprom(struct cx88_core 
 
 /* ----------------------------------------------------------------------- */
 
-static int
-i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len)
-{
-	unsigned char buf;
-	int err;
-
-	c->addr = 0xa0 >> 1;
-	buf = 0;
-	if (1 != (err = i2c_master_send(c,&buf,1))) {
-		printk(KERN_INFO "cx88: Huh, no eeprom present (err=%d)?\n",
-		       err);
-		return -1;
-	}
-	if (len != (err = i2c_master_recv(c,eedata,len))) {
-		printk(KERN_WARNING "cx88: i2c eeprom read error (err=%d)\n",
-		       err);
-		return -1;
-	}
-#if 0
-	for (i = 0; i < len; i++) {
-		if (0 == (i % 16))
-			printk(KERN_INFO "cx88 ee: %02x:",i);
-		printk(" %02x",eedata[i]);
-		if (15 == (i % 16))
-			printk("\n");
-	}
-#endif
-	return 0;
-}
-
 void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
 	int i;
@@ -823,41 +877,46 @@ void cx88_card_setup(struct cx88_core *c
 {
 	static u8 eeprom[128];
 
+	if (0 == core->i2c_rc) {
+		core->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
+	}
+
 	switch (core->board) {
 	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_ROSLYN:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		hauppauge_eeprom(core,eeprom+8);
+			hauppauge_eeprom(core,eeprom+8);
 		break;
 	case CX88_BOARD_GDI:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		gdi_eeprom(core,eeprom);
+			gdi_eeprom(core,eeprom);
 		break;
-	case CX88_BOARD_WINFAST2000XP:
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		leadtek_eeprom(core,eeprom);
+			leadtek_eeprom(core,eeprom);
+		break;
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		if (0 == core->i2c_rc)
+			hauppauge_eeprom_dvb(core,eeprom);
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		/* Tuner reset is hooked to  the tuner out of reset */
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		/* GPIO0:0 is hooked to mt352 reset pin */
 		cx_set(MO_GP0_IO, 0x00000101);
 		cx_clear(MO_GP0_IO, 0x00000001);
 		msleep(1);
 		cx_set(MO_GP0_IO, 0x00000101);
 		break;
-#ifdef WITH_DVB
-	case CX88_BOARD_HAUPPAUGE_DVB_T1:
-		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		hauppauge_eeprom_dvb(core,eeprom);
-		break;
-	case CX88_BOARD_CONEXANT_DVB_T1:
-		core->pll_type   = PLLTYPE_DTT7579;
-		core->pll_addr   = 0x60;
-		core->demod_addr = 0x43;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		cx_set(MO_GP0_IO, 0x00000707);
+		cx_set(MO_GP2_IO, 0x00000101);
+		cx_clear(MO_GP2_IO, 0x00000001);
+		msleep(1);
+		cx_clear(MO_GP0_IO, 0x00000007);
+		cx_set(MO_GP2_IO, 0x00000101);
 		break;
-#endif
 	}
 	if (cx88_boards[core->board].radio.type == CX88_RADIO)
 		core->has_radio = 1;
Index: linux-2.6.11/drivers/media/video/cx88/cx88-core.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-core.c	2005-03-07 10:13:16.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-core.c	2005-03-08 10:33:15.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-core.c,v 1.15 2004/10/25 11:26:36 kraxel Exp $
+ * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * driver core
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -62,6 +63,10 @@ static unsigned int nicam = 0;
 module_param(nicam,int,0644);
 MODULE_PARM_DESC(nicam,"tv audio is nicam");
 
+static unsigned int nocomb = 0;
+module_param(nocomb,int,0644);
+MODULE_PARM_DESC(nocomb,"disable comb filter");
+
 #define dprintk(level,fmt, arg...)	if (core_debug >= level)	\
 	printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
 
@@ -462,6 +467,7 @@ int cx88_risc_decode(u32 risc)
 	return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
+#if 0 /* currently unused, but useful for debugging */
 void cx88_risc_disasm(struct cx88_core *core,
 		      struct btcx_riscmem *risc)
 {
@@ -479,6 +485,7 @@ void cx88_risc_disasm(struct cx88_core *
 			break;
 	}
 }
+#endif
 
 void cx88_sram_channel_dump(struct cx88_core *core,
 			    struct sram_channel *ch)
@@ -579,10 +586,19 @@ void cx88_print_irqbits(char *name, char
 
 /* ------------------------------------------------------------------ */
 
-void cx88_irq(struct cx88_core *core, u32 status, u32 mask)
+int cx88_core_irq(struct cx88_core *core, u32 status)
 {
-	cx88_print_irqbits(core->name, "irq pci",
-			   cx88_pci_irqs, status, mask);
+	int handled = 0;
+
+	if (status & (1<<18)) {
+		cx88_ir_irq(core);
+		handled++;
+	}
+	if (!handled)
+		cx88_print_irqbits(core->name, "irq pci",
+				   cx88_pci_irqs, status,
+				   core->pci_irqmask);
+	return handled;
 }
 
 void cx88_wakeup(struct cx88_core *core,
@@ -800,6 +816,8 @@ int cx88_set_scale(struct cx88_core *cor
 		value |= (1 << 0); // 3-tap interpolation
 	if (width < 193)
 		value |= (1 << 1); // 5-tap interpolation
+	if (nocomb)
+		value |= (3 << 5); // disable comb filter
 
 	cx_write(MO_FILTER_EVEN,  value);
 	cx_write(MO_FILTER_ODD,   value);
@@ -887,8 +905,8 @@ static int set_tvaudio(struct cx88_core 
 	cx88_set_tvaudio(core);
 	// cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
 
-	cx_write(MO_AUDD_LNGTH, 128/8);  /* fifo size */
-	cx_write(MO_AUDR_LNGTH, 128/8);  /* fifo size */
+	cx_write(MO_AUDD_LNGTH,    128); /* fifo size */
+	cx_write(MO_AUDR_LNGTH,    128); /* fifo size */
 	cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
 	return 0;
 }
@@ -969,6 +987,9 @@ int cx88_set_tvnorm(struct cx88_core *co
 	cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
 				 norm_vbipack(norm)));
 
+	// this is needed as well to set all tvnorm parameter
+	cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
+
 	// audio
 	set_tvaudio(core);
 
@@ -1105,9 +1126,10 @@ struct cx88_core* cx88_core_get(struct p
 		goto fail_unlock;
 
 	memset(core,0,sizeof(*core));
+	atomic_inc(&core->refcount);
 	core->pci_bus  = pci->bus->number;
 	core->pci_slot = PCI_SLOT(pci->devfn);
-	atomic_inc(&core->refcount);
+	core->pci_irqmask = 0x00fc00;
 
 	core->nr = cx88_devcount++;
 	sprintf(core->name,"cx88[%d]",core->nr);
@@ -1150,6 +1172,7 @@ struct cx88_core* cx88_core_get(struct p
 	cx88_reset(core);
 	cx88_i2c_init(core,pci);
 	cx88_card_setup(core);
+	cx88_ir_init(core,pci);
 
 	up(&devlist);
 	return core;
@@ -1170,6 +1193,7 @@ void cx88_core_put(struct cx88_core *cor
 		return;
 
 	down(&devlist);
+	cx88_ir_fini(core);
 	if (0 == core->i2c_rc)
 		i2c_bit_del_bus(&core->i2c_adap);
 	list_del(&core->devlist);
@@ -1187,7 +1211,7 @@ EXPORT_SYMBOL(cx88_vid_irqs);
 EXPORT_SYMBOL(cx88_mpeg_irqs);
 EXPORT_SYMBOL(cx88_print_irqbits);
 
-EXPORT_SYMBOL(cx88_irq);
+EXPORT_SYMBOL(cx88_core_irq);
 EXPORT_SYMBOL(cx88_wakeup);
 EXPORT_SYMBOL(cx88_reset);
 EXPORT_SYMBOL(cx88_shutdown);
@@ -1197,8 +1221,6 @@ EXPORT_SYMBOL(cx88_risc_databuffer);
 EXPORT_SYMBOL(cx88_risc_stopper);
 EXPORT_SYMBOL(cx88_free_buffer);
 
-EXPORT_SYMBOL(cx88_risc_disasm);
-
 EXPORT_SYMBOL(cx88_sram_channels);
 EXPORT_SYMBOL(cx88_sram_channel_setup);
 EXPORT_SYMBOL(cx88_sram_channel_dump);
Index: linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-blackbird.c	2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-blackbird.c	2005-03-08 10:33:20.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-blackbird.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $
  *
  *  Support for a cx23416 mpeg encoder via cx2388x host port.
  *  "blackbird" reference design.
@@ -25,6 +25,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
@@ -207,10 +208,6 @@ static int register_write(struct cx88_co
 	cx_read(P1_RADDR0);
 
 	return wait_ready_gpio0_bit1(core,1);
-#if 0
-	udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */
-	/* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */
-#endif
 }
 
 
@@ -283,7 +280,7 @@ static int blackbird_api_cmd(struct cx88
 	timeout = jiffies + msecs_to_jiffies(10);
 	for (;;) {
 		memory_read(dev->core, dev->mailbox, &flag);
-		if (0 == (flag & 4))
+		if (0 != (flag & 4))
 			break;
 		if (time_after(jiffies,timeout)) {
 			dprintk(0, "ERROR: API Mailbox timeout\n");
@@ -324,7 +321,7 @@ static int blackbird_find_mailbox(struct
 			signaturecnt = 0;
 		if (4 == signaturecnt) {
 			dprintk(1, "Mailbox signature found\n");
-			return i;
+			return i+1;
 		}
 	}
 	dprintk(0, "Mailbox signature values not found!\n");
@@ -427,7 +424,8 @@ static void blackbird_codec_settings(str
         blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
 
         /* assign frame size */
-        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720);
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0,
+			  dev->height, dev->width);
 
         /* assign aspect ratio */
         blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
@@ -629,8 +627,8 @@ static int mpeg_do_ioctl(struct inode *i
 
 		memset(f,0,sizeof(*f));
 		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->fmt.pix.width        = 720;
-		f->fmt.pix.height       = 576;
+		f->fmt.pix.width        = dev->width;
+		f->fmt.pix.height       = dev->height;
 		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 		f->fmt.pix.sizeimage    = 1024 * 512 /* FIXME: BUFFER_SIZE */;
 	}
@@ -694,6 +692,10 @@ static int mpeg_open(struct inode *inode
 	file->private_data = fh;
 	fh->dev      = dev;
 
+	/* FIXME: locking against other video device */
+	cx88_set_scale(dev->core, dev->width, dev->height,
+		       V4L2_FIELD_INTERLACED);
+
 	videobuf_queue_init(&fh->mpegq, &blackbird_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -715,6 +717,7 @@ static int mpeg_release(struct inode *in
 	if (fh->mpegq.reading)
 		videobuf_read_stop(&fh->mpegq);
 
+	videobuf_mmap_free(&fh->mpegq);
 	file->private_data = NULL;
 	kfree(fh);
 	return 0;
@@ -821,6 +824,8 @@ static int __devinit blackbird_probe(str
 	memset(dev,0,sizeof(*dev));
 	dev->pci = pci_dev;
 	dev->core = core;
+	dev->width = 720;
+	dev->height = 480;
 
 	err = cx8802_init_common(dev);
 	if (0 != err)
@@ -852,6 +857,8 @@ static void __devexit blackbird_remove(s
 
 	/* common */
 	cx8802_fini_common(dev);
+	cx88_core_put(dev->core,dev->pci);
+	kfree(dev);
 }
 
 static struct pci_device_id cx8802_pci_tbl[] = {
Index: linux-2.6.11/drivers/media/video/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/media/video/Kconfig	2005-03-07 10:15:21.000000000 +0100
+++ linux-2.6.11/drivers/media/video/Kconfig	2005-03-08 10:33:15.000000000 +0100
@@ -305,11 +305,14 @@ config VIDEO_HEXIUM_GEMINI
 
 config VIDEO_CX88
 	tristate "Conexant 2388x (bt878 successor) support"
-	depends on VIDEO_DEV && PCI && EXPERIMENTAL
+	depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
 	select I2C_ALGOBIT
+	select FW_LOADER
 	select VIDEO_BTCX
 	select VIDEO_BUF
 	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_IR
 	---help---
 	  This is a video4linux driver for Conexant 2388x based
 	  TV cards.
@@ -319,10 +322,11 @@ config VIDEO_CX88
 
 config VIDEO_CX88_DVB
 	tristate "DVB Support for cx2388x based TV cards"
-	depends on VIDEO_CX88 && DVB_CORE && BROKEN
+	depends on VIDEO_CX88 && DVB_CORE
 	select VIDEO_BUF_DVB
+	select DVB_MT352
 	---help---
-	  This adds support for DVB cards based on the
+	  This adds support for DVB/ATSC cards based on the
 	  Connexant 2388x chip.
 
 config VIDEO_OVCAMCHIP
Index: linux-2.6.11/drivers/media/video/cx88/cx88-video.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-video.c	2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-video.c	2005-03-08 10:33:20.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-video.c,v 1.46 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * video4linux video interface
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -428,7 +429,7 @@ static int start_video_dma(struct cx8800
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
 	cx_set(MO_VID_INTMSK, 0x0f0011);
 
 	/* enable capture */
@@ -994,7 +995,7 @@ static int video_open(struct inode *inod
 		cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
 		dev->core->tvaudio = WW_FM;
 		cx88_set_tvaudio(core);
-		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO);
+		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
 		cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL);
 	}
 
@@ -1002,7 +1003,7 @@ static int video_open(struct inode *inod
 }
 
 static ssize_t
-video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char *data, size_t count, loff_t *ppos)
 {
 	struct cx8800_fh *fh = file->private_data;
 
@@ -1083,6 +1084,8 @@ static int video_release(struct inode *i
 		res_free(dev,fh,RESOURCE_VBI);
 	}
 
+	videobuf_mmap_free(&fh->vidq);
+	videobuf_mmap_free(&fh->vbiq);
 	file->private_data = NULL;
 	kfree(fh);
 	return 0;
@@ -1338,7 +1341,6 @@ static int video_do_ioctl(struct inode *
 			0;
 		if (UNSET != core->tuner_type)
 			cap->capabilities |= V4L2_CAP_TUNER;
-
 		return 0;
 	}
 
@@ -1429,6 +1431,7 @@ static int video_do_ioctl(struct inode *
 		if (*i >= 4)
 			return -EINVAL;
 		down(&dev->lock);
+		cx88_newstation(core);
 		video_mux(dev,*i);
 		up(&dev->lock);
 		return 0;
@@ -1560,7 +1563,7 @@ static int video_do_ioctl(struct inode *
 			return -EINVAL;
 		if (0 != t->index)
 			return -EINVAL;
-		cx88_set_stereo(core, t->audmode);
+		cx88_set_stereo(core, t->audmode, 1);
 		return 0;
 	}
 	case VIDIOC_G_FREQUENCY:
@@ -1590,6 +1593,7 @@ static int video_do_ioctl(struct inode *
 			return -EINVAL;
 		down(&dev->lock);
 		dev->freq = f->frequency;
+		cx88_newstation(core);
 #ifdef V4L2_I2C_CLIENTS
 		cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
 #else
@@ -1880,19 +1884,18 @@ static irqreturn_t cx8800_irq(int irq, v
 {
 	struct cx8800_dev *dev = dev_id;
 	struct cx88_core *core = dev->core;
-	u32 status, mask;
+	u32 status;
 	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x01);
-		mask   = cx_read(MO_PCI_INTMSK);
-		if (0 == (status & mask))
+		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01);
+		if (0 == status)
 			goto out;
 		cx_write(MO_PCI_INTSTAT, status);
 		handled = 1;
 
-		if (status & mask & ~0x1f)
-			cx88_irq(core,status,mask);
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
 		if (status & 0x01)
 			cx8800_vid_irq(dev);
 	};
@@ -2055,6 +2058,7 @@ static int __devinit cx8800_initdev(stru
 		       core->name,pci_dev->irq);
 		goto fail_core;
 	}
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* load and configure helper modules */
 	if (TUNER_ABSENT != core->tuner_type)
@@ -2156,7 +2160,7 @@ static void __devexit cx8800_finidev(str
 	kfree(dev);
 }
 
-static int cx8800_suspend(struct pci_dev *pci_dev, u32 state)
+static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
         struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -2181,7 +2185,7 @@ static int cx8800_suspend(struct pci_dev
 #endif
 
 	pci_save_state(pci_dev);
-	if (0 != pci_set_power_state(pci_dev, state)) {
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
 		pci_disable_device(pci_dev);
 		dev->state.disabled = 1;
 	}
@@ -2197,7 +2201,7 @@ static int cx8800_resume(struct pci_dev 
 		pci_enable_device(pci_dev);
 		dev->state.disabled = 0;
 	}
-	pci_set_power_state(pci_dev, 0);
+	pci_set_power_state(pci_dev, PCI_D0);
 	pci_restore_state(pci_dev);
 
 #if 1
Index: linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-mpeg.c	2005-03-07 10:16:04.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-mpeg.c	2005-03-08 10:33:15.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-mpeg.c,v 1.14 2004/10/25 11:26:36 kraxel Exp $
+ * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $
  *
  *  Support for the mpeg transport stream transfers
  *  PCI function #2 of the cx2388x.
@@ -24,6 +24,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
@@ -68,8 +69,14 @@ static int cx8802_start_dma(struct cx880
 	 * also: move to cx88-blackbird + cx88-dvb source files? */
 
 	if (cx88_boards[core->board].dvb) {
-		/* Setup TS portion of chip */
-		cx_write(TS_GEN_CNTRL, 0x0c);
+		/* negedge driven & software reset */
+		cx_write(TS_GEN_CNTRL, 0x40); 
+		udelay(100);
+		cx_write(MO_PINMUX_IO, 0x00);
+		cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00);
+		cx_write(TS_SOP_STAT,0x00);
+		cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); 
+		udelay(100);
 	}
 
 	if (cx88_boards[core->board].blackbird) {
@@ -93,7 +100,7 @@ static int cx8802_start_dma(struct cx880
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc04);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
 	cx_write(MO_TS_INTMSK,  0x1f0011);
 
 	/* start dma */
@@ -292,19 +299,18 @@ static irqreturn_t cx8802_irq(int irq, v
 {
 	struct cx8802_dev *dev = dev_id;
 	struct cx88_core *core = dev->core;
-	u32 status, mask;
+	u32 status;
 	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x04);
-		mask   = cx_read(MO_PCI_INTMSK);
-		if (0 == (status & mask))
+		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
+		if (0 == status)
 			goto out;
 		handled = 1;
 		cx_write(MO_PCI_INTSTAT, status);
 
-		if (status & mask & ~0x1f)
-			cx88_irq(core,status,mask);
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core,status);
 		if (status & 0x04)
 			cx8802_mpeg_irq(dev);
 	};
@@ -323,6 +329,7 @@ static irqreturn_t cx8802_irq(int irq, v
 
 int cx8802_init_common(struct cx8802_dev *dev)
 {
+	struct cx88_core *core = dev->core;
 	int err;
 
 	/* pci init */
@@ -354,11 +361,6 @@ int cx8802_init_common(struct cx8802_dev
 	cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
 			  MO_TS_DMACNTRL,0x11,0x00);
 
-#if 0 /* FIXME */
-	/* initialize hardware */
-	cx8802_reset(dev);
-#endif
-
 	/* get irq */
 	err = request_irq(dev->pci->irq, cx8802_irq,
 			  SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev);
@@ -367,11 +369,7 @@ int cx8802_init_common(struct cx8802_dev
 		       dev->core->name, dev->pci->irq);
 		return err;
 	}
-
-#if 0 /* FIXME */
-	/* register i2c bus + load i2c helpers */
-	cx88_card_setup(dev);
-#endif
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* everything worked */
 	pci_set_drvdata(dev->pci,dev);
@@ -393,7 +391,7 @@ void cx8802_fini_common(struct cx8802_de
 
 /* ----------------------------------------------------------- */
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state)
+int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
         struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -413,7 +411,7 @@ int cx8802_suspend_common(struct pci_dev
 #endif
 
 	pci_save_state(pci_dev);
-	if (0 != pci_set_power_state(pci_dev, state)) {
+	if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
 		pci_disable_device(pci_dev);
 		dev->state.disabled = 1;
 	}
@@ -429,7 +427,7 @@ int cx8802_resume_common(struct pci_dev 
 		pci_enable_device(pci_dev);
 		dev->state.disabled = 0;
 	}
-	pci_set_power_state(pci_dev, 0);
+	pci_set_power_state(pci_dev, PCI_D0);
 	pci_restore_state(pci_dev);
 
 #if 1
Index: linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-tvaudio.c	2005-03-07 10:13:41.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-tvaudio.c	2005-03-08 10:33:20.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $
+    $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $
 
     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
 
@@ -37,6 +37,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -56,7 +57,7 @@
 
 #include "cx88.h"
 
-static unsigned int audio_debug = 1;
+static unsigned int audio_debug = 0;
 module_param(audio_debug,int,0644);
 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
 
@@ -141,6 +142,13 @@ static void set_audio_finish(struct cx88
 {
 	u32 volume;
 
+	if (cx88_boards[core->board].blackbird) {
+		// 'pass-thru mode': this enables the i2s output to the mpeg encoder
+		cx_set(AUD_CTL, 0x2000);
+		cx_write(AUD_I2SOUTPUTCNTL, 1);
+		//cx_write(AUD_APB_IN_RATE_ADJ, 0);
+	}
+
 	// finish programming
 	cx_write(AUD_SOFT_RESET, 0x0000);
 
@@ -263,6 +271,7 @@ static void set_audio_standard_BTSC(stru
 	set_audio_finish(core);
 }
 
+#if 0
 static void set_audio_standard_NICAM(struct cx88_core *core)
 {
 	static const struct rlist nicam_common[] = {
@@ -335,128 +344,243 @@ static void set_audio_standard_NICAM(str
 	};
         set_audio_finish(core);
 }
+#endif
 
-static void set_audio_standard_NICAM_L(struct cx88_core *core)
+static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
 {
-	/* This is officially weird.. register dumps indicate windows
-	 * uses audio mode 4.. A2. Let's operate and find out. */
+        /* This is probably weird..
+         * Let's operate and find out. */
 
-	static const struct rlist nicam_l[] = {
-		// setup QAM registers
-		{ AUD_PDF_DDS_CNST_BYTE2,	   0x48 },
-		{ AUD_PDF_DDS_CNST_BYTE1,          0x3d },
-		{ AUD_PDF_DDS_CNST_BYTE0,          0xf5 },
-		{ AUD_QAM_MODE,                    0x00 },
-		{ AUD_PHACC_FREQ_8MSB,             0x3a },
-		{ AUD_PHACC_FREQ_8LSB,             0x4a },
+        static const struct rlist nicam_l_mono[] = {
+                { AUD_ERRLOGPERIOD_R,     0x00000064 },
+                { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
+                { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
+                { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
 
-		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_IIR1_0_SEL,                  0x00000000 },
-		{ AUD_IIR1_1_SEL,                  0x00000002 },
-		{ AUD_IIR1_2_SEL,                  0x00000023 },
-		{ AUD_IIR1_3_SEL,                  0x00000004 },
-		{ AUD_IIR1_4_SEL,                  0x00000005 },
-		{ AUD_IIR1_5_SEL,                  0x00000007 },
-		{ AUD_IIR1_0_SHIFT,                0x00000007 },
-		{ AUD_IIR1_1_SHIFT,                0x00000000 },
-		{ AUD_IIR1_2_SHIFT,                0x00000000 },
-		{ AUD_IIR1_3_SHIFT,                0x00000007 },
-		{ AUD_IIR1_4_SHIFT,                0x00000007 },
-		{ AUD_IIR1_5_SHIFT,                0x00000007 },
-		{ AUD_IIR2_0_SEL,                  0x00000002 },
-		{ AUD_IIR2_1_SEL,                  0x00000003 },
-		{ AUD_IIR2_2_SEL,                  0x00000004 },
-		{ AUD_IIR2_3_SEL,                  0x00000005 },
-		{ AUD_IIR3_0_SEL,                  0x00000007 },
-		{ AUD_IIR3_1_SEL,                  0x00000023 },
-		{ AUD_IIR3_2_SEL,                  0x00000016 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000000 },
-		{ AUD_IIR3_2_SHIFT,                0x00000002 },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_IIR4_1_SEL,                  0x00000019 },
-		{ AUD_IIR4_2_SEL,                  0x00000008 },
-		{ AUD_IIR4_0_SHIFT,                0x00000000 },
-		{ AUD_IIR4_1_SHIFT,                0x00000007 },
-		{ AUD_IIR4_2_SHIFT,                0x00000007 },
-		{ AUD_IIR4_0_CA0,                  0x0003e57e },
-		{ AUD_IIR4_0_CA1,                  0x00005e11 },
-		{ AUD_IIR4_0_CA2,                  0x0003a7cf },
-		{ AUD_IIR4_0_CB0,                  0x00002368 },
-		{ AUD_IIR4_0_CB1,                  0x0003bf1b },
-		{ AUD_IIR4_1_CA0,                  0x00006349 },
-		{ AUD_IIR4_1_CA1,                  0x00006f27 },
-		{ AUD_IIR4_1_CA2,                  0x0000e7a3 },
-		{ AUD_IIR4_1_CB0,                  0x00005653 },
-		{ AUD_IIR4_1_CB1,                  0x0000cf97 },
-		{ AUD_IIR4_2_CA0,                  0x00006349 },
-		{ AUD_IIR4_2_CA1,                  0x00006f27 },
-		{ AUD_IIR4_2_CA2,                  0x0000e7a3 },
-		{ AUD_IIR4_2_CB0,                  0x00005653 },
-		{ AUD_IIR4_2_CB1,                  0x0000cf97 },
-		{ AUD_HP_MD_IIR4_1,                0x00000001 },
-		{ AUD_HP_PROG_IIR4_1,              0x0000001a },
-		{ AUD_DN0_FREQ,                    0x00000000 },
-		{ AUD_DN1_FREQ,                    0x00003318 },
-		{ AUD_DN1_SRC_SEL,                 0x00000017 },
-		{ AUD_DN1_SHFT,                    0x00000007 },
-		{ AUD_DN1_AFC,                     0x00000000 },
-		{ AUD_DN1_FREQ_SHIFT,              0x00000000 },
-		{ AUD_DN2_FREQ,                    0x00003551 },
-		{ AUD_DN2_SRC_SEL,                 0x00000001 },
-		{ AUD_DN2_SHFT,                    0x00000000 },
-		{ AUD_DN2_AFC,                     0x00000002 },
-		{ AUD_DN2_FREQ_SHIFT,              0x00000000 },
-		{ AUD_PDET_SRC,                    0x00000014 },
-		{ AUD_PDET_SHIFT,                  0x00000000 },
-		{ AUD_DEEMPH0_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH1_SRC_SEL,             0x00000011 },
-		{ AUD_DEEMPH0_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH1_SHIFT,               0x00000000 },
-		{ AUD_DEEMPH0_G0,                  0x00007000 },
-		{ AUD_DEEMPH0_A0,                  0x00000000 },
-		{ AUD_DEEMPH0_B0,                  0x00000000 },
-		{ AUD_DEEMPH0_A1,                  0x00000000 },
-		{ AUD_DEEMPH0_B1,                  0x00000000 },
-		{ AUD_DEEMPH1_G0,                  0x00007000 },
-		{ AUD_DEEMPH1_A0,                  0x00000000 },
-		{ AUD_DEEMPH1_B0,                  0x00000000 },
-		{ AUD_DEEMPH1_A1,                  0x00000000 },
-		{ AUD_DEEMPH1_B1,                  0x00000000 },
-		{ AUD_DMD_RA_DDS,                  0x00f5c285 },
-		{ AUD_RATE_ADJ1,                   0x00000100 },
-		{ AUD_RATE_ADJ2,                   0x00000200 },
-		{ AUD_RATE_ADJ3,                   0x00000300 },
-		{ AUD_RATE_ADJ4,                   0x00000400 },
-		{ AUD_RATE_ADJ5,                   0x00000500 },
-		{ AUD_C2_UP_THR,                   0x00005400 },
-		{ AUD_C2_LO_THR,                   0x00003000 },
-		{ AUD_C1_UP_THR,                   0x00007000 },
-		{ AUD_C2_LO_THR,                   0x00005400 },
-		{ AUD_CTL,                         0x0000100c },
-		{ AUD_DCOC_0_SRC,                  0x00000021 },
-		{ AUD_DCOC_1_SRC,                  0x00000003 },
-		{ AUD_DCOC1_SHIFT,                 0x00000000 },
-		{ AUD_DCOC_1_SHIFT_IN0,            0x0000000a },
-		{ AUD_DCOC_1_SHIFT_IN1,            0x00000008 },
-		{ AUD_DCOC_PASS_IN,                0x00000000 },
-		{ AUD_DCOC_2_SRC,                  0x0000001b },
-		{ AUD_IIR4_0_SEL,                  0x0000001d },
-		{ AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
-		{ AUD_PHASE_FIX_CTL,               0x00000000 },
-		{ AUD_CORDIC_SHIFT_1,              0x00000007 },
-		{ AUD_PLL_EN,                      0x00000000 },
-		{ AUD_PLL_PRESCALE,                0x00000002 },
-		{ AUD_PLL_INT,                     0x0000001e },
-		{ AUD_OUT1_SHIFT,                  0x00000000 },
+                { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
+                { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
+                { AUD_QAM_MODE,           0x00 },
+                { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
+                { AUD_PHACC_FREQ_8MSB,    0x3a },
+                { AUD_PHACC_FREQ_8LSB,    0x4a },
 
-		{ /* end of list */ },
-	};
+                { AUD_DEEMPHGAIN_R, 0x6680 },
+                { AUD_DEEMPHNUMER1_R, 0x353DE },
+                { AUD_DEEMPHNUMER2_R, 0x1B1 },
+                { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
+                { AUD_DEEMPHDENOM2_R, 0x0 },
+                { AUD_FM_MODE_ENABLE, 0x7 },
+                { AUD_POLYPH80SCALEFAC, 0x3 },
+                { AUD_AFE_12DB_EN, 0x1 },
+                { AAGC_GAIN, 0x0 },
+                { AAGC_HYST, 0x18 },
+                { AAGC_DEF, 0x20 },
+                { AUD_DN0_FREQ, 0x0 },
+                { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
+                { AUD_DCOC_0_SRC, 0x21 },
+                { AUD_IIR1_0_SEL, 0x0 },
+                { AUD_IIR1_0_SHIFT, 0x7 },
+                { AUD_IIR1_1_SEL, 0x2 },
+                { AUD_IIR1_1_SHIFT, 0x0 },
+                { AUD_DCOC_1_SRC, 0x3 },
+                { AUD_DCOC1_SHIFT, 0x0 },
+                { AUD_DCOC_PASS_IN, 0x0 },
+                { AUD_IIR1_2_SEL, 0x23 },
+                { AUD_IIR1_2_SHIFT, 0x0 },
+                { AUD_IIR1_3_SEL, 0x4 },
+                { AUD_IIR1_3_SHIFT, 0x7 },
+                { AUD_IIR1_4_SEL, 0x5 },
+                { AUD_IIR1_4_SHIFT, 0x7 },
+                { AUD_IIR3_0_SEL, 0x7 },
+                { AUD_IIR3_0_SHIFT, 0x0 },
+                { AUD_DEEMPH0_SRC_SEL, 0x11 },
+                { AUD_DEEMPH0_SHIFT, 0x0 },
+                { AUD_DEEMPH0_G0, 0x7000 },
+                { AUD_DEEMPH0_A0, 0x0 },
+                { AUD_DEEMPH0_B0, 0x0 },
+                { AUD_DEEMPH0_A1, 0x0 },
+                { AUD_DEEMPH0_B1, 0x0 },
+                { AUD_DEEMPH1_SRC_SEL, 0x11 },
+                { AUD_DEEMPH1_SHIFT, 0x0 },
+                { AUD_DEEMPH1_G0, 0x7000 },
+                { AUD_DEEMPH1_A0, 0x0 },
+                { AUD_DEEMPH1_B0, 0x0 },
+                { AUD_DEEMPH1_A1, 0x0 },
+                { AUD_DEEMPH1_B1, 0x0 },
+                { AUD_OUT0_SEL, 0x3F },
+                { AUD_OUT1_SEL, 0x3F },
+                { AUD_DMD_RA_DDS, 0x0F5C285 },
+                { AUD_PLL_INT, 0x1E },
+                { AUD_PLL_DDS, 0x0 },
+                { AUD_PLL_FRAC, 0x0E542 },
 
-	dprintk("%s (status: unknown)\n",__FUNCTION__);
-        set_audio_start(core, 0x0004,
-			0 /* FIXME */);
-	set_audio_registers(core, nicam_l);
+                // setup QAM registers
+                { AUD_RATE_ADJ1,      0x00000100 },
+                { AUD_RATE_ADJ2,      0x00000200 },
+                { AUD_RATE_ADJ3,      0x00000300 },
+                { AUD_RATE_ADJ4,      0x00000400 },
+                { AUD_RATE_ADJ5,      0x00000500 },
+                { AUD_RATE_THRES_DMD, 0x000000C0 },
+                { /* end of list */ },
+        };
+
+        static const struct rlist nicam_l[] = {
+                // setup QAM registers
+                { AUD_RATE_ADJ1, 0x00000060 },
+                { AUD_RATE_ADJ2, 0x000000F9 },
+                { AUD_RATE_ADJ3, 0x000001CC },
+                { AUD_RATE_ADJ4, 0x000002B3 },
+                { AUD_RATE_ADJ5, 0x00000726 },
+                { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
+                { AUD_DEEMPHDENOM2_R, 0x00000000 },
+                { AUD_ERRLOGPERIOD_R, 0x00000064 },
+                { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
+                { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
+                { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
+                { AUD_POLYPH80SCALEFAC, 0x00000003 },
+                { AUD_DMD_RA_DDS, 0x00C00000 },
+                { AUD_PLL_INT, 0x0000001E },
+                { AUD_PLL_DDS, 0x00000000 },
+                { AUD_PLL_FRAC, 0x0000E542 },
+                { AUD_START_TIMER, 0x00000000 },
+                { AUD_DEEMPHNUMER1_R, 0x000353DE },
+                { AUD_DEEMPHNUMER2_R, 0x000001B1 },
+                { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
+                { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
+                { AUD_QAM_MODE, 0x05 },
+                { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
+                { AUD_PHACC_FREQ_8MSB, 0x34 },
+                { AUD_PHACC_FREQ_8LSB, 0x4C },
+                { AUD_DEEMPHGAIN_R, 0x00006680 },
+                { AUD_RATE_THRES_DMD, 0x000000C0  },
+                { /* end of list */ },
+        } ;
+        dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+
+        if (!stereo) {
+		/* AM mono sound */
+                set_audio_start(core, 0x0004,
+				0x100c /* FIXME again */);
+                set_audio_registers(core, nicam_l_mono);
+        } else {
+                set_audio_start(core, 0x0010,
+				0x1924 /* FIXME again */);
+                set_audio_registers(core, nicam_l);
+        }
+        set_audio_finish(core);
+
+}
+
+static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
+{
+       static const struct rlist pal_i_fm_mono[] = {
+            {AUD_ERRLOGPERIOD_R,       0x00000064},
+            {AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
+            {AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
+            {AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
+            {AUD_PDF_DDS_CNST_BYTE2,   0x06},
+            {AUD_PDF_DDS_CNST_BYTE1,   0x82},
+            {AUD_PDF_DDS_CNST_BYTE0,   0x12},
+            {AUD_QAM_MODE,             0x05},
+            {AUD_PHACC_FREQ_8MSB,      0x3a},
+            {AUD_PHACC_FREQ_8LSB,      0x93},
+            {AUD_DMD_RA_DDS,           0x002a4f2f},
+            {AUD_PLL_INT,              0x0000001e},
+            {AUD_PLL_DDS,              0x00000004},
+            {AUD_PLL_FRAC,             0x0000e542},
+            {AUD_RATE_ADJ1,            0x00000100},
+            {AUD_RATE_ADJ2,            0x00000200},
+            {AUD_RATE_ADJ3,            0x00000300},
+            {AUD_RATE_ADJ4,            0x00000400},
+            {AUD_RATE_ADJ5,            0x00000500},
+            {AUD_THR_FR,               0x00000000},
+            {AUD_PILOT_BQD_1_K0,       0x0000755b},
+            {AUD_PILOT_BQD_1_K1,       0x00551340},
+            {AUD_PILOT_BQD_1_K2,       0x006d30be},
+            {AUD_PILOT_BQD_1_K3,       0xffd394af},
+            {AUD_PILOT_BQD_1_K4,       0x00400000},
+            {AUD_PILOT_BQD_2_K0,       0x00040000},
+            {AUD_PILOT_BQD_2_K1,       0x002a4841},
+            {AUD_PILOT_BQD_2_K2,       0x00400000},
+            {AUD_PILOT_BQD_2_K3,       0x00000000},
+            {AUD_PILOT_BQD_2_K4,       0x00000000},
+            {AUD_MODE_CHG_TIMER,       0x00000060},
+            {AUD_AFE_12DB_EN,          0x00000001},
+            {AAGC_HYST,                0x0000000a},
+            {AUD_CORDIC_SHIFT_0,       0x00000007},
+            {AUD_CORDIC_SHIFT_1,       0x00000007},
+            {AUD_C1_UP_THR,            0x00007000},
+            {AUD_C1_LO_THR,            0x00005400},
+            {AUD_C2_UP_THR,            0x00005400},
+            {AUD_C2_LO_THR,            0x00003000},
+            {AUD_DCOC_0_SRC,           0x0000001a},
+            {AUD_DCOC0_SHIFT,          0x00000000},
+            {AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
+            {AUD_DCOC_0_SHIFT_IN1,     0x00000008},
+            {AUD_DCOC_PASS_IN,         0x00000003},
+            {AUD_IIR3_0_SEL,           0x00000021},
+            {AUD_DN2_AFC,              0x00000002},
+            {AUD_DCOC_1_SRC,           0x0000001b},
+            {AUD_DCOC1_SHIFT,          0x00000000},
+            {AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
+            {AUD_DCOC_1_SHIFT_IN1,     0x00000008},
+            {AUD_IIR3_1_SEL,           0x00000023},
+            {AUD_DN0_FREQ,             0x000035a3},
+            {AUD_DN2_FREQ,             0x000029c7},
+            {AUD_CRDC0_SRC_SEL,        0x00000511},
+            {AUD_IIR1_0_SEL,           0x00000001},
+            {AUD_IIR1_1_SEL,           0x00000000},
+            {AUD_IIR3_2_SEL,           0x00000003},
+            {AUD_IIR3_2_SHIFT,         0x00000000},
+            {AUD_IIR3_0_SEL,           0x00000002},
+            {AUD_IIR2_0_SEL,           0x00000021},
+            {AUD_IIR2_0_SHIFT,         0x00000002},
+            {AUD_DEEMPH0_SRC_SEL,      0x0000000b},
+            {AUD_DEEMPH1_SRC_SEL,      0x0000000b},
+            {AUD_POLYPH80SCALEFAC,     0x00000001},
+            {AUD_START_TIMER,          0x00000000},
+            { /* end of list */ },
+       };
+
+       static const struct rlist pal_i_nicam[] = {
+           { AUD_RATE_ADJ1,           0x00000010 },
+           { AUD_RATE_ADJ2,           0x00000040 },
+           { AUD_RATE_ADJ3,           0x00000100 },
+           { AUD_RATE_ADJ4,           0x00000400 },
+           { AUD_RATE_ADJ5,           0x00001000 },
+	   //     { AUD_DMD_RA_DDS,          0x00c0d5ce },
+	   { AUD_DEEMPHGAIN_R,        0x000023c2 },
+	   { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
+	   { AUD_DEEMPHNUMER2_R,      0x0003023e },
+	   { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
+	   { AUD_DEEMPHDENOM2_R,      0x00000000 },
+	   { AUD_DEEMPHDENOM2_R,      0x00000000 },
+	   { AUD_ERRLOGPERIOD_R,      0x00000fff },
+	   { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
+	   { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
+	   { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
+	   { AUD_POLYPH80SCALEFAC,    0x00000003 },
+	   { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
+	   { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
+	   { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
+	   { AUD_QAM_MODE,            0x05 },
+	   { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
+	   { AUD_PHACC_FREQ_8MSB,     0x3a },
+	   { AUD_PHACC_FREQ_8LSB,     0x93 },
+            { /* end of list */ },
+        };
+
+        dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+
+        if (!stereo) {
+		// FM mono
+		set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
+		set_audio_registers(core, pal_i_fm_mono);
+        } else {
+		// Nicam Stereo
+		set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
+		set_audio_registers(core, pal_i_nicam);
+        }
         set_audio_finish(core);
 }
 
@@ -553,13 +677,6 @@ static void set_audio_standard_A2(struct
 	set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
 	set_audio_registers(core, a2_common);
 	switch (core->tvaudio) {
-	case WW_NICAM_I:
-		/* gives at least mono according to the dscaler guys */
-		/* so use use that while nicam is broken ...         */
-		dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__);
-		set_audio_registers(core, a2_table1);
-		cx_write(AUD_CTL, EN_A2_FORCE_MONO1);
-		break;
 	case WW_A2_BG:
 		dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
 		set_audio_registers(core, a2_table1);
@@ -646,11 +763,12 @@ void cx88_set_tvaudio(struct cx88_core *
 	case WW_BTSC:
 		set_audio_standard_BTSC(core,0);
 		break;
-	// case WW_NICAM_I:
 	case WW_NICAM_BGDKL:
-		set_audio_standard_NICAM(core);
+		set_audio_standard_NICAM_L(core,0);
 		break;
 	case WW_NICAM_I:
+		set_audio_standard_PAL_I(core,0);
+		break;
 	case WW_A2_BG:
 	case WW_A2_DK:
 	case WW_A2_M:
@@ -663,7 +781,7 @@ void cx88_set_tvaudio(struct cx88_core *
 		set_audio_standard_FM(core);
 		break;
 	case WW_SYSTEM_L_AM:
-		set_audio_standard_NICAM_L(core);
+		set_audio_standard_NICAM_L(core, 1);
 		break;
 	case WW_NONE:
 	default:
@@ -674,6 +792,19 @@ void cx88_set_tvaudio(struct cx88_core *
 	return;
 }
 
+void cx88_newstation(struct cx88_core *core)
+{
+	core->audiomode_manual = UNSET;
+	
+	switch (core->tvaudio) {
+	case WW_SYSTEM_L_AM:
+		/* try nicam ... */
+		core->audiomode_current = V4L2_TUNER_MODE_STEREO;
+		set_audio_standard_NICAM_L(core, 1);
+		break;
+	}
+}
+
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
 	static char *m[] = {"stereo", "dual mono", "mono", "sap"};
@@ -721,22 +852,37 @@ void cx88_get_stereo(struct cx88_core *c
 		}
 		break;
 	case WW_NICAM_BGDKL:
-		if (0 == mode)
+		if (0 == mode) {
 			t->audmode = V4L2_TUNER_MODE_STEREO;
+			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		}
 		break;
+        case WW_SYSTEM_L_AM:
+                if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
+                        t->audmode = V4L2_TUNER_MODE_STEREO;
+			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+		}
+                break ;
 	default:
-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
-		t->audmode    = V4L2_TUNER_MODE_MONO;
+		/* nothing */
 		break;
 	}
 	return;
 }
 
-void cx88_set_stereo(struct cx88_core *core, u32 mode)
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
 {
 	u32 ctl  = UNSET;
 	u32 mask = UNSET;
 
+	if (manual) {
+		core->audiomode_manual = mode;
+	} else {
+		if (UNSET != core->audiomode_manual)
+			return;
+	}
+	core->audiomode_current = mode;
+
 	switch (core->tvaudio) {
 	case WW_BTSC:
 		switch (mode) {
@@ -789,6 +935,28 @@ void cx88_set_stereo(struct cx88_core *c
 			break;
 		}
 		break;
+	case WW_SYSTEM_L_AM:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:  /* FIXME */
+			set_audio_standard_NICAM_L(core, 0);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			set_audio_standard_NICAM_L(core, 1);
+			break;
+		}
+		break;
+	case WW_NICAM_I:
+		switch (mode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+			set_audio_standard_PAL_I(core, 0);
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+			set_audio_standard_PAL_I(core, 1);
+			break;
+		}
+		break;
 	case WW_FM:
 		switch (mode) {
 		case V4L2_TUNER_MODE_MONO:
@@ -804,13 +972,11 @@ void cx88_set_stereo(struct cx88_core *c
 	}
 
 	if (UNSET != ctl) {
-		cx_write(AUD_SOFT_RESET, 0x0001);
-		cx_andor(AUD_CTL, mask,  ctl);
-		cx_write(AUD_SOFT_RESET, 0x0000);
 		dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
 			"[status=0x%x,ctl=0x%x,vol=0x%x]\n",
 			mask, ctl, cx_read(AUD_STATUS),
 			cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
+		cx_andor(AUD_CTL, mask, ctl);
 	}
 	return;
 }
@@ -819,16 +985,32 @@ int cx88_audio_thread(void *data)
 {
 	struct cx88_core *core = data;
 	struct v4l2_tuner t;
+	u32 mode = 0;
 
 	dprintk("cx88: tvaudio thread started\n");
 	for (;;) {
+		msleep_interruptible(1000);
 		if (kthread_should_stop())
 			break;
 
 		/* just monitor the audio status for now ... */
 		memset(&t,0,sizeof(t));
 		cx88_get_stereo(core,&t);
-		msleep_interruptible(1000);
+
+		if (UNSET != core->audiomode_manual)
+			/* manually set, don't do anything. */
+			continue;
+
+		/* monitor signal */
+		if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
+			mode = V4L2_TUNER_MODE_STEREO;
+		else
+			mode = V4L2_TUNER_MODE_MONO;
+		if (mode == core->audiomode_current)
+			continue;
+
+		/* automatically switch to best available mode */
+		cx88_set_stereo(core, mode, 0);
 	}
 
 	dprintk("cx88: tvaudio thread exiting\n");
@@ -838,6 +1020,7 @@ int cx88_audio_thread(void *data)
 /* ----------------------------------------------------------- */
 
 EXPORT_SYMBOL(cx88_set_tvaudio);
+EXPORT_SYMBOL(cx88_newstation);
 EXPORT_SYMBOL(cx88_set_stereo);
 EXPORT_SYMBOL(cx88_get_stereo);
 EXPORT_SYMBOL(cx88_audio_thread);
Index: linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-dvb.c	2005-03-08 10:33:15.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-dvb.c	2005-03-08 10:33:20.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88-dvb.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $
+ * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
@@ -30,10 +30,20 @@
 #include <linux/file.h>
 #include <linux/suspend.h>
 
+/* those two frontends need merging via linuxtv cvs ... */
+#define HAVE_CX22702 0
+#define HAVE_OR51132 0
+
 #include "cx88.h"
-#include "cx22702.h"
+#include "dvb-pll.h"
 #include "mt352.h"
-#include "mt352_priv.h" /* FIXME */
+#include "mt352_priv.h"
+#if HAVE_CX22702
+# include "cx22702.h"
+#endif
+#if HAVE_OR51132
+# include "or51132.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -110,111 +120,144 @@ static int dvico_fusionhdtv_demod_init(s
 	return 0;
 }
 
-#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-
-static int lg_z201_pll_set(struct dvb_frontend* fe,
-			   struct dvb_frontend_parameters* params, u8* pllbuf)
+static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
 {
-	u32 div;
-	unsigned char cp = 0;
-	unsigned char bs = 0;
-
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency < 542000000) cp = 0xbc;
-	else if (params->frequency < 830000000) cp = 0xf4;
-	else cp = 0xfc;
+	static u8 clock_config []  = { 0x89, 0x38, 0x39 };
+	static u8 reset []         = { 0x50, 0x80 };
+	static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+	                               0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 dntv_extra[]     = { 0xB5, 0x7A };
+	static u8 capt_range_cfg[] = { 0x75, 0x32 };
 
-	if (params->frequency == 0) bs = 0x03;
-	else if (params->frequency < 157500000) bs = 0x01;
-	else if (params->frequency < 443250000) bs = 0x02;
-	else bs = 0x04;
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
 
-	pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */
-	pllbuf[1] = div >> 8;
-	pllbuf[2] = div & 0xff;
-	pllbuf[3] = cp;
-	pllbuf[4] = bs;
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
 
 	return 0;
 }
 
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe,
-				   struct dvb_frontend_parameters* params,
-				   u8* pllbuf)
+static int mt352_pll_set(struct dvb_frontend* fe,
+			 struct dvb_frontend_parameters* params,
+			 u8* pllbuf)
 {
-	u32 div;
-	unsigned char cp = 0;
-	unsigned char bs = 0;
-
-	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-	if (params->frequency < 542000000) cp = 0xb4;
-	else if (params->frequency < 771000000) cp = 0xbc;
-	else cp = 0xf4;
-
-        if (params->frequency == 0) bs = 0x03;
-	else if (params->frequency < 443250000) bs = 0x02;
-	else bs = 0x08;
-
-	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
-	pllbuf[1] = div >> 8;
-   	pllbuf[2] = div & 0xff;
-   	pllbuf[3] = cp;
-   	pllbuf[4] = bs;
+	struct cx8802_dev *dev= fe->dvb->priv;
 
+	pllbuf[0] = dev->core->pll_addr << 1;
+	dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+			  params->frequency,
+			  params->u.ofdm.bandwidth);
 	return 0;
 }
 
-struct mt352_config dvico_fusionhdtv_dvbt1 = {
+static struct mt352_config dvico_fusionhdtv = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = lg_z201_pll_set,
+	.pll_set       = mt352_pll_set,
 };
 
-struct mt352_config dvico_fusionhdtv_dvbt_plus = {
-	.demod_address = 0x0F,
-	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = thomson_dtt7579_pll_set,
+static struct mt352_config dntv_live_dvbt_config = {
+	.demod_address = 0x0f,
+	.demod_init    = dntv_live_dvbt_demod_init,
+	.pll_set       = mt352_pll_set,
+};
+
+#if HAVE_CX22702
+static struct cx22702_config connexant_refboard_config = {
+	.demod_address = 0x43,
+	.pll_address   = 0x60,
+	.pll_desc      = &dvb_pll_thomson_dtt7579,
+};
+
+static struct cx22702_config hauppauge_novat_config = {
+	.demod_address = 0x43,
+	.pll_address   = 0x61,
+	.pll_desc      = &dvb_pll_thomson_dtt759x,
+};
+#endif
+
+#if HAVE_OR51132
+static int or51132_set_ts_param(struct dvb_frontend* fe, 
+				int is_punctured)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+	return 0;
+}
+
+struct or51132_config pchdtv_hd3000 = {
+	.demod_address    = 0x15,
+	.pll_address      = 0x61,
+	.pll_desc         = &dvb_pll_thomson_dtt7610,
+	.set_ts_params    = or51132_set_ts_param,
 };
+#endif
 
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
 	dev->dvb.name = dev->core->name;
+	dev->ts_gen_cntrl = 0x0c;
 
 	/* init frontend */
 	switch (dev->core->board) {
+#if HAVE_CX22702
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
+						   &dev->core->i2c_adap);
+		break;
 	case CX88_BOARD_CONEXANT_DVB_T1:
-		dev->dvb.frontend = cx22702_create(&dev->core->i2c_adap,
-						   dev->core->pll_addr,
-						   dev->core->pll_type,
-						   dev->core->demod_addr);
+		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
+						   &dev->core->i2c_adap);
 		break;
+#endif
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1,
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_lg_z201;
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops->info.frequency_min = 174000000;
-			dev->dvb.frontend->ops->info.frequency_max = 862000000;
-		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt_plus,
+		dev->core->pll_addr = 0x60;
+		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
+						 &dev->core->i2c_adap);
+		break;
+	case CX88_BOARD_KWORLD_DVB_T:
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		dev->core->pll_addr = 0x61;
+		dev->core->pll_desc = &dvb_pll_unknown_1;
+		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
 						 &dev->core->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops->info.frequency_min = 174000000;
-			dev->dvb.frontend->ops->info.frequency_max = 862000000;
-		}
 		break;
+#if HAVE_OR51132
+	case CX88_BOARD_PCHDTV_HD3000:
+		dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
+						 &dev->core->i2c_adap);
+		break;
+#endif
 	default:
-		printk("%s: FIXME: frontend handling not here yet ...\n",
-		       dev->core->name);
+		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n"
+		       "%s: you might want to look out for patches here:\n"
+		       "%s:     http://dl.bytesex.org/patches/\n",
+		       dev->core->name, dev->core->name, dev->core->name);
 		break;
 	}
-	if (NULL == dev->dvb.frontend)
+	if (NULL == dev->dvb.frontend) {
+		printk("%s: frontend initialization failed\n",dev->core->name);
 		return -1;
+	}
+
+	if (dev->core->pll_desc) {
+		dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
+		dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+	}
 
 	/* Copy the board name into the DVB structure */
 	strlcpy(dev->dvb.frontend->ops->info.name,
@@ -222,7 +265,7 @@ static int dvb_register(struct cx8802_de
 		sizeof(dev->dvb.frontend->ops->info.name));
 
 	/* register everything */
-	return videobuf_dvb_register(&dev->dvb);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
 
 /* ----------------------------------------------------------- */
Index: linux-2.6.11/drivers/media/video/cx88/cx88-input.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11/drivers/media/video/cx88/cx88-input.c	2005-03-08 10:33:15.000000000 +0100
@@ -0,0 +1,396 @@
+/*
+ * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $
+ *
+ * Device driver for GPIO attached remote control interfaces
+ * on Conexant 2388x based TV/DVB cards.
+ *
+ * Copyright (c) 2003 Pavel Machek
+ * Copyright (c) 2004 Gerd Knorr
+ * Copyright (c) 2004 Chris Pascoe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <media/ir-common.h>
+
+#include "cx88.h"
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live DVB-T Remote */
+static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
+	[ 0x00 ] = KEY_ESC,         // 'go up a level?'
+	[ 0x01 ] = KEY_KP1,         // '1'
+	[ 0x02 ] = KEY_KP2,         // '2'
+	[ 0x03 ] = KEY_KP3,         // '3'
+	[ 0x04 ] = KEY_KP4,         // '4'
+	[ 0x05 ] = KEY_KP5,         // '5'
+	[ 0x06 ] = KEY_KP6,         // '6'
+	[ 0x07 ] = KEY_KP7,         // '7'
+	[ 0x08 ] = KEY_KP8,         // '8'
+	[ 0x09 ] = KEY_KP9,         // '9'
+	[ 0x0a ] = KEY_KP0,         // '0'
+	[ 0x0b ] = KEY_TUNER,       // 'tv/fm'
+	[ 0x0c ] = KEY_SEARCH,      // 'scan'
+	[ 0x0d ] = KEY_STOP,        // 'stop'
+	[ 0x0e ] = KEY_PAUSE,       // 'pause'
+	[ 0x0f ] = KEY_LIST,        // 'source'
+
+	[ 0x10 ] = KEY_MUTE,        // 'mute'
+	[ 0x11 ] = KEY_REWIND,      // 'backward <<'
+	[ 0x12 ] = KEY_POWER,       // 'power'
+	[ 0x13 ] = KEY_S,           // 'snap'
+	[ 0x14 ] = KEY_AUDIO,       // 'stereo'
+	[ 0x15 ] = KEY_CLEAR,       // 'reset'
+	[ 0x16 ] = KEY_PLAY,        // 'play'
+	[ 0x17 ] = KEY_ENTER,       // 'enter'
+	[ 0x18 ] = KEY_ZOOM,        // 'full screen'
+	[ 0x19 ] = KEY_FASTFORWARD, // 'forward >>'
+	[ 0x1a ] = KEY_CHANNELUP,   // 'channel +'
+	[ 0x1b ] = KEY_VOLUMEUP,    // 'volume +'
+	[ 0x1c ] = KEY_INFO,        // 'preview'
+	[ 0x1d ] = KEY_RECORD,      // 'record'
+	[ 0x1e ] = KEY_CHANNELDOWN, // 'channel -'
+	[ 0x1f ] = KEY_VOLUMEDOWN,  // 'volume -'
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* IO-DATA BCTV7E Remote */
+static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
+	[ 0x40 ] = KEY_TV,              // TV
+	[ 0x20 ] = KEY_RADIO,           // FM
+	[ 0x60 ] = KEY_EPG,             // EPG
+	[ 0x00 ] = KEY_POWER,           // power
+
+	[ 0x50 ] = KEY_KP1,             // 1
+	[ 0x30 ] = KEY_KP2,             // 2
+	[ 0x70 ] = KEY_KP3,             // 3
+	[ 0x10 ] = KEY_L,               // Live
+
+	[ 0x48 ] = KEY_KP4,             // 4
+	[ 0x28 ] = KEY_KP5,             // 5
+	[ 0x68 ] = KEY_KP6,             // 6
+	[ 0x08 ] = KEY_T,               // Time Shift
+
+	[ 0x58 ] = KEY_KP7,             // 7
+	[ 0x38 ] = KEY_KP8,             // 8
+	[ 0x78 ] = KEY_KP9,             // 9
+	[ 0x18 ] = KEY_PLAYPAUSE,       // Play
+
+	[ 0x44 ] = KEY_KP0,             // 10
+	[ 0x24 ] = KEY_ENTER,           // 11
+	[ 0x64 ] = KEY_ESC,             // 12
+	[ 0x04 ] = KEY_M,               // Multi
+
+	[ 0x54 ] = KEY_VIDEO,           // VIDEO
+	[ 0x34 ] = KEY_CHANNELUP,       // channel +
+	[ 0x74 ] = KEY_VOLUMEUP,        // volume +
+	[ 0x14 ] = KEY_MUTE,            // Mute
+
+	[ 0x4c ] = KEY_S,               // SVIDEO
+	[ 0x2c ] = KEY_CHANNELDOWN,     // channel -
+	[ 0x6c ] = KEY_VOLUMEDOWN,      // volume -
+	[ 0x0c ] = KEY_ZOOM,            // Zoom
+
+	[ 0x5c ] = KEY_PAUSE,           // pause
+	[ 0x3c ] = KEY_C,               // || (red)
+	[ 0x7c ] = KEY_RECORD,          // recording
+	[ 0x1c ] = KEY_STOP,            // stop
+
+	[ 0x41 ] = KEY_REWIND,          // backward <<
+	[ 0x21 ] = KEY_PLAY,            // play
+	[ 0x61 ] = KEY_FASTFORWARD,     // forward >>
+	[ 0x01 ] = KEY_NEXT,            // skip >|
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct cx88_IR {
+	struct cx88_core	*core;
+	struct input_dev        input;
+	struct ir_input_state   ir;
+	char                    name[32];
+	char                    phys[32];
+
+	/* sample from gpio pin 16 */
+	int                     sampling;
+	u32                     samples[16];
+	int                     scount;
+	unsigned long           release;
+
+	/* poll external decoder */
+	int                     polling;
+	struct work_struct      work;
+	struct timer_list       timer;
+	u32			gpio_addr;
+	u32                     last_gpio;
+	u32                     mask_keycode;
+	u32                     mask_keydown;
+	u32                     mask_keyup;
+};
+
+static int ir_debug = 0;
+module_param(ir_debug, int, 0644);    /* debug level [IR] */
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
+
+#define ir_dprintk(fmt, arg...)	if (ir_debug) \
+	printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static void cx88_ir_handle_key(struct cx88_IR *ir)
+{
+	struct cx88_core *core = ir->core;
+	u32 gpio, data;
+
+	/* read gpio value */
+	gpio = cx_read(ir->gpio_addr);
+	if (ir->polling) {
+		if (ir->last_gpio == gpio)
+			return;
+		ir->last_gpio = gpio;
+	}
+
+	/* extract data */
+	data = ir_extract_bits(gpio, ir->mask_keycode);
+	ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
+		gpio, data,
+		ir->polling               ? "poll"  : "irq",
+		(gpio & ir->mask_keydown) ? " down" : "",
+		(gpio & ir->mask_keyup)   ? " up"   : "");
+
+	if (ir->mask_keydown) {
+		/* bit set on keydown */
+		if (gpio & ir->mask_keydown) {
+			ir_input_keydown(&ir->input,&ir->ir,data,data);
+		} else {
+			ir_input_nokey(&ir->input,&ir->ir);
+		}
+
+	} else if (ir->mask_keyup) {
+		/* bit cleared on keydown */
+		if (0 == (gpio & ir->mask_keyup)) {
+			ir_input_keydown(&ir->input,&ir->ir,data,data);
+		} else {
+			ir_input_nokey(&ir->input,&ir->ir);
+		}
+
+	} else {
+		/* can't distinguish keydown/up :-/ */
+		ir_input_keydown(&ir->input,&ir->ir,data,data);
+		ir_input_nokey(&ir->input,&ir->ir);
+	}
+}
+
+static void ir_timer(unsigned long data)
+{
+	struct cx88_IR *ir = (struct cx88_IR*)data;
+
+	schedule_work(&ir->work);
+}
+
+static void cx88_ir_work(void *data)
+{
+	struct cx88_IR *ir = data;
+	unsigned long timeout;
+
+	cx88_ir_handle_key(ir);
+	timeout = jiffies + (ir->polling * HZ / 1000);
+	mod_timer(&ir->timer, timeout);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
+{
+	struct cx88_IR *ir;
+	IR_KEYTAB_TYPE *ir_codes = NULL;
+	int ir_type = IR_TYPE_OTHER;
+
+	ir = kmalloc(sizeof(*ir),GFP_KERNEL);
+	if (NULL == ir)
+		return -ENOMEM;
+	memset(ir,0,sizeof(*ir));
+
+	/* detect & configure */
+	switch (core->board) {
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		ir_codes         = ir_codes_dntv_live_dvb_t;
+		ir->gpio_addr    = MO_GP1_IO;
+		ir->mask_keycode = 0x1f;
+		ir->mask_keyup   = 0x60;
+		ir->polling      = 50; // ms
+		break;
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		ir_codes         = ir_codes_hauppauge_new;
+		ir_type          = IR_TYPE_RC5;
+		ir->sampling     = 1;
+		break;
+	case CX88_BOARD_WINFAST2000XP_EXPERT:
+		ir_codes         = ir_codes_winfast;
+		ir->gpio_addr    = MO_GP0_IO;
+		ir->mask_keycode = 0x8f8; 
+		ir->mask_keyup   = 0x100;
+		ir->polling      = 1; // ms
+		break;
+	case CX88_BOARD_IODATA_GVBCTV7E:
+		ir_codes         = ir_codes_iodata_bctv7e;
+		ir->gpio_addr    = MO_GP0_IO;
+		ir->mask_keycode = 0xfd;
+		ir->mask_keydown = 0x02;
+		ir->polling      = 5; // ms
+		break;
+	}
+	if (NULL == ir_codes) {
+		kfree(ir);
+		return -ENODEV;
+	}
+
+	/* init input device */
+	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
+		 cx88_boards[core->board].name);
+	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+		 pci_name(pci));
+
+	ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes);
+	ir->input.name = ir->name;
+	ir->input.phys = ir->phys;
+	ir->input.id.bustype = BUS_PCI;
+	ir->input.id.version = 1;
+	if (pci->subsystem_vendor) {
+		ir->input.id.vendor  = pci->subsystem_vendor;
+		ir->input.id.product = pci->subsystem_device;
+	} else {
+		ir->input.id.vendor  = pci->vendor;
+		ir->input.id.product = pci->device;
+	}
+
+	/* record handles to ourself */
+	ir->core = core;
+	core->ir = ir;
+
+	if (ir->polling) {
+		INIT_WORK(&ir->work, cx88_ir_work, ir);
+		init_timer(&ir->timer);
+		ir->timer.function = ir_timer;
+		ir->timer.data     = (unsigned long)ir;
+		schedule_work(&ir->work);
+	}
+	if (ir->sampling) {
+		core->pci_irqmask |= (1<<18);   // IR_SMP_INT
+		cx_write(MO_DDS_IO, 0xa80a80);  // 4 kHz sample rate
+		cx_write(MO_DDSCFG_IO,   0x5);  // enable
+	}
+
+	/* all done */
+	input_register_device(&ir->input);
+	printk("%s: registered IR remote control\n", core->name);
+
+	return 0;
+}
+
+int cx88_ir_fini(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+
+	/* skip detach on non attached boards */
+	if (NULL == ir)
+		return 0;
+
+	if (ir->polling) {
+		del_timer(&ir->timer);
+		flush_scheduled_work();
+	}
+
+	input_unregister_device(&ir->input);
+	kfree(ir);
+
+	/* done */
+	core->ir = NULL;
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void cx88_ir_irq(struct cx88_core *core)
+{
+	struct cx88_IR *ir = core->ir;
+	u32 samples,rc5;
+	int i;
+
+	if (NULL == ir)
+		return;
+	if (!ir->sampling)
+		return;
+
+	samples = cx_read(MO_SAMPLE_IO);
+	if (0 != samples  &&  0xffffffff != samples) {
+		/* record sample data */
+		if (ir->scount < ARRAY_SIZE(ir->samples))
+			ir->samples[ir->scount++] = samples;
+		return;
+	}
+	if (!ir->scount) {
+		/* nothing to sample */
+		if (ir->ir.keypressed && time_after(jiffies,ir->release))
+			ir_input_nokey(&ir->input,&ir->ir);
+		return;
+	}
+
+	/* have a complete sample */
+	if (ir->scount < ARRAY_SIZE(ir->samples))
+		ir->samples[ir->scount++] = samples;
+	for (i = 0; i < ir->scount; i++)
+		ir->samples[i] = ~ir->samples[i];
+	if (ir_debug)
+		ir_dump_samples(ir->samples,ir->scount);
+
+	/* decode it */
+	switch (core->board) {
+	case CX88_BOARD_HAUPPAUGE:
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7);
+		ir_dprintk("biphase decoded: %x\n",rc5);
+		if ((rc5 & 0xfffff000) != 0x3000)
+			break;
+		ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5);
+		ir->release = jiffies + msecs_to_jiffies(120);
+		break;
+	}
+
+	ir->scount = 0;
+	return;
+}
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
+MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
Index: linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-vbi.c	2005-03-07 10:13:49.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-vbi.c	2005-03-08 10:33:15.000000000 +0100
@@ -1,8 +1,9 @@
 /*
- * $Id: cx88-vbi.c,v 1.14 2004/11/07 13:17:15 kraxel Exp $
+ * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
@@ -64,7 +65,7 @@ int cx8800_start_vbi_dma(struct cx8800_d
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, 0x00fc01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
 	cx_set(MO_VID_INTMSK, 0x0f0088);
 
 	/* enable capture */
Index: linux-2.6.11/drivers/media/video/cx88/cx88.h
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88.h	2005-03-07 10:15:48.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88.h	2005-03-08 10:33:15.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88.h,v 1.40 2004/11/03 09:04:51 kraxel Exp $
+ * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $
  *
  * v4l2 device driver for cx2388x based TV cards
  *
@@ -27,6 +27,7 @@
 #include <linux/kdev_t.h>
 
 #include <media/tuner.h>
+#include <media/tveeprom.h>
 #include <media/audiochip.h>
 #include <media/video-buf.h>
 #include <media/video-buf-dvb.h>
@@ -139,7 +140,7 @@ extern struct sram_channel cx88_sram_cha
 #define CX88_BOARD_GDI                      2
 #define CX88_BOARD_PIXELVIEW                3
 #define CX88_BOARD_ATI_WONDER_PRO           4
-#define CX88_BOARD_WINFAST2000XP            5
+#define CX88_BOARD_WINFAST2000XP_EXPERT     5
 #define CX88_BOARD_AVERTV_303               6
 #define CX88_BOARD_MSI_TVANYWHERE_MASTER    7
 #define CX88_BOARD_WINFAST_DV2000           8
@@ -156,6 +157,11 @@ extern struct sram_channel cx88_sram_cha
 #define CX88_BOARD_CONEXANT_DVB_T1         19
 #define CX88_BOARD_PROVIDEO_PV259          20
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
+#define CX88_BOARD_PCHDTV_HD3000           22
+#define CX88_BOARD_DNTV_LIVE_DVB_T         23
+#define CX88_BOARD_HAUPPAUGE_ROSLYN        24
+#define CX88_BOARD_DIGITALLOGIC_MEC	       25
+#define CX88_BOARD_IODATA_GVBCTV7E         26
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -238,6 +244,7 @@ struct cx88_core {
         u32                        __iomem *lmmio;
         u8                         __iomem *bmmio;
 	u32                        shadow[SHADOW_MAX];
+	int                        pci_irqmask;
 
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
@@ -252,16 +259,20 @@ struct cx88_core {
 	unsigned int               has_radio;
 
 	/* config info -- dvb */
-	unsigned int               pll_type;
+	struct dvb_pll_desc        *pll_desc;
 	unsigned int               pll_addr;
-	unsigned int               demod_addr;
 
 	/* state info */
 	struct task_struct         *kthread;
 	struct cx88_tvnorm         *tvnorm;
 	u32                        tvaudio;
+	u32                        audiomode_manual;
+	u32                        audiomode_current;
 	u32                        input;
 	u32                        astat;
+
+	/* IR remote control state */
+	struct cx88_IR             *ir;
 };
 
 struct cx8800_dev;
@@ -371,11 +382,16 @@ struct cx8802_dev {
 	struct list_head           devlist;
 	struct video_device        *mpeg_dev;
 	u32                        mailbox;
+	int                        width;
+	int                        height;
 
 	/* for dvb only */
 	struct videobuf_dvb        dvb;
 	void*                      fe_handle;
 	int                        (*fe_release)(void *handle);
+
+	/* for switching modulation types */
+	unsigned char              ts_gen_cntrl;
 };
 
 /* ----------------------------------------------------------- */
@@ -411,7 +427,7 @@ extern void cx88_print_irqbits(char *nam
 			       u32 bits, u32 mask);
 extern void cx88_print_ioctl(char *name, unsigned int cmd);
 
-extern void cx88_irq(struct cx88_core *core, u32 status, u32 mask);
+extern int cx88_core_irq(struct cx88_core *core, u32 status);
 extern void cx88_wakeup(struct cx88_core *core,
 			struct cx88_dmaqueue *q, u32 count);
 extern void cx88_shutdown(struct cx88_core *core);
@@ -503,11 +519,19 @@ extern void cx88_card_setup(struct cx88_
 #define WW_FM		12
 
 void cx88_set_tvaudio(struct cx88_core *core);
+void cx88_newstation(struct cx88_core *core);
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
-void cx88_set_stereo(struct cx88_core *core, u32 mode);
+void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
 int cx88_audio_thread(void *data);
 
 /* ----------------------------------------------------------- */
+/* cx88-input.c                                                */
+
+int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
+int cx88_ir_fini(struct cx88_core *core);
+void cx88_ir_irq(struct cx88_core *core);
+
+/* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
 int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
@@ -517,7 +541,7 @@ void cx8802_cancel_buffers(struct cx8802
 int cx8802_init_common(struct cx8802_dev *dev);
 void cx8802_fini_common(struct cx8802_dev *dev);
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state);
+int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
 int cx8802_resume_common(struct pci_dev *pci_dev);
 
 /*
Index: linux-2.6.11/drivers/media/video/cx88/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/Makefile	2005-03-07 10:13:03.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/Makefile	2005-03-08 10:33:15.000000000 +0100
@@ -1,4 +1,5 @@
-cx88xx-objs	:= cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o
+cx88xx-objs	:= cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
+		   cx88-input.o
 cx8800-objs	:= cx88-video.o cx88-vbi.o
 cx8802-objs	:= cx88-mpeg.o
 
Index: linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c
===================================================================
--- linux-2.6.11.orig/drivers/media/video/cx88/cx88-i2c.c	2005-03-07 10:13:32.000000000 +0100
+++ linux-2.6.11/drivers/media/video/cx88/cx88-i2c.c	2005-03-08 10:33:15.000000000 +0100
@@ -1,5 +1,5 @@
 /*
-    $Id: cx88-i2c.c,v 1.18 2004/10/13 10:39:00 kraxel Exp $
+    $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $
 
     cx88-i2c.c  --  all the i2c code is here
 
@@ -25,6 +25,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include <asm/io.h>

-- 
#define printk(args...) fprintf(stderr, ## args)

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-03-08 11:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-08 11:00 [patch] v4l: cx88 driver update Gerd Knorr
  -- strict thread matches above, loose matches on Subject: below --
2004-06-18 10:02 Gerd Knorr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox