Subject: [patch] cx88 update

FIXME: description

Signed-off-by: Gerd Knorr <kraxel@bytesex.org>
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-cards.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-cards.c	2004-12-17 12:09:01.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-cards.c	2004-12-17 12:47:15.117293538 +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.53 2004/12/14 15:33:30 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * card-specific stuff.
@@ -32,7 +32,8 @@
 
 #include "cx88.h"
 #ifdef WITH_DVB
-#include "cx22702.h"
+# include "dvb-pll.h"
+# include "cx22702.h"
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -91,7 +92,7 @@ struct cx88_board cx88_boards[] = {
 	},
 	[CX88_BOARD_PIXELVIEW] = {
 		.name           = "PixelView",
-		.tuner_type     = UNSET,
+		.tuner_type     = 5,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
@@ -223,20 +224,26 @@ struct cx88_board cx88_boards[] = {
                 },
         },
         [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,
         },
@@ -452,6 +459,22 @@ 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,
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -543,6 +566,18 @@ 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,
 	}
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -632,11 +667,13 @@ static struct {
 	{ 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"}
+	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"},
+	{ TUNER_THOMSON_DTT7610,  "DTT-7610"}
 };
 
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
+#if 0
 	unsigned int blk2,tuner,radio,model;
 
 	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) {
@@ -663,6 +700,13 @@ static void hauppauge_eeprom(struct cx88
 	       core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner)
 				   ? hauppauge_tuner[tuner].name : "?"),
 	       core->tuner_type, radio ? "yes" : "no");
+#else
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&tv, eeprom_data);
+	core->tuner_type = tv.tuner_type;
+	core->has_radio  = tv.has_radio;
+#endif
 }
 
 #ifdef WITH_DVB
@@ -670,7 +714,6 @@ static int hauppauge_eeprom_dvb(struct c
 {
 	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,23 +732,20 @@ 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: /* ddt 7595 */
+	case 0x4C: /* dtt 7592 */
+		core->pll_desc = &dvb_pll_thomson_dtt759x;
 		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);
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%d (%s)\n",
+	       core->name, model, tuner, 
+	       core->pll_desc ? core->pll_desc->name : "UNKNOWN");
 
-	core->pll_addr = 0x61;
+	core->pll_addr   = 0x61;
 	core->demod_addr = 0x43;
 }
 #endif
@@ -763,36 +803,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,21 +833,33 @@ 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:
 		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:
 		if (0 == core->i2c_rc)
-			i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
-		leadtek_eeprom(core,eeprom);
+			leadtek_eeprom(core,eeprom);
+		break;
+#ifdef WITH_DVB
+	case CX88_BOARD_HAUPPAUGE_DVB_T1:
+		if (0 == core->i2c_rc)
+			hauppauge_eeprom_dvb(core,eeprom);
+		break;
+	case CX88_BOARD_CONEXANT_DVB_T1:
+		core->pll_desc   = &dvb_pll_thomson_dtt7579;
+		core->pll_addr   = 0x60;
+		core->demod_addr = 0x43;
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
 		/* Tuner reset is hooked to  the tuner out of reset */
@@ -845,17 +867,22 @@ void cx88_card_setup(struct cx88_core *c
 		cx_clear(MO_GP0_IO, 0x00000001);
 		msleep(1);
 		cx_set(MO_GP0_IO, 0x00000101);
+		core->pll_addr = 0x61;
+		core->pll_desc = &dvb_pll_lg_z201;
 		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);
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		core->pll_addr = 0x60;
+		core->pll_desc = &dvb_pll_thomson_dtt7579;
 		break;
-	case CX88_BOARD_CONEXANT_DVB_T1:
-		core->pll_type   = PLLTYPE_DTT7579;
-		core->pll_addr   = 0x60;
-		core->demod_addr = 0x43;
+	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);
+		core->pll_addr = 0x61;
+		core->pll_desc = &dvb_pll_unknown_1;
 		break;
 #endif
 	}
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-core.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-core.c	2004-12-17 12:07:24.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-core.c	2004-12-17 12:47:15.126291846 +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.21 2004/12/10 12:33:39 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(nicam,"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);
@@ -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,8 @@ 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);
+	cx_write(MO_PCI_INTMSK, core->pci_irqmask);
 
 	up(&devlist);
 	return core;
@@ -1170,6 +1194,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 +1212,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 +1222,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-2004-12-16/drivers/media/video/cx88/cx88-blackbird.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-blackbird.c	2004-12-17 12:09:05.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-blackbird.c	2004-12-17 12:47:15.136289964 +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.23 2004/12/10 12:33:39 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)
Index: linux-2004-12-16/drivers/media/video/Kconfig
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/Kconfig	2004-12-17 12:47:08.871468650 +0100
+++ linux-2004-12-16/drivers/media/video/Kconfig	2004-12-17 12:47:43.205009038 +0100
@@ -309,6 +309,7 @@ config VIDEO_CX88
 	select VIDEO_BTCX
 	select VIDEO_BUF
 	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
 	---help---
 	  This is a video4linux driver for Conexant 2388x based
 	  TV cards.
@@ -318,7 +319,7 @@ 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
 	---help---
 	  This adds support for DVB cards based on the
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-video.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-video.c	2004-12-17 12:08:16.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-video.c	2004-12-17 12:47:15.148287707 +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.50 2004/12/10 12:33:39 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 */
@@ -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;
@@ -1880,19 +1883,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);
 	};
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-mpeg.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-mpeg.c	2004-12-17 12:09:55.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-mpeg.c	2004-12-17 12:47:15.150287331 +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.16 2004/12/10 12:33:39 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>
@@ -93,7 +94,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 +293,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);
 	};
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-tvaudio.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-tvaudio.c	2004-12-17 12:07:52.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-tvaudio.c	2004-12-17 12:47:15.155286390 +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.26 2004/12/10 12:33:39 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>
Index: linux-2004-12-16/drivers/media/video/cx88/cx88-dvb.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-dvb.c	2004-12-17 12:08:32.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-dvb.c	2004-12-17 12:47:15.164284697 +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.21 2004/12/09 12:51:35 kraxel Exp $
  *
  * device driver for Conexant 2388x based TV cards
  * MPEG Transport Stream (DVB) routines
@@ -31,6 +31,7 @@
 #include <linux/suspend.h>
 
 #include "cx88.h"
+#include "dvb-pll.h"
 #include "cx22702.h"
 #include "mt352.h"
 #include "mt352_priv.h" /* FIXME */
@@ -110,72 +111,52 @@ 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;
-
-	if (params->frequency == 0) bs = 0x03;
-	else if (params->frequency < 157500000) bs = 0x01;
-	else if (params->frequency < 443250000) bs = 0x02;
-	else bs = 0x04;
-
-	pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */
-	pllbuf[1] = div >> 8;
-	pllbuf[2] = div & 0xff;
-	pllbuf[3] = cp;
-	pllbuf[4] = bs;
+	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 };
+  
+	mt352_write(fe, clock_config,   sizeof(clock_config));
+	udelay(2000);
+	mt352_write(fe, reset,          sizeof(reset));
+	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+	udelay(2000);
+	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
+	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
 
 	return 0;
 }
 
-static int thomson_dtt7579_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;
-
+static int mt352_pll_set(struct dvb_frontend* fe,
+			 struct dvb_frontend_parameters* params,
+			 u8* pllbuf)
+{
+	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,
 };
 
 static int dvb_register(struct cx8802_dev *dev)
@@ -189,32 +170,32 @@ static int dvb_register(struct cx8802_de
 	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->pll_desc,
 						   dev->core->demod_addr);
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1,
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+		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,
+	case CX88_BOARD_DNTV_LIVE_DVB_T:
+		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;
 	default:
 		printk("%s: FIXME: frontend handling not here yet ...\n",
 		       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 +203,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-2004-12-16/drivers/media/video/cx88/cx88-input.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-input.c	2004-12-17 12:47:15.165284509 +0100
@@ -0,0 +1,394 @@
+/*
+ * $Id: cx88-input.c,v 1.3 2004/12/10 12:33:39 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 -'
+};
+
+/* ---------------------------------------------------------------------- */
+
+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 disturgissh 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_rc5_tv;
+		ir_type          = IR_TYPE_RC5;
+		ir->sampling     = 1;
+		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;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int inline getbit(u32 *samples, int bit)
+{
+	return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
+}
+
+static int dump_samples(u32 *samples, int count)
+{
+	int i, bit, start;
+
+	printk(KERN_DEBUG "ir samples @ 4kHz: ");
+	start = 0;
+	for (i = 0; i < count * 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			start = 1;
+		if (0 == start)
+			continue;
+		printk("%s", bit ? "#" : "_");
+	}
+	printk("\n");
+}
+
+static int ir_decode_biphase(u32 *samples, int count, int low, int high)
+{
+	int i,last,bit,len,flips;
+	u32 value;
+
+	/* find start bit (1) */
+	for (i = 0; i < 32; i++) {
+		bit = getbit(samples,i);
+		if (bit)
+			break;
+	}
+
+	/* go decoding */
+	len   = 0;
+	flips = 0;
+	value = 1;
+	for (; i < count * 32; i++) {
+		if (len > high)
+			break;
+		if (flips > 1)
+			break;
+		last = bit;
+		bit  = getbit(samples,i);
+		if (last == bit) {
+			len++;
+			continue;
+		}
+		if (len < low) {
+			len++;
+			flips++;
+			continue;
+		}
+		value <<= 1;
+		value |= bit;
+		flips = 0;
+		len   = 1;
+	}
+	return value;
+}
+
+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)
+		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-2004-12-16/drivers/media/video/cx88/cx88-vbi.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-vbi.c	2004-12-17 12:08:00.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-vbi.c	2004-12-17 12:47:15.166284321 +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-2004-12-16/drivers/media/video/cx88/cx88.h
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88.h	2004-12-17 12:09:48.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88.h	2004-12-17 12:47:15.169283757 +0100
@@ -1,5 +1,5 @@
 /*
- * $Id: cx88.h,v 1.40 2004/11/03 09:04:51 kraxel Exp $
+ * $Id: cx88.h,v 1.47 2004/12/14 15:33:30 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>
@@ -156,6 +157,8 @@ 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
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -238,6 +241,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,7 +256,7 @@ 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;
 
@@ -262,6 +266,9 @@ struct cx88_core {
 	u32                        tvaudio;
 	u32                        input;
 	u32                        astat;
+
+	/* IR remote control state */
+	struct cx88_IR             *ir;
 };
 
 struct cx8800_dev;
@@ -371,6 +378,8 @@ 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;
@@ -411,7 +420,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);
@@ -508,6 +517,13 @@ void cx88_set_stereo(struct cx88_core *c
 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);
Index: linux-2004-12-16/drivers/media/video/cx88/Makefile
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/Makefile	2004-12-17 12:07:11.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/Makefile	2004-12-17 12:47:15.177282252 +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-2004-12-16/drivers/media/video/cx88/cx88-i2c.c
===================================================================
--- linux-2004-12-16.orig/drivers/media/video/cx88/cx88-i2c.c	2004-12-17 12:07:37.000000000 +0100
+++ linux-2004-12-16/drivers/media/video/cx88/cx88-i2c.c	2004-12-17 12:47:15.184280935 +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.19 2004/12/10 12:33:39 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>
