linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][2.6][0/14] DVB subsystem update
@ 2004-09-17 14:20 Michael Hunold
  2004-09-17 14:22 ` [PATCH][2.6][1/14] update saa7146 driver Michael Hunold
  2004-09-17 23:41 ` [PATCH][2.6][0/14] DVB subsystem update Andrew Morton
  0 siblings, 2 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

Hi there,

here comes a patchset consisting of 14 patches bringing the in-kernel 
DVB subsystem in sync with the LinuxTV.org CVS driver.

The most important changes include:
- remove non-linux compatibility stuff
- remove home-brewn dvb-i2c stuff, use kernel-i2c instead
- convert home-brewn bttv i2c access drivers to real bttv sub-drivers
- add new driver for mobile USB Budget DVB-T devices by DiBcom
- add new drivers for Zarlink DVB-T MT352 frontend, Conexant 22702 DVB 
OFDM frontend and DVB-T demodulator DiBcom 3000-MB frontend
- plus lots of other changes, explained in the top of each patch.

Please apply. Thanks!

Regards.
Michael Hunold.

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

* [PATCH][2.6][1/14] update saa7146 driver
  2004-09-17 14:20 [PATCH][2.6][0/14] DVB subsystem update Michael Hunold
@ 2004-09-17 14:22 ` Michael Hunold
  2004-09-17 14:24   ` [PATCH][2.6][2/14] documentation update Michael Hunold
  2004-09-17 23:41 ` [PATCH][2.6][0/14] DVB subsystem update Andrew Morton
  1 sibling, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:22 UTC (permalink / raw)
  To: Michael Hunold; +Cc: Linus Torvalds, Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2: 01-DVB-update-saa7146.diff --]
[-- Type: text/plain, Size: 13945 bytes --]

- [DVB] uses msleep() instead of my_wait(), thanks to Kernel Janitors/Nishanth Aravamudan <nacc@us.ibm.com>
- [DVB] fix videodev has no release callback
- [DVB] use PAGE_SIZE for pagetables, not home-brewn SAA7146_PGTABLE_SIZE
- [DVB] use cpu_to_le32() at various places for endianess independency
- [DVB] turn some error checks into BUG()s
- [DVB] make saa7146_i2c_adapter_prepare() support an adapter class
- [DVB] add support for V4L2_PIX_FMT_RGB32 pixelformat
- [DVB] replace generic saa7146 i2c name by card specific name, suggested by Uli Luckas <luckas@musoft.de>

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/common/saa7146_core.c linux-2.6.8.1-patched/drivers/media/common/saa7146_core.c
--- xx-linux-2.6.8.1/drivers/media/common/saa7146_core.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/common/saa7146_core.c	2004-04-28 18:31:39.000000000 +0200
@@ -133,8 +133,6 @@
 /********************************************************************************/
 /* common page table functions */
 
-#define SAA7146_PGTABLE_SIZE 4096
-
 char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
 {
 	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
@@ -182,11 +180,11 @@
         u32          *cpu;
         dma_addr_t   dma_addr;
 
-	cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr);
+	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
 	if (NULL == cpu) {
 		return -ENOMEM;
 	}
-	pt->size = SAA7146_PGTABLE_SIZE;
+	pt->size = PAGE_SIZE;
 	pt->cpu  = cpu;
 	pt->dma  = dma_addr;
 
@@ -201,11 +199,7 @@
 	int   i,p;
 
 	BUG_ON( 0 == sglen);
-
-	if (list->offset > PAGE_SIZE) {
-		DEB_D(("offset > PAGE_SIZE. this should not happen."));
-		return -EINVAL;
-	}
+	BUG_ON(list->offset > PAGE_SIZE);
 	
 	/* if we have a user buffer, the first page may not be
 	   aligned to a page boundary. */
@@ -217,7 +211,7 @@
 		printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);
 */
 		for (p = 0; p * 4096 < list->length; p++, ptr++) {
-			*ptr = sg_dma_address(list) + p * 4096;
+			*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
 			nr_pages++;
 		}
 	}
diff -uraNwB xx-linux-2.6.8.1/drivers/media/common/saa7146_fops.c linux-2.6.8.1-patched/drivers/media/common/saa7146_fops.c
--- xx-linux-2.6.8.1/drivers/media/common/saa7146_fops.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/common/saa7146_fops.c	2004-07-31 02:05:45.000000000 +0200
@@ -88,10 +88,7 @@
 #endif
 	DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf));
 
-	if( NULL == q ) {
-		ERR(("internal error: fatal NULL pointer for q.\n"));
-		return 0;
-	}
+	BUG_ON(!q);
 
 	if (NULL == q->curr) {
 		q->curr = buf;
@@ -112,14 +109,11 @@
 #ifdef DEBUG_SPINLOCKS
 	BUG_ON(!spin_is_locked(&dev->slock));
 #endif
-	if( NULL == q->curr ) {
-		ERR(("internal error: fatal NULL pointer for q->curr.\n"));
-		return;
-	}
-
 	DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state));
 	DEB_EE(("q->curr:%p\n",q->curr));
 
+	BUG_ON(!q->curr);
+
 	/* finish current buffer */
 	if (NULL == q->curr) {
 		DEB_D(("aiii. no current buffer\n"));
@@ -138,10 +132,7 @@
 {
 	struct saa7146_buf *buf,*next = NULL;
 
-	if( NULL == q ) {
-		ERR(("internal error: fatal NULL pointer for q.\n"));
-		return;
-	}
+	BUG_ON(!q);
 
 	DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi));
 
@@ -515,45 +506,58 @@
 	return 0;
 }
 
-int saa7146_register_device(struct video_device *vid, struct saa7146_dev* dev, char *name, int type)
+int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
+			    char *name, int type)
 {
 	struct saa7146_vv *vv = dev->vv_data;
+	struct video_device *vfd;
 
 	DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
  
- 	*vid = device_template;
-	strlcpy(vid->name, name, sizeof(vid->name));
-	vid->priv = dev;
+	// released by vfd->release
+ 	vfd = video_device_alloc();
+	if (vfd == NULL)
+		return -ENOMEM;
+
+	memcpy(vfd, &device_template, sizeof(struct video_device));
+	strlcpy(vfd->name, name, sizeof(vfd->name));
+	vfd->release = video_device_release;
+	vfd->priv = dev;
 
 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
-	if (video_register_device(vid,type,-1) < 0) {
+	if (video_register_device(vfd, type, -1) < 0) {
 		ERR(("cannot register v4l2 device. skipping.\n"));
 		return -1;
 	}
 
 	if( VFL_TYPE_GRABBER == type ) {
-		vv->video_minor = vid->minor;
-		INFO(("%s: registered device video%d [v4l2]\n", dev->name,vid->minor & 0x1f));
+		vv->video_minor = vfd->minor;
+		INFO(("%s: registered device video%d [v4l2]\n",
+			dev->name, vfd->minor & 0x1f));
 	} else {
-		vv->vbi_minor = vid->minor;
-		INFO(("%s: registered device vbi%d [v4l2]\n", dev->name,vid->minor & 0x1f));
+		vv->vbi_minor = vfd->minor;
+		INFO(("%s: registered device vbi%d [v4l2]\n",
+			dev->name, vfd->minor & 0x1f));
 	}
 
+	*vid = vfd;
 	return 0;
 }
 
-int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev* dev)
+int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
 	struct saa7146_vv *vv = dev->vv_data;
 	
 	DEB_EE(("dev:%p\n",dev));
 
-	if( VFL_TYPE_GRABBER == vid->type ) {
+	if( VFL_TYPE_GRABBER == (*vid)->type ) {
 		vv->video_minor = -1;
 	} else {
 		vv->vbi_minor = -1;
 	}
-	video_unregister_device(vid);
+
+	video_unregister_device(*vid);
+	*vid = NULL;
 
 	return 0;
 }
diff -uraNwB xx-linux-2.6.8.1/drivers/media/common/saa7146_hlp.c linux-2.6.8.1-patched/drivers/media/common/saa7146_hlp.c
--- xx-linux-2.6.8.1/drivers/media/common/saa7146_hlp.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/common/saa7146_hlp.c	2004-04-28 18:31:39.000000000 +0200
@@ -413,10 +413,10 @@
 
 	/* fill up cliptable */
 	for(i = 0; i < cnt_pixel; i++) {
-		clipping[2*i] |= (pixel_list[i] << 16);
+		clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
 	}
 	for(i = 0; i < cnt_line; i++) {
-		clipping[(2*i)+1] |= (line_list[i] << 16);
+		clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
 	}
 
 	/* fill up cliptable with the display infos */
@@ -430,7 +430,7 @@
 			if( pixel_list[i] < (x[j] + w[j])) {
 			
 				if ( pixel_list[i] >= x[j] ) {
-					clipping[2*i] |= (1 << j);			
+					clipping[2*i] |= cpu_to_le32(1 << j);			
 				}
 			}
 		}
@@ -442,7 +442,7 @@
 			if( line_list[i] < (y[j] + h[j]) ) {
 
 				if( line_list[i] >= y[j] ) {
-					clipping[(2*i)+1] |= (1 << j);			
+					clipping[(2*i)+1] |= cpu_to_le32(1 << j);			
 				}
 			}
 		}
@@ -560,9 +560,10 @@
 }
 
 /* calculate the new memory offsets for a desired position */
-static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field)
+static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
 {	
 	struct saa7146_vv *vv = dev->vv_data;
+	struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
 
 	int b_depth = vv->ov_fmt->depth;
 	int b_bpl = vv->ov_fb.fmt.bytesperline;
@@ -601,7 +602,7 @@
 		vdma1.pitch *= -1;
 	}
 		
-	vdma1.base_page = 0;
+	vdma1.base_page = sfmt->swap;
 	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
 
 	saa7146_write_out_dma(dev, 1, &vdma1);
@@ -657,7 +658,7 @@
 	struct saa7146_vv *vv = dev->vv_data;
 
 	saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
-	saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field);
+	saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);
 	saa7146_set_output_format(dev, vv->ov_fmt->trans);
 	saa7146_set_clipping_rect(fh);
 
@@ -727,7 +729,7 @@
 	vdma1.pitch		= (width*depth*2)/8;
 	}
 	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
-	vdma1.base_page		= buf->pt[0].dma | ME1;
+	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;
 	
 	if( 0 != vv->vflip ) {
 		vdma1.prot_addr	= buf->pt[0].offset;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/common/saa7146_i2c.c linux-2.6.8.1-patched/drivers/media/common/saa7146_i2c.c
--- xx-linux-2.6.8.1/drivers/media/common/saa7146_i2c.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/common/saa7146_i2c.c	2004-08-11 11:59:36.000000000 +0200
@@ -1,13 +1,6 @@
 #include <linux/version.h>
 #include <media/saa7146_vv.h>
 
-/* helper function */
-static void my_wait(struct saa7146_dev *dev, long ms)
-{
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout((((ms+10)/10)*HZ)/1000);
-}
-
 u32 saa7146_i2c_func(struct i2c_adapter *adapter)
 {
 //fm	DEB_I2C(("'%s'.\n", adapter->name));
@@ -136,12 +129,12 @@
 		/* set "ABORT-OPERATION"-bit (bit 7)*/
 		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		my_wait(dev,SAA7146_I2C_DELAY);
+		msleep(SAA7146_I2C_DELAY);
 
 		/* clear all error-bits pending; this is needed because p.123, note 1 */
 		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		my_wait(dev,SAA7146_I2C_DELAY);
+		msleep(SAA7146_I2C_DELAY);
  	}
 
 	/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
@@ -155,18 +148,18 @@
 		   after serious protocol errors caused by e.g. the SAA7740 */
 		saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		my_wait(dev,SAA7146_I2C_DELAY);
+		msleep(SAA7146_I2C_DELAY);
 
 		/* clear all error-bits pending */
 		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		my_wait(dev,SAA7146_I2C_DELAY);
+		msleep(SAA7146_I2C_DELAY);
 
 		/* the data sheet says it might be necessary to clear the status
 		   twice after an abort */
 		saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
 		saa7146_write(dev, MC2, (MASK_00 | MASK_16));
-		my_wait(dev,SAA7146_I2C_DELAY);
+		msleep(SAA7146_I2C_DELAY);
      	}
 
 	/* if any error is still present, a fatal error has occured ... */
@@ -243,7 +236,7 @@
 			if ((++trial < 20) && short_delay)
 				udelay(10);
 			else
-			my_wait(dev,1);
+			msleep(1);
 		}
 	}
 
@@ -345,7 +338,7 @@
 		}
 	        
 	        /* delay a bit before retrying */
-	        my_wait(dev, 10);
+	        msleep(10);
 		
 	} while (err != num && retries--);
 
@@ -400,7 +393,7 @@
 	.functionality	= saa7146_i2c_func,
 };
 
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate)
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
 {
 	DEB_EE(("bitrate: 0x%08x\n",bitrate));
 	
@@ -411,13 +404,11 @@
 	saa7146_i2c_reset(dev);
 
 	if( NULL != i2c_adapter ) {
-		memset(i2c_adapter,0,sizeof(struct i2c_adapter));
-		strcpy(i2c_adapter->name, dev->name);	
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 		i2c_adapter->data = dev;
 #else
+		BUG_ON(!i2c_adapter->class);
 		i2c_set_adapdata(i2c_adapter,dev);
-		i2c_adapter->class = class;
 #endif
 		i2c_adapter->algo	   = &saa7146_algo;
 		i2c_adapter->algo_data     = NULL;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/common/saa7146_video.c linux-2.6.8.1-patched/drivers/media/common/saa7146_video.c
--- xx-linux-2.6.8.1/drivers/media/common/saa7146_video.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/common/saa7146_video.c	2004-07-31 02:05:45.000000000 +0200
@@ -38,6 +38,13 @@
 		.depth		= 32,
 		.flags		= 0,
 	}, {
+		.name 		= "RGB-32 (R-G-B)",
+		.pixelformat	= V4L2_PIX_FMT_RGB32,
+		.trans 		= RGB32_COMPOSED,
+		.depth		= 32,
+		.flags		= 0,
+		.swap		= 0x2,
+	}, {
 		.name 		= "Greyscale-8",
 		.pixelformat	= V4L2_PIX_FMT_GREY,
 		.trans 		= Y8,
@@ -634,7 +641,7 @@
 		/* walk all pages, copy all page addresses to ptr1 */
 		for (i = 0; i < length; i++, list++) {
 			for (p = 0; p * 4096 < list->length; p++, ptr1++) {
-				*ptr1 = sg_dma_address(list) - list->offset;
+				*ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
 			}
 		}
 /*
diff -uraNwB xx-linux-2.6.8.1/include/media/saa7146.h linux-2.6.8.1-patched/include/media/saa7146.h
--- xx-linux-2.6.8.1/include/media/saa7146.h	2004-07-19 19:39:40.000000000 +0200
+++ linux-2.6.8.1-patched/include/media/saa7146.h	2004-06-21 18:52:14.000000000 +0200
@@ -154,7 +166,7 @@
 };
 
 /* from saa7146_i2c.c */
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, unsigned int class, u32 bitrate);
+int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
 int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num,  int retries);
 
 /* from saa7146_core.c */
diff -uraNwB xx-linux-2.6.8.1/include/media/saa7146_vv.h linux-2.6.8.1-patched/include/media/saa7146_vv.h
--- xx-linux-2.6.8.1/include/media/saa7146_vv.h	2004-08-23 09:35:40.000000000 +0200
+++ linux-2.6.8.1-patched/include/media/saa7146_vv.h	2004-07-31 02:05:47.000000000 +0200
@@ -35,6 +35,7 @@
 	u32	trans;
 	u8	depth;
 	u8	flags;
+	u8	swap;
 };
 
 struct saa7146_standard
@@ -188,8 +189,8 @@
 };
 
 /* from saa7146_fops.c */
-int saa7146_register_device(struct video_device *vid, struct saa7146_dev* dev, char *name, int type);
-int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev* dev);
+int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, char *name, int type);
+int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev);
 void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state);
 void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi);
 int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf);

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

* Re: [PATCH][2.6][2/14] documentation update
  2004-09-17 14:22 ` [PATCH][2.6][1/14] update saa7146 driver Michael Hunold
@ 2004-09-17 14:24   ` Michael Hunold
  2004-09-17 14:26     ` [PATCH][2.6][3/14] dvb-bt8xx and skystar2 driver update Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:24 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2: 02-DVB-documentation-update.diff --]
[-- Type: text/plain, Size: 43243 bytes --]

- [DVB] add udev.txt which describes how to use dvb and udev/sysfs
- [DVB] add Visionplus VisionDTV USB-Ter DVB-T adapter documentation
- [DVB] update TT USB DEC documentation
- [DVB] update various Kconfig entries

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

#diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/cards.txt linux-2.6.8.1-patched/Documentation/dvb/cards.txt
--- xx-linux-2.6.8.1/Documentation/dvb/cards.txt	2004-07-19 19:40:45.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/cards.txt	2004-06-21 00:53:32.000000000 +0200
@@ -49,7 +49,7 @@
   - "budget" cards (i.e. without hardware MPEG decoder):
     - Technotrend Budget / Hauppauge WinTV-Nova PCI Cards
     - SATELCO Multimedia PCI
-    - KNC1 DVB-S
+    - KNC1 DVB-S, Typhoon DVB-S, Terratec Cinergy 1200 DVB-S (no CI support)
     - Typhoon DVB-S budget
     - Fujitsu-Siemens Activy DVB-S budget card
 
diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/contributors.txt linux-2.6.8.1-patched/Documentation/dvb/contributors.txt
--- xx-linux-2.6.8.1/Documentation/dvb/contributors.txt	2004-07-19 19:40:45.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/contributors.txt	2004-05-02 18:30:56.000000000 +0200
@@ -69,6 +69,8 @@
 Kenneth Aafløy <ke-aa@frisurf.no>
   for adding support for Typhoon DVB-S budget card
 
+Ernst Peinlich <e.peinlich@inode.at>
+  for tuning/DiSEqC support for the DEC 3000-s
 
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/firmware.txt linux-2.6.8.1-patched/Documentation/dvb/firmware.txt
--- xx-linux-2.6.8.1/Documentation/dvb/firmware.txt	2004-08-23 09:34:29.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/firmware.txt	2004-07-20 22:52:19.000000000 +0200
@@ -2,7 +2,7 @@
 binary-only firmware.
 
 The DVB drivers will be converted to use the request_firmware()
-hotplug interface (see Documentation/firmware_class/).
+hotplug interface (see linux/Documentation/firmware_class/).
 (CONFIG_FW_LOADER)
 
 The firmware can be loaded automatically via the hotplug manager
@@ -12,18 +12,45 @@
 to load their firmwares, so here's just a short list of the
 current state:
 
-- dvb-ttpci: driver uses firmware hotplug interface
+Drivers using the firmware hotplug interface:
+- dvb-ttpci
+- tda1004x:
+
+Proprietary solutions which need to be converted:
 - ttusb-budget: firmware is compiled in (dvb-ttusb-dspbootcode.h)
 - sp887x: firmware is compiled in (sp887x_firm.h)
 - alps_tdlb7: firmware is loaded from path specified by
 		"mcfile" module parameter; the binary must be
 		extracted from the Windows driver (Sc_main.mc).
-- tda1004x: firmware is loaded from path specified in
-		DVB_TDA1004X_FIRMWARE_FILE kernel config
-		variable (default /usr/lib/hotplug/firmware/tda1004x.bin); the
-		firmware binary must be extracted from the windows
-		driver
 - ttusb-dec: see "ttusb-dec.txt" for details
+- vp7041: see vp7041.txt for more information
+
+0) Getting a usable firmware file 
+
+- For the dvb-ttpci driver/av7110 card you can download the firmware files from
+http://linuxtv.org/download/dvb/firmware/
+
+Please note that in case of the dvb-ttpci driver this is *not* the "Root"
+file you probably know from the 2.4 DVB releases driver.
+
+The ttpci-firmware utility from linuxtv.org CVS can be used to
+convert Dpram and Root files into a usable firmware image.
+See dvb-kerrnel/scripts/ in http://linuxtv.org/cvs/.
+
+> wget http://www.linuxtv.org/download/dvb/firmware/dvb-ttpci-01.fw-261c
+> mv dvb-ttpci-01.fw-261c /usr/lib/hotplug/firmware/dvb-ttpci-01.fw
+
+- The tda1004x driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
+windows driver. Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
+added reasonably painlessly.
+
+Windows driver URL: http://www.technotrend.de/
+
+> wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
+> unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
+
+Rename "ttlcdacc.dll" to "tda1004x.bin" -- that's currently the default name
+for the firmware file.
 
 1) Automatic firmware loading
 
@@ -44,8 +71,23 @@
   driver/firmware internal API changes (so users are free to install the
   latest firmware compatible with the driver).
 
+Currently the drivers mentionend above support firmware upload through the
+hotplug manager. If you have such a card, a simple "modprobe" of the driver
+will take care of everything, ie.
+
+> modprobe dvb-ttpci
+or
+> modprobe tda1004x
+
+If you have the hotplug firmware scripts installed, both drivers will ask the hotplug
+daemon for their default firmware. If the scripts are there, but the firmware cannot
+be found, an error message will be printed immediately. Make sure that the firmware
+are in a path where the hotplug manager can find them.
+
+Please note that the default firmware name of the tda1004x doesn't follow the
+naming conventions stated above. It's still called "tda1004x.bin".
+
 2) Manually loading the firmware into a driver
-   (currently only the dvb-ttpci / av7110 driver supports this)
    
 Step a) Mount sysfs-filesystem.
 
@@ -73,29 +115,17 @@
 
 > echo "180" > /sys/class/firmware/timeout
 
-Step c) Getting a usable firmware file for the dvb-ttpci driver/av7110 card.
-
-You can download the firmware files from
-http://linuxtv.org/download/dvb/
-
-Please note that in case of the dvb-ttpci driver this is *not* the "Root"
-file you probably know from the 2.4 DVB releases driver.
-
-The ttpci-firmware utility from linuxtv.org CVS can be used to
-convert Dpram and Root files into a usable firmware image.
-See dvb-kerrnel/scripts/ in http://linuxtv.org/cvs/.
-
-> wget http://www.linuxtv.org/download/dvb/dvb-ttpci-01.fw
-gets you the version 01 of the firmware fot the ttpci driver.
-
-Step d) Loading the dvb-ttpci driver and loading the firmware
+Step c) Loading the driver and uploading the firmware manually
 
 "modprobe" will take care that every needed module will be loaded
-automatically (except the frontend driver)
+automatically 
 
 > modprobe dvb-ttpci
+or
+> modprobe tda1004x
 
-The "modprobe" process will hang until
+If you don't have the hotplug subsystem running, the "modprobe" process will
+now hang until
 a) you upload the firmware or
 b) the timeout occurs.
 
@@ -107,14 +137,24 @@
 drwxr-xr-x    2 root     root            0 Jul 29 11:00 0000:03:05.0
 -rw-r--r--    1 root     root            0 Jul 29 10:41 timeout
 
-"0000:03:05.0" is the id for my dvb-c card. It depends on the pci slot,
-so it changes if you plug the card to different slots.
+"0000:03:05.0" is the id of the device that needs an firmware upload.
+
+In this example, this is the pci id of my dvb-c card. It depends on the pci slot,
+so it changes if you plug the card to different slots. For the tda1004x,
+the id will be an artifical number consisting on the i2c bus the device is on.
 
 You can upload the firmware like that:
 
 > export DEVDIR=/sys/class/firmware/0000\:03\:05.0
 > echo 1 > $DEVDIR/loading
+
+For the dvb-ttpci card:
 > cat dvb-ttpci-01.fw > $DEVDIR/data
+
+For the tda1004x frontend, the path above might be different, but the other things
+are the same:
+> cat tda1004x.bin > $DEVDIR/data
+
 > echo 0 > $DEVDIR/loading
 
 That's it. The driver should be up and running now.
diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/readme.txt linux-2.6.8.1-patched/Documentation/dvb/readme.txt
--- xx-linux-2.6.8.1/Documentation/dvb/readme.txt	2004-07-19 19:40:45.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/readme.txt	2004-08-06 13:23:24.000000000 +0200
@@ -41,4 +41,11 @@
 various bt8xx based "budget" DVB cards
 (Nebula, Pinnacle PCTV, Twinhan DST)
 
+"vp7041.txt"
+contains detailed informations about the
+Visionplus VisionDTV USB-Ter DVB-T adapter.
+
+"udev.txt"
+how to get DVB and udev up and running.
+
 Good luck and have fun!
diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/ttusb-dec.txt linux-2.6.8.1-patched/Documentation/dvb/ttusb-dec.txt
--- xx-linux-2.6.8.1/Documentation/dvb/ttusb-dec.txt	2004-08-23 09:34:29.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/ttusb-dec.txt	2004-05-02 18:30:56.000000000 +0200
@@ -6,6 +6,8 @@
 
 Supported:
 	DEC2000-t
+	DEC2450-t
+	DEC3000-s
 	Linux Kernels 2.4 and 2.6
 	Video Streaming
 	Audio Streaming
@@ -13,14 +15,11 @@
 	Channel Zapping
 	Hotplug firmware loader under 2.6 kernels
 
-In Progress:
-	DEC2540-t
-	DEC3000-s
-
 To Do:
 	Tuner status information
 	DVB network interface
 	Streaming video PC->DEC
+	Conax support for 2450-t
 
 Getting the Firmware
 --------------------
@@ -57,7 +56,7 @@
 Hotplug Firmware Loading for 2.6 kernels
 ----------------------------------------
 For 2.6 kernels the firmware is loaded at the point that the driver module is
-loaded.  See Documentation/dvb/firmware.txt for more information.
+loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
 mv STB_PC_T.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2000t.fw
 mv STB_PC_X.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2540t.fw
diff -uraNwB xx-linux-2.6.8.1/Documentation/dvb/udev.txt linux-2.6.8.1-patched/Documentation/dvb/udev.txt
--- xx-linux-2.6.8.1/Documentation/dvb/udev.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/Documentation/dvb/udev.txt	2004-08-11 11:44:45.000000000 +0200
@@ -0,0 +1,46 @@
+The DVB subsystem currently registers to the sysfs subsystem using the
+"class_simple" interface.
+
+This means that only the basic informations like module loading parameters
+are presented through sysfs. Other things that might be interesting are
+currently *not* available.
+
+Nevertheless it's now possible to add proper udev rules so that the
+DVB device nodes are created automatically.
+
+We assume that you have udev already up and running and that have been
+creating the DVB device nodes manually up to now due to the missing sysfs
+support.
+
+0. Don't forget to disable your current method of creating the
+device nodes manually.
+
+1. Unfortunately, you'll need a helper script to transform the kernel
+sysfs device name into the well known dvb adapter / device naming scheme.
+The script should be called "dvb.sh" and should be placed into a script
+dir where udev can execute it, most likely /etc/udev/scripts/
+
+So, create a new file /etc/udev/scripts/dvb.sh and add the following:
+------------------------------schnipp------------------------------------------------
+#!/bin/sh
+/bin/echo $1 | /bin/sed -e 's,dvb\([0-9]\)\.\([^0-9]*\)\([0-9]\),dvb/adapter\1/\2\3,'
+------------------------------schnipp------------------------------------------------
+
+Don't forget to make the script executable with "chmod".
+
+1. You need to create a proper udev rule that will create the device nodes
+like you know them. All real distributions out there scan the /etc/udev/rules.d
+directory for rule files. The main udev configuration file /etc/udev/udev.conf
+will tell you the directory where the rules are, most likely it's /etc/udev/rules.d/
+
+Create a new rule file in that directory called "dvb.rule" and add the following line:
+------------------------------schnipp------------------------------------------------
+KERNEL="dvb*", PROGRAM="/etc/udev/scripts/dvb.sh %k", NAME="%c"
+------------------------------schnipp------------------------------------------------
+
+If you want more control over the device nodes (for example a special group membership)
+have a look at "man udev".
+
+For every device that registers to the sysfs subsystem with a "dvb" prefix,
+the helper script /etc/udev/scripts/dvb.sh is invoked, which will then
+create the proper device node in your /dev/ directory.
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/avermedia.txt linux-2.6.8.1-patched/Documentation/dvb/avermedia.txt
--- linux-2.6.8.1-dvb1/Documentation/dvb/avermedia.txt	2004-09-15 15:34:48.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/avermedia.txt	2004-09-01 12:18:59.000000000 +0200
@@ -6,7 +6,6 @@
    Assumptions and Introduction
    The Avermedia DVB-T
    Getting the card going
-   Getting the Firmware
    Receiving DVB-T in Australia
    Known Limitations
    Further Update
@@ -149,28 +148,9 @@
    to start accessing the card with utilities such as scan, tzap,
    dvbstream etc.
 
-   The  current version of the frontend module sp887x.o, contains
-   no firmware drivers?, so the first time you open it with a DVB
-   utility  the driver will try to download some initial firmware
-   to  the card. You will need to download this firmware from the
-   web,  or  copy  it from an installation of the Windows drivers
-   that probably came with your card, before you can use it.
-
-   The  default  Linux  filesystem  location for this firmware is
-   /usr/lib/hotplug/firmware/sc_main.mc .
-     _________________________________________________________
-
-Getting the Firmware
-
-   As the firmware for the card is no longer contained within the
-   driver,  it  is  necessary  to  extract  it  from  the windows
-   drivers.
-
-   The  Windows  drivers  for the Avermedia DVB-T can be obtained
-   from: http://babyurl.com/H3U970 and you can get an application
-   to extract the firmware from:
-   http://www.kyz.uklinux.net/cabextract.php.
-     _________________________________________________________
+   The frontend module sp887x.o, requires an external   firmware.
+   Please use  the  command "get_dvb_firmware sp887x" to download
+   it. Then copy it to /usr/lib/hotplug/firmware.
 
 Receiving DVB-T in Australia
 
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/cards.txt linux-2.6.8.1-patched/Documentation/dvb/cards.txt
--- linux-2.6.8.1-dvb1/Documentation/dvb/cards.txt	2004-09-17 12:27:25.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/cards.txt	2004-09-15 10:26:44.000000000 +0200
@@ -38,6 +38,7 @@
                		  Comtech DVBT-6k07 (SP5730 PLL)
                		  (NxtWave Communications NXT6000 demodulator)
    - sp887x		: Microtune 7202D
+   - dib3000mb	: DiBcom 3000-MB Frontend
   DVB-S/C/T:
    - dst		: TwinHan DST Frontend
 
@@ -66,4 +67,9 @@
   - Nova USB
   - DEC 2000-T, 3000-S, 2540-T
 
+o DiBcom DVB-T USB based devices:
+  - Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device
+  - KWorld V-Stream XPERT DTV - DVB-T USB
+  - HAMA DVB-T USB device
+
 o Experimental support for the analog module of the Siemens DVB-C PCI card
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/firmware.txt linux-2.6.8.1-patched/Documentation/dvb/firmware.txt
--- linux-2.6.8.1-dvb1/Documentation/dvb/firmware.txt	2004-09-17 12:27:25.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/firmware.txt	2004-09-15 15:36:15.000000000 +0200
@@ -2,7 +2,7 @@
 binary-only firmware.
 
 The DVB drivers will be converted to use the request_firmware()
-hotplug interface (see linux/Documentation/firmware_class/).
+hotplug interface (see Documentation/firmware_class/).
 (CONFIG_FW_LOADER)
 
 The firmware can be loaded automatically via the hotplug manager
@@ -12,45 +12,18 @@
 to load their firmwares, so here's just a short list of the
 current state:
 
-Drivers using the firmware hotplug interface:
-- dvb-ttpci
-- tda1004x:
-
-Proprietary solutions which need to be converted:
+- dvb-ttpci: driver uses firmware hotplug interface
 - ttusb-budget: firmware is compiled in (dvb-ttusb-dspbootcode.h)
 - sp887x: firmware is compiled in (sp887x_firm.h)
 - alps_tdlb7: firmware is loaded from path specified by
 		"mcfile" module parameter; the binary must be
 		extracted from the Windows driver (Sc_main.mc).
+- tda1004x: firmware is loaded from path specified in
+		DVB_TDA1004X_FIRMWARE_FILE kernel config
+		variable (default /usr/lib/hotplug/firmware/tda1004x.bin); the
+		firmware binary must be extracted from the windows
+		driver
 - ttusb-dec: see "ttusb-dec.txt" for details
-- vp7041: see vp7041.txt for more information
-
-0) Getting a usable firmware file 
-
-- For the dvb-ttpci driver/av7110 card you can download the firmware files from
-http://linuxtv.org/download/dvb/firmware/
-
-Please note that in case of the dvb-ttpci driver this is *not* the "Root"
-file you probably know from the 2.4 DVB releases driver.
-
-The ttpci-firmware utility from linuxtv.org CVS can be used to
-convert Dpram and Root files into a usable firmware image.
-See dvb-kerrnel/scripts/ in http://linuxtv.org/cvs/.
-
-> wget http://www.linuxtv.org/download/dvb/firmware/dvb-ttpci-01.fw-261c
-> mv dvb-ttpci-01.fw-261c /usr/lib/hotplug/firmware/dvb-ttpci-01.fw
-
-- The tda1004x driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
-windows driver. Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
-added reasonably painlessly.
-
-Windows driver URL: http://www.technotrend.de/
-
-> wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
-> unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
-
-Rename "ttlcdacc.dll" to "tda1004x.bin" -- that's currently the default name
-for the firmware file.
 
 1) Automatic firmware loading
 
@@ -71,23 +44,8 @@
   driver/firmware internal API changes (so users are free to install the
   latest firmware compatible with the driver).
 
-Currently the drivers mentionend above support firmware upload through the
-hotplug manager. If you have such a card, a simple "modprobe" of the driver
-will take care of everything, ie.
-
-> modprobe dvb-ttpci
-or
-> modprobe tda1004x
-
-If you have the hotplug firmware scripts installed, both drivers will ask the hotplug
-daemon for their default firmware. If the scripts are there, but the firmware cannot
-be found, an error message will be printed immediately. Make sure that the firmware
-are in a path where the hotplug manager can find them.
-
-Please note that the default firmware name of the tda1004x doesn't follow the
-naming conventions stated above. It's still called "tda1004x.bin".
-
 2) Manually loading the firmware into a driver
+   (currently only the dvb-ttpci / av7110 driver supports this)
    
 Step a) Mount sysfs-filesystem.
 
@@ -115,17 +73,29 @@
 
 > echo "180" > /sys/class/firmware/timeout
 
-Step c) Loading the driver and uploading the firmware manually
+Step c) Getting a usable firmware file for the dvb-ttpci driver/av7110 card.
+
+You can download the firmware files from
+http://linuxtv.org/download/dvb/
+
+Please note that in case of the dvb-ttpci driver this is *not* the "Root"
+file you probably know from the 2.4 DVB releases driver.
+
+The ttpci-firmware utility from linuxtv.org CVS can be used to
+convert Dpram and Root files into a usable firmware image.
+See dvb-kerrnel/scripts/ in http://linuxtv.org/cvs/.
+
+> wget http://www.linuxtv.org/download/dvb/dvb-ttpci-01.fw
+gets you the version 01 of the firmware fot the ttpci driver.
+
+Step d) Loading the dvb-ttpci driver and loading the firmware
 
 "modprobe" will take care that every needed module will be loaded
-automatically 
+automatically (except the frontend driver)
 
 > modprobe dvb-ttpci
-or
-> modprobe tda1004x
 
-If you don't have the hotplug subsystem running, the "modprobe" process will
-now hang until
+The "modprobe" process will hang until
 a) you upload the firmware or
 b) the timeout occurs.
 
@@ -137,24 +107,14 @@
 drwxr-xr-x    2 root     root            0 Jul 29 11:00 0000:03:05.0
 -rw-r--r--    1 root     root            0 Jul 29 10:41 timeout
 
-"0000:03:05.0" is the id of the device that needs an firmware upload.
-
-In this example, this is the pci id of my dvb-c card. It depends on the pci slot,
-so it changes if you plug the card to different slots. For the tda1004x,
-the id will be an artifical number consisting on the i2c bus the device is on.
+"0000:03:05.0" is the id for my dvb-c card. It depends on the pci slot,
+so it changes if you plug the card to different slots.
 
 You can upload the firmware like that:
 
 > export DEVDIR=/sys/class/firmware/0000\:03\:05.0
 > echo 1 > $DEVDIR/loading
-
-For the dvb-ttpci card:
 > cat dvb-ttpci-01.fw > $DEVDIR/data
-
-For the tda1004x frontend, the path above might be different, but the other things
-are the same:
-> cat tda1004x.bin > $DEVDIR/data
-
 > echo 0 > $DEVDIR/loading
 
 That's it. The driver should be up and running now.
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/get_dvb_firmware linux-2.6.8.1-patched/Documentation/dvb/get_dvb_firmware
--- linux-2.6.8.1-dvb1/Documentation/dvb/get_dvb_firmware	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/Documentation/dvb/get_dvb_firmware	2004-09-15 10:26:44.000000000 +0200
@@ -0,0 +1,339 @@
+#!/usr/bin/perl
+#     DVB firmware extractor
+#  
+#     (c) 2004 Andrew de Quincey
+#  
+#     This program is free software; you can redistribute it and/or modify
+#       it under the terms of the GNU General Public License as published by
+#       the Free Software Foundation; either version 2 of the License, or
+#       (at your option) any later version.
+#  
+#     This program is distributed in the hope that it will be useful,
+#       but WITHOUT ANY WARRANTY; without even the implied warranty of
+#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  
+#     GNU General Public License for more details.
+#  
+#     You should have received a copy of the GNU General Public License
+#       along with this program; if not, write to the Free Software
+#       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use File::Temp qw/ tempdir /;
+use IO::Handle;
+
+@components = ( "alps_tdlb7", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" );
+
+# Check args
+syntax() if (scalar(@ARGV) != 1);
+$cid = $ARGV[0];
+
+# Do it!
+for($i=0; $i < scalar(@components); $i++) {
+    if ($cid eq $components[$i]) {
+	$outfile = eval($cid);
+	die $@ if $@;
+	print STDERR "Firmware $outfile extracted successfully. Now copy it to /usr/lib/hotplug/firmware/.\n";
+	exit(0);
+    }
+}
+
+# If we get here, it wasn't found
+print STDERR "Unknown component \"$cid\"\n";
+syntax();
+
+
+
+
+# ---------------------------------------------------------------
+# Firmware-specific extraction subroutines
+
+sub alps_tdlb7 {
+    my $sourcefile = "tt_Premium_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "53970ec17a538945a6d8cb608a7b3899";
+    my $outfile = "dvb-fe-tdlb7.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $hash);
+    copy("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $outfile);
+    
+    $outfile;
+}
+
+sub sp887x {
+    my $sourcefile = "Dvbt1.3.57.6.zip";
+    my $url = "http://www.avermedia.com/software/$sourcefile";
+    my $cabfile = "DVBT Net  Ver1.3.57.6/disk1/data1.cab";
+    my $hash = "237938d53a7f834c05c42b894ca68ac3";
+    my $outfile = "dvb-fe-sp887x.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+    
+    checkstandard();
+    checkunshield();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    unshield("$tmpdir/$cabfile", $tmpdir);
+    verify("$tmpdir/sc_main.mc", $hash);
+    copy("$tmpdir/sc_main.mc", $outfile);
+    
+    $outfile;
+}
+
+sub tda10045 {
+    my $sourcefile = "tt_budget_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "2105fd5bf37842fbcdfa4bfd58f3594a";
+    my $outfile = "dvb-fe-tda10045.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();    
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x37ef9, 30555, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+    
+    $outfile;
+}
+
+sub tda10046 {
+    my $sourcefile = "tt_budget_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "a25b579e37109af60f4a36c37893957c";
+    my $outfile = "dvb-fe-tda10046.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24479, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+    
+    $outfile;
+}
+
+sub av7110 {
+    my $sourcefile = "dvb-ttpci-01.fw-261c";
+    my $url = "http://www.linuxtv.org/download/dvb/firmware/$sourcefile";
+    my $hash = "7b263de6b0b92d2347319c65adc7d4fb";
+    my $outfile = "dvb-ttpci-01.fw";
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    verify($sourcefile, $hash);
+    copy($sourcefile, $outfile);
+    
+    $outfile;
+}
+
+sub dec2000t {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "bd86f458cee4a8f0a8ce2d20c66215a9";
+    my $outfile = "dvb-ttusb-dec-2000t.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $outfile);
+
+    $outfile;
+}
+
+sub dec2540t {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "53e58f4f5b5c2930beee74a7681fed92";
+    my $outfile = "dvb-ttusb-dec-2540t.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $outfile);
+
+    $outfile;
+}
+
+sub dec3000s {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "b013ececea83f4d6d8d2a29ac7c1b448";
+    my $outfile = "dvb-ttusb-dec-3000s.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $outfile);
+
+    $outfile;
+}
+
+sub vp7041 {
+    my $sourcefile = "2.422.zip";
+    my $url = "http://www.twinhan.com/files/driver/USB-Ter/$sourcefile";
+    my $hash = "e88c9372d1f66609a3e7b072c53fbcfe";
+    my $outfile = "dvb-vp7041-2.422.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+    
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 12503, 3036, "$tmpdir/fwtmp1");
+    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 2207, 10274, "$tmpdir/fwtmp2");
+
+    my $CMD = "\000\001\000\222\177\000";
+    my $PAD = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
+    my ($FW);
+    open $FW, ">$tmpdir/fwtmp3";
+    print $FW "$CMD\001$PAD";
+    print $FW "$CMD\001$PAD";
+    appendfile($FW, "$tmpdir/fwtmp1");
+    print $FW "$CMD\000$PAD";
+    print $FW "$CMD\001$PAD";
+    appendfile($FW, "$tmpdir/fwtmp2");
+    print $FW "$CMD\001$PAD";
+    print $FW "$CMD\000$PAD";
+    close($FW);
+
+    verify("$tmpdir/fwtmp3", $hash);
+    copy("$tmpdir/fwtmp3", $outfile);
+
+    $outfile;
+}
+
+sub dibusb {
+	my $url = "http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain";
+	my $outfile = "dvb-dibusb-5.0.0.11.fw";
+	my $hash = "fa490295a527360ca16dcdf3224ca243";
+
+	checkstandard();
+
+	wgetfile($outfile, $url);
+	verify($outfile,$hash);
+
+	$outfile;
+}
+
+# ---------------------------------------------------------------
+# Utilities
+
+sub checkstandard {
+    if (system("which unzip > /dev/null 2>&1")) {
+	die "This firmware requires the unzip command - see ftp://ftp.info-zip.org/pub/infozip/UnZip.html\n";
+    }
+    if (system("which md5sum > /dev/null 2>&1")) {
+	die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n";
+    }
+    if (system("which wget > /dev/null 2>&1")) {
+	die "This firmware requires the wget command - see http://wget.sunsite.dk/\n";
+    }
+}
+
+sub checkunshield {
+    if (system("which unshield > /dev/null 2>&1")) {
+	die "This firmware requires the unshield command - see http://sourceforge.net/projects/synce/\n";
+    }
+}
+
+sub wgetfile {
+    my ($sourcefile, $url) = @_;
+
+    if (! -f $sourcefile) {
+	system("wget -O \"$sourcefile\" \"$url\"") and die "wget failed - unable to download firmware";
+    }
+}
+
+sub unzip {
+    my ($sourcefile, $todir) = @_;
+
+    $status = system("unzip -q -o -d \"$todir\" \"$sourcefile\" 2>/dev/null" );
+    if ((($status >> 8) > 2) || (($status & 0xff) != 0)) {
+	die ("unzip failed - unable to extract firmware");
+    }
+}
+
+sub unshield {
+    my ($sourcefile, $todir) = @_;
+
+    system("unshield -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
+}
+
+sub verify {
+    my ($filename, $hash) = @_;
+    my ($testhash);
+
+    open(CMD, "md5sum \"$filename\"|");
+    $testhash = <CMD>;
+    $testhash =~ /([a-zA-Z0-9]*)/;
+    $testhash = $1;
+    close CMD;
+    die "Hash of extracted file does not match!\n" if ($testhash ne $hash);
+}
+
+sub copy {
+    my ($from, $to) = @_;
+    
+    system("cp -f \"$from\" \"$to\"") and die ("cp failed");
+}
+
+sub extract {
+    my ($infile, $offset, $length, $outfile) = @_;
+    my ($chunklength, $buf, $rcount);
+    
+    open INFILE, "<$infile";
+    open OUTFILE, ">$outfile";
+    sysseek(INFILE, $offset, SEEK_SET);
+    while($length > 0) {
+	# Calc chunk size
+	$chunklength = 2048;
+	$chunklength = $length if ($chunklength > $length);
+	
+	$rcount = sysread(INFILE, $buf, $chunklength);
+	die "Ran out of data\n" if ($rcount != $chunklength);
+	syswrite(OUTFILE, $buf);
+	$length -= $rcount;
+    }
+    close INFILE;
+    close OUTFILE;
+}
+
+sub appendfile {
+    my ($FH, $infile) = @_;
+    my ($buf);
+    
+    open INFILE, "<$infile";
+    while(1) {
+	$rcount = sysread(INFILE, $buf, 2048);
+	last if ($rcount == 0);
+	print $FH $buf;
+    }
+    close(INFILE);
+}
+
+sub syntax() {
+    print STDERR "syntax: get_dvb_firmware <component>\n";
+    print STDERR "Supported components:\n";
+    for($i=0; $i < scalar(@components); $i++) {
+	print STDERR "\t" . $components[$i] . "\n";
+    }
+    exit(1);
+}
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/README.dibusb linux-2.6.8.1-patched/Documentation/dvb/README.dibusb
--- linux-2.6.8.1-dvb1/Documentation/dvb/README.dibusb	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/Documentation/dvb/README.dibusb	2004-09-17 12:25:15.000000000 +0200
@@ -0,0 +1,152 @@
+Documentation for dib3000mb frontend driver and dibusb device driver
+
+The drivers should work with 
+
+- Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device (VP7041)
+	http://www.twinhan.com/visiontv-2_4.htm
+	
+- CTS Portable (Chinese Television System)
+	http://www.2cts.tv/ctsportable/
+
+- KWorld V-Stream XPERT DTV - DVB-T USB
+	http://www.kworld.com.tw/asp/pindex.asp?id=4&pid=13
+
+- HAMA DVB-T USB device
+	http://www.hama.de/portal/articleId*110620/action*2598
+ 
+- DiBcom USB DVB-T reference device
+
+- Ultima Electronic/Artec T1 USB TVBOX
+	http://www.arteceuro.com/products-tvbox.html
+
+
+Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de), 
+
+both drivers based on GPL code, which has
+
+Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation, version 2.
+
+
+NEWS:
+  2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
+               to Christian Motschke for reporting
+  2004-09-05 - released the dibusb device and dib3000mb-frontend driver
+
+  (old news for vp7041.c)
+  2004-07-15 - found out, by accident, that the device has a TUA6010XS for 
+               frequency generator
+  2004-07-12 - figured out, that the driver should also work with the
+               CTS Portable (Chinese Television System)
+  2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working 
+               properly with firmware extracted from 2.422
+			 - #if for 2.6.4 (dvb), compile issue
+			 - changed firmware handling, see vp7041.txt sec 1.1
+  2004-07-02 - some tuner modifications, v0.1, cleanups, first public
+  2004-06-28 - now using the dvb_dmx_swfilter_packets, everything 
+               runs fine now
+  2004-06-27 - able to watch and switching channels (pre-alpha)
+             - no section filtering yet
+  2004-06-06 - first TS received, but kernel oops :/
+  2004-05-14 - firmware loader is working
+  2004-05-11 - start writing the driver
+
+1. How to use?
+NOTE: This driver was developed using Linux 2.6.6., 
+it is working with 2.6.7, 2.6.8.1.
+
+Linux 2.4.x support is not planned, but patches are very welcome.
+
+NOTE: I'm using Debian testing, so the following explaination (especially
+the hotplug-path) needn't match your system, but probably it will :).
+
+1.1. Firmware
+
+The USB driver needs to download a firmware to start working.
+
+You can either use "get_dvb_firmware dibusb" to download the firmware or you
+can get it directly via 
+
+http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain
+
+1.2. Compiling
+
+Since the driver is in the linux kernel, activating the driver in
+your favorite config-environment should sufficient. I recommend
+to compile the driver as module. Hotplug does the rest.
+
+1.3. Loading the drivers
+
+Hotplug is able to load the driver, when it is needed (because you plugged
+in the device).
+
+If you want to enable debug output, you have to load the driver manually.
+
+modprobe dvb-dibusb debug=1 
+modprobe dib3000mb debug=1
+
+should do the trick.
+
+When the driver is loaded successfully, the firmware file was in 
+the right place and the device is connected, the "Power"-LED should be
+turned on.
+
+At this point you should be able to start a dvb-capable application. For myself
+I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
+as a slave device in vdr, was not working for me. Some work has to be done 
+(patches and comments are very welcome).
+
+2. Known problems and bugs
+
+TODO: 
+- add some additional URBs for USB data transfer
+- due a firmware problem i2c writes during mpeg transfers destroy the stream
+  no i2c writes during streaming, interrupt streaming, when adding another pid
+
+2.1. Adding new devices 
+
+It is not possible to determine the range of devices based on the DiBcom 
+reference design. This is because the reference design of DiBcom can be sold
+to third persons, without telling DiBcom (so done with the Twinhan VP7041 and 
+the HAMA device).
+
+When you think you have a device like this and the driver does not recognizes it,
+please send the ****load.inf and the ****cap.inf of the Windows driver to me.
+
+Sometimes the Vendor or Product ID is identical to the ones of Twinhan, even 
+though it is not a Twinhan device (e.g. HAMA), then please send me the name 
+of the device. I will add it to this list in order to make this clear to 
+others.
+
+If you are familar with C you can also add the VID and PID of the device to 
+the dvb-dibusb.[hc]-files and create a patch and send it over to me or to 
+the linux-dvb mailing list, _after_ you have tried compiling and modprobing
+it.
+
+2.2. Comments
+  
+Patches, comments and suggestions are very very welcome
+
+3. Acknowledgements
+	Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for 
+	providing specs, code and help, on which the dvb-dibusb and dib3000mb are 
+	based.
+  
+   Alex Woods for frequently answering question about usb and dvb
+    stuff, a big thank you
+
+   Bernd Wagner for helping with huge bug reports and discussions.
+   
+   Some guys on the linux-dvb mailing list for encouraging me
+   
+   Peter Schildmann >peter.schildmann-nospam-at-web.de< for his 
+    user-level firmware loader, which saves a lot of time 
+    (when writing the vp7041 driver)
+
+   Ulf Hermenau for helping me out with traditional chinese.
+   
+   André Smoktun and Christian Frömmel for supporting me with
+    hardware and listening to my problems very patient
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/readme.txt linux-2.6.8.1-patched/Documentation/dvb/readme.txt
--- linux-2.6.8.1-dvb1/Documentation/dvb/readme.txt	2004-09-17 12:27:25.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/readme.txt	2004-09-01 12:19:00.000000000 +0200
@@ -28,9 +28,9 @@
 "faq.txt"
 contains frequently asked questions and their answers.
 
-"firmware.txt" 
-contains informations for required external firmware
-files and where to get them.
+"get_dvb_firmware"
+script to download and extract firmware for those devices
+that require it.
 
 "ttusb-dec.txt"
 contains detailed informations about the
diff -uraNwB linux-2.6.8.1-dvb1/Documentation/dvb/ttusb-dec.txt linux-2.6.8.1-patched/Documentation/dvb/ttusb-dec.txt
--- linux-2.6.8.1-dvb1/Documentation/dvb/ttusb-dec.txt	2004-09-17 12:27:25.000000000 +0200
+++ linux-2.6.8.1-patched/Documentation/dvb/ttusb-dec.txt	2004-09-01 12:19:00.000000000 +0200
@@ -23,34 +23,17 @@
 
 Getting the Firmware
 --------------------
-The firmware can be found in the software update zip files on this page:
-http://www.hauppauge.de/sw_dec.htm
-
-The firmwares are named as follows:
-DEC2000-t:	STB_PC_T.bin
-DEC2540-t:	STB_PC_X.bin
-DEC3000-s:	STB_PC_S.bin
-
-Note that firmwares since version 2.16 beta2 for the DEC2000-t give the device
-the USB ID of the DEC3000-s.  The driver copes with this.
-
-Instructions follow for retrieving version 2.16 of the firmware:
-
-wget http://hauppauge.lightpath.net/de/dec216.exe
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_T.bin
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_X.bin
-unzip -j dec216.exe software/OEM/STB/App/Boot/STB_PC_S.bin
+To download the firmware, use the following commands:
+"get_dvb_firmware dec2000t"
+"get_dvb_firmware dec2540t"
+"get_dvb_firmware dec3000s"
 
 
 Compilation Notes for 2.4 kernels
 ---------------------------------
 For 2.4 kernels the firmware for the DECs is compiled into the driver itself.
-The firmwares are expected to be in the build-2.4 directory at compilation
-time.
 
-mv STB_PC_T.bin build-2.4/dvb-ttusb-dec-2000t.fw
-mv STB_PC_X.bin build-2.4/dvb-ttusb-dec-2540t.fw
-mv STB_PC_S.bin build-2.4/dvb-ttusb-dec-3000s.fw
+Copy the three files downloaded above into the build-2.4 directory.
 
 
 Hotplug Firmware Loading for 2.6 kernels
@@ -58,6 +41,4 @@
 For 2.6 kernels the firmware is loaded at the point that the driver module is
 loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
-mv STB_PC_T.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2000t.fw
-mv STB_PC_X.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-2540t.fw
-mv STB_PC_S.bin /usr/lib/hotplug/firmware/dvb-ttusb-dec-3000s.fw
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/Kconfig
--- linux-2.6.8.1-dvb1/drivers/media/dvb/Kconfig	2004-09-15 15:34:22.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/Kconfig	2004-09-15 10:26:44.000000000 +0200
@@ -12,20 +12,11 @@
 	  own a DVB adapter and want to use it or if you compile Linux for 
 	  a digital SetTopBox.
 
-	  API specs and user tools are available from
-	  <http://www.linuxtv.org/>. 
+	  API specs and user tools are available from <http://www.linuxtv.org/>.
 
 	  Please report problems regarding this driver to the LinuxDVB 
 	  mailing list.
 
-	  You might want add the following lines to your /etc/modules.conf:
-	  	
-	  	alias char-major-250 dvb
-	  	alias dvb dvb-ttpci
-	  	below dvb-ttpci alps_bsru6 alps_bsrv2 \
-	  			grundig_29504-401 grundig_29504-491 \
-	  			ves1820
-
 	  If unsure say N.
 
 source "drivers/media/dvb/dvb-core/Kconfig"
@@ -40,6 +31,7 @@
 	depends on DVB_CORE && USB
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
+source "drivers/media/dvb/dibusb/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
 	depends on DVB_CORE && PCI
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-dec/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/Kconfig
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-dec/Kconfig	2004-09-15 15:34:22.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/Kconfig	2004-09-01 12:19:01.000000000 +0200
@@ -12,8 +12,10 @@
 	  only compressed MPEG data over the USB bus, so you need
 	  an external software decoder to watch TV on your computer.	  
 
-	  The DEC devices require firmware in order to boot into a mode in
-	  which they are slaves to the PC.  See
-	  <file:Documentation/dvb/ttusb-dec.txt> for details.
+          This driver needs external firmware. Please use the commands
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",	
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+          download/extract them, and then copy them to /usr/lib/hotplug/firmware.
 
 	  Say Y if you own such a device and want to use it.
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/ttpci/Kconfig
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/Kconfig	2004-09-15 15:34:22.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/Kconfig	2004-09-15 10:26:45.000000000 +0200
@@ -11,11 +11,16 @@
 	  This driver only supports the fullfeatured cards with
 	  onboard MPEG2 decoder.
 
+          This driver needs an external firmware. Please use the script
+          "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+          download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+
 	  Say Y if you own such a card and want to use it.
 
 config DVB_AV7110_FIRMWARE
 	bool "Compile AV7110 firmware into the driver"
 	depends on DVB_AV7110 && !STANDALONE
+	default y if DVB_AV7110=y
 	help
 	  The AV7110 firmware is normally loaded by the firmware hotplug manager.
 	  If you want to compile the firmware into the driver you need to say
@@ -33,6 +38,7 @@
 config DVB_AV7110_OSD
 	bool "AV7110 OSD support"
 	depends on DVB_AV7110
+	default y if DVB_AV7110=y || DVB_AV7110=m
 	help
 	  The AV7110 firmware provides some code to generate an OnScreenDisplay
 	  on the video output. This is kind of nonstandard and not guaranteed to
@@ -91,7 +97,7 @@
 
 config DVB_BUDGET_PATCH
 	tristate "AV7110 cards with Budget Patch"
-	depends on DVB_BUDGET
+	depends on DVB_CORE && DVB_BUDGET
 	select DVB_AV7110
 	help
 	  Support for Budget Patch (full TS) modification on 

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

* Re: [PATCH][2.6][3/14] dvb-bt8xx and skystar2 driver update
  2004-09-17 14:24   ` [PATCH][2.6][2/14] documentation update Michael Hunold
@ 2004-09-17 14:26     ` Michael Hunold
  2004-09-17 14:27       ` [PATCH][2.6][4/14] dvb core update Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:26 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 03-DVB-skystar2-dvb-bt8xx-update.diff --]
[-- Type: text/plain, Size: 26580 bytes --]

- [DVB] convert drivers from dvb-i2c to kernel-i2c
- [DVB] convert MODULE_PARM() to module_param()
- [DVB] convert dvb_delay() to mdelay()
- [DVB] dvb-bt8xx: convert home-brewn bttv i2c access to a real bttv sub-driver

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/b2c2/skystar2.c linux-2.6.8.1-patched/drivers/media/dvb/b2c2/skystar2.c
--- xx-linux-2.6.8.1/drivers/media/dvb/b2c2/skystar2.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/b2c2/skystar2.c	2004-08-23 16:49:55.000000000 +0200
@@ -30,14 +30,16 @@
  * 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/module.h>
+#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/version.h>
 
 #include <asm/io.h>
 
-#include "dvb_i2c.h"
 #include "dvb_frontend.h"
 
 #include <linux/dvb/frontend.h>
@@ -49,12 +51,17 @@
 #include "demux.h"
 #include "dvb_net.h"
 
-#include "dvb_functions.h"
 
-static int debug = 0;
+static int debug;
+static int enable_hw_filters = 2;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages).");
+module_param(enable_hw_filters, int, 0444);
+MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");
+
 #define dprintk(x...)	do { if (debug>=1) printk(x); } while (0)
 #define ddprintk(x...)	do { if (debug>=2) printk(x); } while (0)
-static int enable_hw_filters = 2;
 
 #define SIZE_OF_BUF_DMA1	0x3ac00
 #define SIZE_OF_BUF_DMA2	0x758
@@ -89,7 +96,7 @@
 	struct dmxdev dmxdev;
 	struct dmx_frontend hw_frontend;
 	struct dmx_frontend mem_frontend;
-	struct dvb_i2c_bus *i2c_bus;
+	struct i2c_adapter i2c_adap;	
 	struct dvb_net dvbnet;
 
 	struct semaphore i2c_sem;
@@ -277,9 +284,9 @@
 	return buf - start;
 }
 
-static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg *msgs, int num)
+static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int num)
 {
-	struct adapter *tmp = i2c->data;
+	struct adapter *tmp = i2c_get_adapdata(adapter);
 	int i, ret = 0;
 
 	if (down_interruptible(&tmp->i2c_sem))
@@ -291,10 +298,10 @@
 		ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
 			 msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
 	
-		/* allow only the mt312 and stv0299 frontends to access the bus */
-		if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) && (msgs[i].addr != 0x61)) {
+		/* allow only the mt312, mt352 and stv0299 frontends to access the bus */
+		if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) &&
+		    (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) {
 		up(&tmp->i2c_sem);
-
 		return -EREMOTEIO;
 	}
 	}
@@ -2122,7 +2128,7 @@
 			udelay(12500);
 			set_tuner_tone(adapter, 0);
 		}
-		dvb_delay(20);
+		msleep(20);
 	}
 
 	return 0;
@@ -2228,6 +2235,44 @@
 	return 0;
 }
 
+
+int client_register(struct i2c_client *client)
+{
+	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+
+	dprintk("client_register\n");
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter);
+	return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+
+	dprintk("client_unregister\n");
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter);
+	return 0;
+}
+
+u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+{
+	printk("flexcop_i2c_func\n");
+
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm    flexcop_algo = {
+	.name		= "flexcop i2c algorithm",
+	.id		= I2C_ALGO_BIT,
+	.master_xfer	= master_xfer,
+	.functionality	= flexcop_i2c_func,
+};
+
+
 static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct adapter *adapter;
@@ -2258,10 +2303,27 @@
 
 	init_MUTEX(&adapter->i2c_sem);
 
-	adapter->i2c_bus = dvb_register_i2c_bus(master_xfer, adapter, adapter->dvb_adapter, 0);
 
-	if (!adapter->i2c_bus)
+	memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter));
+	strcpy(adapter->i2c_adap.name, "Technisat SkyStar2 driver");
+
+	i2c_set_adapdata(&adapter->i2c_adap, adapter);
+
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+	adapter->i2c_adap.class 	    = I2C_ADAP_CLASS_TV_DIGITAL;
+#else
+	adapter->i2c_adap.class 	    = I2C_CLASS_TV_DIGITAL;
+#endif
+	adapter->i2c_adap.algo              = &flexcop_algo;
+	adapter->i2c_adap.algo_data         = NULL;
+	adapter->i2c_adap.id                = I2C_ALGO_BIT;
+	adapter->i2c_adap.client_register   = client_register;
+	adapter->i2c_adap.client_unregister = client_unregister;
+
+	if (i2c_add_adapter(&adapter->i2c_adap) < 0) {
+		dvb_unregister_adapter (adapter->dvb_adapter);
 		return -ENOMEM;
+	}
 
 	dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter);
 
@@ -2327,8 +2389,7 @@
 		if (adapter->dvb_adapter != NULL) {
 			dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL);
 
-			if (adapter->i2c_bus != NULL)
-				dvb_unregister_i2c_bus(master_xfer, adapter->i2c_bus->adapter, adapter->i2c_bus->id);
+			i2c_del_adapter(&adapter->i2c_adap);
 
 			dvb_unregister_adapter(adapter->dvb_adapter);
 		}
@@ -2364,10 +2425,5 @@
 module_init(skystar2_init);
 module_exit(skystar2_cleanup);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages: supported values: 1 and 2");
-MODULE_PARM(enable_hw_filters, "i");
-MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");
-
 MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");
 MODULE_LICENSE("GPL");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/bt878.c linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/bt878.c
--- xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/bt878.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/bt878.c	2004-08-18 19:52:17.000000000 +0200
@@ -27,8 +27,8 @@
  * 
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/io.h>
@@ -46,20 +46,19 @@
 #include "bt878.h"
 #include "dst-bt878.h"
 
-#include "dvb_functions.h"
 
 /**************************************/
 /* Miscellaneous utility  definitions */
 /**************************************/
 
-unsigned int bt878_verbose = 1;
-unsigned int bt878_debug = 0;
-MODULE_PARM(bt878_verbose, "i");
+static unsigned int bt878_verbose = 1;
+static unsigned int bt878_debug;
+
+module_param_named(verbose, bt878_verbose, int, 0444);
 MODULE_PARM_DESC(bt878_verbose,
 		 "verbose startup messages, default is 1 (yes)");
-MODULE_PARM(bt878_debug, "i");
-MODULE_PARM_DESC(bt878_debug, "debug messages, default is 0 (no)");
-MODULE_LICENSE("GPL");
+module_param_named(debug, bt878_debug, int, 0644);
+MODULE_PARM_DESC(bt878_debug, "Turn on/off debugging (default:off).");
 
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
@@ -339,10 +338,6 @@
 	return IRQ_HANDLED;
 }
 
-extern int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data);
-extern int bttv_read_gpio(unsigned int card, unsigned long *data);
-extern int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data);
-
 int
 bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
 {
@@ -386,20 +381,20 @@
 
 EXPORT_SYMBOL(bt878_device_control);
 
-struct bt878 *bt878_find_by_dvb_adap(struct dvb_adapter *adap)
+struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adapter)
 {
 	unsigned int card_nr;
 	
-	printk("bt878 find by dvb adap: checking \"%s\"\n",adap->name);
+	printk("bt878 find by dvb adap: checking \"%s\"\n",adapter->name);
 	for (card_nr = 0; card_nr < bt878_num; card_nr++) {
-		if (bt878[card_nr].adap_ptr == adap)
+		if (bt878[card_nr].adapter == adapter)
 			return &bt878[card_nr];
 	}
-	printk("bt878 find by dvb adap: NOT found \"%s\"\n",adap->name);
+	printk("bt878 find by dvb adap: NOT found \"%s\"\n",adapter->name);
 	return NULL;
 }
 
-EXPORT_SYMBOL(bt878_find_by_dvb_adap);
+EXPORT_SYMBOL(bt878_find_by_i2c_adap);
 
 /***********************/
 /* PCI device handling */
@@ -607,6 +602,9 @@
 module_init(bt878_init_module);
 module_exit(bt878_cleanup_module);
 
+
+MODULE_LICENSE("GPL");
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/bt878.h linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/bt878.h
--- xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/bt878.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/bt878.h	2004-08-18 16:44:48.000000000 +0200
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include "bt848.h"
+#include "bttv.h"
 
 #define BT878_VERSION_CODE 0x000000
 
@@ -94,7 +95,7 @@
 	struct semaphore  gpio_lock;
 	unsigned int nr;
 	unsigned int bttv_nr;
-	struct dvb_adapter *adap_ptr;
+	struct i2c_adapter *adapter;
 	struct pci_dev *dev;
 	unsigned int id;
 	unsigned int TS_Size;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/dvb-bt8xx.c linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2004-08-18 19:52:17.000000000 +0200
@@ -21,7 +21,9 @@
 
 #include <asm/bitops.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
@@ -33,33 +35,32 @@
 
 #include "dvb-bt8xx.h"
 
-#include "dvb_functions.h"
-
 #include "bt878.h"
 
-/* ID THAT MUST GO INTO i2c ids */
-#ifndef  I2C_DRIVERID_DVB_BT878A
-# define I2C_DRIVERID_DVB_BT878A I2C_DRIVERID_EXP0+10
-#endif
-
-
-#define dprintk if (debug) printk
+static int debug;
 
-extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
-extern struct pci_dev* bttv_get_pcidev(unsigned int card);
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-static LIST_HEAD(card_list);
-static int debug = 0;
+#define dprintk( args... ) \
+	do { \
+		if (debug) printk(KERN_DEBUG args); \
+	} while (0)
 
 static void dvb_bt8xx_task(unsigned long data)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
 
-	//printk("%d ", finished_block);
+	//printk("%d ", card->bt->finished_block);
 
 	while (card->bt->last_block != card->bt->finished_block) {
-		(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)(&card->demux, &card->bt->buf_cpu[card->bt->last_block * card->bt->block_bytes], card->bt->block_bytes);
-		card->bt->last_block = (card->bt->last_block + 1) % card->bt->block_count;
+		(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+			(&card->demux,
+			 &card->bt->buf_cpu[card->bt->last_block *
+					    card->bt->block_bytes],
+			 card->bt->block_bytes);
+		card->bt->last_block = (card->bt->last_block + 1) %
+					card->bt->block_count;
 	}
 }
 
@@ -103,23 +104,6 @@
 	return 0;
 }
 
-static int master_xfer (struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[], int num)
-{
-	struct dvb_bt8xx_card *card = i2c->data;
-	int retval;
-
-	if (down_interruptible (&card->bt->gpio_lock))
-		return -ERESTARTSYS;
-
-	retval = i2c_transfer(card->i2c_adapter,
-			      (struct i2c_msg*) msgs,
-			      num);
-
-	up(&card->bt->gpio_lock);
-
-	return retval;
-}
-
 static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
 {
 	if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
@@ -142,168 +126,18 @@
 	return NULL;
 }
 
-static int __init dvb_bt8xx_card_match(unsigned int bttv_nr, char *card_name, u32 gpio_mode, u32 op_sync_orin, u32 irq_err_ignore)
-{
-	struct dvb_bt8xx_card *card;
-	struct pci_dev* bttv_pci_dev;
-
-	dprintk("dvb_bt8xx: identified card%d as %s\n", bttv_nr, card_name);
-			
-	if (!(card = kmalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
-		return -ENOMEM;
-
-	memset(card, 0, sizeof(*card));
-	card->bttv_nr = bttv_nr;
-	strncpy(card->card_name, card_name, sizeof(card_name) - 1);
-	
-	if (!(bttv_pci_dev = bttv_get_pcidev(bttv_nr))) {
-		printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
-		kfree(card);
-		return -EFAULT;
-	}
-
-	if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
-		printk("dvb_bt8xx: unable to determine DMA core of card %d\n", card->bttv_nr);
-	
-		kfree(card);
-		return -EFAULT;
-		
-	}
-	init_MUTEX(&card->bt->gpio_lock);
-	card->bt->bttv_nr = bttv_nr;
-	card->gpio_mode = gpio_mode;
-	card->op_sync_orin = op_sync_orin;
-	card->irq_err_ignore = irq_err_ignore;
-	list_add_tail(&card->list, &card_list);
-
-	return 0;
-}
-
-static struct dvb_bt8xx_card *dvb_bt8xx_find_by_i2c_adap(struct i2c_adapter *adap)
-{
-	struct dvb_bt8xx_card *card;
-	struct list_head *item;
-	
-	printk("find by i2c adap: checking \"%s\"\n",adap->name);
-	list_for_each(item, &card_list) {
-		card = list_entry(item, struct dvb_bt8xx_card, list);
-		if (card->i2c_adapter == adap)
-			return card;
-	}
-	return NULL;
-}
-
-static struct dvb_bt8xx_card *dvb_bt8xx_find_by_pci(struct i2c_adapter *adap)
-{
-	struct dvb_bt8xx_card *card;
-	struct list_head *item;
-	struct device  *dev;
-	struct pci_dev *pci;
-	
-	printk("find by pci: checking \"%s\"\n",adap->name);
-	dev = adap->dev.parent;
-	if (NULL == dev) {
-		/* shoudn't happen with 2.6.0-test7 + newer */
-		printk("attach: Huh? i2c adapter not in sysfs tree?\n");
-		return NULL;
-	}
-	pci = to_pci_dev(dev);
-	list_for_each(item, &card_list) {
-		card = list_entry(item, struct dvb_bt8xx_card, list);
-		if (is_pci_slot_eq(pci, card->bt->dev)) {
-			return card;
-		}
-	}
-	return NULL;
-}
-
-static int dvb_bt8xx_attach(struct i2c_adapter *adap)
-{
-	struct dvb_bt8xx_card *card;
-	
-	printk("attach: checking \"%s\"\n",adap->name);
-
-	/* looking for bt878 cards ... */
-	if (adap->id != (I2C_ALGO_BIT | I2C_HW_B_BT848))
-		return 0;
-	card = dvb_bt8xx_find_by_pci(adap);
-	if (!card)
-		return 0;
-	card->i2c_adapter = adap;
-	printk("attach: \"%s\", to card %d\n",
-	       adap->name, card->bttv_nr);
-	try_module_get(adap->owner);
-
-	return 0;
-}
-
-static void dvb_bt8xx_i2c_adap_free(struct i2c_adapter *adap)
-{
-	module_put(adap->owner);
-}
-
-static int dvb_bt8xx_detach(struct i2c_adapter *adap)
-{
-	struct dvb_bt8xx_card *card;
-
-	card = dvb_bt8xx_find_by_i2c_adap(adap);
-	if (!card)
-		return 0;
-
-	/* This should not happen. We have locked the module! */
-	printk("detach: \"%s\", for card %d removed\n",
-	       adap->name, card->bttv_nr);
-	return 0;
-}
-
-static struct i2c_driver dvb_bt8xx_driver = {
-	.owner           = THIS_MODULE,
-	.name            = "dvb_bt8xx",
-        .id              = I2C_DRIVERID_DVB_BT878A,
-	.flags           = I2C_DF_NOTIFY,
-        .attach_adapter  = dvb_bt8xx_attach,
-        .detach_adapter  = dvb_bt8xx_detach,
-};
-
-static void __init dvb_bt8xx_get_adaps(void)
-{
-	i2c_add_driver(&dvb_bt8xx_driver);
-}
-
-static void __exit dvb_bt8xx_exit_adaps(void)
-{
-	i2c_del_driver(&dvb_bt8xx_driver);
-}
-
 static int __init dvb_bt8xx_load_card( struct dvb_bt8xx_card *card)
 {
 	int result;
 
-	if (!card->i2c_adapter) {
-		printk("dvb_bt8xx: unable to determine i2c adaptor of card %d, deleting\n", card->bttv_nr);
-
-		return -EFAULT;
-	
-	}
-
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
-	
+	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
+					   THIS_MODULE)) < 0) {
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
-		
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
 		return result;
 		
 	}
-	card->bt->adap_ptr = card->dvb_adapter;
 
-	if (!(dvb_register_i2c_bus(master_xfer, card, card->dvb_adapter, 0))) {
-		printk("dvb_bt8xx: dvb_register_i2c_bus of card%d failed\n", card->bttv_nr);
-
-		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-
-		return -EFAULT;
-	}
+	card->bt->adapter = card->i2c_adapter;
 
 	memset(&card->demux, 0, sizeof(struct dvb_demux));
 
@@ -319,10 +153,7 @@
 	if ((result = dvb_dmx_init(&card->demux)) < 0) {
 		printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
 
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
 		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-		
 		return result;
 	}
 
@@ -334,10 +165,7 @@
 		printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
 
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
 		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-		
 		return result;
 	}
 
@@ -348,10 +176,7 @@
 
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
 		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-		
 		return result;
 	}
 	
@@ -363,10 +188,7 @@
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
 		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-		
 		return result;
 	}
 
@@ -377,10 +199,7 @@
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
 		dvb_unregister_adapter(card->dvb_adapter);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
-		
 		return result;
 	}
 
@@ -393,67 +212,52 @@
 	return 0;
 }
 
-static int __init dvb_bt8xx_load_all(void)
+static int dvb_bt8xx_probe(struct device *dev)
 {
+	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
 	struct dvb_bt8xx_card *card;
-	struct list_head *entry, *entry_safe;
-
-	list_for_each_safe(entry, entry_safe, &card_list) {
-		card = list_entry(entry, struct dvb_bt8xx_card, list);
-		if (dvb_bt8xx_load_card(card) < 0) {
-			list_del(&card->list);
-			kfree(card);
-			continue;
-		}
-	}
-	return 0;
-
-}
+	struct pci_dev* bttv_pci_dev;
+	int ret;
 
-#define BT878_NEBULA	0x68
-#define BT878_TWINHAN_DST 0x71
+	if (!(card = kmalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
+		return -ENOMEM;
 
-static int __init dvb_bt8xx_init(void)
-{
-	unsigned int card_nr = 0;
-	int card_id;
-	int card_type;
-
-	dprintk("dvb_bt8xx: enumerating available bttv cards...\n");
-	
-	while (bttv_get_cardinfo(card_nr, &card_type, &card_id) == 0) {
-		switch(card_id) {
-			case 0x001C11BD:
-				dvb_bt8xx_card_match(card_nr, "Pinnacle PCTV DVB-S",
-					       0x0400C060, 0, 0);
+	memset(card, 0, sizeof(*card));
+	card->bttv_nr = sub->core->nr;
+	strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
+	card->i2c_adapter = &sub->core->i2c_adap;
+
+	switch(sub->core->type)
+	{
+	case BTTV_PINNACLESAT:
+		card->gpio_mode = 0x0400C060;
+		card->op_sync_orin = 0;
+		card->irq_err_ignore = 0;
 				/* 26, 15, 14, 6, 5 
-				 * A_G2X  DA_DPM DA_SBR DA_IOM_DA 
+		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA 
 				 * DA_APP(parallel) */
 				break;
-			case 0x01010071:
-nebula:
-				dvb_bt8xx_card_match(card_nr, "Nebula DigiTV DVB-T",
-					     (1 << 26) | (1 << 14) | (1 << 5),
-					     0, 0);
+
+	case BTTV_NEBULA_DIGITV:
+	case BTTV_AVDVBT_761:
+		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
+		card->op_sync_orin = 0;
+		card->irq_err_ignore = 0;
 				/* A_PWRDN DA_SBR DA_APP (high speed serial) */
 				break;
-			case 0x07611461:
-				dvb_bt8xx_card_match(card_nr, "Avermedia DVB-T",
-					     (1 << 26) | (1 << 14) | (1 << 5),
-					     0, 0);
-				/* A_PWRDN DA_SBR DA_APP (high speed serial) */
+
+	case BTTV_AVDVBT_771: //case 0x07711461:
+		card->gpio_mode = 0x0400402B;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = 0;
+		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
 				break;
-			case 0x0:
-				if (card_type == BT878_NEBULA ||
-					card_type == BT878_TWINHAN_DST)
-					goto dst;
-				goto unknown_card;
-			case 0x2611BD:
-			case 0x11822:
-dst:
-				dvb_bt8xx_card_match(card_nr, "DST DVB-S", 0x2204f2c,
-						BT878_RISC_SYNC_MASK,
-						BT878_APABORT | BT878_ARIPERR | BT878_APPERR | BT878_AFBUS);
+
+	case BTTV_TWINHAN_DST:
+		card->gpio_mode = 0x2204f2c;
+		card->op_sync_orin = BT878_RISC_SYNC_MASK;
+		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
+				       BT878_APPERR | BT878_AFBUS;
 				/* 25,21,14,11,10,9,8,3,2 then
 				 * 0x33 = 5,4,1,0
 				 * A_SEL=SML, DA_MLB, DA_SBR, 
@@ -466,42 +270,45 @@
 				 * ACAP_EN = 1,
 				 * RISC+FIFO ENABLE */
 				break;
+
 			default:
-unknown_card:
-				printk("%s: unknown card_id found %0X\n",
-					__FUNCTION__, card_id);
-				if (card_type == BT878_NEBULA) {
-					printk("%s: bttv type set to nebula\n",
-						__FUNCTION__);
-					goto nebula;
-				}
-				if (card_type == BT878_TWINHAN_DST) {
-					printk("%s: bttv type set to Twinhan DST\n",
-						__FUNCTION__);
-					goto dst;
-				}
-				printk("%s: unknown card_type found %0X, NOT LOADED\n",
-					__FUNCTION__, card_type);
-				printk("%s: unknown card_nr found %0X\n",
-					__FUNCTION__, card_nr);
+		printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
+				sub->core->type);
+		kfree(card);
+		return -ENODEV;
 		}
-		card_nr++;
+
+	dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
+			
+	if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
+		printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
+		kfree(card);
+		return -EFAULT;
 	}
-	dvb_bt8xx_get_adaps();
-	dvb_bt8xx_load_all();
 
-	return 0;
+	if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
+		printk("dvb_bt8xx: unable to determine DMA core of card %d\n", card->bttv_nr);
+	
+		kfree(card);
+		return -EFAULT;
 
 }
 
-static void __exit dvb_bt8xx_exit(void)
-{
-	struct dvb_bt8xx_card *card;
-	struct list_head *entry, *entry_safe;
+	init_MUTEX(&card->bt->gpio_lock);
+	card->bt->bttv_nr = sub->core->nr;
 
-	dvb_bt8xx_exit_adaps();
-	list_for_each_safe(entry, entry_safe, &card_list) {
-		card = list_entry(entry, struct dvb_bt8xx_card, list);
+	if ( (ret = dvb_bt8xx_load_card(card)) ) {
+		kfree(card);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, card);
+	return 0;
+}
+
+static int dvb_bt8xx_remove(struct device *dev)
+{
+	struct dvb_bt8xx_card *card = dev_get_drvdata(dev);
 		
 		dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
 
@@ -512,14 +319,54 @@
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
-		dvb_unregister_i2c_bus(master_xfer, card->dvb_adapter, 0);
-		dvb_bt8xx_i2c_adap_free(card->i2c_adapter);
 		dvb_unregister_adapter(card->dvb_adapter);
 		
 		list_del(&card->list);
 		kfree(card);
+
+	return 0;
 	}
 
+static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub,
+			       struct i2c_client *client, int attach)
+{
+	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
+
+	if (attach) {
+		printk("xxx attach\n");
+		if (client->driver->command)
+			client->driver->command(client, FE_REGISTER,
+						card->dvb_adapter);
+	} else {
+		printk("xxx detach\n");
+		if (client->driver->command)
+			client->driver->command(client, FE_UNREGISTER,
+						card->dvb_adapter);
+	}
+}
+
+static struct bttv_sub_driver driver = {
+	.drv = {
+		.name		= "dvb-bt8xx",
+		.probe		= dvb_bt8xx_probe,
+		.remove		= dvb_bt8xx_remove,
+		/* FIXME:
+		 * .shutdown	= dvb_bt8xx_shutdown,
+		 * .suspend	= dvb_bt8xx_suspend,
+		 * .resume	= dvb_bt8xx_resume,
+		 */
+	},
+	.i2c_info = dvb_bt8xx_i2c_info,
+};
+
+static int __init dvb_bt8xx_init(void)
+{
+	return bttv_sub_register(&driver, "dvb");
+}
+
+static void __exit dvb_bt8xx_exit(void)
+{
+	bttv_sub_unregister(&driver);
 }
 
 module_init(dvb_bt8xx_init);
@@ -527,4 +375,4 @@
 MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
 MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
+
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/dvb-bt8xx.h linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/dvb-bt8xx.h
--- xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2004-08-18 16:44:48.000000000 +0200
@@ -25,9 +25,9 @@
 #include <linux/i2c.h>
 #include "dvbdev.h"
 #include "dvb_net.h"
+#include "bttv.h"
 
 struct dvb_bt8xx_card {
-
 	struct list_head list;
 	u8 active;
 	char card_name[32];
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/Kconfig
--- xx-linux-2.6.8.1/drivers/media/dvb/bt8xx/Kconfig	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/bt8xx/Kconfig	2004-05-28 13:08:43.000000000 +0200
@@ -1,13 +1,16 @@
 config DVB_BT8XX
-	tristate "Nebula/Pinnacle PCTV PCI cards"
+	tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
 	depends on DVB_CORE && PCI && VIDEO_BT848
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
-	  the Nebula cards, the Pinnacle PCTV cards, and Twinhan DST cards.
+	  the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
 
           Since these cards have no MPEG decoder onboard, they transmit
 	  only compressed MPEG data over the PCI bus, so you need
 	  an external software decoder to watch TV on your computer.
 
+	  If you have a Twinhan card, don't forget to select
+	  "Twinhan DST based DVB-S/-T frontend".
+
 	  Say Y if you own such a device and want to use it.
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/dst-bt878.h linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst-bt878.h
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/dst-bt878.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst-bt878.h	2004-08-18 16:45:40.000000000 +0200
@@ -32,7 +32,6 @@
 
 struct bt878 ;
 
-int
-bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
+int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
 
-struct bt878 *bt878_find_by_dvb_adap(struct dvb_adapter *adap);
+struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);

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

* Re: [PATCH][2.6][4/14] dvb core update
  2004-09-17 14:26     ` [PATCH][2.6][3/14] dvb-bt8xx and skystar2 driver update Michael Hunold
@ 2004-09-17 14:27       ` Michael Hunold
  2004-09-17 14:29         ` [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3 Michael Hunold
                           ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:27 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 04-DVB-dvb-core-update.diff --]
[-- Type: text/plain, Size: 76188 bytes --]

- [DVB] remove non-linux compatibility stuff from dvb_functions. rest in peace.
- [DVB] remove home-brewn dvb-i2c stuff. rest in peace.
- [DVB] convert MODULE_PARM() to module_param()
- [DVB] convert dvb_delay() to mdelay()
- [DVB] convert C++ comments to C comments
- [DVB] dvb_ca_en50221: fix for matrix CAMs from Sjoerd Simons, use c99 initializers, Fix for aston CAM read timeout problems, Moved CAM CTRL IF reset to a better place, better debugging with multiple cards (Sjoerd Simons)
- [DVB] dvb-frontend: patch by Wolfgang Fritz: suppress spurious events during tuning,  Do not allow write (and related) ioctls when frontend is opened RDONLY, Properly lock the frontend module on open/close, patch by Christopher Pascoe: remove bogus up(fe->sem) on fe thread exit, patch by Christopher Pascoe: remove bogus up(fe->sem) on fe thread exit
- [DVB] dvb-demux: using spin_lock instead of spin_lock_irq caused a race condition between irq/tasklet and user space task
- [DVB] dvb-core: add sysfs/udev support using "class_simple", prevent Oops when PES filter is set with invalid pes_type, protect feed_list with spin_locks

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dmxdev.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dmxdev.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dmxdev.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dmxdev.c	2004-08-18 19:52:17.000000000 +0200
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/sched.h>
 #include <linux/poll.h>
 #include <linux/ioctl.h>
@@ -33,10 +34,11 @@
 #include <asm/system.h>
 
 #include "dmxdev.h"
-#include "dvb_functions.h"
 
-MODULE_PARM(debug,"i");
-static int debug = 0;
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
 #define dprintk	if (debug) printk
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ca_en50221.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ca_en50221.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.c	2004-08-18 19:52:17.000000000 +0200
@@ -32,16 +32,20 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <asm/semaphore.h>
+#include <asm/rwsem.h>
 #include <asm/atomic.h>
 
 #include "dvb_ca_en50221.h"
-#include "dvb_functions.h"
 #include "dvb_ringbuffer.h"
 
-static int dvb_ca_en50221_debug = 0;
+static int dvb_ca_en50221_debug;
+
+module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
+MODULE_PARM_DESC(dvb_ca_en50221_debug, "enable verbose debug messages");
+
 #define dprintk if (dvb_ca_en50221_debug) printk
 
 #define INIT_TIMEOUT_SECS 5
@@ -108,7 +112,7 @@
         int link_buf_size;
 
         /* semaphore for syncing access to slot structure */
-        struct semaphore sem;
+        struct rw_semaphore sem;
 
         /* buffer for incoming packets */
         struct dvb_ringbuffer rx_buffer;
@@ -199,7 +203,6 @@
 static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
 {
         int slot_status;
-        int status;
         int cam_present_now;
         int cam_changed;
 
@@ -209,9 +212,7 @@
         }
 
         /* poll mode */
-        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
         slot_status = ca->pub->poll_slot_status(ca->pub, slot);
-        up(&ca->slot_info[slot].sem);
 
         cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0;
         cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0;
@@ -277,7 +278,7 @@
                 }
 
                 /* wait for a bit */
-                dvb_delay(1);
+                msleep(1);
         }
 
         dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
@@ -360,6 +361,13 @@
 
         /* grab the next tuple length and type */
         if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) return _tupleType;
+        if (_tupleType == 0xff) {
+                dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+                *address += 2;
+                *tupleType = _tupleType;
+                *tupleLength = 0;
+                return 0;
+        }
         if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address+2)) < 0) return _tupleLength;
         _address += 4;
 
@@ -550,25 +558,22 @@
 
         dprintk ("%s\n", __FUNCTION__);
 
-        /* acquire the slot */
-        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
-
         /* check if we have space for a link buf in the rx_buffer */
         if (ebuf == NULL) {
-                if (dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer) <
-                    (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+		int buf_free;
+		
+		down_read(&ca->slot_info[slot].sem);
+		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
+		up_read(&ca->slot_info[slot].sem);
+		
+                if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
                         status = -EAGAIN;
                         goto exit;
                 }
         }
 
-        /* reset the interface if there's been a tx error */
+        /* check if there is data available */
         if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
-        if (status & STATUSREG_TXERR) {
-                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                status = -EIO;
-                goto exit;
-        }
         if (!(status & STATUSREG_DA)) {
                 /* no data */
                 status = 0;
@@ -612,20 +617,25 @@
                 buf[i] = status;
         }
 
-        /* check for read error (RE should now go to 0) */
+        /* check for read error (RE should now be 0) */
         if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
         if (status & STATUSREG_RE) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
                 status = -EIO;
                 goto exit;
         }
 
         /* OK, add it to the receive buffer, or copy into external buffer if supplied */
         if (ebuf == NULL) {
+		down_read(&ca->slot_info[slot].sem);
                 dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
+		up_read(&ca->slot_info[slot].sem);
         } else {
                 memcpy(ebuf, buf, bytes_read);
         }
 
+	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_read);
+
         /* wake up readers when a last_fragment is received */
         if ((buf[1] & 0x80) == 0x00) {
                 wake_up_interruptible(&ca->wait_queue);
@@ -634,7 +643,6 @@
         status = bytes_read;
 
 exit:
-        up(&ca->slot_info[slot].sem);
         return status;
 }
 
@@ -662,19 +670,9 @@
         // sanity check
         if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL;
 
-        /* acquire the slot */
-        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
-
-        /* reset the interface if there's been a tx error */
+        /* check if interface is actually waiting for us to read from it, or if a read is in progress */
         if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite;
-        if (status & STATUSREG_TXERR) {
-                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                status = -EIO;
-                goto exitnowrite;
-        }
-
-        /* check if interface is actually waiting for us to read from it */
-        if (status & STATUSREG_DA) {
+        if (status & (STATUSREG_DA|STATUSREG_RE)) {
                 status = -EAGAIN;
                 goto exitnowrite;
         }
@@ -702,16 +700,18 @@
         /* check for write error (WE should now be 0) */
         if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
         if (status & STATUSREG_WE) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
                 status = -EIO;
                 goto exit;
         }
         status = bytes_write;
 
+	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_write);
+	
 exit:
         ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
 
 exitnowrite:
-        up(&ca->slot_info[slot].sem);
         return status;
 }
 
@@ -729,16 +729,14 @@
  */
 static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
 {
-        int status;
-
         dprintk ("%s\n", __FUNCTION__);
 
-        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
+        down_write(&ca->slot_info[slot].sem);
         ca->pub->slot_shutdown(ca->pub, slot);
         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
         if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data);
         ca->slot_info[slot].rx_buffer.data = NULL;
-        up(&ca->slot_info[slot].sem);
+        up_write(&ca->slot_info[slot].sem);
 
         /* need to wake up all processes to check if they're now
            trying to write to a defunct CAM */
@@ -821,10 +819,7 @@
                 break;
 
         case DVB_CA_SLOTSTATE_RUNNING:
-                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
-                if (flags & STATUSREG_DA) {
-                        dvb_ca_en50221_thread_wakeup(ca);
-                }
+		if (ca->open) dvb_ca_en50221_read_data(ca, slot, NULL, 0);
                 break;
         }
 }
@@ -934,7 +929,11 @@
 
         /* setup kernel thread */
         snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-        dvb_kernel_thread_setup(name);
+
+        lock_kernel ();
+        daemonize (name);
+        sigfillset (&current->blocked);
+        unlock_kernel ();
 
         /* choose the correct initial delay */
         dvb_ca_en50221_thread_update_delay(ca);
@@ -993,6 +992,12 @@
                                 break;
 
                         case DVB_CA_SLOTSTATE_VALIDATE:
+                                if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) {
+                                        printk("dvb_ca: Unable to reset CAM IF\n");
+                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                        dvb_ca_en50221_thread_update_delay(ca);
+                                        break;
+                                }
                                 if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
                                         printk("dvb_ca: Invalid PC card inserted :(\n");
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1054,6 +1058,10 @@
                         case DVB_CA_SLOTSTATE_RUNNING:
                                 if (!ca->open) break;
 
+				// no need to poll if the CAM supports IRQs
+				if (ca->slot_info[slot].da_irq_supported) break;
+
+				// poll mode
                                 pktcount = 0;
                                 while(dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) {
                                         if (!ca->open) break;
@@ -1233,7 +1241,7 @@
 			}
                         if (status != -EAGAIN) goto exit;
 
-                        dvb_delay(1);
+                        msleep(1);
                 }
 	        if (!written) {
 		        status = -EIO;
@@ -1266,7 +1274,7 @@
         while((slot_count < ca->slot_count) && (!found)) {
                 if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot;
 
-                if ((*result = down_interruptible(&ca->slot_info[slot].sem)) != 0) return 1;
+                down_read(&ca->slot_info[slot].sem);
 
                 idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
                 while(idx != -1) {
@@ -1281,7 +1289,7 @@
                         idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
                 }
 
-                if (!found) up(&ca->slot_info[slot].sem);
+                if (!found) up_read(&ca->slot_info[slot].sem);
 
 nextslot:
                 slot = (slot + 1) % ca->slot_count;
@@ -1378,7 +1386,7 @@
         status = pktlen;
 
 exit:
-        up(&ca->slot_info[slot].sem);
+        up_read(&ca->slot_info[slot].sem);
         return status;
 }
 
@@ -1406,7 +1414,9 @@
 
         for(i=0; i< ca->slot_count; i++) {
                 if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+		        down_write(&ca->slot_info[i].sem);
                         dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+		        up_write(&ca->slot_info[i].sem);
                 }
         }
 
@@ -1464,7 +1474,7 @@
         dprintk ("%s\n", __FUNCTION__);
 
         if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-                up(&ca->slot_info[slot].sem);
+                up_read(&ca->slot_info[slot].sem);
                 mask |= POLLIN;
         }
 
@@ -1475,7 +1485,7 @@
         poll_wait(file, &ca->wait_queue, wait);
 
         if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-                up(&ca->slot_info[slot].sem);
+                up_read(&ca->slot_info[slot].sem);
                 mask |= POLLIN;
         }
 
@@ -1484,21 +1494,21 @@
 
 
 static struct file_operations dvb_ca_fops = {
-        owner: THIS_MODULE,
-        read: dvb_ca_en50221_io_read,
-        write: dvb_ca_en50221_io_write,
-        ioctl: dvb_ca_en50221_io_ioctl,
-        open: dvb_ca_en50221_io_open,
-        release: dvb_ca_en50221_io_release,
-        poll: dvb_ca_en50221_io_poll,
+        .owner	= THIS_MODULE,
+        .read	= dvb_ca_en50221_io_read,
+        .write	= dvb_ca_en50221_io_write,
+        .ioctl	= dvb_ca_en50221_io_ioctl,
+        .open	= dvb_ca_en50221_io_open,
+        .release= dvb_ca_en50221_io_release,
+        .poll	= dvb_ca_en50221_io_poll,
 };
 
 static struct dvb_device dvbdev_ca = {
-        priv: NULL,
-        users: 1,
-        readers: 1,
-        writers: 1,
-        fops: &dvb_ca_fops,
+        .priv	= NULL,
+        .users	= 1,
+        .readers= 1,
+        .writers= 1,
+        .fops	= &dvb_ca_fops,
 };
 
 
@@ -1559,7 +1569,7 @@
                 ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
                 atomic_set(&ca->slot_info[i].camchange_count, 0);
                 ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-                init_MUTEX(&ca->slot_info[i].sem);
+                init_rwsem(&ca->slot_info[i].sem);
         }
 
         if (signal_pending(current)) {
@@ -1623,6 +1635,3 @@
         pubca->private = NULL;
 }
 
-MODULE_PARM(dvb_ca_en50221_debug,"i");
-
-MODULE_PARM_DESC(dvb_ca_en50221_debug, "enable verbose debug messages");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ca_en50221.h linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ca_en50221.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.h	2004-05-14 18:54:27.000000000 +0200
@@ -42,6 +42,9 @@
 /* Structure describing a CA interface */
 struct dvb_ca_en50221 {
 
+	/* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
+	 * they may be called from several threads at once */
+
 	/* functions for accessing attribute memory on the CAM */
 	int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
 	int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_demux.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_demux.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_demux.c	2004-08-18 19:52:17.000000000 +0200
@@ -31,7 +31,6 @@
 #include <asm/uaccess.h>
 
 #include "dvb_demux.h"
-#include "dvb_functions.h"
 
 #define NOBUFS  
 /* 
@@ -570,24 +570,30 @@
 
 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
 {
+	spin_lock(&feed->demux->lock);
 	if (dvb_demux_feed_find(feed)) {
 		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
 				__FUNCTION__, feed->type, feed->state, feed->pid);
-		return;
+		goto out;
 	}
 
 	list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+	spin_unlock(&feed->demux->lock);
 }
 
 static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
 {
+	spin_lock(&feed->demux->lock);
 	if (!(dvb_demux_feed_find(feed))) {
 		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
 				__FUNCTION__, feed->type, feed->state, feed->pid);
-		return;
+		goto out;
 }
 
 	list_del(&feed->list_head);
+out:
+	spin_unlock(&feed->demux->lock);
 }
 
 static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, 
@@ -789,7 +795,7 @@
 
 		feed->pid = 0xffff;
 	
-	if (feed->ts_type & TS_DECODER)
+	if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
 		demux->pesfilter[feed->pes_type] = NULL;
 
 	up(&demux->mutex);
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvbdev.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvbdev.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvbdev.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvbdev.c	2004-08-18 19:58:18.000000000 +0200
@@ -25,22 +25,26 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/device.h>
 
 #include "dvbdev.h"
-#include "dvb_functions.h"
 
-static int dvbdev_debug = 0;
+static int dvbdev_debug;
+
+module_param(dvbdev_debug, int, 0644);
+MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
+
 #define dprintk if (dvbdev_debug) printk
 
 static LIST_HEAD(dvb_adapter_list);
 static DECLARE_MUTEX(dvbdev_register_lock);
 
-
-static char *dnames[] = { 
+static const char * const dnames[] = {
         "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
 	"net", "osd"
 };
@@ -49,6 +52,9 @@
 #define DVB_MAX_IDS              4
 #define nums2minor(num,type,id)  ((num << 6) | (id << 4) | type)
 
+struct class_simple *dvb_class;
+EXPORT_SYMBOL(dvb_class);
+
 static struct dvb_device* dvbdev_find_device (int minor)
 {
 	struct list_head *entry;
@@ -219,6 +224,9 @@
 			S_IFCHR | S_IRUSR | S_IWUSR,
 			"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
+	class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+				NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+
 	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
 		nums2minor(adap->num, type, id));
@@ -235,6 +243,9 @@
 		devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
 				dnames[dvbdev->type], dvbdev->id);
 
+	class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+					dvbdev->type, dvbdev->id)));
+
 		list_del(&dvbdev->list_head);
 		kfree(dvbdev);
 	}
@@ -300,24 +310,95 @@
 
 int dvb_unregister_adapter(struct dvb_adapter *adap)
 {
+	devfs_remove("dvb/adapter%d", adap->num);
+
 	if (down_interruptible (&dvbdev_register_lock))
 		return -ERESTARTSYS;
-        devfs_remove("dvb/adapter%d", adap->num);
 	list_del (&adap->list_head);
 	up (&dvbdev_register_lock);
 	kfree (adap);
 	return 0;
 }
 
+/* if the miracle happens and "generic_usercopy()" is included into
+   the kernel, then this can vanish. please don't make the mistake and
+   define this as video_usercopy(). this will introduce a dependecy
+   to the v4l "videodev.o" module, which is unnecessary for some
+   cards (ie. the budget dvb-cards don't need the v4l module...) */
+int dvb_usercopy(struct inode *inode, struct file *file,
+	             unsigned int cmd, unsigned long arg,
+		     int (*func)(struct inode *inode, struct file *file,
+		     unsigned int cmd, void *arg))
+{
+        char    sbuf[128];
+        void    *mbuf = NULL;
+        void    *parg = NULL;
+        int     err  = -EINVAL;
+
+        /*  Copy arguments into temp kernel buffer  */
+        switch (_IOC_DIR(cmd)) {
+        case _IOC_NONE:
+		/*
+		 * For this command, the pointer is actually an integer
+		 * argument.
+		 */
+		parg = (void *) arg;
+		break;
+        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+        case _IOC_WRITE:
+        case (_IOC_WRITE | _IOC_READ):
+                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+                        parg = sbuf;
+                } else {
+                        /* too big to allocate from stack */
+                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                        if (NULL == mbuf)
+                                return -ENOMEM;
+                        parg = mbuf;
+                }
+
+                err = -EFAULT;
+                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+                        goto out;
+                break;
+        }
+
+        /* call driver */
+        if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
+                err = -EINVAL;
+
+        if (err < 0)
+                goto out;
+
+        /*  Copy results into user buffer  */
+        switch (_IOC_DIR(cmd))
+        {
+        case _IOC_READ:
+        case (_IOC_WRITE | _IOC_READ):
+                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+                        err = -EFAULT;
+                break;
+        }
+
+out:
+        if (mbuf)
+                kfree(mbuf);
+
+        return err;
+}
 
 static int __init init_dvbdev(void)
 {
 	int retval;
+
+	if ((retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops)))
+		printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+
 	devfs_mk_dir("dvb");
 
-	retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops);
-	if (retval)
-		printk("video_dev: unable to get major %d\n", DVB_MAJOR);
+	dvb_class = class_simple_create(THIS_MODULE, "dvb");
+	if (IS_ERR(dvb_class))
+		return PTR_ERR(dvb_class);
 
 	return retval;
 }
@@ -327,6 +408,7 @@
 {
 	unregister_chrdev(DVB_MAJOR, "DVB");
         devfs_remove("dvb");
+	class_simple_destroy(dvb_class);
 }
 
 module_init(init_dvbdev);
@@ -336,6 +418,3 @@
 MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(dvbdev_debug,"i");
-MODULE_PARM_DESC(dvbdev_debug, "enable verbose debug messages");
-
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvbdev.h linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvbdev.h
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvbdev.h	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvbdev.h	2004-08-18 19:58:18.000000000 +0200
@@ -28,6 +28,7 @@
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/smp_lock.h>
 
 #define DVB_MAJOR 212
 
@@ -92,5 +90,15 @@
 extern int dvb_generic_release (struct inode *inode, struct file *file);
 extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
 			      unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy()  someday... */
+
+extern int dvb_usercopy(struct inode *inode, struct file *file,
+	                    unsigned int cmd, unsigned long arg,
+			    int (*func)(struct inode *inode, struct file *file,
+			    unsigned int cmd, void *arg));
+			      
 #endif /* #ifndef _DVBDEV_H_ */
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_frontend.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_frontend.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.c	2004-08-18 19:52:17.000000000 +0200
@@ -1,5 +1,6 @@
 /*
- * dvb-core.c: DVB core driver
+ * dvb_frontend.c: DVB frontend tuning interface/thread
+ *
  *
  * Copyright (C) 1999-2001 Ralph  Metzler
  *                         Marcus Metzler
@@ -31,13 +32,33 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/list.h>
 #include <asm/processor.h>
 #include <asm/semaphore.h>
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
-#include "dvb_functions.h"
+
+static int dvb_frontend_debug;
+static int dvb_shutdown_timeout = 5;
+static int dvb_override_frequency_bending;
+static int dvb_force_auto_inversion;
+static int dvb_override_tune_delay;
+static int do_frequency_bending;
+
+module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
+MODULE_PARM_DESC(dvb_frontend_debug, "Turn on/off frontend core debugging (default:off).");
+module_param(dvb_shutdown_timeout, int, 0444);
+MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+module_param(dvb_override_frequency_bending, int, 0444);
+MODULE_PARM_DESC(dvb_override_frequency_bending, "0: normal (default), 1: never use frequency bending, 2: always use frequency bending");
+module_param(dvb_force_auto_inversion, int, 0444);
+MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
+module_param(dvb_override_tune_delay, int, 0444);
+MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+
+#define dprintk if (dvb_frontend_debug) printk
 
 #define FESTATE_IDLE 1
 #define FESTATE_RETUNE 2
@@ -66,17 +87,6 @@
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-
-static int dvb_frontend_debug = 0;
-static int dvb_shutdown_timeout = 5;
-static int dvb_override_frequency_bending = 0;
-static int dvb_force_auto_inversion = 0;
-static int dvb_override_tune_delay = 0;
-
-static int do_frequency_bending = 0;
-
-#define dprintk if (dvb_frontend_debug) printk
-
 #define MAX_EVENT 8
 
 struct dvb_fe_events {
@@ -95,6 +105,7 @@
 	struct dvb_device *dvbdev;
 	struct dvb_frontend_parameters parameters;
 	struct dvb_fe_events events;
+	struct module *module;
 	struct semaphore sem;
 	struct list_head list_head;
 	wait_queue_head_t wait_queue;
@@ -174,7 +185,7 @@
 {
 	struct list_head *entry;
 	int stepsize = this_fe->info->frequency_stepsize;
-	int this_fe_adap_num = this_fe->frontend.i2c->adapter->num;
+	int this_fe_adap_num = this_fe->frontend.dvb_adapter->num;
 	int frequency;
 
 	if (!stepsize || recursive > 10) {
@@ -198,7 +209,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.i2c->adapter->num != this_fe_adap_num)
+		if (fe->frontend.dvb_adapter->num != this_fe_adap_num)
 			continue;
 
 		f = fe->parameters.frequency;
@@ -233,13 +244,10 @@
 	dprintk ("%s\n", __FUNCTION__);
 
 	if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK))
-		dvb_delay (fe->info->notifier_delay);
+		msleep (fe->info->notifier_delay);
 
 	fe->status = s;
 
-	if (!(s & FE_HAS_LOCK) && (fe->info->caps & FE_CAN_MUTE_TS))
-		return;
-
 	/**
 	 *   now tell the Demux about the TS status changes...
 	 */
@@ -333,8 +341,8 @@
 {
 	struct dvb_frontend *frontend = &fe->frontend;
 
-	dprintk ("DVB: initialising frontend %i:%i (%s)...\n",
-		 frontend->i2c->adapter->num, frontend->i2c->id,
+	dprintk ("DVB: initialising frontend %i (%s)...\n",
+		 frontend->dvb_adapter->num,
 		 fe->info->name);
 
 	dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL);
@@ -371,25 +379,26 @@
 	int original_inversion = fe->parameters.inversion;
 	u32 original_frequency = fe->parameters.frequency;
 
-	// are we using autoinversion?
-	autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO));
+	/* are we using autoinversion? */
+	autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) &&
+			 (fe->parameters.inversion == INVERSION_AUTO));
 
-	// setup parameters correctly
+	/* setup parameters correctly */
 	while(!ready) {
-		// calculate the lnb_drift
+		/* calculate the lnb_drift */
 		fe->lnb_drift = fe->auto_step * fe->step_size;
 
-		// wrap the auto_step if we've exceeded the maximum drift
+		/* wrap the auto_step if we've exceeded the maximum drift */
 		if (fe->lnb_drift > fe->max_drift) {
 			fe->auto_step = 0;
 			fe->auto_sub_step = 0;
 			fe->lnb_drift = 0;
 		}
 
-		// perform inversion and +/- zigzag
+		/* perform inversion and +/- zigzag */
 		switch(fe->auto_sub_step) {
 		case 0:
-			// try with the current inversion and current drift setting
+			/* try with the current inversion and current drift setting */
 			ready = 1;
 			break;
 
@@ -418,35 +427,36 @@
 		    
 		default:
 			fe->auto_step++;
-			fe->auto_sub_step = -1; // it'll be incremented to 0 in a moment
+			fe->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
 			break;
 		}
 	    
 		if (!ready) fe->auto_sub_step++;
 	}
 
-	// if this attempt would hit where we started, indicate a complete iteration has occurred
-	if ((fe->auto_step == fe->started_auto_step) && (fe->auto_sub_step == 0) && check_wrapped) {
+	/* if this attempt would hit where we started, indicate a complete
+	 * iteration has occurred */
+	if ((fe->auto_step == fe->started_auto_step) &&
+	    (fe->auto_sub_step == 0) && check_wrapped) {
 		return 1;
 		}
 
-	// perform frequency bending if necessary
+	/* perform frequency bending if necessary */
 	if ((dvb_override_frequency_bending != 1) && do_frequency_bending)
 		dvb_bend_frequency(fe, 0);
 
-	// instrumentation
-	dprintk("%s: drift:%i bending:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", 
-		__FUNCTION__, fe->lnb_drift, fe->bending, fe->inversion, fe->auto_step, fe->auto_sub_step,
-		fe->started_auto_step);
+	dprintk("%s: drift:%i bending:%i inversion:%i auto_step:%i "
+		"auto_sub_step:%i started_auto_step:%i\n",
+		__FUNCTION__, fe->lnb_drift, fe->bending, fe->inversion,
+		fe->auto_step, fe->auto_sub_step, fe->started_auto_step);
     
-	// set the frontend itself
+	/* set the frontend itself */
 	fe->parameters.frequency += fe->lnb_drift + fe->bending;
 	if (autoinversion) fe->parameters.inversion = fe->inversion;
 	dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters);
 	fe->parameters.frequency = original_frequency;
 	fe->parameters.inversion = original_inversion;
 
-	// normal return
 	fe->auto_sub_step++;
 	return 0;
 }
@@ -490,10 +500,13 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	snprintf (name, sizeof(name), "kdvb-fe-%i:%i",
-		  fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);
+	snprintf (name, sizeof(name), "kdvb-fe-%i",
+		  fe->frontend.dvb_adapter->num);
 
-	dvb_kernel_thread_setup (name);
+        lock_kernel ();
+        daemonize (name);
+        sigfillset (&current->blocked);
+        unlock_kernel ();
 
 	dvb_call_frontend_notifiers (fe, 0);
 	dvb_frontend_init (fe);
@@ -511,65 +524,70 @@
 		if (down_interruptible (&fe->sem))
 			break;
 
-		// if we've got no parameters, just keep idling
+		/* if we've got no parameters, just keep idling */
 		if (fe->state & FESTATE_IDLE) {
 			delay = 3*HZ;
 			quality = 0;
 			continue;
 		}
 
-		// get the frontend status
+		/* get the frontend status */
+		if (fe->state & FESTATE_RETUNE) {
+			s = 0;
+		} else {
 		dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s);
-		if (s != fe->status)
+			if (s != fe->status) {
 			dvb_frontend_add_event (fe, s);
-
-		// if we're not tuned, and we have a lock, move to the TUNED state
+			}
+		}
+		/* if we're not tuned, and we have a lock, move to the TUNED state */
 		if ((fe->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
 			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 			fe->state = FESTATE_TUNED;
 
-			// if we're tuned, then we have determined the correct inversion
-			if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)) {
+			/* if we're tuned, then we have determined the correct inversion */
+			if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) &&
+			    (fe->parameters.inversion == INVERSION_AUTO)) {
 				fe->parameters.inversion = fe->inversion;
 			}
 			continue;
 		}
 
-		// if we are tuned already, check we're still locked
+		/* if we are tuned already, check we're still locked */
 		if (fe->state & FESTATE_TUNED) {
 			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 
-			// we're tuned, and the lock is still good...
-		if (s & FE_HAS_LOCK) {
+			/* we're tuned, and the lock is still good... */
+			if (s & FE_HAS_LOCK)
 				continue;
-		} else {
-				// if we _WERE_ tuned, but now don't have a lock, need to zigzag
+			else {
+				/* if we _WERE_ tuned, but now don't have a lock,
+				 * need to zigzag */
 				fe->state = FESTATE_ZIGZAG_FAST;
 				fe->started_auto_step = fe->auto_step;
 				check_wrapped = 0;
-				// fallthrough
 			}
 		}
 
-		// don't actually do anything if we're in the LOSTLOCK state, the frontend is set to
-		// FE_CAN_RECOVER, and the max_drift is 0
+		/* don't actually do anything if we're in the LOSTLOCK state,
+		 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
 		if ((fe->state & FESTATE_LOSTLOCK) && 
 		    (fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
 			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 						continue;
 				}
 	    
-		// don't do anything if we're in the DISEQC state, since this might be someone
-		// with a motorized dish controlled by DISEQC. If its actually a re-tune, there will
-		// be a SET_FRONTEND soon enough.
+		/* don't do anything if we're in the DISEQC state, since this
+		 * might be someone with a motorized dish controlled by DISEQC.
+		 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
 		if (fe->state & FESTATE_DISEQC) {
 			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 			continue;
 				}
 
-		// if we're in the RETUNE state, set everything up for a brand new scan,
-		// keeping the current inversion setting, as the next tune is _very_ likely
-		// to require the same
+		/* if we're in the RETUNE state, set everything up for a brand
+		 * new scan, keeping the current inversion setting, as the next
+		 * tune is _very_ likely to require the same */
 		if (fe->state & FESTATE_RETUNE) {
 			fe->lnb_drift = 0;
 			fe->auto_step = 0;
@@ -578,35 +596,36 @@
 			check_wrapped = 0;
 		}
 
-		// fast zigzag.
+		/* fast zigzag. */
 		if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) {
 			delay = fe->min_delay;
 
-			// peform a tune
+			/* peform a tune */
 			if (dvb_frontend_autotune(fe, check_wrapped)) {
-				// OK, if we've run out of trials at the fast speed. Drop back to
-				// slow for the _next_ attempt
+				/* OK, if we've run out of trials at the fast speed.
+				 * Drop back to slow for the _next_ attempt */
 				fe->state = FESTATE_SEARCHING_SLOW;
 				fe->started_auto_step = fe->auto_step;
 				continue;
 			}
 			check_wrapped = 1;
 
-			// if we've just retuned, enter the ZIGZAG_FAST state. This ensures
-			// we cannot return from an FE_SET_FRONTEND ioctl before the first frontend
-			// tune occurs
+			/* if we've just retuned, enter the ZIGZAG_FAST state.
+			 * This ensures we cannot return from an
+			 * FE_SET_FRONTEND ioctl before the first frontend tune
+			 * occurs */
 			if (fe->state & FESTATE_RETUNE) {
 				fe->state = FESTATE_TUNING_FAST;
 				wake_up_interruptible(&fe->wait_queue);
 			}
 		}
 
-		// slow zigzag
+		/* slow zigzag */
 		if (fe->state & FESTATE_SEARCHING_SLOW) {
 			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
 		    
-			// Note: don't bother checking for wrapping; we stay in this state 
-			// until we get a lock
+			/* Note: don't bother checking for wrapping; we stay in this
+			 * state until we get a lock */
 			dvb_frontend_autotune(fe, 0);
 		}
 	};
@@ -614,8 +633,6 @@
 	if (dvb_shutdown_timeout)
 		dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); 
 
-	up (&fe->sem);
-
 	fe->thread_pid = 0;
 	mb();
 
@@ -711,6 +729,11 @@
 	if (!fe || !fe->frontend.ioctl || fe->exit)
 		return -ENODEV;
 
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
+	    (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
+	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+		return -EPERM;
+
 	if (down_interruptible (&fe->sem))
 		return -ERESTARTSYS;
 
@@ -718,6 +741,7 @@
 	case FE_DISEQC_SEND_MASTER_CMD:
 	case FE_DISEQC_SEND_BURST:
 	case FE_SET_TONE:
+	case FE_SET_VOLTAGE:
 		if (fe->status)
 			dvb_call_frontend_notifiers (fe, 0);
 		dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
@@ -734,43 +758,48 @@
 		memcpy(&fetunesettings.parameters, parg,
 		       sizeof (struct dvb_frontend_parameters));
 		    
-		// force auto frequency inversion if requested
+		/* force auto frequency inversion if requested */
 		if (dvb_force_auto_inversion) {
 			fe->parameters.inversion = INVERSION_AUTO;
 			fetunesettings.parameters.inversion = INVERSION_AUTO;
 		}
 
-		// get frontend-specific tuning settings
-		if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, &fetunesettings) == 0) {
+		/* get frontend-specific tuning settings */
+		if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS,
+						&fetunesettings) == 0) {
 			fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
 			fe->max_drift = fetunesettings.max_drift;
 			fe->step_size = fetunesettings.step_size;
 		} else {
-			// default values
+			/* default values */
 			switch(fe->info->type) {
 			case FE_QPSK:
-				fe->min_delay = HZ/20; // default mindelay of 50ms
+				fe->min_delay = HZ/20;
 				fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000;
 				fe->max_drift = fe->parameters.u.qpsk.symbol_rate / 2000;
 		break;
 			    
 			case FE_QAM:
-				fe->min_delay = HZ/20; // default mindelay of 50ms
-				fe->step_size = 0;
-				fe->max_drift = 0; // don't want any zigzagging under DVB-C frontends
+				fe->min_delay = HZ/20;
+				fe->step_size = 0; /* no zigzag */
+				fe->max_drift = 0;
 				break;
 			    
 			case FE_OFDM:
-				fe->min_delay = HZ/20; // default mindelay of 50ms
+				fe->min_delay = HZ/20;
 				fe->step_size = fe->info->frequency_stepsize * 2;
 				fe->max_drift = (fe->info->frequency_stepsize * 2) + 1;
 				break;
+			case FE_ATSC:
+				printk("dvb-core: FE_ATSC not handled yet.\n");
+				break;
 			}
 		}
 		if (dvb_override_tune_delay > 0) {
 		       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;
 		}
 
+		dvb_frontend_wakeup(fe);
 		dvb_frontend_add_event (fe, 0);	    
 		break;
 
@@ -789,20 +819,13 @@
 	if (err < 0)
 		return err;
 
-	// Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't do it, it is done for it.
+	/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
+	 * do it, it is done for it. */
 	if ((cmd == FE_GET_INFO) && (err == 0)) {
 		struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
 		tmp->caps |= FE_CAN_INVERSION_AUTO;
 	}
 
-	// if the frontend has just been set, wait until the first tune has finished.
-	// This ensures the app doesn't start reading data too quickly, perhaps from the
-	// previous lock, which is REALLY CONFUSING TO DEBUG!
-	if ((cmd == FE_SET_FRONTEND) && (err == 0)) {
-		dvb_frontend_wakeup(fe);
-		err = wait_event_interruptible(fe->wait_queue, fe->state & ~FESTATE_RETUNE);
-	}
-
 	return err;
 }
 
@@ -843,6 +866,11 @@
 		fe->events.eventr = fe->events.eventw = 0;
 	}
 	
+	if (!ret && fe->module) {
+		if (!try_module_get(fe->module))
+			return -EINVAL;
+	}
+
 	return ret;
 }
 
@@ -851,13 +879,19 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend_data *fe = dvbdev->priv;
+	int ret = 0;
 
 	dprintk ("%s\n", __FUNCTION__);
 
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
 		fe->release_jiffies = jiffies;
 
-	return dvb_generic_release (inode, file);
+	ret = dvb_generic_release (inode, file);
+
+	if (!ret && fe->module)
+		module_put(fe->module);
+
+	return ret;
 }
 
 
@@ -897,7 +931,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.i2c->adapter == adapter &&
+		if (fe->frontend.dvb_adapter == adapter &&
 		    fe->frontend.before_ioctl == NULL &&
 		    fe->frontend.after_ioctl == NULL)
 		{
@@ -931,7 +965,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.i2c->adapter == adapter &&
+		if (fe->frontend.dvb_adapter == adapter &&
 		    fe->frontend.before_ioctl == before_ioctl &&
 		    fe->frontend.after_ioctl == after_ioctl)
 		{
@@ -992,7 +1026,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.i2c->adapter == adapter &&
+		if (fe->frontend.dvb_adapter == adapter &&
 		    fe->frontend.notifier_callback == NULL)
 		{
 			fe->frontend.notifier_callback = callback;
@@ -1021,7 +1055,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.i2c->adapter == adapter &&
+		if (fe->frontend.dvb_adapter == adapter &&
 		    fe->frontend.notifier_callback == callback)
 		{
 			fe->frontend.notifier_callback = NULL;
@@ -1061,9 +1093,10 @@
 int
 dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
 				     unsigned int cmd, void *arg),
-		       struct dvb_i2c_bus *i2c,
+		       struct dvb_adapter *dvb_adapter,
 		       void *data,
-		       struct dvb_frontend_info *info)
+		       struct dvb_frontend_info *info,
+		       struct module *module)
 {
 	struct list_head *entry;
 	struct dvb_frontend_data *fe;
@@ -1093,9 +1126,10 @@
 	init_MUTEX (&fe->events.sem);
 	fe->events.eventw = fe->events.eventr = 0;
 	fe->events.overflow = 0;
+	fe->module = module;
 
 	fe->frontend.ioctl = ioctl;
-	fe->frontend.i2c = i2c;
+	fe->frontend.dvb_adapter = dvb_adapter;
 	fe->frontend.data = data;
 	fe->info = info;
 	fe->inversion = INVERSION_OFF;
@@ -1107,7 +1141,7 @@
 				    struct dvb_frontend_ioctl_data,
 				    list_head);
 
-		if (ioctl->adapter == i2c->adapter) {
+		if (ioctl->adapter == dvb_adapter) {
 			fe->frontend.before_ioctl = ioctl->before_ioctl;
 			fe->frontend.after_ioctl = ioctl->after_ioctl;
 			fe->frontend.before_after_data = ioctl->before_after_data;
@@ -1122,7 +1156,7 @@
 				       struct dvb_frontend_notifier_data,
 				       list_head);
 
-		if (notifier->adapter == i2c->adapter) {
+		if (notifier->adapter == dvb_adapter) {
 			fe->frontend.notifier_callback = notifier->callback;
 			fe->frontend.notifier_data = notifier->data;
 			break;
@@ -1131,11 +1165,11 @@
 
 	list_add_tail (&fe->list_head, &frontend_list);
 
-	printk ("DVB: registering frontend %i:%i (%s)...\n",
-		fe->frontend.i2c->adapter->num, fe->frontend.i2c->id,
+	printk ("DVB: registering frontend %i (%s)...\n",
+		fe->frontend.dvb_adapter->num,
 		fe->info->name);
 
-	dvb_register_device (i2c->adapter, &fe->dvbdev, &dvbdev_template,
+	dvb_register_device (dvb_adapter, &fe->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
 
 	if ((info->caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2))
@@ -1146,10 +1179,9 @@
 	return 0;
 }
 
-
-int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
+int dvb_unregister_frontend_new (int (*ioctl) (struct dvb_frontend *frontend,
 					   unsigned int cmd, void *arg),
-			     struct dvb_i2c_bus *i2c)
+			     struct dvb_adapter *dvb_adapter)
 {
         struct list_head *entry, *n;
 
@@ -1162,7 +1194,7 @@
 
 		fe = list_entry (entry, struct dvb_frontend_data, list_head);
 
-		if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) {
+		if (fe->frontend.ioctl == ioctl && fe->frontend.dvb_adapter == dvb_adapter) {
 			dvb_unregister_device (fe->dvbdev);
 			list_del (entry);
 			up (&frontend_mutex);
@@ -1176,14 +1208,3 @@
 	return -EINVAL;
 }
 
-MODULE_PARM(dvb_frontend_debug,"i");
-MODULE_PARM(dvb_shutdown_timeout,"i");
-MODULE_PARM(dvb_override_frequency_bending,"i");
-MODULE_PARM(dvb_force_auto_inversion,"i");
-MODULE_PARM(dvb_override_tune_delay,"i");
-
-MODULE_PARM_DESC(dvb_frontend_debug, "enable verbose debug messages");
-MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-MODULE_PARM_DESC(dvb_override_frequency_bending, "0: normal (default), 1: never use frequency bending, 2: always use frequency bending");
-MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_frontend.h linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.h
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_frontend.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.h	2004-08-18 19:52:17.000000000 +0200
@@ -31,14 +34,29 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/delay.h>
 
 #include <linux/dvb/frontend.h>
 
-#include "dvb_i2c.h"
 #include "dvbdev.h"
 
-
-
+/* FIXME: Move to i2c-id.h */
+#define I2C_DRIVERID_DVBFE_ALPS_TDLB7	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_ALPS_TDMB7	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_AT76C651	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX24110	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DST		I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DUMMY	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_L64781	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_MT312	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_MT352	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_NXT6000	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_SP887X	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_STV0299	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA1004X	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA8083	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_VES1820	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_VES1X93	I2C_DRIVERID_EXP2
 
 /**
  *   when before_ioctl is registered and returns value 0, ioctl and after_ioctl
@@ -50,7 +68,7 @@
 	int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
 	int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
 	void (*notifier_callback) (fe_status_t s, void *data);
-	struct dvb_i2c_bus *i2c;
+	struct dvb_adapter *dvb_adapter;
 	void *before_after_data;   /*  can be used by hardware module... */
 	void *notifier_data;       /*  can be used by hardware module... */
 	void *data;                /*  can be used by hardware module... */
@@ -75,19 +93,21 @@
 #define FE_SLEEP              _IO('v', 80)
 #define FE_INIT               _IO('v', 81)
 #define FE_GET_TUNE_SETTINGS  _IOWR('v', 83, struct dvb_frontend_tune_settings)
-
+#define FE_REGISTER	      _IO  ('v', 84)
+#define FE_UNREGISTER	      _IO  ('v', 85)
 
 extern int
 dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
 				     unsigned int cmd, void *arg),
-		       struct dvb_i2c_bus *i2c,
+		       struct dvb_adapter *dvb_adapter,
 		       void *data,
-		       struct dvb_frontend_info *info);
+		       struct dvb_frontend_info *info,
+		       struct module *module);
 
 extern int
-dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
+dvb_unregister_frontend_new (int (*ioctl) (struct dvb_frontend *frontend,
 				       unsigned int cmd, void *arg),
-			 struct dvb_i2c_bus *i2c);
+			 struct dvb_adapter *dvb_adapter);
 
 
 /**
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ksyms.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ksyms.c
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/dvb_ksyms.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ksyms.c	2004-08-18 19:52:17.000000000 +0200
@@ -24,17 +24,12 @@
 EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
 EXPORT_SYMBOL(dvb_register_frontend);
-EXPORT_SYMBOL(dvb_unregister_frontend);
+EXPORT_SYMBOL(dvb_unregister_frontend_new);
 EXPORT_SYMBOL(dvb_add_frontend_ioctls);
 EXPORT_SYMBOL(dvb_remove_frontend_ioctls);
 EXPORT_SYMBOL(dvb_add_frontend_notifier);
 EXPORT_SYMBOL(dvb_remove_frontend_notifier);
 
-EXPORT_SYMBOL(dvb_register_i2c_bus);
-EXPORT_SYMBOL(dvb_unregister_i2c_bus);
-EXPORT_SYMBOL(dvb_register_i2c_device);
-EXPORT_SYMBOL(dvb_unregister_i2c_device);
-
 EXPORT_SYMBOL(dvb_net_init);
 EXPORT_SYMBOL(dvb_net_release);
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/Makefile linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/Makefile
--- xx-linux-2.6.8.1/drivers/media/dvb/dvb-core/Makefile	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/Makefile	2004-08-18 19:44:05.000000000 +0200
@@ -3,7 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-	        dvb_ca_en50221.o dvb_functions.o dvb_frontend.o \
-		dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
+	        dvb_ca_en50221.o dvb_frontend.o \
+		dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff -uraN a/drivers/media/dvb/dvb-core/dvb_functions.c b/drivers/media/dvb/dvb-core/dvb_functions.c
--- a/drivers/media/dvb/dvb-core/dvb_functions.c	2004-08-24 16:34:45.000000000 +0200
+++ b/drivers/media/dvb/dvb-core/dvb_functions.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,89 +0,0 @@
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-
-void dvb_kernel_thread_setup (const char *thread_name)
-{
-        lock_kernel ();
-
-        daemonize (thread_name);
-
-        sigfillset (&current->blocked);
-
-        unlock_kernel ();
-}
-
-/* if the miracle happens and "generic_usercopy()" is included into
-   the kernel, then this can vanish. please don't make the mistake and
-   define this as video_usercopy(). this will introduce a dependecy
-   to the v4l "videodev.o" module, which is unnecessary for some
-   cards (ie. the budget dvb-cards don't need the v4l module...) */
-int dvb_usercopy(struct inode *inode, struct file *file,
-	             unsigned int cmd, unsigned long arg,
-		     int (*func)(struct inode *inode, struct file *file,
-		     unsigned int cmd, void *arg))
-{
-        char    sbuf[128];
-        void    *mbuf = NULL;
-        void    *parg = NULL;
-        int     err  = -EINVAL;
-
-        /*  Copy arguments into temp kernel buffer  */
-        switch (_IOC_DIR(cmd)) {
-        case _IOC_NONE:
-		/*
-		 * For this command, the pointer is actually an integer
-		 * argument.
-		 */
-                parg = (void *) arg;
-                break;
-        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
-        case _IOC_WRITE:
-        case (_IOC_WRITE | _IOC_READ):
-                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-                        parg = sbuf;
-                } else {
-                        /* too big to allocate from stack */
-                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-                        if (NULL == mbuf)
-                                return -ENOMEM;
-                        parg = mbuf;
-                }
-
-                err = -EFAULT;
-                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-                        goto out;
-                break;
-        }
-
-        /* call driver */
-        if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
-                err = -EINVAL;
-
-        if (err < 0)
-                goto out;
-
-        /*  Copy results into user buffer  */
-        switch (_IOC_DIR(cmd))
-        {
-        case _IOC_READ:
-        case (_IOC_WRITE | _IOC_READ):
-                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-                        err = -EFAULT;
-                break;
-        }
-
-out:
-        if (mbuf)
-                kfree(mbuf);
-
-        return err;
-}
-
-EXPORT_SYMBOL(dvb_usercopy);
-EXPORT_SYMBOL(dvb_kernel_thread_setup);
diff -uraN a/drivers/media/dvb/dvb-core/dvb_functions.h b/drivers/media/dvb/dvb-core/dvb_functions.h
--- a/drivers/media/dvb/dvb-core/dvb_functions.h	2004-08-24 16:34:45.000000000 +0200
+++ b/drivers/media/dvb/dvb-core/dvb_functions.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,50 +0,0 @@
-/* 
- * dvb_functions.h: isolate some Linux specific stuff from the dvb-core
- *                  that can't be expressed as a one-liner
- *                  in order to make porting to other environments easier
- *
- * Copyright (C) 2003 Convergence GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Lesser Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- *
- */
-
-#ifndef __DVB_FUNCTIONS_H__
-#define __DVB_FUNCTIONS_H__
-
-/**
- *  a sleeping delay function, waits i ms
- *
- */
-static inline
-void dvb_delay(int i)
-{
-	current->state=TASK_INTERRUPTIBLE;
-	schedule_timeout((HZ*i)/1000);
-}
-
-/* we don't mess with video_usercopy() any more,
-we simply define out own dvb_usercopy(), which will hopefull become
-generic_usercopy()  someday... */
-
-extern int dvb_usercopy(struct inode *inode, struct file *file,
-	                    unsigned int cmd, unsigned long arg,
-			    int (*func)(struct inode *inode, struct file *file,
-			    unsigned int cmd, void *arg));
-
-extern void dvb_kernel_thread_setup (const char *thread_name);
-
-#endif
-
diff -uraN a/drivers/media/dvb/dvb-core/dvb_i2c.c b/drivers/media/dvb/dvb-core/dvb_i2c.c
--- a/drivers/media/dvb/dvb-core/dvb_i2c.c	2004-08-24 16:34:51.000000000 +0200
+++ b/drivers/media/dvb/dvb-core/dvb_i2c.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,290 +0,0 @@
-/*
- * dvb_i2c.h: simplified i2c interface for DVB adapters to get rid of i2c-core.c
- *
- * Copyright (C) 2002 Holger Waechtler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <asm/semaphore.h>
-
-#include "dvb_i2c.h"
-#include "dvb_functions.h"
-
-
-struct dvb_i2c_device {
-	struct list_head list_head;
-	struct module *owner;
-	int (*attach) (struct dvb_i2c_bus *i2c, void **data);
-	void (*detach) (struct dvb_i2c_bus *i2c, void *data);
-	void *data;
-};
-
-LIST_HEAD(dvb_i2c_buslist);
-LIST_HEAD(dvb_i2c_devicelist);
-
-DECLARE_MUTEX(dvb_i2c_mutex);
-
-static int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
-{
-	struct dvb_i2c_device *client;
-
-	if (!(client = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL)))
-		return -ENOMEM;
-
-	client->detach = dev->detach;
-	client->owner = dev->owner;
-	client->data = dev->data;
-
-	INIT_LIST_HEAD(&client->list_head);
-
-	list_add_tail (&client->list_head, &i2c->client_list);
-
-	return 0;
-}
-
-
-static void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
-{
-	if (dev->owner) {
-		if (!try_module_get(dev->owner))
-			return;
-	}
-
-	if (dev->attach (i2c, &dev->data) == 0) {
-		register_i2c_client (i2c, dev);
-	} else {
-		if (dev->owner)
-			module_put (dev->owner);
-	}
-}
-
-
-static void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
-{
-	dev->detach (i2c, dev->data);
-
-	if (dev->owner)
-		module_put (dev->owner);
-}
-
-
-static void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
-				     struct dvb_i2c_bus *i2c)
-{
-	struct list_head *entry, *n;
-
-	list_for_each_safe (entry, n, &i2c->client_list) {
-                struct dvb_i2c_device *client;
-
-		client = list_entry (entry, struct dvb_i2c_device, list_head);
-
-		if (client->detach == dev->detach) {
-			list_del (entry);
-			detach_device (i2c, dev);
-		}
-	}
-}
-
-
-static void unregister_i2c_client_from_all_busses (struct dvb_i2c_device *dev)
-{
-	struct list_head *entry, *n;
-
-	list_for_each_safe (entry, n, &dvb_i2c_buslist) {
-                struct dvb_i2c_bus *i2c;
-
-		i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
-
-		unregister_i2c_client_from_bus (dev, i2c);
-	}
-}
-
-
-static void unregister_all_clients_from_bus (struct dvb_i2c_bus *i2c)
-{
-	struct list_head *entry, *n;
-
-	list_for_each_safe (entry, n, &(i2c->client_list)) {
-		struct dvb_i2c_device *dev;
-
-		dev = list_entry (entry, struct dvb_i2c_device, list_head);
-
-		unregister_i2c_client_from_bus (dev, i2c);
-	}
-}
-
-
-static void probe_device_on_all_busses (struct dvb_i2c_device *dev)
-{
-	struct list_head *entry;
-
-	list_for_each (entry, &dvb_i2c_buslist) {
-                struct dvb_i2c_bus *i2c;
-
-		i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
-
-		try_attach_device (i2c, dev);
-	}
-}
-
-
-static void probe_devices_on_bus (struct dvb_i2c_bus *i2c)
-{
-	struct list_head *entry;
-
-	list_for_each (entry, &dvb_i2c_devicelist) {
-		struct dvb_i2c_device *dev;
-
-		dev = list_entry (entry, struct dvb_i2c_device, list_head);
-
-		try_attach_device (i2c, dev);
-	}
-}
-
-
-static struct dvb_i2c_bus* dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
-		                                   const struct i2c_msg msgs[],
-						   int num),
-				      struct dvb_adapter *adapter,
-				      int id)
-{
-	struct list_head *entry;
-
-	list_for_each (entry, &dvb_i2c_buslist) {
-		struct dvb_i2c_bus *i2c;
-
-		i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
-
-		if (i2c->xfer == xfer && i2c->adapter == adapter && i2c->id == id)
-			return i2c;
-	}
-
-	return NULL;
-}
-
-
-struct dvb_i2c_bus*
-dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
-				   const struct i2c_msg *msgs, int num),
-		      void *data, struct dvb_adapter *adapter, int id)
-{
-	struct dvb_i2c_bus *i2c;
-
-	if (down_interruptible (&dvb_i2c_mutex))
-		return NULL;
-
-	if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL))) {
-		up (&dvb_i2c_mutex);
-		return NULL;
-	}
-
-	INIT_LIST_HEAD(&i2c->list_head);
-	INIT_LIST_HEAD(&i2c->client_list);
-
-	i2c->xfer = xfer;
-	i2c->data = data;
-	i2c->adapter = adapter;
-	i2c->id = id;
-
-	probe_devices_on_bus (i2c);
-
-	list_add_tail (&i2c->list_head, &dvb_i2c_buslist);
-
-	up (&dvb_i2c_mutex);
-
-	return i2c;
-}
-
-
-void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
-					  const struct i2c_msg msgs[], int num),
-			     struct dvb_adapter *adapter, int id)
-{
-	struct dvb_i2c_bus *i2c;
-
-	down (&dvb_i2c_mutex);
-
-	if ((i2c = dvb_find_i2c_bus (xfer, adapter, id))) {
-		unregister_all_clients_from_bus (i2c);
-		list_del (&i2c->list_head);
-		kfree (i2c);
-	}
-
-	up (&dvb_i2c_mutex);
-}
-
-
-int dvb_register_i2c_device (struct module *owner,
-			     int (*attach) (struct dvb_i2c_bus *i2c, void **data),
-			     void (*detach) (struct dvb_i2c_bus *i2c, void *data))
-{
-	struct dvb_i2c_device *entry;
-
-	if (down_interruptible (&dvb_i2c_mutex))
-		return -ERESTARTSYS;
-
-	if (!(entry = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL))) {
-		up(&dvb_i2c_mutex);
-		return -ENOMEM;
-	}
-
-	entry->owner = owner;
-	entry->attach = attach;
-	entry->detach = detach;
-
-	INIT_LIST_HEAD(&entry->list_head);
-
-	probe_device_on_all_busses (entry);
-
-	list_add_tail (&entry->list_head, &dvb_i2c_devicelist);
-
-	up (&dvb_i2c_mutex);
-
-	return 0;
-}
-
-
-int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data))
-{
-	struct list_head *entry, *n;
-
-	down (&dvb_i2c_mutex);
-
-	list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
-		struct dvb_i2c_device *dev;
-
-		dev = list_entry (entry, struct dvb_i2c_device, list_head);
-
-		if (dev->attach == attach) {
-			list_del (entry);
-			unregister_i2c_client_from_all_busses (dev);
-			kfree (entry);
-			up (&dvb_i2c_mutex);
-			return 0;
-                }
-        }
-
-	up (&dvb_i2c_mutex);
-
-        return -EINVAL;
-}
-
-
diff -uraN a/drivers/media/dvb/dvb-core/dvb_i2c.h b/drivers/media/dvb/dvb-core/dvb_i2c.h
--- a/drivers/media/dvb/dvb-core/dvb_i2c.h	2004-08-24 16:34:51.000000000 +0200
+++ b/drivers/media/dvb/dvb-core/dvb_i2c.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,63 +0,0 @@
-/*
- * dvb_i2c.h: i2c interface to get rid of i2c-core.c
- *
- * Copyright (C) 2002 Holger Waechtler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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.
- */
-
-#ifndef _DVB_I2C_H_
-#define _DVB_I2C_H_
-
-#include <linux/list.h>
-#include <linux/i2c.h>
-
-#include "dvbdev.h"
-
-
-struct dvb_i2c_bus {
-	struct list_head list_head;
-	int (*xfer) (struct dvb_i2c_bus *i2c, 
-		     const struct i2c_msg msgs[],
-		     int num);
-	void *data;
-	struct dvb_adapter *adapter;
-	int id;
-	struct list_head client_list;
-};
-
-
-extern struct dvb_i2c_bus*
-dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
-				   const struct i2c_msg *msgs, int num),
-		      void *data,
-		      struct dvb_adapter *adapter,
-		      int id);
-
-extern
-void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
-					  const struct i2c_msg msgs[], int num),
-			     struct dvb_adapter *adapter,
-			     int id);
-
-
-extern int dvb_register_i2c_device (struct module *owner,
-				    int (*attach) (struct dvb_i2c_bus *i2c, void **data),
-				    void (*detach) (struct dvb_i2c_bus *i2c, void *data));
-
-extern int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data));
-
-#endif
-
diff -uraNwB xx-linux-2.6.8.1/include/linux/dvb/frontend.h linux-2.6.8.1-patched/include/linux/dvb/frontend.h
--- xx-linux-2.6.8.1/include/linux/dvb/frontend.h	2004-07-19 19:39:37.000000000 +0200
+++ linux-2.6.8.1-patched/include/linux/dvb/frontend.h	2004-08-05 20:28:20.000000000 +0200
@@ -32,7 +32,8 @@
 typedef enum fe_type {
         FE_QPSK,
         FE_QAM,
-        FE_OFDM
+	FE_OFDM,
+	FE_ATSC
 } fe_type_t;
 
 
@@ -59,6 +60,8 @@
 	FE_CAN_BANDWIDTH_AUTO         = 0x40000,
 	FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
 	FE_CAN_HIERARCHY_AUTO         = 0x100000,
+	FE_CAN_8VSB			= 0x200000,
+	FE_CAN_16VSB			= 0x400000,
 	FE_NEEDS_BENDING              = 0x20000000, // frontend requires frequency bending
 	FE_CAN_RECOVER                = 0x40000000, // frontend can recover from a cable unplug automatically
 	FE_CAN_MUTE_TS                = 0x80000000  // frontend can stop spurious TS data output
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_ca_en50221.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_ca_en50221.c	2004-09-17 12:26:16.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ca_en50221.c	2004-09-01 12:19:01.000000000 +0200
@@ -35,8 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <asm/rwsem.h>
-#include <asm/atomic.h>
+#include <linux/rwsem.h>
 
 #include "dvb_ca_en50221.h"
 #include "dvb_ringbuffer.h"
@@ -44,7 +43,7 @@
 static int dvb_ca_en50221_debug;
 
 module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
-MODULE_PARM_DESC(dvb_ca_en50221_debug, "enable verbose debug messages");
+MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
 
 #define dprintk if (dvb_ca_en50221_debug) printk
 
@@ -307,10 +306,6 @@
         /* we'll be determining these during this function */
         ca->slot_info[slot].da_irq_supported = 0;
 
-        /* reset the link interface. Note CAM IRQs are disabled */
-        if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS)) != 0) return ret;
-        if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ/10)) != 0) return ret;
-
         /* set the host link buffer size temporarily. it will be overwritten with the
          * real negotiated size later. */
         ca->slot_info[slot].link_buf_size = 2;
@@ -460,8 +455,8 @@
 
         /* is it a version we support? */
         if (strncmp(dvb_str + 8, "1.00", 4)) {
-                printk("dvb_ca: Unsupported DVB CAM module version %c%c%c%c\n",
-                        dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+                printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
+		       ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
                 return -EINVAL;
         }
 
@@ -589,20 +584,20 @@
         /* check it will fit */
         if (ebuf == NULL) {
                 if (bytes_read > ca->slot_info[slot].link_buf_size) {
-                        printk("dvb_ca: CAM tried to send a buffer larger than the link buffer size!\n");
+                        printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size!\n", ca->dvbdev->adapter->num);
                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
                         status = -EIO;
                         goto exit;
                 }
                 if (bytes_read < 2) {
-                        printk("dvb_ca: CAM sent a buffer that was less than 2 bytes!\n");
+                        printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", ca->dvbdev->adapter->num);
                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
                         status = -EIO;
                         goto exit;
                 }
         } else {
                 if (bytes_read > ecount) {
-                        printk("dvb_ca: CAM tried to send a buffer larger than the ecount size!\n");
+                        printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", ca->dvbdev->adapter->num);
                         status = -EIO;
                         goto exit;
                 }
@@ -984,7 +978,7 @@
 
                         case DVB_CA_SLOTSTATE_WAITREADY:
                                 if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-                                        printk("dvb_ca: PC card did not respond :(\n");
+                                        printk("dvb_ca adaptor %d: PC card did not respond :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 				        dvb_ca_en50221_thread_update_delay(ca);
                                         break;
@@ -993,20 +987,20 @@
                                 break;
 
                         case DVB_CA_SLOTSTATE_VALIDATE:
-                                if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) {
-                                        printk("dvb_ca: Unable to reset CAM IF\n");
+                                if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+                                        printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
                                         dvb_ca_en50221_thread_update_delay(ca);
                                         break;
                                 }
-                                if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
-                                        printk("dvb_ca: Invalid PC card inserted :(\n");
+                                if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+                                        printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 				        dvb_ca_en50221_thread_update_delay(ca);
                                         break;
                                 }
-                                if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
-                                        printk("dvb_ca: Unable to initialise CAM :(\n");
+                                if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) {
+                                        printk("dvb_ca adapter %d: Unable to reset CAM IF\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 				        dvb_ca_en50221_thread_update_delay(ca);
                                         break;
@@ -1021,7 +1014,7 @@
 
                         case DVB_CA_SLOTSTATE_WAITFR:
                                 if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-                                        printk("dvb_ca: DVB CAM did not respond :(\n");
+                                        printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 				        dvb_ca_en50221_thread_update_delay(ca);
                                         break;
@@ -1036,7 +1029,7 @@
 
                         case DVB_CA_SLOTSTATE_LINKINIT:
                                 if (dvb_ca_en50221_link_init(ca, slot) != 0) {
-                                        printk("dvb_ca: DVB CAM link initialisation failed :(\n");
+                                        printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 			                dvb_ca_en50221_thread_update_delay(ca);
                                         break;
@@ -1044,7 +1037,7 @@
 
                                 rxbuf = vmalloc(RX_BUFFER_SIZE);
                                 if (rxbuf == NULL) {
-                                        printk("dvb_ca: Unable to allocate CAM rx buffer :(\n");
+                                        printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
                                         ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 				        dvb_ca_en50221_thread_update_delay(ca);
                                         break;
@@ -1054,7 +1047,7 @@
                                 ca->pub->slot_ts_enable(ca->pub, slot);
                                 ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
                                 dvb_ca_en50221_thread_update_delay(ca);
-                                printk("dvb_ca: DVB CAM detected and initialised successfully\n");
+                                printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
                                 break;
 
                         case DVB_CA_SLOTSTATE_RUNNING:
@@ -1351,7 +1344,7 @@
         pktlen = 2;
         do {
                 if (idx == -1) {
-                        printk("dvb_ca: BUG: read packet ended before last_fragment encountered\n");
+                        printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
                         status = -EIO;
                         goto exit;
                 }
@@ -1617,7 +1612,7 @@
         /* shutdown the thread if there was one */
         if (ca->thread_pid) {
                 if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
-                        printk("dvb_ca_release: thread PID %d already died\n", ca->thread_pid);
+                        printk("dvb_ca_release adapter %d: thread PID %d already died\n", ca->dvbdev->adapter->num, ca->thread_pid);
                 } else {
                         ca->exit = 1;
                         mb();
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_demux.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_demux.c	2004-09-17 12:26:16.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_demux.c	2004-09-15 10:26:44.000000000 +0200
@@ -569,7 +570,7 @@
 
 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
 {
-	spin_lock(&feed->demux->lock);
+	spin_lock_irq(&feed->demux->lock);
 	if (dvb_demux_feed_find(feed)) {
 		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
 				__FUNCTION__, feed->type, feed->state, feed->pid);
@@ -578,12 +579,12 @@
 
 	list_add(&feed->list_head, &feed->demux->feed_list);
 out:
-	spin_unlock(&feed->demux->lock);
+	spin_unlock_irq(&feed->demux->lock);
 }
 
 static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
 {
-	spin_lock(&feed->demux->lock);
+	spin_lock_irq(&feed->demux->lock);
 	if (!(dvb_demux_feed_find(feed))) {
 		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
 				__FUNCTION__, feed->type, feed->state, feed->pid);
@@ -592,7 +593,7 @@
 
 	list_del(&feed->list_head);
 out:
-	spin_unlock(&feed->demux->lock);
+	spin_unlock_irq(&feed->demux->lock);
 }
 
 static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, 
diff -uraN a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
--- a/drivers/media/dvb/dvb-core/dvb_net.c	2004-09-17 14:31:22.000000000 +0200
+++ b/drivers/media/dvb/dvb-core/dvb_net.c	2004-09-17 14:31:34.000000000 +0200
@@ -40,8 +40,6 @@
 
 #include "dvb_demux.h"
 #include "dvb_net.h"
-#include "dvb_functions.h"
-
 
 static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 {

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

* Re: [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3
  2004-09-17 14:27       ` [PATCH][2.6][4/14] dvb core update Michael Hunold
@ 2004-09-17 14:29         ` Michael Hunold
  2004-09-17 14:30           ` [PATCH][2.6][6/14] convert frontend drivers to kernel i2c 2/3 Michael Hunold
  2004-09-17 14:58         ` [PATCH][2.6][4/14] dvb core update Jesper Juhl
  2004-09-17 15:28         ` Richard B. Johnson
  2 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:29 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 05-DVB-frontend-conversion.diff --]
[-- Type: text/plain, Size: 81437 bytes --]

- [DVB] stv0299, tda1004x, ves1820, ves1x93: convert from dvb-i2c to kernel-i2c, MODULE_PARM() to module_param(), dvb_delay() to mdelay()
- [DVB] tda1004x: move from home-brewn firmware loading to firmware_class
- [DVB] stv0299: support Cinergy1200, patch by Uli Luckas

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/stv0299.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/stv0299.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/stv0299.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/stv0299.c	2004-08-18 19:52:17.000000000 +0200
@@ -48,21 +48,28 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
+#define FRONTEND_NAME "dvbfe_stv0299"
 
-static int stv0299_status = 0;
-static int disable_typhoon = 0;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+static int stv0299_status;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+module_param(stv0299_status, int, 0444);
+MODULE_PARM_DESC(stv0299_status, "Which status value to support "
+		 "(0 == BER (default), 1 == UCBLOCKS)");
 
 #define STATUS_BER 0
 #define STATUS_UCBLOCKS 1
@@ -77,6 +84,7 @@
 #define SAMSUNG_TBMU24112IMB    4
 #define PHILIPS_SU1278_TSA_TT	5 // SU1278 with TSA5059 synth and TechnoTrend settings
 #define PHILIPS_SU1278_TSA_TY	6 // SU1278 with TUA5059 synth and Typhoon wiring
+#define PHILIPS_SU1278_TSA_CI	7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
 
 /* Master Clock = 88 MHz */
 #define M_CLK (88000000UL) 
@@ -108,6 +116,8 @@
 	u32 tuner_frequency;
 	u32 symbol_rate;
 	fe_code_rate_t fec_inner;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
 };
 
 
@@ -264,26 +274,26 @@
         0x34, 0x13
 };
 
-static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec);
-static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type);
+static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec);
+static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type);
 
-static int stv0299_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
 	int ret;
 	u8 buf [] = { reg, data };
 	struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
 
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 
 	if (ret != 1) 
 		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
 			"ret == %i)\n", __FUNCTION__, reg, data, ret);
 
-	return (ret != 1) ? -1 : 0;
+	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
 
-static u8 stv0299_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
@@ -291,7 +301,7 @@
 	struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = b0, .len = 1 },
 			   { .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
         
 	if (ret != 2) 
 		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
@@ -301,13 +311,13 @@
 }
 
 
-static int stv0299_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len)
+static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
 {
         int ret;
         struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg1, .len = 1 },
                            { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
 
-        ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
 
         if (ret != 2)
                 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -316,7 +326,7 @@
 }
 
 
-static int pll_write (struct dvb_i2c_bus *i2c, u8 addr, u8 *data, int len)
+static int pll_write (struct i2c_adapter *i2c, u8 addr, u8 *data, int len)
 {
 	int ret;
 	struct i2c_msg msg = { addr: addr, .flags = 0, .buf = data, .len = len };
@@ -324,7 +334,7 @@
 
 	stv0299_writereg(i2c, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
 
-	ret =  i2c->xfer (i2c, &msg, 1);
+	ret =  i2c_transfer (i2c, &msg, 1);
 
 	stv0299_writereg(i2c, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
 
@@ -335,7 +345,7 @@
 }
 
 
-static int sl1935_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype)
+static int sl1935_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype)
 {
 	u8 buf[4];
 	u32 div;
@@ -358,7 +368,7 @@
  *   set up the downconverter frequency divisor for a 
  *   reference clock comparision frequency of 125 kHz.
  */
-static int tsa5059_set_tv_freq	(struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
+static int tsa5059_set_tv_freq	(struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
 {
 	u8 addr;
 	u32 div;
@@ -389,7 +399,8 @@
 	case PHILIPS_SU1278_TSA:
 	case PHILIPS_SU1278_TSA_TT:
 	case PHILIPS_SU1278_TSA_TY:
-		if (ftype == PHILIPS_SU1278_TSA_TY)
+	case PHILIPS_SU1278_TSA_CI:
+		if (ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
 			addr = 0x61;
 		else
 		addr = 0x60;
@@ -421,7 +432,7 @@
 #define MIN2(a,b) ((a) < (b) ? (a) : (b))
 #define MIN3(a,b,c) MIN2(MIN2(a,b),c)
 
-static int tua6100_set_tv_freq	(struct dvb_i2c_bus *i2c, u32 freq,
+static int tua6100_set_tv_freq	(struct i2c_adapter *i2c, u32 freq,
 			 int ftype, int srate)
 {
 	u8 reg0 [2] = { 0x00, 0x00 };
@@ -542,7 +553,7 @@
 }
 
 
-static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, int ftype, int srate)
+static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
 {
 	switch(ftype) {
 	case SAMSUNG_TBMU24112IMB:
@@ -560,7 +571,7 @@
 }
 
 #if 0
-static int tsa5059_read_status	(struct dvb_i2c_bus *i2c)
+static int tsa5059_read_status	(struct i2c_adapter *i2c)
 {
 	int ret;
 	u8 rpt1 [] = { 0x05, 0xb5 };
@@ -571,7 +582,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -581,7 +592,7 @@
 #endif
 
 
-static int stv0299_init (struct dvb_i2c_bus *i2c, int ftype)
+static int stv0299_init (struct i2c_adapter *i2c, int ftype)
 {
 	int i;
 
@@ -614,7 +625,7 @@
 		stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
 
         /* AGC1 reference register setup */
-		if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY)
+		if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
 		  stv0299_writereg (i2c, 0x0f, 0x92);  /* Iagc = Inverse, m1 = 18 */
 		else if (ftype == PHILIPS_SU1278_TUA)
 		  stv0299_writereg (i2c, 0x0f, 0x94);  /* Iagc = Inverse, m1 = 20 */
@@ -637,7 +648,7 @@
 }
 
 
-static int stv0299_set_FEC (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -681,7 +692,7 @@
 }
 
 
-static fe_code_rate_t stv0299_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
 {
 	static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
 					     FEC_7_8, FEC_1_2 };
@@ -699,7 +710,7 @@
 }
 
 
-static int stv0299_wait_diseqc_fifo (struct dvb_i2c_bus *i2c, int timeout)
+static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
 {
 	unsigned long start = jiffies;
 
@@ -710,14 +721,14 @@
 			dprintk ("%s: timeout!!\n", __FUNCTION__);
 			return -ETIMEDOUT;
 		}
-		dvb_delay(10);
+		msleep(10);
 	};
 
 	return 0;
 }
 
 
-static int stv0299_wait_diseqc_idle (struct dvb_i2c_bus *i2c, int timeout)
+static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
 {
 	unsigned long start = jiffies;
 
@@ -728,14 +739,14 @@
 			dprintk ("%s: timeout!!\n", __FUNCTION__);
 			return -ETIMEDOUT;
 		}
-		dvb_delay(10);
+		msleep(10);
 	};
 
 	return 0;
 }
 
 
-static int stv0299_send_diseqc_msg (struct dvb_i2c_bus *i2c,
+static int stv0299_send_diseqc_msg (struct i2c_adapter *i2c,
 			     struct dvb_diseqc_master_cmd *m)
 {
 	u8 val;
@@ -766,7 +777,7 @@
 }
 
 
-static int stv0299_send_diseqc_burst (struct dvb_i2c_bus *i2c, fe_sec_mini_cmd_t burst)
+static int stv0299_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
 {
 	u8 val;
 
@@ -793,7 +804,7 @@
 }
 
 
-static int stv0299_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
+static int stv0299_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
 {
 	u8 val;
 
@@ -826,7 +837,7 @@
 }
 
 
-static int stv0299_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage,
+static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage,
 				int tuner_type)
 {
 	u8 reg0x08;
@@ -849,11 +860,18 @@
 		return stv0299_writereg (i2c, 0x08, 0x00); /*	LNB power off! */
 	}
 	
+	if (tuner_type == PHILIPS_SU1278_TSA_CI) 
+	{
+		stv0299_writereg (i2c, 0x08, reg0x08 & 0xBF); // switch LNB power on OP2/LOCK pin off
+	}
+	else
+	{
 		stv0299_writereg (i2c, 0x08, reg0x08 | 0x40);
+	}
 
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
-		if (tuner_type == PHILIPS_SU1278_TSA_TY)
+		if (tuner_type == PHILIPS_SU1278_TSA_TY || tuner_type == PHILIPS_SU1278_TSA_CI)
 			return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10);
 		else
 			return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40);
@@ -867,7 +885,7 @@
 }
 
 
-static int stv0299_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate, int tuner_type)
+static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type)
 {
 	u64 big = srate;
 	u32 ratio;
@@ -918,6 +937,7 @@
 	        break;
 
 	case PHILIPS_SU1278_TSA_TY:
+	case PHILIPS_SU1278_TSA_CI:
 	case PHILIPS_SU1278_TSA:
 		aclk = 0xb5;
 		if (srate < 2000000) bclk = 0x86;
@@ -958,7 +978,7 @@
 }
 
 
-static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type)
+static int stv0299_get_symbolrate (struct i2c_adapter *i2c, int tuner_type)
 {
 	u32 Mclk = M_CLK / 4096L;
 	u32 srate;
@@ -995,8 +1014,8 @@
 
 static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	struct stv0299_state *state = (struct stv0299_state *) fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -1248,9 +1267,9 @@
 	return 0;
 }
 
-static long probe_tuner (struct dvb_i2c_bus *i2c)
+static long probe_tuner (struct i2c_adapter *adapter)
 {
-	struct dvb_adapter * adapter = (struct dvb_adapter *) i2c->adapter;
+	struct i2c_adapter *i2c = adapter; /* superfluous */
 
         /* read the status register of TSA5059 */
 	u8 rpt[] = { 0x05, 0xb5 };
@@ -1269,45 +1288,45 @@
 	stv0299_writereg (i2c, 0x03, 0x00);
 
 
-	printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name);
-
-	if ( strcmp(adapter->name, "Technisat SkyStar2 driver") == 0 )
-	{
-	    printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__);
+	printk("stv0299: try to attach to %s\n", adapter->name);
 
+	if (!strcmp(adapter->name, "Technisat SkyStar2 driver")) {
+	    printk ("stv0299: setup for tuner Samsung TBMU24112IMB\n");
     	    return SAMSUNG_TBMU24112IMB;
 	}
 
-	if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) {
+	if ((ret = i2c_transfer(i2c, msg1, 2)) == 2) {
 	        if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) {
 		        // technotrend cards require non-datasheet settings
-			printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
-				" TechnoTrend hardware\n", __FILE__);
+			printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n");
 		        return PHILIPS_SU1278_TSA_TT;
 		}  else {
 		        // fall back to datasheet-recommended settings
-			printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n",
-				__FILE__);
+			printk ("stv0299: setup for tuner SU1278 (TSA5059 synth)\n");
 		        return PHILIPS_SU1278_TSA;
 		}
 		}
 
-	if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) {
-		if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 &&
-		     !disable_typhoon )
+	if ((ret = i2c_transfer(i2c, msg2, 2)) == 2) {
+		if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 )
 		{
 			// Typhoon cards have unusual wiring.
-			printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
-				" Typhoon hardware\n", __FILE__);
+			printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on Typhoon hardware\n");
 			return PHILIPS_SU1278_TSA_TY;
 		}
+		else if ( strcmp(adapter->name, "TerraTec Cinergy 1200 DVB-S") == 0 )
+		{
+			// Cinergy cards have unusual wiring.
+			printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
+				" TerraTec hardware\n", __FILE__);
+			return PHILIPS_SU1278_TSA_CI;
+		}
 		//else if ((stat[0] & 0x3f) == 0) {
 		else if (0) {
-			printk ("%s: setup for tuner TDQF-S001F\n", __FILE__);
+			printk ("stv0299: setup for tuner TDQF-S001F\n");
 			return LG_TDQF_S001F;
 	} else {
-			printk ("%s: setup for tuner BSRU6, TDQB-S00x\n",
-			__FILE__);
+			printk ("stv0299: setup for tuner BSRU6, TDQB-S00x\n");
 			return ALPS_BSRU6;
 	}
 	}
@@ -1317,29 +1336,29 @@
 	 */
 	stv0299_writereg (i2c, 0x02, 0x00);
 
-	if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) {
-		printk ("%s: setup for tuner Philips SU1278 (TUA6100 synth)\n",
-			__FILE__);
+	if ((ret = i2c_transfer(i2c, msg3, 2)) == 2) {
+		printk ("stv0299: setup for tuner Philips SU1278 (TUA6100 synth)\n");
 		return PHILIPS_SU1278_TUA;
 	}
 
-	printk ("%s: unknown PLL synthesizer (ret == %i), "
-		"please report to <linuxdvb@linuxtv.org>!!\n",
-		__FILE__, ret);
+	printk ("stv0299: unknown PLL synthesizer (ret == %i), please report to <linuxdvb@linuxtv.org>!!\n", ret);
 
 	return UNKNOWN_FRONTEND;
 }
 
+static struct i2c_client client_template;
 
-static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
 {
+	struct i2c_client *client;
 	struct stv0299_state* state;
 	int tuner_type;
+	int ret;
 	u8 id;
  
-	stv0299_writereg (i2c, 0x02, 0x34); /* standby off */
-	dvb_delay(200);
-	id = stv0299_readreg (i2c, 0x00);
+	stv0299_writereg(adapter, 0x02, 0x34); /* standby off */
+	msleep(200);
+	id = stv0299_readreg(adapter, 0x00);
 
 	dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id);
 
@@ -1348,53 +1367,112 @@
 	if (id != 0xa1 && id != 0x80)
 		return -ENODEV;
 
-	if ((tuner_type = probe_tuner(i2c)) < 0)
+	if ((tuner_type = probe_tuner(adapter)) < 0)
 		return -ENODEV;
 
 	if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
 		return -ENOMEM;
 	}
 
-	*data = state;
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
 	state->tuner_type = tuner_type;
 	state->tuner_frequency = 0;
 	state->initialised = 0;
-	return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state,
-			       &uni0299_info);
+	state->i2c = adapter;
+	
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = (0x68>>1);
+	i2c_set_clientdata(client, (void*)state);
+	
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return -EFAULT;
+	}
+	
+	BUG_ON(!state->dvb);
+
+	ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state,
+					&uni0299_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return -EFAULT;
 }
 
+	return 0;
+}
 
-static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data)
+static int detach_client(struct i2c_client *client)
 {
+	struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
+
+	dvb_unregister_frontend_new (uni0299_ioctl, state->dvb);
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
+
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client);
 	dprintk ("%s\n", __FUNCTION__);
-	kfree(data);
-	dvb_unregister_frontend (uni0299_ioctl, i2c);
+
+	switch (cmd) {
+	case FE_REGISTER: {
+		data->dvb = (struct dvb_adapter*)arg;
+		break;
+	}
+	case FE_UNREGISTER: {
+		data->dvb = NULL;
+		break;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_STV0299,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client 	= detach_client,
+	.command 	= command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
 
 static int __init init_uni0299 (void)
 {
-	dprintk ("%s\n", __FUNCTION__);
-	return dvb_register_i2c_device (NULL, uni0299_attach, uni0299_detach);
+	return i2c_add_driver(&driver);
 }
 
-
 static void __exit exit_uni0299 (void)
 {
-	dprintk ("%s\n", __FUNCTION__);
-
-	dvb_unregister_i2c_device (uni0299_attach);
+	if (i2c_del_driver(&driver))
+		printk("stv0299: driver deregistration failed\n");
 }
 
 module_init (init_uni0299);
 module_exit (exit_uni0299);
 
 MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
+              "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(stv0299_status, "i");
-MODULE_PARM_DESC(stv0299_status, "Which status value to support (0: BER, 1: UCBLOCKS)");
-
-MODULE_PARM(disable_typhoon, "i");
-MODULE_PARM_DESC(disable_typhoon, "Disable support for Philips SU1278 on Typhoon hardware.");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/tda1004x.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/tda1004x.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/tda1004x.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/tda1004x.c	2004-08-18 19:52:17.000000000 +0200
@@ -22,36 +22,37 @@
 
 /*
     This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
-    windows driver saved as '/usr/lib/hotplug/firmware/tda1004x.bin'.
-    You can also pass the complete file name with the module parameter 'tda1004x_firmware'.
+	windows driver.
 
     Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
     be added reasonably painlessly.
 
     Windows driver URL: http://www.technotrend.de/
- */
 
+	wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
+	unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
+*/
+#define TDA1004X_DEFAULT_FIRMWARE "tda1004x.bin"
 
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-#ifndef DVB_TDA1004X_FIRMWARE_FILE
-#define DVB_TDA1004X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/tda1004x.bin"
-#endif
+#define FRONTEND_NAME "dvbfe_tda1004x"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
 
-static int tda1004x_debug = 0;
-static char *tda1004x_firmware = DVB_TDA1004X_FIRMWARE_FILE;
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 #define MC44BC374_ADDRESS        0x65
 
@@ -139,8 +140,6 @@
 #define TUNER_TYPE_TD1344     0
 #define TUNER_TYPE_TD1316     1
 
-#define dprintk if (tda1004x_debug) printk
-
 static struct dvb_frontend_info tda10045h_info = {
 	.name = "Philips TDA10045H",
 	.type = FE_OFDM,
@@ -171,12 +169,17 @@
 struct tda1004x_state {
 	u8 tda1004x_address;
 	u8 tuner_address;
-	u8 initialised:1;
-        u8 tuner_type:2;
-        u8 fe_type:2;
+	u8 initialised;
+	u8 tuner_type;
+	u8 fe_type;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+
+	int dspCodeCounterReg;
+	int dspCodeInReg;
+	int dspVersion;
 };
 
-
 struct fwinfo {
 	int file_size;
 	int fw_offset;
@@ -182,16 +185,28 @@
 	int fw_offset;
 	int fw_size;
 };
-static struct fwinfo tda10045h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x34cc5,.fw_size = 30555} };
-static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
 
-static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} };
-static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);
+static struct fwinfo tda10045h_fwinfo[] = {
+	{
+		.file_size = 286720,
+		.fw_offset = 0x34cc5,
+		.fw_size = 30555
+	},
+};
 
-static int errno;
+static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
 
+static struct fwinfo tda10046h_fwinfo[] = {
+	{
+		.file_size = 286720,
+		.fw_offset = 0x3c4f9,
+		.fw_size = 24479
+	}
+};
+
+static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);
 
-static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data)
+static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int data)
 {
 	int ret;
 	u8 buf[] = { reg, data };
@@ -200,7 +215,7 @@
 	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
 
         msg.addr = tda_state->tda1004x_address;
-	ret = i2c->xfer(i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 
 	if (ret != 1)
 		dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
@@ -211,7 +226,7 @@
 	return (ret != 1) ? -1 : 0;
 }
 
-static int tda1004x_read_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg)
+static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg)
 {
 	int ret;
 	u8 b0[] = { reg };
@@ -223,7 +238,7 @@
 
         msg[0].addr = tda_state->tda1004x_address;
         msg[1].addr = tda_state->tda1004x_address;
-	ret = i2c->xfer(i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
 	if (ret != 2) {
 		dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
@@ -236,7 +251,7 @@
 	return b1[0];
 }
 
-static int tda1004x_write_mask(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data)
+static int tda1004x_write_mask(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data)
 {
         int val;
 	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
@@ -255,7 +270,7 @@
 	return tda1004x_write_byte(i2c, tda_state, reg, val);
 }
 
-static int tda1004x_write_buf(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len)
+static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len)
 {
 	int i;
 	int result;
@@ -272,19 +287,18 @@
 	return result;
 }
 
-static int tda1004x_enable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_enable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
 {
         int result;
 	dprintk("%s\n", __FUNCTION__);
 
 	result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2);
-	dvb_delay(1);
+	msleep(1);
 	return result;
 }
 
-static int tda1004x_disable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_disable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
 {
-
 	dprintk("%s\n", __FUNCTION__);
 
 	return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);
@@ -290,8 +304,7 @@
 	return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);
 }
 
-
-static int tda10045h_set_bandwidth(struct dvb_i2c_bus *i2c,
+static int tda10045h_set_bandwidth(struct i2c_adapter *i2c,
 	                           struct tda1004x_state *tda_state,
 		                   fe_bandwidth_t bandwidth)
 {
@@ -321,12 +334,10 @@
 
         tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0);
 
-        // done
         return 0;
 }
 
-
-static int tda10046h_set_bandwidth(struct dvb_i2c_bus *i2c,
+static int tda10046h_set_bandwidth(struct i2c_adapter *i2c,
                                    struct tda1004x_state *tda_state,
                                    fe_bandwidth_t bandwidth)
 {
@@ -354,187 +365,160 @@
                 return -EINVAL;
         }
 
-        // done
         return 0;
 }
 
-
-static int tda1004x_fwupload(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *state, unsigned char *mem, unsigned int len)
 {
-	u8 fw_buf[65];
-	struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = fw_buf,.len = 0 };
-	unsigned char *firmware = NULL;
-	int filesize;
-	int fd;
-	int fwinfo_idx;
-	int fw_size = 0;
-        int fw_pos, fw_offset;
+	u8 buf[65];
+	struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };
 	int tx_size;
-	mm_segment_t fs = get_fs();
-        int dspCodeCounterReg=0, dspCodeInReg=0, dspVersion=0;
-        int fwInfoCount=0;
-        struct fwinfo* fwInfo = NULL;
-        unsigned long timeout;
+	int pos = 0;
 
-        // DSP parameters
-        switch(tda_state->fe_type) {
-        case FE_TYPE_TDA10045H:
-                dspCodeCounterReg = TDA10045H_FWPAGE;
-                dspCodeInReg = TDA10045H_CODE_IN;
-                dspVersion = 0x2c;
-                fwInfoCount = tda10045h_fwinfo_count;
-                fwInfo = tda10045h_fwinfo;
-                break;
+	/* clear code counter */
+	tda1004x_write_byte(i2c, state, state->dspCodeCounterReg, 0);
+	fw_msg.addr = state->tda1004x_address;
 
-        case FE_TYPE_TDA10046H:
-                dspCodeCounterReg = TDA10046H_CODE_CPT;
-                dspCodeInReg = TDA10046H_CODE_IN;
-                dspVersion = 0x20;
-                fwInfoCount = tda10046h_fwinfo_count;
-                fwInfo = tda10046h_fwinfo;
-                break;
+	buf[0] = state->dspCodeInReg;
+	while (pos != len) {
+
+		// work out how much to send this time
+		tx_size = len - pos;
+		if (tx_size > 0x10) {
+			tx_size = 0x10;
         }
 
-	// Load the firmware
-	set_fs(get_ds());
-	fd = sys_open(tda1004x_firmware, 0, 0);
-	if (fd < 0) {
-		printk("%s: Unable to open firmware %s\n", __FUNCTION__,
-		       tda1004x_firmware);
+		// send the chunk
+		memcpy(buf + 1, mem + pos, tx_size);
+		fw_msg.len = tx_size + 1;
+		if (i2c_transfer(i2c, &fw_msg, 1) != 1) {
+			printk("tda1004x: Error during firmware upload\n");
 		return -EIO;
 	}
-	filesize = sys_lseek(fd, 0L, 2);
-	if (filesize <= 0) {
-		printk("%s: Firmware %s is empty\n", __FUNCTION__,
-		       tda1004x_firmware);
-		sys_close(fd);
-		return -EIO;
+		pos += tx_size;
+
+		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
+	}
+	return 0;
 	}
 
-        // find extraction parameters for firmware
+static int tda1004x_find_extraction_params(struct fwinfo* fwInfo, int fwInfoCount, int size)
+{
+	int fwinfo_idx;
+
         for (fwinfo_idx = 0; fwinfo_idx < fwInfoCount; fwinfo_idx++) {
-                if (fwInfo[fwinfo_idx].file_size == filesize)
+		if (fwInfo[fwinfo_idx].file_size == size)
 			break;
 	}
         if (fwinfo_idx >= fwInfoCount) {
-		printk("%s: Unsupported firmware %s\n", __FUNCTION__, tda1004x_firmware);
-		sys_close(fd);
+		printk("tda1004x: Unsupported firmware uploaded.\n");
 		return -EIO;
 	}
-        fw_size = fwInfo[fwinfo_idx].fw_size;
-        fw_offset = fwInfo[fwinfo_idx].fw_offset;
 
-	// allocate buffer for it
-	firmware = vmalloc(fw_size);
-	if (firmware == NULL) {
-		printk("%s: Out of memory loading firmware\n",
-		       __FUNCTION__);
-		sys_close(fd);
-		return -EIO;
+	return fwinfo_idx;
 	}
 
-	// read it!
-	sys_lseek(fd, fw_offset, 0);
-	if (sys_read(fd, firmware, fw_size) != fw_size) {
-		printk("%s: Failed to read firmware\n", __FUNCTION__);
-		vfree(firmware);
-		sys_close(fd);
-		return -EIO;
-	}
-	sys_close(fd);
-	set_fs(fs);
+static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_state *state)
+{
+	u8 data1, data2;
 
-        // set some valid bandwith parameters before uploading
-        switch(tda_state->fe_type) {
-        case FE_TYPE_TDA10045H:
-                // reset chip
-		tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0);
-                tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
-                tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
-                dvb_delay(10);
+	// check upload was OK
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
+	tda1004x_write_byte(i2c, state, TDA1004X_DSP_CMD, 0x67);
 
-                // set parameters
-                tda10045h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ);
-                break;
+	data1 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA1);
+	data2 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA2);
+	if (data1 != 0x67 || data2 != state->dspVersion) {
+		printk("tda1004x: firmware upload failed!\n");
+		return -EIO;
+	}
 
-        case FE_TYPE_TDA10046H:
-                // reset chip
-		tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0);
-                tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 1, 0);
-                dvb_delay(10);
-
-                // set parameters
-                tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10);
-                tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0);
-                tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99);
-                tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-                tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
-                tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-                break;
+	return 0;
         }
 
-	// do the firmware upload
-        tda1004x_write_byte(i2c, tda_state, dspCodeCounterReg, 0); // clear code counter
-        fw_msg.addr = tda_state->tda1004x_address;
-	fw_pos = 0;
-	while (fw_pos != fw_size) {
 
-		// work out how much to send this time
-		tx_size = fw_size - fw_pos;
-                if (tx_size > 0x10) {
-                        tx_size = 0x10;
-		}
+static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, const struct firmware *fw)
+{
+	int index;
+	int ret;
 
-		// send the chunk
-                fw_buf[0] = dspCodeInReg;
-		memcpy(fw_buf + 1, firmware + fw_pos, tx_size);
-		fw_msg.len = tx_size + 1;
-		if (i2c->xfer(i2c, &fw_msg, 1) != 1) {
-                        printk("tda1004x: Error during firmware upload\n");
-			vfree(firmware);
-			return -EIO;
-		}
-		fw_pos += tx_size;
+	index = tda1004x_find_extraction_params(tda10045h_fwinfo, tda10045h_fwinfo_count, fw->size);
+	if (index < 0)
+		return index;
+
+	/* set some valid bandwith parameters before uploading */
+
+	/* reset chip */
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0);
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8);
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 0);
+	msleep(10);
+
+	/* set parameters */
+	tda10045h_set_bandwidth(i2c, state, BANDWIDTH_8_MHZ);
+
+	ret = tda1004x_do_upload(i2c, state, fw->data + tda10045h_fwinfo[index].fw_offset, tda10045h_fwinfo[index].fw_size);
+	if (ret)
+		return ret;
+
+	/* wait for DSP to initialise */
+	/* DSPREADY doesn't seem to work on the TDA10045H */
+	msleep(100);
+
+	ret = tda1004x_check_upload_ok(i2c, state);
+	if (ret)
+		return ret;
 
-		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, fw_pos);
+	return 0;
 	}
-	vfree(firmware);
 
-        // wait for DSP to initialise
-        switch(tda_state->fe_type) {
-        case FE_TYPE_TDA10045H:
-                // DSPREADY doesn't seem to work on the TDA10045H
-                dvb_delay(100);
-                break;
+static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, const struct firmware *fw)
+{
+	unsigned long timeout;
+	int index;
+	int ret;
 
-        case FE_TYPE_TDA10046H:
+	index = tda1004x_find_extraction_params(tda10046h_fwinfo, tda10046h_fwinfo_count, fw->size);
+	if (index < 0)
+		return index;
+
+	/* set some valid bandwith parameters before uploading */
+
+	/* reset chip */
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 1, 0);
+	tda1004x_write_mask(i2c, state, TDA10046H_CONF_TRISTATE1, 1, 0);
+	msleep(10);
+
+	/* set parameters */
+	tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL2, 10);
+	tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL3, 0);
+	tda1004x_write_byte(i2c, state, TDA10046H_FREQ_OFFSET, 99);
+	tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+	tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+
+	ret = tda1004x_do_upload(i2c, state, fw->data + tda10046h_fwinfo[index].fw_offset, tda10046h_fwinfo[index].fw_size);
+	if (ret)
+		return ret;
+
+	/* wait for DSP to initialise */
                 timeout = jiffies + HZ;
-                while(!(tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD) & 0x20)) {
+	while(!(tda1004x_read_byte(i2c, state, TDA1004X_STATUS_CD) & 0x20)) {
                         if (time_after(jiffies, timeout)) {
                                 printk("tda1004x: DSP failed to initialised.\n");
                                 return -EIO;
                         }
-
-                        dvb_delay(1);
-                }
-                break;
+		msleep(1);
         }
 
-        // check upload was OK
-        tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
-	tda1004x_write_byte(i2c, tda_state, TDA1004X_DSP_CMD, 0x67);
-	if ((tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA1) != 0x67) ||
-            (tda1004x_read_byte(i2c, tda_state, TDA1004X_DSP_DATA2) != dspVersion)) {
-		printk("%s: firmware upload failed!\n", __FUNCTION__);
-		return -EIO;
-	}
+	ret = tda1004x_check_upload_ok(i2c, state);
+	if (ret)
+		return ret;
 
-        // success
         return 0;
 }
 
-
-static int tda10045h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda10045h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
 {
         struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
         static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
@@ -548,8 +532,8 @@
         tuner_msg.addr = MC44BC374_ADDRESS;
         tuner_msg.buf = disable_mc44BC374c;
         tuner_msg.len = sizeof(disable_mc44BC374c);
-        if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
-                i2c->xfer(i2c, &tuner_msg, 1);
+	if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
+		i2c_transfer(i2c, &tuner_msg, 1);
         }
         tda1004x_disable_tuner_i2c(i2c, tda_state);
 
@@ -566,13 +550,10 @@
         tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
         tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e);
 
-	// done
 	return 0;
 }
 
-
-
-static int tda10046h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state)
+static int tda10046h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
 {
         struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
         static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
@@ -586,8 +567,8 @@
         tuner_msg.addr = MC44BC374_ADDRESS;
         tuner_msg.buf = disable_mc44BC374c;
         tuner_msg.len = sizeof(disable_mc44BC374c);
-        if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
-                i2c->xfer(i2c, &tuner_msg, 1);
+	if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
+		i2c_transfer(i2c, &tuner_msg, 1);
         }
         tda1004x_disable_tuner_i2c(i2c, tda_state);
 
@@ -618,7 +599,6 @@
         tda1004x_write_mask(i2c, tda_state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
         tda10046h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
 
-        // done
         return 0;
 }
 
@@ -664,7 +642,7 @@
 	return -1;
 }
 
-static int tda1004x_set_frequency(struct dvb_i2c_bus *i2c,
+static int tda1004x_set_frequency(struct i2c_adapter *i2c,
 			   struct tda1004x_state *tda_state,
 			   struct dvb_frontend_parameters *fe_params)
 {
@@ -697,7 +675,7 @@
 		tda1004x_enable_tuner_i2c(i2c, tda_state);
 		tuner_msg.addr = tda_state->tuner_address;
 		tuner_msg.len = 4;
-		i2c->xfer(i2c, &tuner_msg, 1);
+		i2c_transfer(i2c, &tuner_msg, 1);
 
 		// wait for it to finish
 		tuner_msg.len = 1;
@@ -705,7 +683,7 @@
 		counter = 0;
 		counter2 = 0;
 		while (counter++ < 100) {
-			if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+			if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
 				if (tuner_buf[0] & 0x40) {
 					counter2++;
 				} else {
@@ -802,10 +780,10 @@
 		tda1004x_enable_tuner_i2c(i2c, tda_state);
 		tuner_msg.addr = tda_state->tuner_address;
 		tuner_msg.len = 4;
-                if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+		if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
 			return -EIO;
 		}
-		dvb_delay(1);
+		msleep(1);
 		tda1004x_disable_tuner_i2c(i2c, tda_state);
                 if (tda_state->fe_type == FE_TYPE_TDA10046H)
                         tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 4);
@@ -817,11 +795,10 @@
 
 	dprintk("%s: success\n", __FUNCTION__);
 
-	// done
 	return 0;
 }
 
-static int tda1004x_set_fe(struct dvb_i2c_bus *i2c,
+static int tda1004x_set_fe(struct i2c_adapter *i2c,
 	 	           struct tda1004x_state *tda_state,
 		           struct dvb_frontend_parameters *fe_params)
 {
@@ -857,11 +834,9 @@
 		tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp);
 
 		// set LP FEC
-		if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) {
 			tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
 			if (tmp < 0) return tmp;
 			tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
-		}
 
 		// set constellation
 		switch (fe_params->u.ofdm.constellation) {
@@ -992,23 +967,20 @@
         case FE_TYPE_TDA10045H:
 	tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
 	tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
-	dvb_delay(10);
+		msleep(10);
                 break;
 
         case FE_TYPE_TDA10046H:
                 tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x40, 0x40);
-                dvb_delay(10);
+		msleep(10);
                 break;
         }
 
-	// done
 	return 0;
 }
 
-
-static int tda1004x_get_fe(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
+static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
 {
-
 	dprintk("%s\n", __FUNCTION__);
 
 	// inversion status
@@ -1110,12 +1082,10 @@
 		break;
 	}
 
-	// done
 	return 0;
 }
 
-
-static int tda1004x_read_status(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
+static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
 {
 	int status;
         int cber;
@@ -1177,7 +1147,7 @@
 	return 0;
 }
 
-static int tda1004x_read_signal_strength(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * signal)
+static int tda1004x_read_signal_strength(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * signal)
 {
 	int tmp;
         int reg = 0;
@@ -1200,14 +1170,12 @@
 	if (tmp < 0)
 		return -EIO;
 
-	// done
 	*signal = (tmp << 8) | tmp;
 	dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal);
 	return 0;
 }
 
-
-static int tda1004x_read_snr(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * snr)
+static int tda1004x_read_snr(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * snr)
 {
 	int tmp;
 
@@ -1221,13 +1189,12 @@
                 tmp = 255 - tmp;
         }
 
-        // done
 	*snr = ((tmp << 8) | tmp);
 	dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
 	return 0;
 }
 
-static int tda1004x_read_ucblocks(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
+static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
 {
 	int tmp;
 	int tmp2;
@@ -1254,7 +1221,6 @@
 			break;
 	}
 
-	// done
 	if (tmp != 0x7f) {
 		*ucblocks = tmp;
 	} else {
@@ -1264,7 +1230,7 @@
 	return 0;
 }
 
-static int tda1004x_read_ber(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ber)
+static int tda1004x_read_ber(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ber)
 {
         int tmp;
 
@@ -1279,12 +1245,11 @@
         *ber |= (tmp << 9);
         tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
 
-	// done
 	dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
 	return 0;
 }
 
-static int tda1004x_sleep(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state)
+static int tda1004x_sleep(struct i2c_adapter *i2c, struct tda1004x_state* tda_state)
 {
 	switch(tda_state->fe_type) {
 	case FE_TYPE_TDA10045H:
@@ -1299,12 +1264,11 @@
 	return 0;
 }
 
-
 static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	int status = 0;
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	struct tda1004x_state *tda_state = (struct tda1004x_state *) fe->data;
+	struct i2c_adapter *i2c = tda_state->i2c;
+	int status = 0;
 
 	dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
 
@@ -1382,27 +1346,23 @@
 	return 0;
 }
 
-
-static int tda1004x_attach(struct dvb_i2c_bus *i2c, void **data)
+static int tda1004x_attach(struct i2c_adapter *i2c, struct tda1004x_state* state)
 {
         int tda1004x_address = -1;
 	int tuner_address = -1;
         int fe_type = -1;
         int tuner_type = -1;
-	struct tda1004x_state tda_state;
-	struct tda1004x_state* ptda_state;
 	struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=NULL, .len=0 };
         static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab };
         static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
         static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab };
-        int status;
 
 	dprintk("%s\n", __FUNCTION__);
 
         // probe for tda10045h
         if (tda1004x_address == -1) {
-                tda_state.tda1004x_address = 0x08;
-	if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x25) {
+		state->tda1004x_address = 0x08;
+		if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x25) {
                         tda1004x_address = 0x08;
                         fe_type = FE_TYPE_TDA10045H;
                 printk("tda1004x: Detected Philips TDA10045H.\n");
@@ -1411,8 +1371,8 @@
 
         // probe for tda10046h
         if (tda1004x_address == -1) {
-                tda_state.tda1004x_address = 0x08;
-                if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x46) {
+		state->tda1004x_address = 0x08;
+		if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x46) {
                         tda1004x_address = 0x08;
                         fe_type = FE_TYPE_TDA10046H;
                         printk("tda1004x: Detected Philips TDA10046H.\n");
@@ -1425,15 +1385,15 @@
         }
 
         // enable access to the tuner
-	tda1004x_enable_tuner_i2c(i2c, &tda_state);
+	tda1004x_enable_tuner_i2c(i2c, state);
 
         // check for a TD1344 first
         if (tuner_address == -1) {
                 tuner_msg.addr = 0x61;
 	tuner_msg.buf = td1344_init;
 	tuner_msg.len = sizeof(td1344_init);
-	if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
-                dvb_delay(1);
+		if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+			msleep(1);
                         tuner_address = 0x61;
                         tuner_type = TUNER_TYPE_TD1344;
                         printk("tda1004x: Detected Philips TD1344 tuner.\n");
@@ -1445,8 +1405,8 @@
                 tuner_msg.addr = 0x63;
                 tuner_msg.buf = td1316_init;
                 tuner_msg.len = sizeof(td1316_init);
-                if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
-                        dvb_delay(1);
+		if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+			msleep(1);
                         tuner_address = 0x63;
                         tuner_type = TUNER_TYPE_TD1316;
                         printk("tda1004x: Detected Philips TD1316 tuner.\n");
@@ -1458,14 +1418,14 @@
                 tuner_msg.addr = 0x60;
                 tuner_msg.buf = td1316_init_tda10046h;
                 tuner_msg.len = sizeof(td1316_init_tda10046h);
-                if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
-                        dvb_delay(1);
+		if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
+			msleep(1);
                         tuner_address = 0x60;
                         tuner_type = TUNER_TYPE_TD1316;
                         printk("tda1004x: Detected Philips TD1316 tuner.\n");
 		}
 	}
-	tda1004x_disable_tuner_i2c(i2c, &tda_state);
+	tda1004x_disable_tuner_i2c(i2c, state);
 
 	// did we find a tuner?
 	if (tuner_address == -1) {
@@ -1474,57 +1434,172 @@
 	}
 
         // create state
-        tda_state.tda1004x_address = tda1004x_address;
-        tda_state.fe_type = fe_type;
-	tda_state.tuner_address = tuner_address;
-        tda_state.tuner_type = tuner_type;
-	tda_state.initialised = 0;
+	state->tda1004x_address = tda1004x_address;
+	state->fe_type = fe_type;
+	state->tuner_address = tuner_address;
+	state->tuner_type = tuner_type;
+	state->initialised = 0;
 
-        // upload firmware
-        if ((status = tda1004x_fwupload(i2c, &tda_state)) != 0) return status;
+	return 0;
+}
+
+static struct i2c_client client_template;
 
-	// create the real state we'll be passing about
-	if ((ptda_state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL)) == NULL) {
+static int attach_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_client *client;
+	struct tda1004x_state *state;
+	const struct firmware *fw;
+	int ret;
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
 		return -ENOMEM;
 	}
-	memcpy(ptda_state, &tda_state, sizeof(struct tda1004x_state));
-	*data = ptda_state;
 
-	// register
-        switch(tda_state.fe_type) {
+	if (NULL == (state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL))) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->i2c = adapter;
+
+	ret = tda1004x_attach(adapter, state);
+	if (ret) {
+		kfree(state);
+		kfree(client);
+		return -ENODEV;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = state->tda1004x_address;
+	i2c_set_clientdata(client, (void*)state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+
+	// upload firmware
+	BUG_ON(!state->dvb);
+
+	/* request the firmware, this will block until someone uploads it */
+	printk("tda1004x: waiting for firmware upload...\n");
+	ret = request_firmware(&fw, TDA1004X_DEFAULT_FIRMWARE, &client->dev);
+	if (ret) {
+		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+		goto out;
+	}
+
+	switch(state->fe_type) {
         case FE_TYPE_TDA10045H:
-		return dvb_register_frontend(tda1004x_ioctl, i2c, ptda_state, &tda10045h_info);
+		state->dspCodeCounterReg = TDA10045H_FWPAGE;
+		state->dspCodeInReg =  TDA10045H_CODE_IN;
+		state->dspVersion = 0x2c;
+
+		ret = tda10045_fwupload(adapter, state, fw);
+		if (ret) {
+			printk("tda1004x: firmware upload failed\n");
+			goto out;
+		}
 
+		ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
+						state, &tda10045h_info,
+						THIS_MODULE);
+		break;
         case FE_TYPE_TDA10046H:
-		return dvb_register_frontend(tda1004x_ioctl, i2c, ptda_state, &tda10046h_info);
+		state->dspCodeCounterReg = TDA10046H_CODE_CPT;
+		state->dspCodeInReg =  TDA10046H_CODE_IN;
+		state->dspVersion = 0x20;
+
+		ret = tda10046_fwupload(adapter, state, fw);
+		if (ret) {
+			printk("tda1004x: firmware upload failed\n");
+			goto out;
         }
 
-        // should not get here
-        return -EINVAL;
+		ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
+						state, &tda10046h_info,
+						THIS_MODULE);
+		break;
+	default:
+		BUG_ON(1);
 }
 
+	if (ret) {
+		printk("tda1004x: registering frontend failed\n");
+		goto out;
+	}
 
-static
-void tda1004x_detach(struct dvb_i2c_bus *i2c, void *data)
+	return 0;
+out:
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+	return ret;
+}
+
+static int detach_client(struct i2c_client *client)
 {
+	struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+
 	dprintk("%s\n", __FUNCTION__);
 
-	kfree(data);
-	dvb_unregister_frontend(tda1004x_ioctl, i2c);
+	dvb_unregister_frontend_new (tda1004x_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
 }
 
-
-static
-int __init init_tda1004x(void)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	return dvb_register_i2c_device(THIS_MODULE, tda1004x_attach, tda1004x_detach);
+	struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = (struct dvb_adapter*)arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_TDA1004X,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client 	= detach_client,
+	.command 	= command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
 
-static
-void __exit exit_tda1004x(void)
+static int __init init_tda1004x(void)
 {
-	dvb_unregister_i2c_device(tda1004x_attach);
+	return i2c_add_driver(&driver);
+}
+
+static void __exit exit_tda1004x(void)
+{
+	if (i2c_del_driver(&driver))
+		printk("tda1004x: driver deregistration failed\n");
 }
 
 module_init(init_tda1004x);
@@ -1534,8 +1609,3 @@
 MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(tda1004x_debug, "i");
-MODULE_PARM_DESC(tda1004x_debug, "enable verbose debug messages");
-
-MODULE_PARM(tda1004x_firmware, "s");
-MODULE_PARM_DESC(tda1004x_firmware, "Where to find the firmware file");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/ves1820.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1820.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/ves1820.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1820.c	2004-08-18 19:52:18.000000000 +0200
@@ -29,56 +29,27 @@
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
+/* I2C_DRIVERID_VES1820 is already defined in i2c-id.h */
 
 #if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
+static int debug = 0;
+#define dprintk	if (debug) printk
 #endif
 
-#define MAX_UNITS 4
-static int pwm[MAX_UNITS] = { -1, -1, -1, -1 };
 static int verbose;
 
-/**
- *  since we need only a few bits to store internal state we don't allocate
- *  extra memory but use frontend->data as bitfield
- */
+struct ves1820_state {
+	int pwm;
+	u8 reg0;
+	int tuner;
+	u8 demod_addr;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
-#define SET_PWM(data,pwm) do { 		\
-	long d = (long)data;		\
-	d &= ~0xff; 			\
-	d |= pwm; 			\
-	data = (void *)d;		\
-} while (0)
-
-#define SET_REG0(data,reg0) do {	\
-	long d = (long)data;		\
-	d &= ~(0xff << 8); 		\
-	d |= reg0 << 8; 		\
-	data = (void *)d;		\
-} while (0)
-
-#define SET_TUNER(data,type) do {	\
-	long d = (long)data;		\
-	d &= ~(0xff << 16); 		\
-	d |= type << 16;		\
-	data = (void *)d;		\
-} while (0)
-
-#define SET_DEMOD_ADDR(data,type) do {	\
-	long d = (long)data;		\
-	d &= ~(0xff << 24); 		\
-	d |= type << 24;		\
-	data = (void *)d;		\
-} while (0)
-
-#define GET_PWM(data) ((u8) ((long) data & 0xff))
-#define GET_REG0(data) ((u8) (((long) data >> 8) & 0xff))
-#define GET_TUNER(data) ((u8) (((long) data >> 16) & 0xff))
-#define GET_DEMOD_ADDR(data) ((u8) (((long) data >> 24) & 0xff))
+/* possible ves1820 adresses */
+static u8 addr[] = { 0x61, 0x62 };
 
 #if defined(CONFIG_DBOX2)
 #define XIN 69600000UL
@@ -109,15 +78,16 @@
 	.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
 	.notifier_delay = ?,
 #endif
-	.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-		FE_CAN_QAM_128 | FE_CAN_QAM_256 | 
-		FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO,
+	.caps = FE_CAN_QAM_16 |
+		FE_CAN_QAM_32 |
+		FE_CAN_QAM_64 |
+		FE_CAN_QAM_128 |
+		FE_CAN_QAM_256 |
+		FE_CAN_FEC_AUTO |
+		FE_CAN_INVERSION_AUTO,
 };
 
-
-
-static u8 ves1820_inittab [] =
-{
+static u8 ves1820_inittab[] = {
 	0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
 	0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
 	0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -127,57 +97,50 @@
 	0x00, 0x00, 0x00, 0x00, 0x40
 };
 
-
-static int ves1820_writereg (struct dvb_frontend *fe, u8 reg, u8 data)
+static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
 {
-	u8 addr = GET_DEMOD_ADDR(fe->data);
         u8 buf[] = { 0x00, reg, data };
-	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct i2c_msg msg = {.addr = state->demod_addr,.flags = 0,.buf = buf,.len = 3 };
         int ret;
 
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer(state->i2c, &msg, 1);
 
 	if (ret != 1)
-		printk("DVB: VES1820(%d): %s, writereg error "
-			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			fe->i2c->adapter->num, __FUNCTION__, reg, data, ret);
+		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
-	dvb_delay(10);
+	msleep(10);
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
-
-static u8 ves1820_readreg (struct dvb_frontend *fe, u8 reg)
+static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
 {
 	u8 b0 [] = { 0x00, reg };
 	u8 b1 [] = { 0 };
-	u8 addr = GET_DEMOD_ADDR(fe->data);
-	struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b0, .len = 2 },
-	                   { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct i2c_msg msg[] = {
+		{.addr = state->demod_addr,.flags = 0,.buf = b0,.len = 2},
+		{.addr = state->demod_addr,.flags = I2C_M_RD,.buf = b1,.len = 1}
+	};
 	int ret;
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2)
-		printk("DVB: VES1820(%d): %s: readreg error (ret == %i)\n",
-				fe->i2c->adapter->num, __FUNCTION__, ret);
+		printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+		"ret == %i)\n", __FUNCTION__, reg, ret);
 
 	return b1[0];
 }
 
-
-static int tuner_write (struct dvb_i2c_bus *i2c, u8 addr, u8 data [4])
+static int tuner_write(struct ves1820_state *state, u8 addr, u8 data[4])
 {
         int ret;
         struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
 
-        ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer(state->i2c, &msg, 1);
 
         if (ret != 1)
-                printk("DVB: VES1820(%d): %s: i/o error (ret == %i)\n",
-				i2c->adapter->num, __FUNCTION__, ret);
+		printk("ves1820: %s(): i/o error (ret == %i)\n", __FUNCTION__, ret);
 
         return (ret != 1) ? -EREMOTEIO : 0;
 }
@@ -187,19 +149,18 @@
  *   set up the downconverter frequency divisor for a
  *   reference clock comparision frequency of 62.5 kHz.
  */
-static int tuner_set_tv_freq (struct dvb_frontend *fe, u32 freq)
+static int tuner_set_tv_freq(struct ves1820_state *state, u32 freq)
 {
         u32 div, ifreq;
-	static u8 addr [] = { 0x61, 0x62 };
 	static u8 byte3 [] = { 0x8e, 0x85 };
-	int tuner_type = GET_TUNER(fe->data);
+	int tuner_type = state->tuner;
         u8 buf [4];
 
 	if (tuner_type == 0xff)     /*  PLL not reachable over i2c ...  */
 		return 0;
 
-	if (strstr (fe->i2c->adapter->name, "Technotrend") ||
-	    strstr (fe->i2c->adapter->name, "TT-Budget"))
+	if (strstr(state->i2c->name, "Technotrend")
+	 || strstr(state->i2c->name, "TT-Budget"))
 		ifreq = 35937500;
 	else
 		ifreq = 36125000;
@@ -212,70 +173,62 @@
 
 	if (tuner_type == 1) {
 		buf[2] |= (div >> 10) & 0x60;
-		buf[3] = (freq < 174000000 ? 0x88 :
-			  freq < 470000000 ? 0x84 : 0x81);
+		buf[3] = (freq < 174000000 ? 0x88 : freq < 470000000 ? 0x84 : 0x81);
 	} else {
-		buf[3] = (freq < 174000000 ? 0xa1 :
-			  freq < 454000000 ? 0x92 : 0x34);
+		buf[3] = (freq < 174000000 ? 0xa1 : freq < 454000000 ? 0x92 : 0x34);
 	}
 
-        return tuner_write (fe->i2c, addr[tuner_type], buf);
+	return tuner_write(state, addr[tuner_type], buf);
 }
 
-
-static int ves1820_setup_reg0 (struct dvb_frontend *fe, u8 reg0,
-			fe_spectral_inversion_t inversion)
+static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
 {
-	reg0 |= GET_REG0(fe->data) & 0x62;
+	reg0 |= state->reg0 & 0x62;
 	
 	if (INVERSION_ON == inversion)
 		ENABLE_INVERSION(reg0);
 	else if (INVERSION_OFF == inversion)
 		DISABLE_INVERSION(reg0);
 	
-	ves1820_writereg (fe, 0x00, reg0 & 0xfe);
-        ves1820_writereg (fe, 0x00, reg0 | 0x01);
+	ves1820_writereg(state, 0x00, reg0 & 0xfe);
+	ves1820_writereg(state, 0x00, reg0 | 0x01);
 
 	/**
 	 *  check lock and toggle inversion bit if required...
 	 */
-	if (INVERSION_AUTO == inversion && !(ves1820_readreg (fe, 0x11) & 0x08)) {
+	if (INVERSION_AUTO == inversion && !(ves1820_readreg(state, 0x11) & 0x08)) {
 		mdelay(50);
-		if (!(ves1820_readreg (fe, 0x11) & 0x08)) {
+		if (!(ves1820_readreg(state, 0x11) & 0x08)) {
 			reg0 ^= 0x20;
-			ves1820_writereg (fe, 0x00, reg0 & 0xfe);
-        		ves1820_writereg (fe, 0x00, reg0 | 0x01);
+			ves1820_writereg(state, 0x00, reg0 & 0xfe);
+			ves1820_writereg(state, 0x00, reg0 | 0x01);
 		}
 	}
 
-	SET_REG0(fe->data, reg0);
+	state->reg0 = reg0;
 
 	return 0;
 }
 
-
-static int ves1820_init (struct dvb_frontend *fe)
+static int ves1820_init(struct ves1820_state *state)
 {
 	int i;
         
-        dprintk("DVB: VES1820(%d): init chip\n", fe->i2c->adapter->num);
-
-        ves1820_writereg (fe, 0, 0);
+	ves1820_writereg(state, 0, 0);
 
 #if defined(CONFIG_DBOX2)
 	ves1820_inittab[2] &= ~0x08;
 #endif
 
 	for (i=0; i<53; i++)
-                ves1820_writereg (fe, i, ves1820_inittab[i]);
+		ves1820_writereg(state, i, ves1820_inittab[i]);
 
-	ves1820_writereg (fe, 0x34, GET_PWM(fe->data)); 
+	ves1820_writereg(state, 0x34, state->pwm);
 
 	return 0;
 }
 
-
-static int ves1820_set_symbolrate (struct dvb_frontend *fe, u32 symbolrate)
+static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
 {
         s32 BDR; 
         s32 BDRI;
@@ -289,17 +242,27 @@
 	if (symbolrate < 500000)
                 symbolrate = 500000;
 
-        if (symbolrate < XIN/16) NDEC = 1;
-        if (symbolrate < XIN/32) NDEC = 2;
-        if (symbolrate < XIN/64) NDEC = 3;
-
-        if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
-        if (symbolrate < (u32)(XIN/16))	 SFIL = 0;
-        if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
-        if (symbolrate < (u32)(XIN/32))	 SFIL = 0;
-        if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
-        if (symbolrate < (u32)(XIN/64))	 SFIL = 0;
-        if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+	if (symbolrate < XIN / 16)
+		NDEC = 1;
+	if (symbolrate < XIN / 32)
+		NDEC = 2;
+	if (symbolrate < XIN / 64)
+		NDEC = 3;
+
+	if (symbolrate < (u32) (XIN / 12.3))
+		SFIL = 1;
+	if (symbolrate < (u32) (XIN / 16))
+		SFIL = 0;
+	if (symbolrate < (u32) (XIN / 24.6))
+		SFIL = 1;
+	if (symbolrate < (u32) (XIN / 32))
+		SFIL = 0;
+	if (symbolrate < (u32) (XIN / 49.2))
+		SFIL = 1;
+	if (symbolrate < (u32) (XIN / 64))
+		SFIL = 0;
+	if (symbolrate < (u32) (XIN / 98.4))
+		SFIL = 1;
         
         symbolrate <<= NDEC;
         ratio = (symbolrate << 4) / FIN;
@@ -318,20 +281,18 @@
         
         NDEC = (NDEC << 6) | ves1820_inittab[0x03];
 
-        ves1820_writereg (fe, 0x03, NDEC);
-        ves1820_writereg (fe, 0x0a, BDR&0xff);
-        ves1820_writereg (fe, 0x0b, (BDR>> 8)&0xff);
-        ves1820_writereg (fe, 0x0c, (BDR>>16)&0x3f);
+	ves1820_writereg(state, 0x03, NDEC);
+	ves1820_writereg(state, 0x0a, BDR & 0xff);
+	ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff);
+	ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f);
 
-        ves1820_writereg (fe, 0x0d, BDRI);
-        ves1820_writereg (fe, 0x0e, SFIL);
+	ves1820_writereg(state, 0x0d, BDRI);
+	ves1820_writereg(state, 0x0e, SFIL);
 
         return 0;
 }
 
-
-static int ves1820_set_parameters (struct dvb_frontend *fe,
-			    struct dvb_frontend_parameters *p)
+static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_frontend_parameters *p)
 {
 	static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
 	static const u8 reg0x01 [] = {  140,  140,  106,  100,   92 };
@@ -343,16 +304,16 @@
 	if (real_qam < 0 || real_qam > 4)
 		return -EINVAL;
 
-	tuner_set_tv_freq (fe, p->frequency);
-	ves1820_set_symbolrate (fe, p->u.qam.symbol_rate);
-	ves1820_writereg (fe, 0x34, GET_PWM(fe->data));
-
-        ves1820_writereg (fe, 0x01, reg0x01[real_qam]);
-        ves1820_writereg (fe, 0x05, reg0x05[real_qam]);
-        ves1820_writereg (fe, 0x08, reg0x08[real_qam]);
-        ves1820_writereg (fe, 0x09, reg0x09[real_qam]);
+	tuner_set_tv_freq(state, p->frequency);
+	ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
+	ves1820_writereg(state, 0x34, state->pwm);
+
+	ves1820_writereg(state, 0x01, reg0x01[real_qam]);
+	ves1820_writereg(state, 0x05, reg0x05[real_qam]);
+	ves1820_writereg(state, 0x08, reg0x08[real_qam]);
+	ves1820_writereg(state, 0x09, reg0x09[real_qam]);
 
-	ves1820_setup_reg0 (fe, reg0x00[real_qam], p->inversion);
+	ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
 
 	/* yes, this speeds things up: userspace reports lock in about 8 ms
 	   instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */
@@ -361,10 +322,10 @@
 	return 0;
 }
 
-
-
 static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
+	struct ves1820_state *state = (struct ves1820_state *) fe->data;
+
         switch (cmd) {
 	case FE_GET_INFO:
 		memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info));
@@ -377,7 +338,7 @@
 
 		*status = 0;
 
-                sync = ves1820_readreg (fe, 0x11);
+			sync = ves1820_readreg(state, 0x11);
 
 		if (sync & 1)
 			*status |= FE_HAS_SIGNAL;
@@ -399,57 +360,54 @@
 
 	case FE_READ_BER:
 	{
-		u32 ber = ves1820_readreg(fe, 0x14) |
-			 (ves1820_readreg(fe, 0x15) << 8) |
-			 ((ves1820_readreg(fe, 0x16) & 0x0f) << 16);
+			u32 ber = ves1820_readreg(state, 0x14) |
+					(ves1820_readreg(state, 0x15) << 8) |
+					((ves1820_readreg(state, 0x16) & 0x0f) << 16);
 		*((u32*) arg) = 10 * ber;
 		break;
 	}
 	case FE_READ_SIGNAL_STRENGTH:
 	{
-		u8 gain = ves1820_readreg(fe, 0x17);
+			u8 gain = ves1820_readreg(state, 0x17);
 		*((u16*) arg) = (gain << 8) | gain;
 		break;
 	}
 
 	case FE_READ_SNR:
 	{
-		u8 quality = ~ves1820_readreg(fe, 0x18);
+			u8 quality = ~ves1820_readreg(state, 0x18);
 		*((u16*) arg) = (quality << 8) | quality;
 		break;
 	}
 
 	case FE_READ_UNCORRECTED_BLOCKS:
-		*((u32*) arg) = ves1820_readreg (fe, 0x13) & 0x7f;
+		*((u32 *) arg) = ves1820_readreg(state, 0x13) & 0x7f;
 		if (*((u32*) arg) == 0x7f)
 			*((u32*) arg) = 0xffffffff;
 		/* reset uncorrected block counter */
-		ves1820_writereg (fe, 0x10, ves1820_inittab[0x10] & 0xdf);
-	        ves1820_writereg (fe, 0x10, ves1820_inittab[0x10]);
+		ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+		ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
 		break;
 
         case FE_SET_FRONTEND:
-		return ves1820_set_parameters (fe, arg);
+		return ves1820_set_parameters(state, arg);
 
 	case FE_GET_FRONTEND:
 	{
 		struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg;
-		u8 reg0 = GET_REG0(fe->data);
 		int sync;
 		s8 afc = 0;
                 
-                sync = ves1820_readreg (fe, 0x11);
-			afc = ves1820_readreg(fe, 0x19);
+			sync = ves1820_readreg(state, 0x11);
+			afc = ves1820_readreg(state, 0x19);
 		if (verbose) {
 			/* AFC only valid when carrier has been recovered */
-			printk(sync & 2 ? "DVB: VES1820(%d): AFC (%d) %dHz\n" :
-					  "DVB: VES1820(%d): [AFC (%d) %dHz]\n",
-					fe->i2c->adapter->num, afc,
-			       -((s32)p->u.qam.symbol_rate * afc) >> 10);
+				printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+					"ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
 		}
 
-		p->inversion = HAS_INVERSION(reg0) ? INVERSION_ON : INVERSION_OFF;
-		p->u.qam.modulation = ((reg0 >> 2) & 7) + QAM_16;
+			p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
+			p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
 		p->u.qam.fec_inner = FEC_NONE;
 
@@ -459,12 +417,12 @@
 		break;
 	}
 	case FE_SLEEP:
-		ves1820_writereg (fe, 0x1b, 0x02);  /* pdown ADC */
-		ves1820_writereg (fe, 0x00, 0x80);  /* standby */
+		ves1820_writereg(state, 0x1b, 0x02);	/* pdown ADC */
+		ves1820_writereg(state, 0x00, 0x80);	/* standby */
 		break;
 
         case FE_INIT:
-                return ves1820_init (fe);
+		return ves1820_init(state);
 
         default:
                 return -EINVAL;
@@ -473,21 +431,18 @@
         return 0;
 } 
 
-
-static long probe_tuner (struct dvb_i2c_bus *i2c)
+static long probe_tuner(struct i2c_adapter *i2c)
 {
-	static const struct i2c_msg msg1 = 
-		{ .addr = 0x61, .flags = 0, .buf = NULL, .len = 0 };
-	static const struct i2c_msg msg2 =
-		{ .addr = 0x62, .flags = 0, .buf = NULL, .len = 0 };
+	struct i2c_msg msg1 = {.addr = 0x61,.flags = 0,.buf = NULL,.len = 0 };
+	struct i2c_msg msg2 = {.addr = 0x62,.flags = 0,.buf = NULL,.len = 0 };
 	int type;
 
-	if (i2c->xfer(i2c, &msg1, 1) == 1) {
+	if (i2c_transfer(i2c, &msg1, 1) == 1) {
 		type = 0;
-		printk ("DVB: VES1820(%d): setup for tuner spXXXX\n", i2c->adapter->num);
-	} else if (i2c->xfer(i2c, &msg2, 1) == 1) {
+		printk("ves1820: setup for tuner spXXXX\n");
+	} else if (i2c_transfer(i2c, &msg2, 1) == 1) {
 		type = 1;
-		printk ("DVB: VES1820(%d): setup for tuner sp5659c\n", i2c->adapter->num);
+		printk("ves1820: setup for tuner sp5659c\n");
 	} else {
 		type = -1;
 	}
@@ -495,91 +450,186 @@
 	return type;
 }
 
-
-static u8 read_pwm (struct dvb_i2c_bus *i2c)
+static u8 read_pwm(struct i2c_adapter *i2c)
 {
 	u8 b = 0xff;
 	u8 pwm;
 	struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
-			 { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1 } };
+	{.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
+	};
 
-	if ((i2c->xfer(i2c, msg, 2) != 2) || (pwm == 0xff))
+	if ((i2c_transfer(i2c, msg, 2) != 2) || (pwm == 0xff))
 		pwm = 0x48;
 
-	printk("DVB: VES1820(%d): pwm=0x%02x\n", i2c->adapter->num, pwm);
+	printk("ves1820: pwm=0x%02x\n", pwm);
 
 	return pwm;
 }
 
-
-static long probe_demod_addr (struct dvb_i2c_bus *i2c)
+static long probe_demod_addr(struct i2c_adapter *i2c)
 {
 	u8 b [] = { 0x00, 0x1a };
 	u8 id;
 	struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 },
-	                   { .addr = 0x08, .flags = I2C_M_RD, .buf = &id, .len = 1 } };
+	{.addr = 0x08,.flags = I2C_M_RD,.buf = &id,.len = 1}
+	};
 
-	if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
+	if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
 		return msg[0].addr;
 
 	msg[0].addr = msg[1].addr = 0x09;
 
-	if (i2c->xfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
+	if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
 		return msg[0].addr;
 
 	return -1;
 }
 
+static ssize_t attr_read_pwm(struct device *dev, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+	return sprintf(buf, "0x%02x\n", state->pwm);
+}
+
+static ssize_t attr_write_pwm(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+	unsigned long pwm;
+	pwm = simple_strtoul(buf, NULL, 0);
+	state->pwm = pwm & 0xff;
+	return strlen(buf)+1;
+}
+
+static struct device_attribute dev_attr_client_name = {
+	.attr	= { .name = "pwm", .mode = S_IRUGO|S_IWUGO, .owner = THIS_MODULE },
+	.show	= &attr_read_pwm,
+	.store  = &attr_write_pwm,
+};
+
+static struct i2c_client client_template;
 
-static int ves1820_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
 {
-	void *priv = NULL;
+	struct i2c_client *client;
+	struct ves1820_state *state;
 	long demod_addr;
-	long tuner_type;
+	int tuner_type;
+	int ret;
 
-	if ((demod_addr = probe_demod_addr(i2c)) < 0)
+	demod_addr = probe_demod_addr(adapter);
+	if (demod_addr < 0)
 		return -ENODEV;
 
-	tuner_type = probe_tuner(i2c);
+	tuner_type = probe_tuner(adapter);
+	if (tuner_type < 0) {
+		printk("ves1820: demod found, but unknown tuner type.\n");
+		return -ENODEV;
+	}
 
-	if ((i2c->adapter->num < MAX_UNITS) && pwm[i2c->adapter->num] != -1) {
-		printk("DVB: VES1820(%d): pwm=0x%02x (user specified)\n",
-				i2c->adapter->num, pwm[i2c->adapter->num]);
-		SET_PWM(priv, pwm[i2c->adapter->num]);
+	if ((state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
 	}
-	else
-		SET_PWM(priv, read_pwm(i2c));
-	SET_REG0(priv, ves1820_inittab[0]);
-	SET_TUNER(priv, tuner_type);
-	SET_DEMOD_ADDR(priv, demod_addr);
 
-	return dvb_register_frontend (ves1820_ioctl, i2c, priv, &ves1820_info);
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memset(state, 0, sizeof(*state));
+	state->i2c = adapter;
+	state->tuner = tuner_type;
+	state->pwm = read_pwm(adapter);
+	state->reg0 = ves1820_inittab[0];
+	state->demod_addr = demod_addr;
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = addr[tuner_type];
+
+	i2c_set_clientdata(client, (void *) state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return ret;
 }
 
+	BUG_ON(!state->dvb);
+
+	device_create_file(&client->dev, &dev_attr_client_name);
+
+	ret = dvb_register_frontend(ves1820_ioctl, state->dvb, state, &ves1820_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int detach_client(struct i2c_client *client)
+{
+	struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+	dvb_unregister_frontend_new(ves1820_ioctl, state->dvb);
+	device_remove_file(&client->dev, &dev_attr_client_name);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
 
-static void ves1820_detach (struct dvb_i2c_bus *i2c, void *data)
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	dvb_unregister_frontend (ves1820_ioctl, i2c);
+	struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
+
+	switch (cmd) {
+	case FE_REGISTER:{
+			state->dvb = (struct dvb_adapter *) arg;
+			break;
+		}
+	case FE_UNREGISTER:{
+			state->dvb = NULL;
+			break;
+		}
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner = THIS_MODULE,
+	.name = "ves1820",
+	.id = I2C_DRIVERID_VES1820,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client = detach_client,
+	.command = command,
+};
+
+static struct i2c_client client_template = {
+	I2C_DEVNAME("ves1820"),
+	.flags = I2C_CLIENT_ALLOW_USE,
+	.driver = &driver,
+};
 
 static int __init init_ves1820 (void)
 {
-	int i;
-	for (i = 0; i < MAX_UNITS; i++)
-		if (pwm[i] < -1 || pwm[i] > 255)
-			return -EINVAL;
-	return dvb_register_i2c_device (THIS_MODULE,
-					ves1820_attach, ves1820_detach);
+	return i2c_add_driver(&driver);
 }
 
-
 static void __exit exit_ves1820 (void)
 {
-	dvb_unregister_i2c_device (ves1820_attach);
+	if (i2c_del_driver(&driver))
+		printk("ves1820: driver deregistration failed\n");
 }
 
-
 module_init(init_ves1820);
 module_exit(exit_ves1820);
 
@@ -583,8 +633,6 @@
 module_init(init_ves1820);
 module_exit(exit_ves1820);
 
-MODULE_PARM(pwm, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(pwm, "override PWM value stored in EEPROM (tuner calibration)");
 MODULE_PARM(verbose, "i");
 MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/ves1x93.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1x93.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/ves1x93.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1x93.c	2004-08-18 19:52:18.000000000 +0200
@@ -30,7 +30,6 @@
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
 static int debug = 0;
 #define dprintk	if (debug) printk
@@ -112,17 +111,19 @@
 
 struct ves1x93_state {
 	fe_spectral_inversion_t inversion;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
 };
 
 
 
-static int ves1x93_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int ves1x93_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
         u8 buf [] = { 0x00, reg, data };
 	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 };
 	int err;
 
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+	if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
 		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
 		return -EREMOTEIO;
 	}
@@ -131,7 +132,7 @@
 }
 
 
-static u8 ves1x93_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 ves1x93_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { 0x00, reg };
@@ -139,7 +140,7 @@
 	struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 },
 			   { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -148,13 +149,13 @@
 }
 
 
-static int tuner_write (struct dvb_i2c_bus *i2c, u8 *data, u8 len)
+static int tuner_write (struct i2c_adapter *i2c, u8 *data, u8 len)
 {
         int ret;
         struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = len };
 
 	ves1x93_writereg(i2c, 0x00, 0x11);
-        ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 	ves1x93_writereg(i2c, 0x00, 0x01);
 
         if (ret != 1)
@@ -169,7 +170,7 @@
  *   set up the downconverter frequency divisor for a
  *   reference clock comparision frequency of 125 kHz.
  */
-static int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
+static int sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq, u8 pwr)
 {
         u32 div = (freq + 479500) / 125;
 	u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x95, (pwr << 5) | 0x30 };
@@ -178,7 +179,7 @@
 }
 
 
-static int tsa5059_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 	int ret;
 	u8 buf [2];
@@ -194,7 +195,7 @@
 }
 
 
-static int tuner_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr)
+static int tuner_set_tv_freq (struct i2c_adapter *i2c, u32 freq, u8 pwr)
 {
 	if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI))
 		return sp5659_set_tv_freq (i2c, freq, pwr);
@@ -205,7 +206,7 @@
 }
 
 
-static int ves1x93_init (struct dvb_i2c_bus *i2c)
+static int ves1x93_init (struct i2c_adapter *i2c)
 {
 	int i;
 	int size;
@@ -249,24 +250,24 @@
 }
 
 
-static int ves1x93_clr_bit (struct dvb_i2c_bus *i2c)
+static int ves1x93_clr_bit (struct i2c_adapter *i2c)
 {
         ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe);
         ves1x93_writereg (i2c, 0, init_1x93_tab[0]);
-	dvb_delay(5);
+	msleep(5);
 	return 0;
 }
 
-static int ves1x93_init_aquire (struct dvb_i2c_bus *i2c)
+static int ves1x93_init_aquire (struct i2c_adapter *i2c)
 {
         ves1x93_writereg (i2c, 3, 0x00);
 	ves1x93_writereg (i2c, 3, init_1x93_tab[3]);
-	dvb_delay(5);
+	msleep(5);
 	return 0;
 }
 
 
-static int ves1x93_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+static int ves1x93_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
 {
 	u8 val;
 
@@ -293,7 +294,7 @@
 }
 
 
-static int ves1x93_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int ves1x93_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
 {
 	if (fec == FEC_AUTO)
 		return ves1x93_writereg (i2c, 0x0d, 0x08);
@@ -304,13 +305,13 @@
 }
 
 
-static fe_code_rate_t ves1x93_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t ves1x93_get_fec (struct i2c_adapter *i2c)
 {
 	return FEC_1_2 + ((ves1x93_readreg (i2c, 0x0d) >> 4) & 0x7);
 }
 
 
-static int ves1x93_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+static int ves1x93_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
 {
 	u32 BDR;
         u32 ratio;
@@ -414,7 +415,7 @@
 }
 
 
-static int ves1x93_afc (struct dvb_i2c_bus *i2c, u32 freq, u32 srate)
+static int ves1x93_afc (struct i2c_adapter *i2c, u32 freq, u32 srate)
 {
 	int afc;
 
@@ -433,7 +434,7 @@
 	return 0;
 }
 
-static int ves1x93_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+static int ves1x93_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
 {
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -450,8 +451,8 @@
 
 static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	struct ves1x93_state *state = (struct ves1x93_state*) fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
         switch (cmd) {
         case FE_GET_INFO:
@@ -578,11 +579,14 @@
         return 0;
 } 
 
+static struct i2c_client client_template;
 
-static int ves1x93_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
 {
-	u8 identity = ves1x93_readreg(i2c, 0x1e);
+	struct i2c_client *client;
 	struct ves1x93_state* state;
+	u8 identity = ves1x93_readreg(adapter, 0x1e);
+	int ret;
 
 	switch (identity) {
 	case 0xdc: /* VES1893A rev1 */
@@ -608,19 +612,88 @@
 	if ((state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL)) == NULL) {
 		return -ENOMEM;
 	}
+
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
 	state->inversion = INVERSION_OFF;
-	*data = state;
+	state->i2c = adapter;
 
-	return dvb_register_frontend (ves1x93_ioctl, i2c, (void*) state, &ves1x93_info);
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = (0x08>>1);
+	i2c_set_clientdata(client, (void*)state);
+	
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return -EFAULT;
+	}
+
+	BUG_ON(!state->dvb);
+
+	ret = dvb_register_frontend(ves1x93_ioctl, state->dvb, state,
+					&ves1x93_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return -EFAULT;
 }
 
+	return 0;
+}
 
-static void ves1x93_detach (struct dvb_i2c_bus *i2c, void *data)
+static int detach_client(struct i2c_client *client)
 {
-	kfree(data);
-	dvb_unregister_frontend (ves1x93_ioctl, i2c);
+	struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client);
+	dvb_unregister_frontend_new(ves1x93_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
+
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client);
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER: {
+		state->dvb = (struct dvb_adapter*)arg;
+		break;
+	}
+	case FE_UNREGISTER: {
+		state->dvb = NULL;
+		break;
+	}
+	default:
+		return -EOPNOTSUPP;
 }
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= "ves1x93",
+	.id 		= I2C_DRIVERID_DVBFE_VES1X93,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client 	= detach_client,
+	.command 	= command,
+};
 
+static struct i2c_client client_template = {
+	I2C_DEVNAME("ves1x93"),
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
 
 static int __init init_ves1x93 (void)
 {
@@ -638,16 +711,16 @@
 		return -EIO;
 	}
 
-	return dvb_register_i2c_device (THIS_MODULE, ves1x93_attach, ves1x93_detach);
+	return i2c_add_driver(&driver);
 }
 
 
 static void __exit exit_ves1x93 (void)
 {
-	dvb_unregister_i2c_device (ves1x93_attach);
+	if (i2c_del_driver(&driver))
+		printk("vex1x93: driver deregistration failed\n");
 }
 
-
 module_init(init_ves1x93);
 module_exit(exit_ves1x93);
 

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

* Re: [PATCH][2.6][6/14] convert frontend drivers to kernel i2c 2/3
  2004-09-17 14:29         ` [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3 Michael Hunold
@ 2004-09-17 14:30           ` Michael Hunold
  2004-09-17 14:32             ` [PATCH][2.6][7/14] convert frontend drivers to kernel i2c 3/3 Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:30 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 06-DVB-frontend-conversion2.diff --]
[-- Type: text/plain, Size: 68754 bytes --]

- [DVB] alps_tdlb7, alps_tdmb7, at76c651, cx24110, dst: convert from dvb-i2c to kernel-i2c, MODULE_PARM() to module_param(), dvb_delay() to mdelay()
- [DVB] alps_tdlb7: move from home-brewn firmware loading to firmware_class
- [DVB] dst: use sysfs attributes for type and flags for per-card parameters

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/alps_tdlb7.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdlb7.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/alps_tdlb7.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdlb7.c	2004-08-18 19:52:17.000000000 +0200
@@ -20,33 +20,38 @@
 
 */
 
-
 /* 
-    This driver needs a copy of the firmware file 'Sc_main.mc' from the Haupauge
-    windows driver in the '/usr/lib/DVB/driver/frontends' directory.
-    You can also pass the complete file name with the module parameter 'firmware_file'.
+    This driver needs a copy of the firmware file from the Technotrend
+    Windoze driver.
+
+    This page is worth a look:
+    http://www.heise.de/ct/ftp/projekte/vdr/firmware.shtml
     
+    Copy 'Sc_main.mc'  to '/usr/lib/hotplug/firmware/dvb-fe-tdlb7-2.16.fw'.
 */  
+#define SP887X_DEFAULT_FIRMWARE "dvb-fe-tdlb7-2.16.fw"
 
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/unistd.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
 #include <linux/delay.h>
-#include <linux/syscalls.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-#ifndef CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION
-#define CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION "/usr/lib/DVB/driver/frontends/Sc_main.mc"
-#endif
+#define FRONTEND_NAME "dvbfe_alps_tdlb7"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
 
-static char * firmware_file = CONFIG_ALPS_TDLB7_FIRMWARE_LOCATION;
-static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-#define dprintk	if (debug) printk
 
 /* firmware size for sp8870 */
 #define SP8870_FIRMWARE_SIZE 16382
@@ -54,9 +59,6 @@
 /* starting point for firmware in file 'Sc_main.mc' */
 #define SP8870_FIRMWARE_OFFSET 0x0A
 
-
-static int errno;
-
 static struct dvb_frontend_info tdlb7_info = {
 	.name			= "Alps TDLB7",
 	.type			= FE_OFDM,
@@ -71,14 +73,18 @@
 				  FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
 };
 
+struct tdlb7_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
-static int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data)
+static int sp8870_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
 {
         u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
 	struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = buf, .len = 4 };
 	int err;
 
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+        if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
 		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
 		return -EREMOTEIO;
 	}
@@ -86,8 +92,7 @@
         return 0;
 }
 
-
-static u16 sp8870_readreg (struct dvb_i2c_bus *i2c, u16 reg)
+static u16 sp8870_readreg (struct i2c_adapter *i2c, u16 reg)
 {
 	int ret;
 	u8 b0 [] = { reg >> 8 , reg & 0xff };
@@ -95,7 +100,7 @@
 	struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
 			   { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
 
 	if (ret != 2) {
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -105,22 +110,26 @@
 	return (b1[0] << 8 | b1[1]);
 }
 
-
-static int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4])
+static int sp5659_write (struct i2c_adapter *i2c, u8 data [4])
 {
         int ret;
-        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = 4 };
 
-        ret = i2c->xfer (i2c, &msg, 1);
+        u8 buf_open [] = { 0x206 >> 8, 0x206 & 0xff, 0x001 >> 8, 0x001 & 0xff };
+        u8 buf_close [] = { 0x206 >> 8, 0x206 & 0xff, 0x000 >> 8, 0x000 & 0xff };
+
+        struct i2c_msg msg[3] = { {.addr = 0x71, .flags = 0, .buf = buf_open, .len = 4 },
+				  {.addr = 0x60, .flags = 0, .buf = data, .len = 4 },
+				  {.addr = 0x71, .flags = 0, .buf = buf_close, .len = 4 } };
 
-        if (ret != 1)
+        ret = i2c_transfer (i2c, &msg[0], 3);
+
+        if (ret != 3)
                 printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
 
-        return (ret != 1) ? -1 : 0;
+        return (ret != 3) ? -EREMOTEIO : 0;
 }
 
-
-static void sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static void sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
         u32 div = (freq + 36200000) / 166666;
         u8 buf [4];
@@ -137,65 +146,23 @@
 	buf[3] = pwr << 6;
 
 	/* open i2c gate for PLL message transmission... */
-	sp8870_writereg(i2c, 0x206, 0x001);
 	sp5659_write (i2c, buf);
-	sp8870_writereg(i2c, 0x206, 0x000);
 }
 
-
-static int sp8870_read_firmware_file (const char *fn, char **fp)
-{
-        int fd;
-	loff_t filesize;
-	char *dp;
-
-	fd = sys_open(fn, 0, 0);
-	if (fd == -1) {
-                printk("%s: unable to open '%s'.\n", __FUNCTION__, fn);
-		return -EIO;
-	}
-
-	filesize = sys_lseek(fd, 0L, 2);
-	if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) {
-	        printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	*fp= dp = vmalloc(SP8870_FIRMWARE_SIZE);
-	if (dp == NULL)	{
-		printk("%s: out of memory loading '%s'.\n", __FUNCTION__, fn);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0);
-	if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) {
-		printk("%s: failed to read '%s'.\n",__FUNCTION__, fn);
-		vfree(dp);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	sys_close(fd);
-	*fp = dp;
-
-	return 0;
-}
-
-
-static int sp8870_firmware_upload (struct dvb_i2c_bus *i2c)
+static int sp8870_firmware_upload (struct i2c_adapter *i2c, const struct firmware *fw)
 {
 	struct i2c_msg msg;
-	char *fw_buf = NULL;
+	char *fw_buf = fw->data;
 	int fw_pos;
 	u8 tx_buf[255];
 	int tx_len;
 	int err = 0;
-	mm_segment_t fs = get_fs();
 
 	dprintk ("%s: ...\n", __FUNCTION__);
 
+	if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
+		return -EINVAL;
+
 	// system controller stop 
 	sp8870_writereg(i2c,0x0F00,0x0000);
 
@@ -205,19 +172,10 @@
 	// instruction RAM MWR
 	sp8870_writereg(i2c, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
 
-	// reading firmware file to buffer
-	set_fs(get_ds());
-        err = sp8870_read_firmware_file(firmware_file, (char**) &fw_buf);
-	set_fs(fs);
-	if (err != 0) {
-		printk("%s: reading firmware file failed!\n", __FUNCTION__);
-		return err;
-	}
-
 	// do firmware upload
-	fw_pos = 0;
-	while (fw_pos < SP8870_FIRMWARE_SIZE){
-		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE - 252) ? 252 : SP8870_FIRMWARE_SIZE - fw_pos;
+	fw_pos = SP8870_FIRMWARE_OFFSET;
+	while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
+		tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
 		// write register 0xCF0A
 		tx_buf[0] = 0xCF;
 		tx_buf[1] = 0x0A;
@@ -226,23 +184,19 @@
 		msg.flags=0;
 		msg.buf = tx_buf;
 		msg.len = tx_len + 2;
-        	if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+        	if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
 			printk("%s: firmware upload failed!\n", __FUNCTION__);
 			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
-        		vfree(fw_buf);
 			return err;
 		}
 		fw_pos += tx_len;
 	}
 
-	vfree(fw_buf);
-
 	dprintk ("%s: done!\n", __FUNCTION__);
 	return 0;
 };
 
-
-static void sp8870_microcontroller_stop (struct dvb_i2c_bus *i2c)
+static void sp8870_microcontroller_stop (struct i2c_adapter *i2c)
 {
 	sp8870_writereg(i2c, 0x0F08, 0x000);
 	sp8870_writereg(i2c, 0x0F09, 0x000);
@@ -251,8 +205,7 @@
 	sp8870_writereg(i2c, 0x0F00, 0x000);
 }
 
-
-static void sp8870_microcontroller_start (struct dvb_i2c_bus *i2c)
+static void sp8870_microcontroller_start (struct i2c_adapter *i2c)
 {
 	sp8870_writereg(i2c, 0x0F08, 0x000);
 	sp8870_writereg(i2c, 0x0F09, 0x000);
@@ -264,8 +217,7 @@
 	sp8870_readreg(i2c, 0x0D01);
 }
 
-
-static int sp8870_init (struct dvb_i2c_bus *i2c)
+static int sp8870_init (struct i2c_adapter *i2c)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -291,8 +243,7 @@
 	return 0;
 }
 
-
-static int sp8870_read_status (struct dvb_i2c_bus *i2c,  fe_status_t * fe_status)
+static int sp8870_read_status (struct i2c_adapter *i2c,  fe_status_t * fe_status)
 {
 	int status;
 	int signal;
@@ -317,8 +268,7 @@
 	return 0;
 }
 
-
-static int sp8870_read_ber (struct dvb_i2c_bus *i2c, u32 * ber)
+static int sp8870_read_ber (struct i2c_adapter *i2c, u32 * ber)
 {
 	int ret;
 	u32 tmp;
@@ -345,8 +295,7 @@
 	return 0;
 	}
 
-
-static int sp8870_read_signal_strength (struct dvb_i2c_bus *i2c,  u16 * signal)
+static int sp8870_read_signal_strength (struct i2c_adapter *i2c,  u16 * signal)
 	{
 	int ret;
 	u16 tmp;
@@ -371,15 +320,13 @@
 	return 0;
 	}
 
-
-static int sp8870_read_snr(struct dvb_i2c_bus *i2c, u32* snr)
+static int sp8870_read_snr(struct i2c_adapter *i2c, u32* snr)
 	{
                 *snr=0;  
 		return -EOPNOTSUPP;
 	}
 
-
-static int sp8870_read_uncorrected_blocks (struct dvb_i2c_bus *i2c, u32* ublocks)
+static int sp8870_read_uncorrected_blocks (struct i2c_adapter *i2c, u32* ublocks)
 	{
 		int ret;
 
@@ -397,8 +344,7 @@
 		return 0;
 	}
 
-
-static int sp8870_read_data_valid_signal(struct dvb_i2c_bus *i2c)
+static int sp8870_read_data_valid_signal(struct i2c_adapter *i2c)
 {
 	return (sp8870_readreg(i2c, 0x0D02) > 0);
 }
@@ -476,8 +421,7 @@
 	return 0;
 }
 
-
-static int sp8870_set_frontend_parameters (struct dvb_i2c_bus *i2c,
+static int sp8870_set_frontend_parameters (struct i2c_adapter *i2c,
 				      struct dvb_frontend_parameters *p)
         {
 	int  err;
@@ -540,7 +483,7 @@
 // only for debugging: counter for channel switches
 static int switches = 0;
 
-static int sp8870_set_frontend (struct dvb_i2c_bus *i2c, struct dvb_frontend_parameters *p)
+static int sp8870_set_frontend (struct i2c_adapter *i2c, struct dvb_frontend_parameters *p)
 	{
 	/*
 	    The firmware of the sp8870 sometimes locks up after setting frontend parameters.
@@ -595,15 +538,13 @@
 	return 0;
 }
 
-
-static int sp8870_sleep(struct dvb_i2c_bus *i2c)
+static int sp8870_sleep(struct i2c_adapter *i2c)
 {
 	// tristate TS output and disable interface pins
 	return sp8870_writereg(i2c, 0xC18, 0x000);
 }
 
-
-static int sp8870_wake_up(struct dvb_i2c_bus *i2c)
+static int sp8870_wake_up(struct i2c_adapter *i2c)
 {
 	// enable TS output and interface pins
 	return sp8870_writereg(i2c, 0xC18, 0x00D);
@@ -609,10 +550,10 @@
 	return sp8870_writereg(i2c, 0xC18, 0x00D);
 }
 
-
 static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct tdlb7_state *state = (struct tdlb7_state *) fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
         switch (cmd) {
         case FE_GET_INFO:
@@ -667,9 +608,15 @@
         return 0;
 }
 
+static struct i2c_client client_template;
 
-static int tdlb7_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
 {
+	struct i2c_client *client;
+	struct tdlb7_state *state;
+	const struct firmware *fw;
+	int ret;
+
         u8 b0 [] = { 0x02 , 0x00 };
         u8 b1 [] = { 0, 0 };
         struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
@@ -677,48 +624,126 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-        if (i2c->xfer (i2c, msg, 2) != 2)
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	if (NULL == (state = kmalloc(sizeof(struct tdlb7_state), GFP_KERNEL))) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->i2c = adapter;
+
+        if (i2c_transfer (adapter, msg, 2) != 2) {
+		kfree(state);
+		kfree(client);
                 return -ENODEV;
+	}
 
-	sp8870_firmware_upload(i2c);
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	i2c_set_clientdata(client, (void*)state);
 
-	return dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info);
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return ret;
 }
 
+	/* request the firmware, this will block until someone uploads it */
+	printk("tdlb7: waiting for firmware upload...\n");
+	ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev);
+	if (ret) {
+		printk("tdlb7: no firmware upload (timeout or file not found?)\n");
+		goto out;
+	}
 
-static void tdlb7_detach (struct dvb_i2c_bus *i2c, void *data)
-{
-	dprintk ("%s\n", __FUNCTION__);
+	ret = sp8870_firmware_upload(adapter, fw);
+	if (ret) {
+		printk("tdlb7: writing firmware to device failed\n");
+		release_firmware(fw);
+		goto out;
+	}
 
-	dvb_unregister_frontend (tdlb7_ioctl, i2c);
+	ret = dvb_register_frontend(tdlb7_ioctl, state->dvb, state,
+					&tdlb7_info, THIS_MODULE);
+	if (ret) {
+		printk("tdlb7: registering frontend to dvb-core failed.\n");
+		release_firmware(fw);
+		goto out;
 }
 
+	return 0;
+out:
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+	return ret;
+}
 
-static int __init init_tdlb7 (void)
+static int detach_client(struct i2c_client *client)
 {
+	struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
 
-	return dvb_register_i2c_device (THIS_MODULE, tdlb7_attach, tdlb7_detach);
+	dvb_unregister_frontend_new (tdlb7_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
 }
 
-
-static void __exit exit_tdlb7 (void)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_i2c_device (tdlb7_attach);
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = (struct dvb_adapter*)arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_ALPS_TDLB7,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client 	= detach_client,
+	.command 	= command,
+};
 
-module_init(init_tdlb7);
-module_exit(exit_tdlb7);
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
 
+static int __init init_tdlb7(void)
+{
+	return i2c_add_driver(&driver);
+}
 
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
+static void __exit exit_tdlb7(void)
+{
+	if (i2c_del_driver(&driver))
+		printk("tdlb7: driver deregistration failed\n");
+}
 
-MODULE_PARM(firmware_file,"s");
-MODULE_PARM_DESC(firmware_file, "where to find the firmware file");
+module_init(init_tdlb7);
+module_exit(exit_tdlb7);
 
 MODULE_DESCRIPTION("TDLB7 DVB-T Frontend");
 MODULE_AUTHOR("Juergen Peitz");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/alps_tdmb7.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdmb7.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/alps_tdmb7.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdmb7.c	2004-08-18 19:52:17.000000000 +0200
@@ -23,15 +23,23 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
+#define FRONTEND_NAME "dvbfe_alps_tdmb7"
 
-static int debug = 0;
-#define dprintk	if (debug) printk
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 
 static struct dvb_frontend_info tdmb7_info = {
@@ -53,6 +61,10 @@
               FE_CAN_RECOVER
 };
 
+struct tdmb7_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
 static u8 init_tab [] = {
 	0x04, 0x10,
@@ -75,8 +87,7 @@
 	0x47, 0x05,
 };
 
-
-static int cx22700_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int cx22700_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
 	int ret;
 	u8 buf [] = { reg, data };
@@ -84,7 +95,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 
 	if (ret != 1) 
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
@@ -93,8 +104,7 @@
 	return (ret != 1) ? -1 : 0;
 }
 
-
-static u8 cx22700_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 cx22700_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
@@ -104,7 +114,7 @@
         
 	dprintk ("%s\n", __FUNCTION__);
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
         
 	if (ret != 2) 
 		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -112,14 +122,13 @@
 	return b1[0];
 }
 
-
-static int pll_write (struct dvb_i2c_bus *i2c, u8 data [4])
+static int pll_write (struct i2c_adapter *i2c, u8 data [4])
 {
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
 	int ret;
 
 	cx22700_writereg (i2c, 0x0a, 0x00);  /* open i2c bus switch */
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 	cx22700_writereg (i2c, 0x0a, 0x01);  /* close i2c bus switch */
 
 	if (ret != 1)
@@ -133,7 +141,7 @@
  *   set up the downconverter frequency divisor for a 
  *   reference clock comparision frequency of 125 kHz.
  */
-static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 	u32 div = (freq + 36166667) / 166667;
 #if 1 //ALPS_SETTINGS
@@ -149,8 +157,7 @@
 	return pll_write (i2c, buf);
 }
 
-
-static int cx22700_init (struct dvb_i2c_bus *i2c)
+static int cx22700_init (struct i2c_adapter *i2c)
 {
 	int i;
 
@@ -159,7 +166,7 @@
 	cx22700_writereg (i2c, 0x00, 0x02);   /*  soft reset */
 	cx22700_writereg (i2c, 0x00, 0x00);
 
-	dvb_delay(10);
+	msleep(10);
 	
 	for (i=0; i<sizeof(init_tab); i+=2)
 		cx22700_writereg (i2c, init_tab[i], init_tab[i+1]);
@@ -169,8 +176,7 @@
 	return 0;
 }
 
-
-static int cx22700_set_inversion (struct dvb_i2c_bus *i2c, int inversion)
+static int cx22700_set_inversion (struct i2c_adapter *i2c, int inversion)
 {
 	u8 val;
 
@@ -190,8 +196,7 @@
 	}
 }
 
-
-static int cx22700_set_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+static int cx22700_set_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
 {
 	static const u8 qam_tab [4] = { 0, 1, 0, 2 };
 	static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
@@ -253,8 +258,7 @@
 	return 0;
 }
 
-
-static int cx22700_get_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+static int cx22700_get_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
 {
 	static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
 	static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
@@ -300,10 +302,10 @@
 	return 0;
 }
 
-
 static int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct tdmb7_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -406,10 +408,14 @@
 	return 0;
 }
 
+static struct i2c_client client_template;
 
-
-static int tdmb7_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter (struct i2c_adapter *adapter)
 {
+	struct tdmb7_state *state;
+	struct i2c_client *client;
+	int ret;
+
         u8 b0 [] = { 0x7 };
         u8 b1 [] = { 0 };
         struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 },
@@ -417,41 +423,109 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-        if (i2c->xfer (i2c, msg, 2) != 2)
+	if (i2c_transfer(adapter, msg, 2) != 2)
                 return -ENODEV;
 
-	return dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info);
+	if (NULL == (state = kmalloc(sizeof(struct tdmb7_state), GFP_KERNEL)))
+		return -ENOMEM;
+
+	state->i2c = adapter;
+
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
 }
 
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	i2c_set_clientdata(client, state);
 
-static void tdmb7_detach (struct dvb_i2c_bus *i2c, void *data)
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	ret = dvb_register_frontend (tdmb7_ioctl, state->dvb, state,
+					 &tdmb7_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int detach_client (struct i2c_client *client)
 {
+	struct tdmb7_state *state = i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend (tdmb7_ioctl, i2c);
+	dvb_unregister_frontend_new (tdmb7_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
 }
 
-
-static int __init init_tdmb7 (void)
+static int command (struct i2c_client *client,
+		    unsigned int cmd, void *arg)
 {
+	struct tdmb7_state *state = i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
 
-	return dvb_register_i2c_device (THIS_MODULE, tdmb7_attach, tdmb7_detach);
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= FRONTEND_NAME,
+	.id		= I2C_DRIVERID_DVBFE_ALPS_TDMB7,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= attach_adapter,
+	.detach_client	= detach_client,
+	.command	= command,
+};
 
-static void __exit exit_tdmb7 (void)
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
+
+static int __init init_tdmb7 (void)
 {
-	dprintk ("%s\n", __FUNCTION__);
+	return i2c_add_driver(&driver);
+}
 
-	dvb_unregister_i2c_device (tdmb7_attach);
+static void __exit exit_tdmb7 (void)
+{
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "alps_tdmb7: driver deregistration failed.\n");
 }
 
 module_init (init_tdmb7);
 module_exit (exit_tdmb7);
 
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
 MODULE_DESCRIPTION("TDMB7 DVB Frontend driver");
 MODULE_AUTHOR("Holger Waechtler");
 MODULE_LICENSE("GPL");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/at76c651.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/at76c651.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/at76c651.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/at76c651.c	2004-08-18 19:52:17.000000000 +0200
@@ -1,10 +1,10 @@
 /*
  * at76c651.c
  * 
- * Atmel DVB-C Frontend Driver (at76c651/dat7021)
+ * Atmel DVB-C Frontend Driver (at76c651/tua6010xs)
  *
  * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
- *             & 2002 Andreas Oberritter <obi@linuxtv.org>
+ *             & 2002-2004 Andreas Oberritter <obi@linuxtv.org>
  *             & 2003 Wolfram Joost <dbox2@frokaschwei.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,10 +21,17 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * AT76C651
+ * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf
+ * http://www.atmel.com/atmel/acrobat/doc1320.pdf
+ *
+ * TUA6010XS
+ * http://www.infineon.com/cgi/ecrm.dll/ecrm/scripts/public_download.jsp?oid=19512
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -34,29 +41,22 @@
 #endif
 
 #include "dvb_frontend.h"
-#include "dvb_i2c.h"
-#include "dvb_functions.h"
 
-static int debug = 0;
-static u8 at76c651_qam;
-static u8 at76c651_revision;
+#define FRONTEND_NAME "dvbfe_at76c651"
 
-#define dprintk	if (debug) printk
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
 
-/*
- * DAT7021
- * -------
- * Input Frequency Range (RF): 48.25 MHz to 863.25 MHz
- * Band Width: 8 MHz
- * Level Input (Range for Digital Signals): -61 dBm to -41 dBm
- * Output Frequency (IF): 36 MHz
- *
- * (see http://www.atmel.com/atmel/acrobat/doc1320.pdf)
- */
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-static struct dvb_frontend_info at76c651_info = {
 
-	.name = "Atmel AT76C651(B) with DAT7021",
+static struct dvb_frontend_info at76c651_info = {
+	.name = "Atmel AT76C651B with TUA6010XS",
 	.type = FE_QAM,
 	.frequency_min = 48250000,
 	.frequency_max = 863250000,
@@ -74,6 +74,13 @@
 	    FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
 };
 
+struct at76c651_state {
+	u8 revision;
+	u8 qam;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
+
 #if ! defined(__powerpc__)
 static __inline__ int __ilog2(unsigned long x)
 {
@@ -89,60 +96,55 @@
 }
 #endif
 
-static int at76c651_writereg(struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int at76c651_writereg(struct i2c_adapter *i2c, u8 reg, u8 data)
 {
-
 	int ret;
 	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 };
+	struct i2c_msg msg =
+		{ .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 };
 
-	ret = i2c->xfer(i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 
 	if (ret != 1)
 		dprintk("%s: writereg error "
 			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
 			__FUNCTION__, reg, data, ret);
 
-	dvb_delay(10);
+	msleep(10);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
-
 }
 
-static u8 at76c651_readreg(struct dvb_i2c_bus *i2c, u8 reg)
+static u8 at76c651_readreg(struct i2c_adapter *i2c, u8 reg)
 {
-
 	int ret;
-	u8 b0[] = { reg };
-	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = { {.addr =  0x1a >> 1, .flags =  0, .buf =  b0, .len = 1},
-			  {.addr =  0x1a >> 1, .flags =  I2C_M_RD, .buf =  b1, .len = 1} };
+	u8 val;
+	struct i2c_msg msg[] = {
+		{ .addr = 0x1a >> 1, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = 0x1a >> 1, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+	};
 
-	ret = i2c->xfer(i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
 
-	return b1[0];
-
+	return val;
 }
 
-static int at76c651_reset(struct dvb_i2c_bus *i2c)
+static int at76c651_reset(struct i2c_adapter *i2c)
 {
-
 	return at76c651_writereg(i2c, 0x07, 0x01);
-
 }
 
-static int at76c651_disable_interrupts(struct dvb_i2c_bus *i2c)
+static void at76c651_disable_interrupts(struct i2c_adapter *i2c)
 {
-
-	return at76c651_writereg(i2c, 0x0b, 0x00);
-
+	at76c651_writereg(i2c, 0x0b, 0x00);
 }
 
-static int at76c651_set_auto_config(struct dvb_i2c_bus *i2c)
+static int at76c651_set_auto_config(struct at76c651_state *state)
 {
+	struct i2c_adapter *i2c = state->i2c;
 
 	/*
 	 * Autoconfig
@@ -155,19 +157,19 @@
 	 */
 
 	at76c651_writereg(i2c, 0x10, 0x06);
-	at76c651_writereg(i2c, 0x11, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0x12 : 0x10);
+	at76c651_writereg(i2c, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10);
 	at76c651_writereg(i2c, 0x15, 0x28);
 	at76c651_writereg(i2c, 0x20, 0x09);
-	at76c651_writereg(i2c, 0x24, ((at76c651_qam == 5) || (at76c651_qam == 7)) ? 0xC0 : 0x90);
+	at76c651_writereg(i2c, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90);
 	at76c651_writereg(i2c, 0x30, 0x90);
-	if (at76c651_qam == 5)
+	if (state->qam == 5)
 		at76c651_writereg(i2c, 0x35, 0x2A);
 
 	/*
 	 * Initialize A/D-converter
 	 */
 
-	if (at76c651_revision == 0x11) {
+	if (state->revision == 0x11) {
 		at76c651_writereg(i2c, 0x2E, 0x38);
 		at76c651_writereg(i2c, 0x2F, 0x13);
 }
@@ -181,86 +183,62 @@
 	at76c651_reset(i2c);
 
 	return 0;
-
 }
 
-static int at76c651_set_bbfreq(struct dvb_i2c_bus *i2c)
+static void at76c651_set_bbfreq(struct i2c_adapter *i2c)
 {
-
 	at76c651_writereg(i2c, 0x04, 0x3f);
 	at76c651_writereg(i2c, 0x05, 0xee);
-
-	return 0;
-
 }
 
-static int at76c651_switch_tuner_i2c(struct dvb_i2c_bus *i2c, u8 enable)
+static int at76c651_pll_write(struct i2c_adapter *i2c, u8 *buf, size_t len)
 {
-
-	if (enable)
-		return at76c651_writereg(i2c, 0x0c, 0xc2 | 0x01);
-	else
-		return at76c651_writereg(i2c, 0x0c, 0xc2);
-
-}
-
-static int dat7021_write(struct dvb_i2c_bus *i2c, u32 tw)
-{
-
 	int ret;
 	struct i2c_msg msg =
-	    { .addr = 0xc2 >> 1, .flags = 0, .buf = (u8 *) & tw, .len = sizeof (tw) };
+	    { .addr = 0xc2 >> 1, .flags = 0, .buf = buf, .len = len };
 
-#ifdef __LITTLE_ENDIAN
-	tw = __cpu_to_be32(tw);
-#endif
-
-	at76c651_switch_tuner_i2c(i2c, 1);
-
-	ret = i2c->xfer(i2c, &msg, 1);
+	at76c651_writereg(i2c, 0x0c, 0xc3);
 
-	at76c651_switch_tuner_i2c(i2c, 0);
+	ret = i2c_transfer(i2c, &msg, 1);
 
-	if (ret != 4)
-		return -EFAULT;
+	at76c651_writereg(i2c, 0x0c, 0xc2);
 
-	at76c651_reset(i2c);
+	if (ret < 0)
+		return ret;
+	else if (ret != 1)
+		return -EREMOTEIO;
 
 	return 0;
-
 }
 
-static int dat7021_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq)
+static int tua6010_setfreq(struct i2c_adapter *i2c, u32 freq)
 {
+	u32 div;
+	u8 buf[4];
+	u8 vu, p2, p1, p0;
 
-	u32 dw;
-
-	freq /= 1000;
-
-	if ((freq < 48250) || (freq > 863250))
+	if ((freq < 50000000) || (freq > 900000000))
 		return -EINVAL;
 
-	/*
-	 * formula: dw=0x17e28e06+(freq-346000UL)/8000UL*0x800000
-	 *      or: dw=0x4E28E06+(freq-42000) / 125 * 0x20000
-	 */
-
-	dw = (freq - 42000) * 4096;
-	dw = dw / 125;
-	dw = dw * 32;
+	div = (freq + 36125000) / 62500;
 
-	if (freq > 394000)
-		dw += 0x4E28E85;
+	if (freq > 400000000)
+		vu = 1, p2 = 1, p1 = 0, p0 = 1;
+	else if (freq > 140000000)
+		vu = 0, p2 = 1, p1 = 1, p0 = 0;
 	else
-		dw += 0x4E28E06;
+		vu = 0, p2 = 0, p1 = 1, p0 = 1;
 
-	return dat7021_write(i2c, dw);
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+	buf[2] = 0x8e;
+	buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
 
+	return at76c651_pll_write(i2c, buf, 4);
 }
 
-static int at76c651_set_symbolrate(struct dvb_i2c_bus *i2c, u32 symbolrate)
+static int at76c651_set_symbol_rate(struct i2c_adapter *i2c, u32 symbol_rate)
 {
-
 	u8 exponent;
 	u32 mantissa;
 
@@ -264,17 +242,17 @@
 	u8 exponent;
 	u32 mantissa;
 
-	if (symbolrate > 9360000)
+	if (symbol_rate > 9360000)
 		return -EINVAL;
 
 	/*
 	 * FREF = 57800 kHz
-	 * exponent = 10 + floor ( log2 ( symbolrate / FREF ) )
-	 * mantissa = ( symbolrate / FREF) * ( 1 << ( 30 - exponent ) )
+	 * exponent = 10 + floor (log2(symbol_rate / FREF))
+	 * mantissa = (symbol_rate / FREF) * (1 << (30 - exponent))
 	 */
 
-	exponent = __ilog2((symbolrate << 4) / 903125);
-	mantissa = ((symbolrate / 3125) * (1 << (24 - exponent))) / 289;
+	exponent = __ilog2((symbol_rate << 4) / 903125);
+	mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289;
 
 	at76c651_writereg(i2c, 0x00, mantissa >> 13);
 	at76c651_writereg(i2c, 0x01, mantissa >> 5);
@@ -281,37 +259,35 @@
 	at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent);
 
 	return 0;
-
 }
 
-static int at76c651_set_qam(struct dvb_i2c_bus *i2c, fe_modulation_t qam)
+static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam)
 {
-
 	switch (qam) {
 	case QPSK:
-		at76c651_qam = 0x02;
+		state->qam = 0x02;
 		break;
 	case QAM_16:
-		at76c651_qam = 0x04;
+		state->qam = 0x04;
 		break;
 	case QAM_32:
-		at76c651_qam = 0x05;
+		state->qam = 0x05;
 		break;
 	case QAM_64:
-		at76c651_qam = 0x06;
+		state->qam = 0x06;
 		break;
 	case QAM_128:
-		at76c651_qam = 0x07;
+		state->qam = 0x07;
 		break;
 	case QAM_256:
-		at76c651_qam = 0x08;
+		state->qam = 0x08;
 		break;
 #if 0
 	case QAM_512:
-		at76c651_qam = 0x09;
+		state->qam = 0x09;
 		break;
 	case QAM_1024:
-		at76c651_qam = 0x0A;
+		state->qam = 0x0A;
 		break;
 #endif
 	default:
@@ -319,14 +295,12 @@
 
 	}
 
-	return at76c651_writereg(i2c, 0x03, at76c651_qam);
-
+	return at76c651_writereg(state->i2c, 0x03, state->qam);
 }
 
-static int at76c651_set_inversion(struct dvb_i2c_bus *i2c,
+static int at76c651_set_inversion(struct i2c_adapter *i2c,
 		       fe_spectral_inversion_t inversion)
 {
-
 	u8 feciqinv = at76c651_readreg(i2c, 0x60);
 
 	switch (inversion) {
@@ -348,33 +322,36 @@
 	}
 
 	return at76c651_writereg(i2c, 0x60, feciqinv);
-
 }
 
-static int at76c651_set_parameters(struct dvb_i2c_bus *i2c,
+static int at76c651_set_parameters(struct at76c651_state *state,
 			struct dvb_frontend_parameters *p)
 {
+	struct i2c_adapter *i2c = state->i2c;
+	int ret;
 
-	dat7021_set_tv_freq(i2c, p->frequency);
-	at76c651_set_symbolrate(i2c, p->u.qam.symbol_rate);
-	at76c651_set_inversion(i2c, p->inversion);
-	at76c651_set_auto_config(i2c);
-        at76c651_reset(i2c);
+	if ((ret = tua6010_setfreq(i2c, p->frequency)))
+		return ret;
 
-	return 0;
+	if ((ret = at76c651_set_symbol_rate(i2c, p->u.qam.symbol_rate)))
+		return ret;
+
+	if ((ret = at76c651_set_inversion(i2c, p->inversion)))
+		return ret;
 
+	return at76c651_set_auto_config(state);
 }
 
-static int at76c651_set_defaults(struct dvb_i2c_bus *i2c)
+static int at76c651_set_defaults(struct at76c651_state *state)
 {
+	struct i2c_adapter *i2c = state->i2c;
 
-	at76c651_set_symbolrate(i2c, 6900000);
-	at76c651_set_qam(i2c, QAM_64);
+	at76c651_set_symbol_rate(i2c, 6900000);
+	at76c651_set_qam(state, QAM_64);
 	at76c651_set_bbfreq(i2c);
-	at76c651_set_auto_config(i2c);
+	at76c651_set_auto_config(state);
 
 	return 0;
-
 }
 
 static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
@@ -379,9 +356,10 @@
 
 static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
+	struct at76c651_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
 	switch (cmd) {
-
 	case FE_GET_INFO:
 		memcpy(arg, &at76c651_info, sizeof (struct dvb_frontend_info));
 		break;
@@ -388,14 +366,13 @@
 
 	case FE_READ_STATUS:
 		{
-
-			fe_status_t *status = (fe_status_t *) arg;
+		fe_status_t *status = arg;
 			u8 sync;
 
 			/*
 			 * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) 
 			 */
-			sync = at76c651_readreg(fe->i2c, 0x80);
+		sync = at76c651_readreg(i2c, 0x80);
 
 			*status = 0;
 
@@ -420,13 +391,11 @@
 
 	case FE_READ_BER:
 		{
-			u32 *ber = (u32 *) arg;
-
-			*ber = (at76c651_readreg(fe->i2c, 0x81) & 0x0F) << 16;
-			*ber |= at76c651_readreg(fe->i2c, 0x82) << 8;
-			*ber |= at76c651_readreg(fe->i2c, 0x83);
+		u32 *ber = arg;
+		*ber = (at76c651_readreg(i2c, 0x81) & 0x0F) << 16;
+		*ber |= at76c651_readreg(i2c, 0x82) << 8;
+		*ber |= at76c651_readreg(i2c, 0x83);
 			*ber *= 10;
-
 			break;
 		}
 
@@ -432,25 +401,23 @@
 
 	case FE_READ_SIGNAL_STRENGTH:
 		{
-			u8 gain = ~at76c651_readreg(fe->i2c, 0x91);
-
+		u8 gain = ~at76c651_readreg(i2c, 0x91);
 			*(u16 *) arg = (gain << 8) | gain;
 			break;
 		}
 
 	case FE_READ_SNR:
-		*(u16 *) arg =
-		    0xFFFF -
-		    ((at76c651_readreg(fe->i2c, 0x8F) << 8) |
-		     at76c651_readreg(fe->i2c, 0x90));
+		*(u16 *)arg = 0xFFFF -
+		    ((at76c651_readreg(i2c, 0x8F) << 8) |
+		     at76c651_readreg(i2c, 0x90));
 		break;
 
 	case FE_READ_UNCORRECTED_BLOCKS:
-		*(u32 *) arg = at76c651_readreg(fe->i2c, 0x82);
+		*(u32 *)arg = at76c651_readreg(i2c, 0x82);
 		break;
 
 	case FE_SET_FRONTEND:
-		return at76c651_set_parameters(fe->i2c, arg);
+		return at76c651_set_parameters(state, arg);
 
 	case FE_GET_FRONTEND:
 		break;
@@ -459,15 +426,15 @@
 		break;
 
 	case FE_INIT:
-		return at76c651_set_defaults(fe->i2c);
+		return at76c651_set_defaults(state);
 
 	case FE_GET_TUNE_SETTINGS:
 	{
-	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
+	        struct dvb_frontend_tune_settings *fesettings = arg;
 	        fesettings->min_delay_ms = 50;
 	        fesettings->step_size = 0;
 	        fesettings->max_drift = 0;
-	        return 0;
+		break;
 	}	    
 
 	default:
@@ -475,61 +442,129 @@
 	}
 
 	return 0;
-
 }
 
-static int at76c651_attach(struct dvb_i2c_bus *i2c, void **data)
-{
-	if ( (at76c651_readreg(i2c, 0x0E) != 0x65) ||
-	     ( ( (at76c651_revision = at76c651_readreg(i2c, 0x0F)) & 0xFE) != 0x10) )
+static struct i2c_client client_template;
+
+static int attach_adapter(struct i2c_adapter *adapter)
 {
-		dprintk("no AT76C651(B) found\n");
+	struct at76c651_state *state;
+	struct i2c_client *client;
+	int ret;
+
+	if (at76c651_readreg(adapter, 0x0E) != 0x65)
+		return -ENODEV;
+
+	if (!(state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL)))
+		return -ENOMEM;
+
+	state->i2c = adapter;
+	state->revision = at76c651_readreg(adapter, 0x0F) & 0xFE;
+
+	switch (state->revision) {
+	case 0x10:
+		at76c651_info.name[14] = 'A';
+		break;
+	case 0x11:
+		at76c651_info.name[14] = 'B';
+		break;
+	default:
+		kfree(state);
 		return -ENODEV;
 	}
 
-	if (at76c651_revision == 0x10)
-	{
-		dprintk("AT76C651A found\n");
-		strcpy(at76c651_info.name,"Atmel AT76C651A with DAT7021");
+	if (!(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = 0x1a >> 1;
+	i2c_set_clientdata(client, state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	ret = dvb_register_frontend(at76c651_ioctl, state->dvb, state,
+					&at76c651_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return ret;
 		}
-	else
-	{
-		strcpy(at76c651_info.name,"Atmel AT76C651B with DAT7021");
-		dprintk("AT76C651B found\n");
+
+	return 0;
 	}
 
-	at76c651_set_defaults(i2c);
+static int detach_client(struct i2c_client *client)
+{
+	struct at76c651_state *state = i2c_get_clientdata(client);
 
-	return dvb_register_frontend(at76c651_ioctl, i2c, NULL, &at76c651_info);
+	dvb_unregister_frontend_new(at76c651_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
 
+	return 0;
 }
 
-static void at76c651_detach(struct dvb_i2c_bus *i2c, void *data)
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct at76c651_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend(at76c651_ioctl, i2c);
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
 
+	return 0;
 }
 
-static int __init at76c651_init(void)
-{
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= FRONTEND_NAME,
+	.id		= I2C_DRIVERID_DVBFE_AT76C651,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= attach_adapter,
+	.detach_client	= detach_client,
+	.command	= command,
+};
 
-	return dvb_register_i2c_device(THIS_MODULE, at76c651_attach,
-				       at76c651_detach);
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
 
+static int __init at76c651_init(void)
+{
+	return i2c_add_driver(&driver);
 }
 
 static void __exit at76c651_exit(void)
 {
-
-	dvb_unregister_i2c_device(at76c651_attach);
-
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "at76c651: driver deregistration failed.\n");
 }
 
 module_init(at76c651_init);
 module_exit(at76c651_exit);
 
-MODULE_DESCRIPTION("at76c651/dat7021 dvb-c frontend driver");
+MODULE_DESCRIPTION("at76c651/tua6010xs dvb-c frontend driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/cx24110.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx24110.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/cx24110.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx24110.c	2004-08-18 19:52:17.000000000 +0200
@@ -35,13 +35,22 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-static int debug = 0;
-#define dprintk	if (debug) printk
+#define FRONTEND_NAME "dvbfe_cx24110"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 
 static struct dvb_frontend_info cx24110_info = {
@@ -63,6 +72,10 @@
 };
 /* fixme: are these values correct? especially ..._tolerance and caps */
 
+struct cx24110_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
 static struct {u8 reg; u8 data;} cx24110_regdata[]=
                       /* Comments beginning with @ denote this value should
@@ -127,7 +140,7 @@
 	};
 
 
-static int cx24110_writereg (struct dvb_i2c_bus *i2c, int reg, int data)
+static int cx24110_writereg (struct i2c_adapter *i2c, int reg, int data)
 {
         u8 buf [] = { reg, data };
 	struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
@@ -135,8 +148,9 @@
    cx24110 might show up at any address */
 	int err;
 
-        if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
-		dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+        if ((err = i2c_transfer(i2c, &msg, 1)) != 1) {
+		dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
+			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
 		return -EREMOTEIO;
 	}
 
@@ -144,7 +158,7 @@
 }
 
 
-static u8 cx24110_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 cx24110_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
@@ -152,7 +166,7 @@
 	struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
 			   { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 /* fixme (medium): address might be different from 0x55 */
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -161,7 +175,7 @@
 }
 
 
-static int cx24108_write (struct dvb_i2c_bus *i2c, u32 data)
+static int cx24108_write (struct i2c_adapter *i2c, u32 data)
 {
 /* tuner data is 21 bits long, must be left-aligned in data */
 /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
@@ -195,7 +209,7 @@
 }
 
 
-static int cx24108_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int cx24108_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 /* fixme (low): error handling */
         int i, a, n, pump;
@@ -247,7 +261,7 @@
         cx24108_write(i2c,pll);
         cx24110_writereg(i2c,0x56,0x7f);
 
-	dvb_delay(10); /* wait a moment for the tuner pll to lock */
+	msleep(10); /* wait a moment for the tuner pll to lock */
 
 	/* tuner pll lock can be monitored on GPIO pin 4 of cx24110 */
         while (!(cx24110_readreg(i2c,0x66)&0x20)&&i<1000)
@@ -259,7 +273,7 @@
 }
 
 
-static int cx24110_init (struct dvb_i2c_bus *i2c)
+static int cx24110_initfe(struct i2c_adapter *i2c)
 {
 /* fixme (low): error handling */
         int i;
@@ -274,7 +288,7 @@
 }
 
 
-static int cx24110_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+static int cx24110_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
 {
 /* fixme (low): error handling */
 
@@ -309,7 +323,7 @@
 }
 
 
-static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int cx24110_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
 {
 /* fixme (low): error handling */
 
@@ -355,7 +369,7 @@
 }
 
 
-static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t cx24110_get_fec (struct i2c_adapter *i2c)
 {
 	int i;
 
@@ -372,7 +386,7 @@
 }
 
 
-static int cx24110_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+static int cx24110_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
 {
 /* fixme (low): add error handling */
         u32 ratio;
@@ -454,7 +468,7 @@
 }
 
 
-static int cx24110_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+static int cx24110_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
 {
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -466,16 +480,17 @@
 	};
 }
 
-static void sendDiSEqCMessage(struct dvb_i2c_bus *i2c, struct dvb_diseqc_master_cmd *pCmd)
+static void cx24110_send_diseqc_msg(struct i2c_adapter *i2c,
+				    struct dvb_diseqc_master_cmd *cmd)
 {
 	int i, rv;
 
-	for (i = 0; i < pCmd->msg_len; i++)
-		cx24110_writereg(i2c, 0x79 + i, pCmd->msg[i]);
+	for (i = 0; i < cmd->msg_len; i++)
+		cx24110_writereg(i2c, 0x79 + i, cmd->msg[i]);
 
 	rv = cx24110_readreg(i2c, 0x76);
 
-	cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((pCmd->msg_len-3) & 3));
+	cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
 	for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);)
 		; /* wait for LNB ready */
 }
@@ -483,7 +498,8 @@
 
 static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct cx24110_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 	static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;
 
         switch (cmd) {
@@ -618,7 +634,7 @@
 /* cannot do this from the FE end. How to communicate this to the place where it can be done? */
 		break;
         case FE_INIT:
-		return cx24110_init (i2c);
+		return cx24110_initfe(i2c);
 
 	case FE_SET_TONE:
 		return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
@@ -626,7 +642,8 @@
 		return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);
 
 	case FE_DISEQC_SEND_MASTER_CMD:
-		sendDiSEqCMessage(i2c, (struct dvb_diseqc_master_cmd*) arg);
+		// FIXME Status?
+		cx24110_send_diseqc_msg(i2c, (struct dvb_diseqc_master_cmd*) arg);
 		return 0;
 
 	default:
@@ -636,43 +653,118 @@
         return 0;
 }
 
+static struct i2c_client client_template;
 
-static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter (struct i2c_adapter *adapter)
 {
+	struct cx24110_state *state;
+	struct i2c_client *client;
+	int ret = 0;
 	u8 sig;
 
-	sig=cx24110_readreg (i2c, 0x00);
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		adapter->id, adapter->name);
+
+	sig = cx24110_readreg (adapter, 0x00);
 	if ( sig != 0x5a && sig != 0x69 )
 		return -ENODEV;
 
-	return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
+	if ( !(state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	memset(state, 0, sizeof(struct cx24110_state));
+	state->i2c = adapter;
+
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
 }
 
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = 0x55;
+	i2c_set_clientdata(client, state);
 
-static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data)
-{
-	dvb_unregister_frontend (cx24110_ioctl, i2c);
+	if ((ret = i2c_attach_client(client))) {
+		kfree(client);
+		kfree(state);
+		return ret;
 }
 
+	BUG_ON(!state->dvb);
 
-static int __init init_cx24110 (void)
-{
-	return dvb_register_i2c_device (THIS_MODULE, cx24110_attach, cx24110_detach);
+	if ((ret = dvb_register_frontend(cx24110_ioctl, state->dvb, state,
+					     &cx24110_info, THIS_MODULE))) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return ret;
 }
 
+	return 0;
+}
 
-static void __exit exit_cx24110 (void)
+static int detach_client (struct i2c_client *client)
 {
-	dvb_unregister_i2c_device (cx24110_attach);
+	struct cx24110_state *state = i2c_get_clientdata(client);
+
+	dvb_unregister_frontend_new(cx24110_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
 }
 
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct cx24110_state *state = i2c_get_clientdata(client);
 
-module_init(init_cx24110);
-module_exit(exit_cx24110);
+	switch(cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= FRONTEND_NAME,
+	.id		= I2C_DRIVERID_DVBFE_CX24110,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= attach_adapter,
+	.detach_client	= detach_client,
+	.command	= command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
+
+static int __init cx24110_init(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit cx24110_exit(void)
+{
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "cx24110: driver deregistration failed.\n");
+}
 
+module_init(cx24110_init);
+module_exit(cx24110_exit);
 
 MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset");
 MODULE_AUTHOR("Peter Hettkamp");
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug,"i");
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/dst.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/dst.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst.c	2004-08-18 19:52:17.000000000 +0200
@@ -32,32 +30,19 @@
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 #include "dst-bt878.h"
 
-unsigned int dst_debug = 0;
 unsigned int dst_verbose = 0;
-
 MODULE_PARM(dst_verbose, "i");
-MODULE_PARM_DESC(dst_verbose,
-		 "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
+unsigned int dst_debug = 0;
 MODULE_PARM(dst_debug, "i");
 MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
 
-#define DST_MAX_CARDS	6
-unsigned int dst_cur_no = 0;
-
-unsigned int dst_type[DST_MAX_CARDS] = { [0 ... (DST_MAX_CARDS-1)] = (-1U)};
-unsigned int dst_type_flags[DST_MAX_CARDS] = { [0 ... (DST_MAX_CARDS-1)] = (-1U)};
-MODULE_PARM(dst_type, "1-" __stringify(DST_MAX_CARDS) "i");
-MODULE_PARM_DESC(dst_type,
-		"Type of DST card, 0 Satellite, 1 terrestial TV, 2 Cable, default driver determined");
-MODULE_PARM(dst_type_flags, "1-" __stringify(DST_MAX_CARDS) "i");
-MODULE_PARM_DESC(dst_type_flags,
-		"Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv");
-
 #define dprintk	if (dst_debug) printk
 
+#define DST_I2C_ADDR 0x55
+
 #define DST_TYPE_IS_SAT		0
 #define DST_TYPE_IS_TERR	1
 #define DST_TYPE_IS_CABLE	2
@@ -90,8 +75,10 @@
 	unsigned long cur_jiff;
 	u8  k22;
 	fe_bandwidth_t bandwidth;
+
 	struct bt878 *bt;
-	struct dvb_i2c_bus *i2c;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
 } ;
 
 static struct dvb_frontend_info dst_info_sat = {
@@ -105,8 +92,7 @@
 	.symbol_rate_max	= 45000000,
 /*     . symbol_rate_tolerance	= 	???,*/
 	.notifier_delay		= 50,                /* 1/20 s */
-	.caps = FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK
+	.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
 };
 
 static struct dvb_frontend_info dst_info_cable = {
@@ -119,19 +105,16 @@
 	.symbol_rate_max	= 45000000,
 /*     . symbol_rate_tolerance	= 	???,*/
 	.notifier_delay		= 50,                /* 1/20 s */
-	.caps = FE_CAN_FEC_AUTO |
-		FE_CAN_QAM_AUTO
+	.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
 };
 
-static struct dvb_frontend_info dst_info_tv = {
+static struct dvb_frontend_info dst_info_terr = {
 	.name 			= "DST TERR",
 	.type 			= FE_OFDM,
 	.frequency_min 		= 137000000,
 	.frequency_max 		= 858000000,
 	.frequency_stepsize 	= 166667,
-	.caps = FE_CAN_FEC_AUTO |
-	    FE_CAN_QAM_AUTO |
-	    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+	.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
 };
 
 static void dst_packsize(struct dst_data *dst, int psize)
@@ -155,8 +138,7 @@
 		return -EREMOTEIO;
 	}
 
-	/* because complete disabling means no output, no need to do
-	 * output packet */
+	/* because complete disabling means no output, no need to do output packet */
 	if (enbb == 0)
 		return 0;
 
@@ -188,8 +170,7 @@
 #define DST_I2C_ENABLE	1
 #define DST_8820  	2
 
-static int
-dst_reset8820(struct dst_data *dst)
+static int dst_reset8820(struct dst_data *dst)
 {
 int retval;
 	/* pull 8820 gpio pin low, wait, high, wait, then low */
@@ -197,12 +178,12 @@
 	retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
 	if (retval < 0)
 		return retval;
-	dvb_delay(10);
+	msleep(10);
 	retval = dst_gpio_outb(dst, DST_8820, DST_8820, DST_8820);
 	if (retval < 0)
 		return retval;
 	/* wait for more feedback on what works here *
-	dvb_delay(10);
+	   msleep(10);
 	retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
 	if (retval < 0)
 		return retval;
@@ -210,8 +191,7 @@
 	return 0;
 }
 
-static int
-dst_i2c_enable(struct dst_data *dst)
+static int dst_i2c_enable(struct dst_data *dst)
 {
 int retval;
 	/* pull I2C enable gpio pin low, wait */
@@ -220,12 +200,11 @@
 	if (retval < 0)
 		return retval;
 	// dprintk ("%s: i2c enable delay\n", __FUNCTION__);
-	dvb_delay(33);
+	msleep(33);	
 	return 0;
 }
 
-static int
-dst_i2c_disable(struct dst_data *dst)
+static int dst_i2c_disable(struct dst_data *dst)
 {
 int retval;
 	/* release I2C enable gpio pin, wait */
@@ -234,12 +213,11 @@
 	if (retval < 0)
 		return retval;
 	// dprintk ("%s: i2c disable delay\n", __FUNCTION__);
-	dvb_delay(33);
+	msleep(33);
 	return 0;
 }
 
-static int
-dst_wait_dst_ready(struct dst_data *dst)
+static int dst_wait_dst_ready(struct dst_data *dst)
 {
 u8 reply;
 int retval;
@@ -252,18 +230,17 @@
 			dprintk ("%s: dst wait ready after %d\n", __FUNCTION__, i);
 			return 1;
 		}
-		dvb_delay(5);
+		msleep(5);
 	}
 	dprintk ("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
 	return 0;
 }
 
-#define DST_I2C_ADDR 0x55
-
 static int write_dst (struct dst_data *dst, u8 *data, u8 len)
 {
 	struct i2c_msg msg = {
-		.addr = DST_I2C_ADDR, .flags = 0, .buf = data, .len = len };
+		.addr = DST_I2C_ADDR,.flags = 0,.buf = data,.len = len
+	};
 	int err;
 	int cnt;
 
@@ -275,14 +252,14 @@
 		}
 		dprintk("\n");
 	}
-	dvb_delay(30);
+	msleep(30);
 	for (cnt = 0; cnt < 4; cnt++) {
-		if ((err = dst->i2c->xfer (dst->i2c, &msg, 1)) < 0) {
+		if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
 			dprintk ("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
 			dst_i2c_disable(dst);
-			dvb_delay(500);
+			msleep(500);
 			dst_i2c_enable(dst);
-			dvb_delay(500);
+			msleep(500);
 			continue;
 		} else
 			break;
@@ -294,13 +271,12 @@
 
 static int read_dst (struct dst_data *dst, u8 *ret, u8 len)
 {
-	struct i2c_msg msg = 
-		{ .addr = DST_I2C_ADDR, .flags = I2C_M_RD, .buf = ret, .len = len };
+	struct i2c_msg msg = {.addr = DST_I2C_ADDR,.flags = I2C_M_RD,.buf = ret,.len = len };
 	int err;
 	int cnt;
 
 	for (cnt = 0; cnt < 4; cnt++) {
-		if ((err = dst->i2c->xfer (dst->i2c, &msg, 1)) < 0) {
+		if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
 			dprintk ("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
 			dst_i2c_disable(dst);
 			dst_i2c_enable(dst);
@@ -505,7 +480,9 @@
 	{ "DSTFCI",  1,  DST_TYPE_IS_SAT,    DST_TYPE_HAS_NEWTUNE },
 	{ "DCTNEW",  1,  DST_TYPE_IS_CABLE,  DST_TYPE_HAS_NEWTUNE },
 	{ "DCT_CI",  1,  DST_TYPE_IS_CABLE,  DST_TYPE_HAS_NEWTUNE|DST_TYPE_HAS_TS204 },
-	{ "DTTDIG" , 1,  DST_TYPE_IS_TERR,   0} };
+	{"DTTDIG",  1, DST_TYPE_IS_TERR, 0}
+};
+
 /* DCTNEW and DCT-CI are guesses */
 
 static void dst_type_flags_print(u32 type_flags)
@@ -534,8 +511,7 @@
 			otype = "terrestial TV";
 			break;
 		default:
-			printk("%s: invalid dst type %d\n",
-				__FUNCTION__, type);
+		printk("%s: invalid dst type %d\n", __FUNCTION__, type);
 			return -EINVAL;
 	}
 	printk("DST type : %s\n", otype);
@@ -564,7 +540,7 @@
 		dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
 		return retval;
 	}
-	dvb_delay(3);
+	msleep(3);
 	retval = read_dst (dst, rxbuf, 1);
 	dst_i2c_disable(dst);
 	if (retval < 0) {
@@ -590,9 +566,7 @@
 	}
 	rxbuf[7] = '\0';
 	for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
-		if (!strncmp(&rxbuf[dsp->offs],
-				dsp->mstr,
-				strlen(dsp->mstr))) {
+		if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
 			use_type_flags = dsp->type_flags;
 			use_dst_type = dsp->dst_type;
 			printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
@@ -605,26 +579,8 @@
 		use_dst_type = DST_TYPE_IS_SAT;
 		use_type_flags = DST_TYPE_HAS_SYMDIV;
 	}
-	switch (dst_type[dst_cur_no]) {
-		case (-1U):
-			/* not used */
-			break;
-		case DST_TYPE_IS_SAT:
-		case DST_TYPE_IS_TERR:
-		case DST_TYPE_IS_CABLE:
-			use_dst_type = (u8)(dst_type[dst_cur_no]);
-			break;
-		default:
-			printk("%s: invalid user override dst type %d, not used\n",
-				__FUNCTION__, dst_type[dst_cur_no]);
-			break;
-	}
 	dst_type_print(use_dst_type);
-	if (dst_type_flags[dst_cur_no] != (-1U)) {
-		printk("%s: user override dst type flags 0x%x\n",
-				__FUNCTION__, dst_type_flags[dst_cur_no]);
-		use_type_flags = dst_type_flags[dst_cur_no];
-	}
+
 	dst->type_flags = use_type_flags;
 	dst->dst_type= use_dst_type;
 	dst_type_flags_print(dst->type_flags);
@@ -648,7 +604,7 @@
 		dprintk("%s: write not successful\n", __FUNCTION__);
 		return retval;
 	}
-	dvb_delay(33);
+	msleep(33);
 	retval = read_dst (dst, &reply, 1);
 	dst_i2c_disable(dst);
 	if (retval < 0) {
@@ -695,15 +651,11 @@
 		if (retval < 0)
 			return retval;
 		if (dst->dst_type == DST_TYPE_IS_SAT) {
-			dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ?
-					1 : 0;
+			dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
 			dst->decode_strength = dst->rxbuffer[5] << 8;
-			dst->decode_snr = dst->rxbuffer[2] << 8 |
-				dst->rxbuffer[3];
-		} else if ((dst->dst_type == DST_TYPE_IS_TERR) ||
-				(dst->dst_type == DST_TYPE_IS_CABLE)) {
-			dst->decode_lock = (dst->rxbuffer[1]) ?
-					1 : 0;
+			dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3];
+		} else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) {
+			dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0;
 			dst->decode_strength = dst->rxbuffer[4] << 8;
 			dst->decode_snr = dst->rxbuffer[3] << 8;
 		}
@@ -899,7 +851,7 @@
 		dprintk("%s: write not successful\n", __FUNCTION__);
 		return retval;
 	}
-	dvb_delay(3);
+	msleep(3);
 	retval = read_dst (dst, &reply, 1);
 	dst_i2c_disable(dst);
 	if (retval < 0) {
@@ -933,19 +885,13 @@
 	dst->cur_jiff = jiffies;
 	if (dst->dst_type == DST_TYPE_IS_SAT) {
 		dst->frequency = 950000;
-		memcpy(dst->tx_tuna, ((dst->type_flags &  DST_TYPE_HAS_NEWTUNE )? 
-					ini_satci_tuna : ini_satfta_tuna),
-				sizeof(ini_satfta_tuna));
+		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
 	} else if (dst->dst_type == DST_TYPE_IS_TERR) {
 		dst->frequency = 137000000;
-		memcpy(dst->tx_tuna, ((dst->type_flags &  DST_TYPE_HAS_NEWTUNE )? 
-					ini_tvci_tuna : ini_tvfta_tuna),
-				sizeof(ini_tvfta_tuna));
+		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
 	} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
 		dst->frequency = 51000000;
-		memcpy(dst->tx_tuna, ((dst->type_flags &  DST_TYPE_HAS_NEWTUNE )? 
-					ini_cabci_tuna : ini_cabfta_tuna),
-				sizeof(ini_cabfta_tuna));
+		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
 	}
 }
 
@@ -953,19 +899,19 @@
 	unsigned int cmd;
 	char *desc;
 } looker[] = {
-	{FE_GET_INFO,                "FE_GET_INFO:"},
-	{FE_READ_STATUS,             "FE_READ_STATUS:" },
-	{FE_READ_BER,                "FE_READ_BER:" },
-	{FE_READ_SIGNAL_STRENGTH,    "FE_READ_SIGNAL_STRENGTH:" },
-	{FE_READ_SNR,                "FE_READ_SNR:" },
-	{FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:" },
-	{FE_SET_FRONTEND,            "FE_SET_FRONTEND:" },
-	{FE_GET_FRONTEND,            "FE_GET_FRONTEND:" },
-	{FE_SLEEP,                   "FE_SLEEP:" },
-	{FE_INIT,                    "FE_INIT:" },
-	{FE_SET_TONE,                "FE_SET_TONE:" },
-	{FE_SET_VOLTAGE,             "FE_SET_VOLTAGE:" },
-	};
+	{
+	FE_GET_INFO, "FE_GET_INFO:"}, {
+	FE_READ_STATUS, "FE_READ_STATUS:"}, {
+	FE_READ_BER, "FE_READ_BER:"}, {
+	FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, {
+	FE_READ_SNR, "FE_READ_SNR:"}, {
+	FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, {
+	FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, {
+	FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, {
+	FE_SLEEP, "FE_SLEEP:"}, {
+	FE_INIT, "FE_INIT:"}, {
+	FE_SET_TONE, "FE_SET_TONE:"}, {
+FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},};
 
 static int dst_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
@@ -985,14 +931,14 @@
 	*/
 	// printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c);
 	/* should be set by attach, but just in case */
-	dst->i2c = fe->i2c;
+
         switch (cmd) {
         case FE_GET_INFO: 
 	{
 	     struct dvb_frontend_info *info;
 		info = &dst_info_sat;
 		if (dst->dst_type == DST_TYPE_IS_TERR)
-			info = &dst_info_tv;
+				info = &dst_info_terr;
 		else if (dst->dst_type == DST_TYPE_IS_CABLE)
 			info = &dst_info_cable;
 		memcpy (arg, info, sizeof(struct dvb_frontend_info));
@@ -1006,11 +952,7 @@
 		if (dst->diseq_flags & HAS_LOCK) {
 			dst_get_signal(dst);
 			if (dst->decode_lock)
-				*status |= FE_HAS_LOCK 
-					| FE_HAS_SIGNAL 
-					| FE_HAS_CARRIER
-					| FE_HAS_SYNC
-					| FE_HAS_VITERBI;
+					*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
 		}
 		break;
 	}
@@ -1115,21 +1057,68 @@
         return 0;
 } 
 
+static ssize_t attr_read_type(struct device *dev, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
+	return sprintf(buf, "0x%02x\n", dst->dst_type);
+}
 
-static int dst_attach (struct dvb_i2c_bus *i2c, void **data)
+static ssize_t attr_write_type(struct device *dev, const char *buf, size_t count)
 {
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
+	unsigned long type;
+	type = simple_strtoul(buf, NULL, 0);
+	dst->dst_type = type & 0xff;
+	return strlen(buf) + 1;
+}
+
+/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */
+static struct device_attribute dev_attr_client_type = {
+	.attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
+	.show = &attr_read_type,
+	.store = &attr_write_type,
+};
+
+static ssize_t attr_read_flags(struct device *dev, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
+	return sprintf(buf, "0x%02x\n", dst->type_flags);
+}
+
+static ssize_t attr_write_flags(struct device *dev, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
+	unsigned long flags;
+	flags = simple_strtoul(buf, NULL, 0);
+	dst->type_flags = flags & 0xffffffff;
+	return strlen(buf) + 1;
+}
+
+/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */
+static struct device_attribute dev_attr_client_flags = {
+	.attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
+	.show = &attr_read_flags,
+	.store = &attr_write_flags,
+};
+
+static struct i2c_client client_template;
+
+static int attach_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_client *client;
 	struct dst_data *dst;
 	struct bt878 *bt;
 	struct dvb_frontend_info *info;
+	int ret;
 
-	dprintk("%s: check ci\n", __FUNCTION__);
-	if (dst_cur_no >= DST_MAX_CARDS) {
-		dprintk("%s: can't have more than %d cards\n", __FUNCTION__, DST_MAX_CARDS);
-		return -ENODEV;
-	}
-	bt = bt878_find_by_dvb_adap(i2c->adapter);
+	bt = bt878_find_by_i2c_adap(adapter);
 	if (!bt)
 		return -ENODEV;
+
 	dst = kmalloc(sizeof(struct dst_data), GFP_KERNEL);
 	if (dst == NULL) {
 		printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__);
@@ -1135,10 +1124,10 @@
 		printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__);
 		return -ENOMEM;
 	}
+
 	memset(dst, 0, sizeof(*dst));
-	*data = dst;
 	dst->bt = bt;
-	dst->i2c = i2c;
+	dst->i2c = adapter;
 	if (dst_check_ci(dst) < 0) {
 		kfree(dst);
 		return -ENODEV;
@@ -1143,41 +1132,122 @@
 		kfree(dst);
 		return -ENODEV;
 	}
-
 	dst_init (dst);
-	dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, 
-			(u32)dst, (u32)(dst->bt), (u32)(dst->i2c));
 
-	info = &dst_info_sat;
-	if (dst->dst_type == DST_TYPE_IS_TERR)
-		info = &dst_info_tv;
-	else if (dst->dst_type == DST_TYPE_IS_CABLE)
+	dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, (u32) dst, (u32) (dst->bt), (u32) (dst->i2c));
+
+	switch (dst->dst_type) {
+	case DST_TYPE_IS_TERR:
+		info = &dst_info_terr;
+		break;
+	case DST_TYPE_IS_CABLE:
 		info = &dst_info_cable;
+		break;
+	case DST_TYPE_IS_SAT:
+		info = &dst_info_sat;
+		break;
+	default:
+		printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
+		kfree(dst);
+		return -ENODEV;
+	}
+
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(dst);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = DST_I2C_ADDR;
+
+	i2c_set_clientdata(client, (void *) dst);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(dst);
+		return -EFAULT;
+	}
+
+	BUG_ON(!dst->dvb);
+
+	device_create_file(&client->dev, &dev_attr_client_type);
+	device_create_file(&client->dev, &dev_attr_client_flags);
+
+	ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(dst);
+		return -EFAULT;
+	}
 
-	dvb_register_frontend (dst_ioctl, i2c, dst, info);
-	dst_cur_no++;
 	return 0;
 }
 
-static void dst_detach (struct dvb_i2c_bus *i2c, void *data)
+static int detach_client(struct i2c_client *client)
 {
-	dvb_unregister_frontend (dst_ioctl, i2c);
-	dprintk("%s: unregister dst %8.8x\n", __FUNCTION__, (u32)(data));
-	if (data)
-		kfree(data);
+	struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
+	
+	dvb_unregister_frontend_new(dst_ioctl, state->dvb);
+
+	device_remove_file(&client->dev, &dev_attr_client_type);
+	device_remove_file(&client->dev, &dev_attr_client_flags);
+
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+
+	kfree(client);
+	kfree(state);
+
+	return 0;
 }
 
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = (struct dvb_adapter *) arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner = THIS_MODULE,
+	.name = "dst",
+	.id = I2C_DRIVERID_DVBFE_DST,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client = detach_client,
+	.command = command,
+};
+
+static struct i2c_client client_template = {
+	I2C_DEVNAME("dst"),
+	.flags = I2C_CLIENT_ALLOW_USE,
+	.driver = &driver,
+};
+
 static int __init init_dst (void)
 {
-	return dvb_register_i2c_device (THIS_MODULE, dst_attach, dst_detach);
+	return i2c_add_driver(&driver);
 }
 
 static void __exit exit_dst (void)
 {
-	dvb_unregister_i2c_device (dst_attach);
+	if (i2c_del_driver(&driver))
+		printk("dst: driver deregistration failed\n");
 }
 
-
 module_init(init_dst);
 module_exit(exit_dst);
 

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

* Re: [PATCH][2.6][7/14] convert frontend drivers to kernel i2c 3/3
  2004-09-17 14:30           ` [PATCH][2.6][6/14] convert frontend drivers to kernel i2c 2/3 Michael Hunold
@ 2004-09-17 14:32             ` Michael Hunold
  2004-09-17 14:33               ` [PATCH][2.6][8/14] some more frontend drivers to converted to kernel i2c Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:32 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 07-DVB-frontend-conversion3.diff --]
[-- Type: text/plain, Size: 49548 bytes --]

- [DVB] dvb_dummy_fe, grundig_29504-401, grundig_29504-491, mt312: convert from dvb-i2c to kernel-i2c, MODULE_PARM() to module_param(), dvb_delay() to mdelay()
- [DVB] update frontend Kconfig

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/dvb_dummy_fe.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/dvb_dummy_fe.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/dvb_dummy_fe.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dvb_dummy_fe.c	2004-08-18 19:52:17.000000000 +0200
@@ -20,12 +20,16 @@
  */    
 
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
 
-static int sct = 0;
+#define FRONTEND_NAME "dvbfe_dummy"
 
+static int frontend_type;
+module_param(frontend_type, int, 0444);
+MODULE_PARM_DESC(frontend_type, "0 == DVB-S, 1 == DVB-C, 2 == DVB-T");
 
 /* depending on module parameter sct deliver different infos
  */
@@ -87,8 +91,7 @@
 
 struct dvb_frontend_info *frontend_info(void)
 {
-	switch(sct)
-	{
+	switch(frontend_type) {
 	case 2:
 		return &dvb_t_dummyfe_info;
 	case 1:
@@ -168,30 +171,89 @@
         return 0;
 } 
 
+static struct i2c_client client_template;
 
-static int dvbdummyfe_attach (struct dvb_i2c_bus *i2c, void **data)
+static int dvbdummyfe_attach_adapter(struct i2c_adapter *adapter)
 {
-	return dvb_register_frontend (dvbdummyfe_ioctl, i2c, NULL, frontend_info());
+	struct dvb_adapter *dvb;
+	struct i2c_client *client;
+	int ret;
+
+	if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+
+	if ((ret = i2c_attach_client(client))) {
+		kfree(client);
+		return ret;
 }
 
+	dvb = i2c_get_clientdata(client);
+	BUG_ON(!dvb);
 
-static void dvbdummyfe_detach (struct dvb_i2c_bus *i2c, void *data)
+	if ((ret = dvb_register_frontend(dvbdummyfe_ioctl, dvb, NULL,
+					     frontend_info(), THIS_MODULE))) {
+		kfree(client);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static int dvbdummyfe_detach_client(struct i2c_client *client)
 {
-	dvb_unregister_frontend (dvbdummyfe_ioctl, i2c);
+	struct dvb_adapter *dvb = i2c_get_clientdata(client);
+
+	dvb_unregister_frontend_new(dvbdummyfe_ioctl, dvb);
+	i2c_detach_client(client);
+	kfree(client);
+	return 0;
 }
 
+static int dvbdummyfe_command(struct i2c_client *client,
+			      unsigned int cmd, void *arg)
+{
+	switch(cmd) {
+	case FE_REGISTER:
+		i2c_set_clientdata(client, arg);
+		break;
+	case FE_UNREGISTER:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= FRONTEND_NAME,
+	.id		= I2C_DRIVERID_DVBFE_DUMMY,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= dvbdummyfe_attach_adapter,
+	.detach_client	= dvbdummyfe_detach_client,
+	.command	= dvbdummyfe_command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
 
 static int __init init_dvbdummyfe (void)
 {
-	return dvb_register_i2c_device (THIS_MODULE,
-					dvbdummyfe_attach, 
-					dvbdummyfe_detach);
+	return i2c_add_driver(&driver);
 }
 
-
 static void __exit exit_dvbdummyfe (void)
 {
-	dvb_unregister_i2c_device (dvbdummyfe_attach);
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "dummyfe: driver deregistration failed.\n");
 }
 
 
@@ -202,4 +263,4 @@
 MODULE_DESCRIPTION("DVB DUMMY Frontend");
 MODULE_AUTHOR("Emard");
 MODULE_LICENSE("GPL");
-MODULE_PARM(sct, "i");
+
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/grundig_29504-401.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-401.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/grundig_29504-401.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-401.c	2004-08-18 19:52:17.000000000 +0200
@@ -25,22 +25,35 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-static int debug = 0;
+#define FRONTEND_NAME "dvbfe_l64781"
 
-#define dprintk	if (debug) printk
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+static int old_set_tv_freq;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+module_param(old_set_tv_freq, int, 0644);
+MODULE_PARM_DESC(old_set_tv_freq, "Use old tsa5060_set_tv_freq calculations.");
 
-struct grundig_state {
+struct l64781_state {
 	int first:1;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
 };
 
-struct dvb_frontend_info grundig_29504_401_info = {
-	.name = "Grundig 29504-401",
+struct dvb_frontend_info l64781_info = {
+	.name = "Grundig 29504-401 (LSI L64781 Based)",
 	.type = FE_OFDM,
 /*	.frequency_min = ???,*/
 /*	.frequency_max = ???,*/
@@ -55,13 +68,13 @@
 };
 
 
-static int l64781_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int l64781_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
 	int ret;
 	u8 buf [] = { reg, data };
 	struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
 
-	if ((ret = i2c->xfer (i2c, &msg, 1)) != 1)
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
 		dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
 			 __FUNCTION__, reg, ret);
 
@@ -69,7 +82,7 @@
 }
 
 
-static u8 l64781_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 l64781_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
@@ -77,7 +90,7 @@
 	struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
 			   { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -86,12 +99,12 @@
 }
 
 
-static int tsa5060_write (struct dvb_i2c_bus *i2c, u8 data [4])
+static int tsa5060_write (struct i2c_adapter *i2c, u8 data [4])
 {
 	int ret;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
 
-	if ((ret = i2c->xfer (i2c, &msg, 1)) != 1)
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
 		dprintk ("%s: write_reg error == %02x!\n", __FUNCTION__, ret);
 
 	return (ret != 1) ? -1 : 0;
@@ -103,14 +116,17 @@
  *   reference clock comparision frequency of 166666 Hz.
  *   frequency offset is 36125000 Hz.
  */
-static int tsa5060_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int tsa5060_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
-#if 1
 	u32 div;
 	u8 buf [4];
 	u8 cfg, cpump, band_select;
 
+	if (old_set_tv_freq)
+	        div = (36000000 + freq) / 166666;
+	else
 	div = (36125000 + freq) / 166666;
+
 	cfg = 0x88;
 
 	cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
@@ -121,27 +137,18 @@
 	buf [0] = (div >> 8) & 0x7f;
 	buf [1] = div & 0xff;
 	buf [2] = ((div >> 10) & 0x60) | cfg;
-	buf [3] = (cpump << 6) | band_select;
-#else
-	/* old code which seems to work better for at least one person */
-        u32 div;
-        u8 buf [4];
-        u8 cfg;
-
-        div = (36000000 + freq) / 166666;
-        cfg = 0x88;
 
-        buf [0] = (div >> 8) & 0x7f;
-        buf [1] = div & 0xff;
-        buf [2] = ((div >> 10) & 0x60) | cfg;
+	if (old_set_tv_freq)
         buf [3] = 0xc0;
-#endif
+	else
+		buf [3] = (cpump << 6) | band_select;
 
 	return tsa5060_write (i2c, buf);
 }
 
 
-static void apply_tps (struct dvb_i2c_bus *i2c)
+
+static void apply_tps (struct i2c_adapter *i2c)
 {
 	l64781_writereg (i2c, 0x2a, 0x00);
 	l64781_writereg (i2c, 0x2a, 0x01);
@@ -155,7 +162,7 @@
 }
 
 
-static void reset_afc (struct dvb_i2c_bus *i2c)
+static void reset_afc (struct i2c_adapter *i2c)
 {
 	/* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
 	   timing offset */
@@ -173,7 +180,7 @@
 }
 
 
-static int apply_frontend_param (struct dvb_i2c_bus *i2c,
+static int apply_frontend_param (struct i2c_adapter *i2c,
 			  struct dvb_frontend_parameters *param)
 {
 	/* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
@@ -285,16 +292,16 @@
 }
 
 
-static int reset_and_configure (struct dvb_i2c_bus *i2c)
+static int reset_and_configure (struct i2c_adapter *i2c)
 {
 	u8 buf [] = { 0x06 };
 	struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
 
-	return (i2c->xfer (i2c, &msg, 1) == 1) ? 0 : -ENODEV;
+	return (i2c_transfer(i2c, &msg, 1) == 1) ? 0 : -ENODEV;
 }
 
 
-static int get_frontend(struct dvb_i2c_bus* i2c, struct dvb_frontend_parameters* param)
+static int get_frontend(struct i2c_adapter* i2c, struct dvb_frontend_parameters* param)
 {
 	int tmp;
 
@@ -412,7 +419,7 @@
 }
 
 
-static int init (struct dvb_i2c_bus *i2c)
+static int init (struct i2c_adapter *i2c)
 {
         reset_and_configure (i2c);
 
@@ -449,16 +456,16 @@
 
 
 static 
-int grundig_29504_401_ioctl (struct dvb_frontend *fe,
+int l64781_ioctl (struct dvb_frontend *fe,
 			     unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct l64781_state* state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 	int res;
-	struct grundig_state* state = (struct grundig_state*) fe->data;
 
         switch (cmd) {
         case FE_GET_INFO:
-		memcpy (arg, &grundig_29504_401_info,
+		memcpy (arg, &l64781_info,
 			sizeof(struct dvb_frontend_info));
                 break;
 
@@ -546,7 +553,7 @@
 		res = init (i2c);
 		if ((res == 0) && (state->first)) {
 			state->first = 0;
-			dvb_delay(200);
+			msleep(200);
 		}
 		return res;
 
@@ -567,28 +574,26 @@
         return 0;
 } 
 
-
-static int l64781_attach (struct dvb_i2c_bus *i2c, void **data)
+static int l64781_probe(struct i2c_adapter *i2c)
 {
 	u8 reg0x3e;
 	u8 b0 [] = { 0x1a };
 	u8 b1 [] = { 0x00 };
 	struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
 			   { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-	struct grundig_state* state;
 
 	/**
 	 *  the L64781 won't show up before we send the reset_and_configure()
 	 *  broadcast. If nothing responds there is no L64781 on the bus...
 	 */
 	if (reset_and_configure(i2c) < 0) {
-		dprintk("no response on reset_and_configure() broadcast, bailing out...\n");
+		dprintk("No response to reset and configure broadcast...\n");
 		return -ENODEV;
 	}
 
 	/* The chip always responds to reads */
-	if (i2c->xfer(i2c, msg, 2) != 2) {  
-	        dprintk("no response to read on I2C bus\n");
+	if (i2c_transfer(i2c, msg, 2) != 2) {  
+	        dprintk("No response to read on I2C bus\n");
 		return -ENODEV;
 	}
 
@@ -607,7 +612,7 @@
 	/* Responds to all reads with 0 */
 	if (l64781_readreg(i2c, 0x1a) != 0) {
  	        dprintk("Read 1 returned unexpcted value\n");
-	        goto bailout;
+	        goto out;
 	}	  
 
 	/* Turn the chip on */
@@ -616,49 +621,129 @@
 	/* Responds with register default value */
 	if (l64781_readreg(i2c, 0x1a) != 0xa1) { 
  	        dprintk("Read 2 returned unexpcted value\n");
-	        goto bailout;
+	        goto out;
+	}
+
+	return 0;
+out:
+	l64781_writereg (i2c, 0x3e, reg0x3e);  /* restore reg 0x3e */
+	return -ENODEV;
 	}
 
-	state = kmalloc(sizeof(struct grundig_state), GFP_KERNEL);
-	if (state == NULL) goto bailout;
-	*data = state;
+static struct i2c_client client_template;
+
+static int l64781_attach_adapter(struct i2c_adapter *adapter)
+{
+	struct l64781_state *state;
+	struct i2c_client *client;
+	int ret;
+
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		adapter->id, adapter->name);
+
+	if ((ret = l64781_probe(adapter)))
+		return ret;
+
+	if ( !(state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	memset(state, 0, sizeof(struct l64781_state));
+	state->i2c = adapter;
 	state->first = 1;
 
-	return dvb_register_frontend (grundig_29504_401_ioctl, i2c, state,
-			       &grundig_29504_401_info);
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = 0; //XXX
+	i2c_set_clientdata(client, state);
+
+	if ((ret = i2c_attach_client(client))) {
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	if ((ret = dvb_register_frontend(l64781_ioctl, state->dvb, state,
+					     &l64781_info, THIS_MODULE))) {
+		i2c_detach_client(client);
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
 
- bailout:
-	l64781_writereg (i2c, 0x3e, reg0x3e);  /* restore reg 0x3e */
-	return -ENODEV;
+	return 0;
 }
 
+static int l64781_detach_client(struct i2c_client *client)
+{
+	struct l64781_state *state = i2c_get_clientdata(client);
 
+	dvb_unregister_frontend_new(l64781_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
 
-static void l64781_detach (struct dvb_i2c_bus *i2c, void *data)
+static int l64781_command(struct i2c_client *client,
+			  unsigned int cmd, void *arg)
 {
-	kfree(data);
-	dvb_unregister_frontend (grundig_29504_401_ioctl, i2c);
+	struct l64781_state *data = i2c_get_clientdata(client);
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER: {
+		data->dvb = arg;
+		break;
+	}
+	case FE_UNREGISTER: {
+		data->dvb = NULL;
+		break;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_L64781,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = l64781_attach_adapter,
+	.detach_client 	= l64781_detach_client,
+	.command 	= l64781_command,
+};
 
-static int __init init_grundig_29504_401 (void)
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
+
+static int __init init_l64781 (void)
 {
-	return dvb_register_i2c_device (THIS_MODULE,
-					l64781_attach, l64781_detach);
+	return i2c_add_driver(&driver);
 }
 
-
-static void __exit exit_grundig_29504_401 (void)
+static void __exit exit_l64781 (void)
 {
-	dvb_unregister_i2c_device (l64781_attach);
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "l64781: driver deregistration failed\n");
 }
 
-module_init(init_grundig_29504_401);
-module_exit(exit_grundig_29504_401);
+module_init(init_l64781);
+module_exit(exit_l64781);
 
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-MODULE_DESCRIPTION("Grundig 29504-401 DVB-T Frontend");
+MODULE_DESCRIPTION("Grundig 29504-401 DVB-T Frontend (LSI L64781 Based)");
 MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
 MODULE_LICENSE("GPL");
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/grundig_29504-491.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-491.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/grundig_29504-491.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-491.c	2004-08-18 19:52:17.000000000 +0200
@@ -27,17 +27,31 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-static int debug = 0;
-#define dprintk	if (debug) printk
+#define FRONTEND_NAME "dvbfe_tda8083"
 
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
 
-static struct dvb_frontend_info grundig_29504_491_info = {
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+struct tda8083_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
+
+static struct dvb_frontend_info tda8083_info = {
 	.name			= "Grundig 29504-491, (TDA8083 based)",
 	.type			= FE_QPSK,
 	.frequency_min		= 950000,     /* FIXME: guessed! */
@@ -67,14 +79,13 @@
 };
 
 
-
-static int tda8083_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int tda8083_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
 	int ret;
 	u8 buf [] = { reg, data };
 	struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
 
-        ret = i2c->xfer (i2c, &msg, 1);
+        ret = i2c_transfer(i2c, &msg, 1);
 
         if (ret != 1)
                 dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
@@ -84,13 +95,13 @@
 }
 
 
-static int tda8083_readregs (struct dvb_i2c_bus *i2c, u8 reg1, u8 *b, u8 len)
+static int tda8083_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
 {
 	int ret;
 	struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg1, .len = 1 },
 			   { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
 	if (ret != 2)
 		dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
@@ -100,7 +111,7 @@
 }
 
 
-static inline u8 tda8083_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static inline u8 tda8083_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	u8 val;
 
@@ -110,12 +121,12 @@
 }
 
 
-static int tsa5522_write (struct dvb_i2c_bus *i2c, u8 data [4])
+static int tsa5522_write (struct i2c_adapter *i2c, u8 data [4])
 {
 	int ret;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
 
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 
 	if (ret != 1)
 		dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
@@ -128,7 +139,7 @@
  *   set up the downconverter frequency divisor for a
  *   reference clock comparision frequency of 125 kHz.
  */
-static int tsa5522_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int tsa5522_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 	u32 div = freq / 125;
 	u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x8e, 0x00 };
@@ -137,7 +148,7 @@
 }
 
 
-static int tda8083_init (struct dvb_i2c_bus *i2c)
+static int tda8083_init (struct i2c_adapter *i2c)
 {
 	int i;
 	
@@ -150,7 +161,7 @@
 }
 
 
-static int tda8083_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
+static int tda8083_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
 {
 	/*  XXX FIXME: implement other modes than FEC_AUTO */
 	if (inversion == INVERSION_AUTO)
@@ -160,7 +171,7 @@
 }
 
 
-static int tda8083_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
+static int tda8083_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
 {
 	if (fec == FEC_AUTO)
 		return tda8083_writereg (i2c, 0x07, 0xff);
@@ -172,7 +183,7 @@
 }
 
 
-static fe_code_rate_t tda8083_get_fec (struct dvb_i2c_bus *i2c)
+static fe_code_rate_t tda8083_get_fec (struct i2c_adapter *i2c)
 {
 	u8 index;
 	static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
@@ -184,7 +195,7 @@
 }
 
 
-static int tda8083_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
+static int tda8083_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
 {
         u32 ratio;
 	u32 tmp;
@@ -224,19 +235,19 @@
 }
 
 
-static void tda8083_wait_diseqc_fifo (struct dvb_i2c_bus *i2c, int timeout)
+static void tda8083_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
 {
 	unsigned long start = jiffies;
 
 	while (jiffies - start < timeout &&
                !(tda8083_readreg(i2c, 0x02) & 0x80))
 	{
-		dvb_delay(50);
+		msleep(50);
 	};
 }
 
 
-static int tda8083_send_diseqc_msg (struct dvb_i2c_bus *i2c,
+static int tda8083_send_diseqc_msg (struct i2c_adapter *i2c,
 			     struct dvb_diseqc_master_cmd *m)
 {
 	int i;
@@ -254,7 +265,7 @@
 }
 
 
-static int tda8083_send_diseqc_burst (struct dvb_i2c_bus *i2c, fe_sec_mini_cmd_t burst)
+static int tda8083_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
 {
 	switch (burst) {
 	case SEC_MINI_A:
@@ -273,7 +284,7 @@
 }
 
 
-static int tda8083_set_tone (struct dvb_i2c_bus *i2c, fe_sec_tone_mode_t tone)
+static int tda8083_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
 {
 	tda8083_writereg (i2c, 0x26, 0xf1);
 
@@ -288,7 +299,7 @@
 }
 
 
-static int tda8083_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
+static int tda8083_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
 {
 	switch (voltage) {
 	case SEC_VOLTAGE_13:
@@ -301,15 +312,15 @@
 }
 
 
-static int grundig_29504_491_ioctl (struct dvb_frontend *fe, unsigned int cmd,
+static int tda8083_ioctl(struct dvb_frontend *fe, unsigned int cmd,
 			     void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct tda8083_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
         switch (cmd) {
 	case FE_GET_INFO:
-		memcpy (arg, &grundig_29504_491_info, 
-			sizeof(struct dvb_frontend_info));
+		memcpy (arg, &tda8083_info, sizeof(struct dvb_frontend_info));
                 break;
 
         case FE_READ_STATUS:
@@ -426,40 +437,119 @@
 	return 0;
 } 
 
+static struct i2c_client client_template;
 
-static int tda8083_attach (struct dvb_i2c_bus *i2c, void **data)
+static int tda8083_attach_adapter(struct i2c_adapter *adapter)
 {
-	if ((tda8083_readreg (i2c, 0x00)) != 0x05)
+	struct tda8083_state *state;
+	struct i2c_client *client;
+	int ret;
+
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		adapter->id, adapter->name);
+
+	if ((tda8083_readreg (adapter, 0x00)) != 0x05)
 		return -ENODEV;
 
-	return dvb_register_frontend (grundig_29504_491_ioctl, i2c, NULL,
-			       &grundig_29504_491_info);
+	if ( !(state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memset(state, 0, sizeof(struct tda8083_state));
+	state->i2c = adapter;
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = 0; //XXX
+	i2c_set_clientdata(client, state);
+
+	if ((ret = i2c_attach_client(client))) {
+		kfree(state);
+		kfree(client);
+		return ret;
 }
 
+	BUG_ON(!state->dvb);
+
+	if ((ret = dvb_register_frontend(tda8083_ioctl, state->dvb, state,
+					     &tda8083_info, THIS_MODULE))) {
+		i2c_detach_client(client);
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	return 0;
+}
 
-static void tda8083_detach (struct dvb_i2c_bus *i2c, void *data)
+static int tda8083_detach_client(struct i2c_client *client)
 {
-	dvb_unregister_frontend (grundig_29504_491_ioctl, i2c);
+	struct tda8083_state *state = i2c_get_clientdata(client);
+
+	dvb_unregister_frontend_new (tda8083_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
+
+static int tda8083_command (struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct tda8083_state *data = i2c_get_clientdata(client);
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER: {
+		data->dvb = arg;
+		break;
+	}
+	case FE_UNREGISTER: {
+		data->dvb = NULL;
+		break;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_TDA8083,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = tda8083_attach_adapter,
+	.detach_client 	= tda8083_detach_client,
+	.command 	= tda8083_command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
 
 static int __init init_tda8083 (void)
 {
-	return dvb_register_i2c_device (THIS_MODULE,
-					tda8083_attach, tda8083_detach);
+	return i2c_add_driver(&driver);
 }
 
-
 static void __exit exit_tda8083 (void)
 {
-	dvb_unregister_i2c_device (tda8083_attach);
+	if (i2c_del_driver(&driver))
+		printk("grundig_29504_401: driver deregistration failed\n");
 }
 
 module_init(init_tda8083);
 module_exit(exit_tda8083);
 
-MODULE_PARM(debug,"i");
-MODULE_DESCRIPTION("Grundig 29504-491 DVB frontend driver");
+MODULE_DESCRIPTION("Grundig 29504-491 DVB frontend driver (TDA8083 Based)");
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
 MODULE_LICENSE("GPL");
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/frontends/Kconfig
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/Kconfig	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/Kconfig	2004-06-22 15:49:15.000000000 +0200
@@ -1,24 +1,11 @@
-comment "Supported Frontend Modules"
-	depends on DVB
-
-config DVB_TWINHAN_DST
-	tristate "TWINHAN DST based DVB-S frontend (QPSK)"
-	depends on DVB_CORE && DVB_BT8XX
-	help
-	  Used in such cards as the VP-1020/1030, Twinhan DST,
-	  VVmer TV@SAT. Say Y when you want to support frontends 
-	  using this asic.
-
-	  This module requires the dvb-bt8xx driver and dvb bt878
-	  module.
+comment "DVB-S (satellite) frontends"
+	depends on DVB_CORE
 
 config DVB_STV0299
-	tristate "STV0299 based DVB-S frontend (QPSK)"
+	tristate "ST STV0299 based"
 	depends on DVB_CORE
 	help
-	  The stv0299 by ST is used in many DVB-S tuner modules, 
-	  say Y when you want to support frontends based on this 
-	  DVB-S demodulator.
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 	  Some examples are the Alps BSRU6, the Philips SU1278 and
 	  the LG TDQB-S00x.
@@ -27,92 +14,83 @@
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_SP887X
- 	tristate "Frontends with sp887x demodulators, e.g. Microtune DTF7072"
+config DVB_CX24110
+	tristate "Connexant CX24110 based"
  	depends on DVB_CORE
  	help
- 	  A DVB-T demodulator driver. Say Y when you want to support the sp887x.
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
  
  	  If you don't know what tuner module is soldered on your
  	  DVB adapter simply enable all supported frontends, the
  	  right one will get autodetected.
 
-
-config DVB_SP887X_FIRMWARE_FILE
-        string "Full pathname of sp887x firmware file"
-        depends on DVB_SP887X
-        default "/usr/lib/hotplug/firmware/sc_main.mc"
-        help
-          This driver needs a copy of the Avermedia firmware. The version tested
-	  is part of the Avermedia DVB-T 1.3.26.3 Application. This can be downloaded
-	  from the Avermedia web site.
-	  If the software is installed in Windows the file will be in the
-	  /Program Files/AVerTV DVB-T/ directory and is called sc_main.mc.
-	  Alternatively it can "extracted" from the install cab files but this will have
-	  to be done in windows as I don't know of a linux version of extract.exe.
-	  Copy this file to /usr/lib/hotplug/firmware/sc_main.mc.
-	  With this version of the file the first 10 bytes are discarded and the next
-	  0x4000 loaded. This may change in future versions.
-
-config DVB_ALPS_TDLB7
-	tristate "Alps TDLB7 (OFDM)"
+config DVB_GRUNDIG_29504_491
+	tristate "Grundig 29504-491 based"
 	depends on DVB_CORE
 	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
-
-	  This tuner module needs some microcode located in a file called
-	  "Sc_main.mc" in the windows driver. Please pass the module parameter
-	  mcfile="/PATH/FILENAME" when loading alps_tdlb7.o.
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
 
-
-config DVB_ALPS_TDMB7
-	tristate "Alps TDMB7 (OFDM)"
+config DVB_MT312
+	tristate "Zarlink MT312 based"
 	depends on DVB_CORE
 	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
 
-config DVB_ATMEL_AT76C651
-	tristate "Atmel AT76C651 (QAM)"
+config DVB_VES1X93
+	tristate "VLSI VES1893 or VES1993 based"
 	depends on DVB_CORE
 	help
-	  The AT76C651 Demodulator is used in some DVB-C SetTopBoxes. Say Y
-	  when you see this demodulator chip near your tuner module.
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
 
-config DVB_CX24110
-	tristate "Frontends with Connexant CX24110 demodulator (QPSK)"
+comment "DVB-T (terrestrial) frontends"
+	depends on DVB_CORE
+
+config DVB_SP887X
+ 	tristate "Microtune sp887x based (i.e. Microtune DTF7072)"
 	depends on DVB_CORE
 	help
-	  The CX24110 Demodulator is used in some DVB-S frontends. 
-	  Say Y if you want support for this chip in your kernel.
+ 	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs a copy of the Avermedia firmware. The version tested
+	  is part of the Avermedia DVB-T 1.3.26.3 Application. If the software is
+	  installed in Windoze the file will be in the /Program Files/AVerTV DVB-T/
+	  directory and is called sc_main.mc. Alternatively it can "extracted" from
+	  the install cab files.
+   
+   	  Copy this file to '/usr/lib/hotplug/firmware/dvb-fe-sp887x.fw'.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_GRUNDIG_29504_491
-	tristate "Grundig 29504-491 (QPSK)"
+config DVB_ALPS_TDLB7
+	tristate "Alps TDLB7 based"
 	depends on DVB_CORE
 	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  This driver needs a copy of the firmware file from the Haupauge
+	  Windoze driver. Copy 'Sc_main.mc' to
+	  '/usr/lib/hotplug/firmware/dvb-fe-tdlb7.fw'.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_GRUNDIG_29504_401
-	tristate "Grundig 29504-401 (OFDM)"
+config DVB_ALPS_TDMB7
+	tristate "Alps TDMB7 based"
 	depends on DVB_CORE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -121,40 +99,38 @@
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_MT312
-	tristate "Zarlink MT312 Satellite Channel Decoder (QPSK)"
+config DVB_GRUNDIG_29504_401
+	tristate "Grundig 29504-401 based"
 	depends on DVB_CORE
 	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_VES1820
-	tristate "Frontends with external VES1820 demodulator (QAM)"
+config DVB_TDA1004X
+	tristate "Philips TDA10045H/TDA10046H based"
 	depends on DVB_CORE
 	help
-	  The VES1820 Demodulator is used on many DVB-C PCI cards and in some
-	  DVB-C SetTopBoxes. Say Y when you see this demodulator chip near your
-	  tuner module.
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_VES1X93
-	tristate "Frontends with VES1893 or VES1993 demodulator (QPSK)"
+config DVB_NXT6000
+	tristate "NxtWave Communications NXT6000 based"
 	depends on DVB_CORE
 	help
-	  A DVB-S tuner module. Say Y when you want to support this frontend.
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
-config DVB_TDA1004X
-	tristate "Frontends with external TDA10045H or TDA10046H demodulators (OFDM)"
+config DVB_MT352
+	tristate "Zarlink MT352 based"
 	depends on DVB_CORE
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -163,25 +139,36 @@
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
 
-config DVB_TDA1004X_FIRMWARE_FILE
-        string "Full pathname of tda1004x.bin firmware file"
-        depends on DVB_TDA1004X
-        default "/usr/lib/hotplug/firmware/tda1004x.bin"
+comment "DVB-C (cable) frontends"
+	depends on DVB_CORE
+
+config DVB_ATMEL_AT76C651
+	tristate "Atmel AT76C651 based"
+	depends on DVB_CORE
         help
-          The TDA1004X requires additional firmware in order to function.
-          The firmware file can obtained as follows:
-            wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
-            unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
-            mv ttlcdacc.dll /usr/lib/hotplug/firmware/tda1004x.bin
-	  Note: even if you're using a USB device, you MUST get the file from the
-	  TechnoTrend PCI drivers.
+ 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
-config DVB_NXT6000
-	tristate "Frontends with NxtWave Communications NXT6000 demodulator (OFDM)"
+	  If you don't know what tuner module is soldered on your
+	  DVB adapter simply enable all supported frontends, the
+	  right one will get autodetected.
+
+config DVB_VES1820
+	tristate "VLSI VES1820 based"
 	depends on DVB_CORE
 	help
-	  A DVB-T tuner module. Say Y when you want to support this frontend.
+ 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
 	  If you don't know what tuner module is soldered on your
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
+
+comment "Misc. Frontend Modules"
+	depends on DVB_CORE
+
+config DVB_TWINHAN_DST
+	tristate "Twinhan DST based DVB-S/-T frontend"
+	depends on DVB_CORE && DVB_BT8XX
+	help
+	  Used in such cards as the VP-1020/1030, Twinhan DST,
+	  VVmer TV@SAT. Say Y when you want to support frontends
+	  using this asic.
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt312.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt312.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt312.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt312.c	2004-08-18 19:52:17.000000000 +0200
@@ -28,30 +28,32 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include "dvb_frontend.h"
 #include "mt312.h"
 
+#define FRONTEND_NAME "dvbfe_mt312"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
 #define I2C_ADDR_MT312		0x0e
 #define I2C_ADDR_SL1935		0x61
 #define I2C_ADDR_TSA5059	0x61
 
-#define MT312_DEBUG		0
-
 #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
 #define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
 
-/* number of active frontends */
-static int mt312_count = 0;
-
-#if MT312_DEBUG == 0
-#define dprintk(x...)
-#else
-static int debug = 0;
-#define dprintk if(debug == 1) printk
-#endif
-
 static struct dvb_frontend_info mt312_info = {
 	.name = "Zarlink MT312",
 	.type = FE_QPSK,
@@ -70,7 +72,13 @@
             FE_CAN_RECOVER
 };
 
-static int mt312_read(struct dvb_i2c_bus *i2c,
+struct mt312_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+	int id;
+};
+
+static int mt312_read(struct i2c_adapter *i2c,
 		      const enum mt312_reg_addr reg, void *buf,
 		      const size_t count)
 {
@@ -87,26 +95,25 @@
 	msg[1].buf = buf;
 	msg[1].len = count;
 
-	ret = i2c->xfer(i2c, msg, 2);
+	ret = i2c_transfer(i2c, msg, 2);
 
-	if ((ret != 2) && (mt312_count != 0)) {
+	if (ret != 2) {
 		printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
 		return -EREMOTEIO;
 	}
-#if MT312_DEBUG
+
 	if(debug) {
 		int i;
-		printk(KERN_INFO "R(%d):", reg & 0x7f);
+		dprintk("R(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
 			printk(" %02x", ((const u8 *) buf)[i]);
 		printk("\n");
 	}
-#endif
 
 	return 0;
 }
 
-static int mt312_write(struct dvb_i2c_bus *i2c,
+static int mt312_write(struct i2c_adapter *i2c,
 		       const enum mt312_reg_addr reg, const void *src,
 		       const size_t count)
 {
@@ -114,15 +121,13 @@
 	u8 buf[count + 1];
 	struct i2c_msg msg;
 
-#if MT312_DEBUG
 	if(debug) {
 		int i;
-		printk(KERN_INFO "W(%d):", reg & 0x7f);
+		dprintk("W(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
 			printk(" %02x", ((const u8 *) src)[i]);
 		printk("\n");
 	}
-#endif
 
 	buf[0] = reg;
 	memcpy(&buf[1], src, count);
@@ -132,29 +137,29 @@
 	msg.buf = buf;
 	msg.len = count + 1;
 
-	ret = i2c->xfer(i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 
 	if (ret != 1) {
-		printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
+		dprintk("%s: ret == %d\n", __FUNCTION__, ret);
 		return -EREMOTEIO;
 	}
 
 	return 0;
 }
 
-static inline int mt312_readreg(struct dvb_i2c_bus *i2c,
+static inline int mt312_readreg(struct i2c_adapter *i2c,
 				const enum mt312_reg_addr reg, u8 * val)
 {
 	return mt312_read(i2c, reg, val, 1);
 }
 
-static inline int mt312_writereg(struct dvb_i2c_bus *i2c,
+static inline int mt312_writereg(struct i2c_adapter *i2c,
 				 const enum mt312_reg_addr reg, const u8 val)
 {
 	return mt312_write(i2c, reg, &val, 1);
 }
 
-static int mt312_pll_write(struct dvb_i2c_bus *i2c, const u8 addr,
+static int mt312_pll_write(struct i2c_adapter *i2c, const u8 addr,
 			   u8 * buf, const u8 len)
 {
 	int ret;
@@ -168,7 +173,7 @@
 	if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0)
 		return ret;
 
-	if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
 		printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret);
 
 	if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0)
@@ -182,7 +187,7 @@
 	return (a + (b / 2)) / b;
 }
 
-static int sl1935_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
+static int sl1935_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr)
 {
 	/* 155 uA, Baseband Path B */
 	u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 };
@@ -219,7 +224,7 @@
 	return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
 }
 
-static int tsa5059_set_tv_freq(struct dvb_i2c_bus *i2c, u32 freq, u32 sr)
+static int tsa5059_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr)
 {
 	u8 buf[4];
 
@@ -239,13 +244,14 @@
 	return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf));
 }
 
-static int mt312_reset(struct dvb_i2c_bus *i2c, const u8 full)
+static int mt312_reset(struct i2c_adapter *i2c, const u8 full)
 {
 	return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40);
 }
 
-static int mt312_init(struct dvb_i2c_bus *i2c, const long id, u8 pll)
+static int mt312_initfe(struct mt312_state *state, u8 pll)
 {
+	struct i2c_adapter *i2c = state->i2c;
 	int ret;
 	u8 buf[2];
 
@@ -297,7 +303,7 @@
 	return 0;
 }
 
-static int mt312_send_master_cmd(struct dvb_i2c_bus *i2c,
+static int mt312_send_master_cmd(struct i2c_adapter *i2c,
 				 const struct dvb_diseqc_master_cmd *c)
 {
 	int ret;
@@ -328,14 +334,14 @@
 	return 0;
 }
 
-static int mt312_recv_slave_reply(struct dvb_i2c_bus *i2c,
+static int mt312_recv_slave_reply(struct i2c_adapter *i2c,
 				  struct dvb_diseqc_slave_reply *r)
 {
 	/* TODO */
 	return -EOPNOTSUPP;
 }
 
-static int mt312_send_burst(struct dvb_i2c_bus *i2c, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct i2c_adapter *i2c, const fe_sec_mini_cmd_t c)
 {
 	const u8 mini_tab[2] = { 0x02, 0x03 };
 
@@ -356,7 +362,7 @@
 	return 0;
 }
 
-static int mt312_set_tone(struct dvb_i2c_bus *i2c, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct i2c_adapter *i2c, const fe_sec_tone_mode_t t)
 {
 	const u8 tone_tab[2] = { 0x01, 0x00 };
 
@@ -377,7 +383,7 @@
 	return 0;
 }
 
-static int mt312_set_voltage(struct dvb_i2c_bus *i2c, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct i2c_adapter *i2c, const fe_sec_voltage_t v)
 {
 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
 
@@ -387,8 +393,9 @@
 	return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]);
 }
 
-static int mt312_read_status(struct dvb_i2c_bus *i2c, fe_status_t *s, const long id)
+static int mt312_read_status(struct mt312_state *state, fe_status_t *s)
 {
+	struct i2c_adapter *i2c = state->i2c;
 	int ret;
 	u8 status[3], vit_mode;
 
@@ -409,8 +416,9 @@
 		*s |= FE_HAS_SYNC;	/* byte align lock */
 	if (status[0] & 0x01)
 		*s |= FE_HAS_LOCK;	/* qpsk lock */
+
 	// VP310 doesn't have AUTO, so we "implement it here" ACCJr
-	if ((id == ID_VP310) && !(status[0] & 0x01)) {
+	if ((state->id == ID_VP310) && !(status[0] & 0x01)) {
 		if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
 			return ret;
 		vit_mode ^= 0x40;
@@ -423,7 +431,7 @@
 	return 0;
 }
 
-static int mt312_read_bercnt(struct dvb_i2c_bus *i2c, u32 * ber)
+static int mt312_read_bercnt(struct i2c_adapter *i2c, u32 *ber)
 {
 	int ret;
 	u8 buf[3];
@@ -436,7 +444,7 @@
 	return 0;
 }
 
-static int mt312_read_agc(struct dvb_i2c_bus *i2c, u16 * signal_strength)
+static int mt312_read_agc(struct i2c_adapter *i2c, u16 *signal_strength)
 {
 	int ret;
 	u8 buf[3];
@@ -456,7 +464,7 @@
 	return 0;
 }
 
-static int mt312_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
+static int mt312_read_snr(struct i2c_adapter *i2c, u16 *snr)
 {
 	int ret;
 	u8 buf[2];
@@ -469,7 +477,7 @@
 	return 0;
 }
 
-static int mt312_read_ubc(struct dvb_i2c_bus *i2c, u32 * ubc)
+static int mt312_read_ubc(struct i2c_adapter *i2c, u32 *ubc)
 {
 	int ret;
 	u8 buf[2];
@@ -482,10 +490,10 @@
 	return 0;
 }
 
-static int mt312_set_frontend(struct dvb_i2c_bus *i2c,
-			      const struct dvb_frontend_parameters *p,
-			      const long id)
+static int mt312_set_frontend(struct mt312_state *state,
+			      const struct dvb_frontend_parameters *p)
 {
+	struct i2c_adapter *i2c = state->i2c;
 	int ret;
 	u8 buf[5], config_val;
 	u16 sr;
@@ -494,7 +502,7 @@
 	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
 	const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
 
-	int (*set_tv_freq)(struct dvb_i2c_bus *i2c, u32 freq, u32 sr);
+	int (*set_tv_freq)(struct i2c_adapter *i2c, u32 freq, u32 sr);
 
 	dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
 
@@ -518,7 +526,7 @@
 	    || (p->u.qpsk.fec_inner == FEC_8_9))
 		return -EINVAL;
 
-	switch (id) {
+	switch (state->id) {
 	case ID_VP310:
 	// For now we will do this only for the VP310.
 	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
@@ -527,13 +535,13 @@
 		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
 		{
 			if ((config_val & 0x0c) == 0x08) //We are running 60MHz
-				if ((ret = mt312_init(i2c, id, (u8) 90)) < 0)
+				if ((ret = mt312_initfe(state, (u8) 90)) < 0)
 					return ret;
 		}
 		else
 		{
 			if ((config_val & 0x0c) == 0x0C) //We are running 90MHz
-				if ((ret = mt312_init(i2c, id, (u8) 60)) < 0)
+				if ((ret = mt312_initfe(state, (u8) 60)) < 0)
 					return ret;
 		}
 		set_tv_freq = tsa5059_set_tv_freq;
@@ -575,7 +583,7 @@
 	return 0;
 }
 
-static int mt312_get_inversion(struct dvb_i2c_bus *i2c,
+static int mt312_get_inversion(struct i2c_adapter *i2c,
 			       fe_spectral_inversion_t * i)
 {
 	int ret;
@@ -590,7 +598,7 @@
 	return 0;
 }
 
-static int mt312_get_symbol_rate(struct dvb_i2c_bus *i2c, u32 * sr)
+static int mt312_get_symbol_rate(struct i2c_adapter *i2c, u32 *sr)
 {
 	int ret;
 	u8 sym_rate_h;
@@ -637,7 +645,7 @@
 	return 0;
 }
 
-static int mt312_get_code_rate(struct dvb_i2c_bus *i2c, fe_code_rate_t * cr)
+static int mt312_get_code_rate(struct i2c_adapter *i2c, fe_code_rate_t *cr)
 {
 	const fe_code_rate_t fec_tab[8] =
 	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
@@ -654,7 +662,7 @@
 	return 0;
 }
 
-static int mt312_get_frontend(struct dvb_i2c_bus *i2c,
+static int mt312_get_frontend(struct i2c_adapter *i2c,
 			      struct dvb_frontend_parameters *p)
 {
 	int ret;
@@ -671,7 +679,7 @@
 	return 0;
 }
 
-static int mt312_sleep(struct dvb_i2c_bus *i2c)
+static int mt312_sleep(struct i2c_adapter *i2c)
 {
 	int ret;
 	u8 config;
@@ -692,7 +700,8 @@
 
 static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct mt312_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
 	switch (cmd) {
 	case FE_GET_INFO:
@@ -706,7 +715,7 @@
 		return mt312_send_master_cmd(i2c, arg);
 
 	case FE_DISEQC_RECV_SLAVE_REPLY:
-		if ((long) fe->data == ID_MT312)
+		if (state->id == ID_MT312)
 			return mt312_recv_slave_reply(i2c, arg);
 		else
 			return -EOPNOTSUPP;
@@ -724,7 +733,7 @@
 		return -EOPNOTSUPP;
 
 	case FE_READ_STATUS:
-		return mt312_read_status(i2c, arg, (long) fe->data);
+		return mt312_read_status(state, arg);
 
 	case FE_READ_BER:
 		return mt312_read_bercnt(i2c, arg);
@@ -739,7 +748,7 @@
 		return mt312_read_ubc(i2c, arg);
 
 	case FE_SET_FRONTEND:
-		return mt312_set_frontend(i2c, arg, (long) fe->data);
+		return mt312_set_frontend(state, arg);
 
 	case FE_GET_FRONTEND:
 		return mt312_get_frontend(i2c, arg);
@@ -751,12 +760,14 @@
 		return mt312_sleep(i2c);
 
 	case FE_INIT:
-	//For the VP310 we should run at 60MHz when ever possible.
-	//It should be better to run the mt312 ar lower speed when ever possible, but tunning will be slower. ACCJr 09/29/03
-		if ((long)fe->data == ID_MT312)
-			return mt312_init(i2c, (long) fe->data, (u8) 90);
+		/* For the VP310 we should run at 60MHz when ever possible.
+		 * It should be better to run the mt312 ar lower speed when
+		 * ever possible, but tunning will be slower. ACCJr 09/29/03
+		 */
+		if (state->id == ID_MT312)
+			return mt312_initfe(state, (u8) 90);
 		else
-			return mt312_init(i2c, (long) fe->data, (u8) 60);
+			return mt312_initfe(state, (u8) 60);
 
 	case FE_GET_TUNE_SETTINGS:
 	{
@@ -774,52 +785,123 @@
 	return 0;
 }
 
-static int mt312_attach(struct dvb_i2c_bus *i2c, void **data)
+static struct i2c_client client_template;
+
+static int mt312_attach_adapter(struct i2c_adapter *adapter)
 {
+	struct mt312_state *state;
+	struct i2c_client *client;
 	int ret;
 	u8 id;
 
-	if ((ret = mt312_readreg(i2c, ID, &id)) < 0)
-		return ret;
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		adapter->id, adapter->name);
+
+	if (mt312_readreg(adapter, ID, &id) < 0)
+		return -ENODEV;
 
 	if ((id != ID_VP310) && (id != ID_MT312))
 		return -ENODEV;
 
-	if ((ret = dvb_register_frontend(mt312_ioctl, i2c,
-				(void *)(long)id, &mt312_info)) < 0)
+	if ( !(state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	memset(state, 0, sizeof(struct mt312_state));
+	state->i2c = adapter;
+	state->id = id;
+
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = I2C_ADDR_MT312;
+	i2c_set_clientdata(client, state);
+
+	if ((ret = i2c_attach_client(client))) {
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	if ((ret = dvb_register_frontend(mt312_ioctl, state->dvb, state,
+					     &mt312_info, THIS_MODULE))) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
 		return ret;
+	}
+
+	return 0;
+}
+
+static int mt312_detach_client(struct i2c_client *client)
+{
+	struct mt312_state *state = i2c_get_clientdata(client);
 
-	mt312_count++;
+	dprintk ("%s\n", __FUNCTION__);
 
+	dvb_unregister_frontend_new (mt312_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
 	return 0;
 }
 
-static void mt312_detach(struct dvb_i2c_bus *i2c, void *data)
+static int mt312_command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	dvb_unregister_frontend(mt312_ioctl, i2c);
+	struct mt312_state *state = i2c_get_clientdata(client);
 
-	if (mt312_count)
-		mt312_count--;
+	dprintk ("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_MT312,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = mt312_attach_adapter,
+	.detach_client 	= mt312_detach_client,
+	.command 	= mt312_command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
+
 static int __init mt312_module_init(void)
 {
-	return dvb_register_i2c_device(THIS_MODULE, mt312_attach, mt312_detach);
+	return i2c_add_driver(&driver);
 }
 
 static void __exit mt312_module_exit(void)
 {
-	dvb_unregister_i2c_device(mt312_attach);
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "mt312: driver deregistration failed.\n");
 }
 
 module_init(mt312_module_init);
 module_exit(mt312_module_exit);
 
-#if MT312_DEBUG != 0
-MODULE_PARM(debug,"i");
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#endif
-
 MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");

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

* Re: [PATCH][2.6][8/14] some more frontend drivers to converted to kernel i2c
  2004-09-17 14:32             ` [PATCH][2.6][7/14] convert frontend drivers to kernel i2c 3/3 Michael Hunold
@ 2004-09-17 14:33               ` Michael Hunold
  2004-09-17 14:34                 ` [PATCH][2.6][9/14] add new frontend drivers 1/2 Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:33 UTC (permalink / raw)
  Cc: Linus Torvalds, Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 08-DVB-frontend-conversion4.diff --]
[-- Type: text/plain, Size: 28073 bytes --]

- [DVB] nxt6000, sp887x: convert from dvb-i2c to kernel-i2c, MODULE_PARM() to module_param(), dvb_delay() to mdelay()
- [DVB] sp887x: move from home-brewn firmware loading to firmware_class

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/nxt6000.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/nxt6000.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/nxt6000.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/nxt6000.c	2004-08-18 19:52:17.000000000 +0200
@@ -36,11 +34,11 @@
 #include "dvb_frontend.h"
 #include "nxt6000.h"
 
-static int debug = 0;
-
 MODULE_DESCRIPTION("NxtWave NXT6000 DVB demodulator driver");
 MODULE_AUTHOR("Florian Schirmer");
 MODULE_LICENSE("GPL");
+
+static int debug = 0;
 MODULE_PARM(debug, "i");
 
 static struct dvb_frontend_info nxt6000_info = {
@@ -68,20 +65,21 @@
 	u8 tuner_addr;
 	u8 tuner_type;
 	u8 clock_inversion;
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
 };
 
 #define TUNER_TYPE_ALP510	0
 #define TUNER_TYPE_SP5659	1
 #define TUNER_TYPE_SP5730	2
 
-#define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data))
+// #define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data))
 #define FREQ2DIV(freq) ((freq + 36166667) / 166667)
 
 #define dprintk if (debug) printk
 
-static int nxt6000_write(struct dvb_i2c_bus *i2c, u8 addr, u8 reg, u8 data)
+static int nxt6000_write(struct i2c_adapter *i2c, u8 addr, u8 reg, u8 data)
 {
-
 	u8 buf[] = {reg, data};
 	struct i2c_msg msg = {.addr = addr >> 1, .flags = 0, .buf = buf, .len = 2};
 	int ret;
@@ -86,7 +84,7 @@
 	struct i2c_msg msg = {.addr = addr >> 1, .flags = 0, .buf = buf, .len = 2};
 	int ret;
 	
-	if ((ret = i2c->xfer(i2c, &msg, 1)) != 1)
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
 		dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret);
 
 	return (ret != 1) ? -EFAULT : 0;
@@ -90,21 +88,15 @@
 		dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret);
 
 	return (ret != 1) ? -EFAULT : 0;
-	
 }
 
-static u8 nxt6000_writereg(struct dvb_frontend *fe, u8 reg, u8 data)
+static u8 nxt6000_writereg(struct nxt6000_config *nxt, u8 reg, u8 data)
 {
-
-	struct nxt6000_config *nxt = FE2NXT(fe);
-
-	return nxt6000_write(fe->i2c, nxt->demod_addr, reg, data);
-
+	return nxt6000_write(nxt->i2c, nxt->demod_addr, reg, data);
 }
 
-static u8 nxt6000_read(struct dvb_i2c_bus *i2c, u8 addr, u8 reg)
+static u8 nxt6000_read(struct i2c_adapter *i2c, u8 addr, u8 reg)
 {
-
 	int ret;
 	u8 b0[] = {reg};
 	u8 b1[] = {0};
@@ -113,7 +105,7 @@
 		{.addr = addr >> 1,.flags = I2C_M_RD,.buf = b1,.len = 1}
 	};
 
-	ret = i2c->xfer(i2c, msgs, 2);
+	ret = i2c_transfer(i2c, msgs, 2);
 	
 	if (ret != 2)
 		dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret);
@@ -119,33 +111,28 @@
 		dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret);
 	
 	return b1[0];
-
 }
 
-static u8 nxt6000_readreg(struct dvb_frontend *fe, u8 reg)
+static u8 nxt6000_readreg(struct nxt6000_config *nxt, u8 reg)
 {
-
-	struct nxt6000_config *nxt = FE2NXT(fe);
-
-	return nxt6000_read(fe->i2c, nxt->demod_addr, reg);
+	return nxt6000_read(nxt->i2c, nxt->demod_addr, reg);
 }
 
-static int pll_test(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr)
+static int pll_test(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr)
 {
 	u8 buf [1];
 	struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = I2C_M_RD,.buf = buf,.len = 1 };
 	int ret;
 
 	nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01);	/* open i2c bus switch */
-	ret = i2c->xfer(i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 	nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00);	/* close i2c bus switch */
 
 	return (ret != 1) ? -EFAULT : 0;
 }
 
-static int pll_write(struct dvb_i2c_bus *i2c, u8 demod_addr, u8 tuner_addr, u8 *buf, u8 len)
+static int pll_write(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr, u8 * buf, u8 len)
 {
-
 	struct i2c_msg msg = {.addr = tuner_addr >> 1, .flags = 0, .buf = buf, .len = len};
 	int ret;
 				
@@ -150,7 +137,7 @@
 	int ret;
 				
 	nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01);		/* open i2c bus switch */
-	ret = i2c->xfer(i2c, &msg, 1);
+	ret = i2c_transfer(i2c, &msg, 1);
 	nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00);		/* close i2c bus switch */
 										
 	if (ret != 1)
@@ -157,14 +144,11 @@
 		dprintk("nxt6000: pll_write error %d\n", ret);
 																
 	return (ret != 1) ? -EFAULT : 0;
-
 }
 
-static int sp5659_set_tv_freq(struct dvb_frontend *fe, u32 freq)
+static int sp5659_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
 {
-
 	u8 buf[4];
-	struct nxt6000_config *nxt = FE2NXT(fe);
 
 	buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
 	buf[1] = FREQ2DIV(freq) & 0xFF;
@@ -179,15 +163,12 @@
 	else
 		return -EINVAL;
 
-	return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-	
+	return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
 }
 
-static int alp510_set_tv_freq(struct dvb_frontend *fe, u32 freq)
+static int alp510_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
 {
-
 	u8 buf[4];
-	struct nxt6000_config *nxt = FE2NXT(fe);
 
 	buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
 	buf[1] = FREQ2DIV(freq) & 0xFF;
@@ -217,15 +198,12 @@
 		return -EINVAL;
 #endif
 
-	return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-	
+	return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
 }
 
-static int sp5730_set_tv_freq(struct dvb_frontend *fe, u32 freq)
+static int sp5730_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
 {
-
 	u8 buf[4];
-	struct nxt6000_config *nxt = FE2NXT(fe);
 
 	buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
 	buf[1] = FREQ2DIV(freq) & 0xFF;
@@ -250,13 +228,11 @@
 	else
 		return -EINVAL;
 
-	return pll_write(fe->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-	
+	return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
 }
 
-static void nxt6000_reset(struct dvb_frontend *fe)
+static void nxt6000_reset(struct nxt6000_config *fe)
 {
-
 	u8 val;
 
 	val = nxt6000_readreg(fe, OFDM_COR_CTL);
@@ -263,12 +239,10 @@
 	
 	nxt6000_writereg(fe, OFDM_COR_CTL, val & ~COREACT);
 	nxt6000_writereg(fe, OFDM_COR_CTL, val | COREACT);
-	
 }
 
-static int nxt6000_set_bandwidth(struct dvb_frontend *fe, fe_bandwidth_t bandwidth)
+static int nxt6000_set_bandwidth(struct nxt6000_config *fe, fe_bandwidth_t bandwidth)
 {
-
 	u16 nominal_rate;
 	int result;
 
@@ -302,12 +268,10 @@
 		return result;
 		
 	return nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
-		
 }
 
-static int nxt6000_set_guard_interval(struct dvb_frontend *fe, fe_guard_interval_t guard_interval)
+static int nxt6000_set_guard_interval(struct nxt6000_config *fe, fe_guard_interval_t guard_interval)
 {
-
 	switch(guard_interval) {
 	
 		case GUARD_INTERVAL_1_32:
@@ -328,16 +288,12 @@
 			return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
 			
 		default:
-		
 			return -EINVAL;
-
 	}
-
 }
 
-static int nxt6000_set_inversion(struct dvb_frontend *fe, fe_spectral_inversion_t inversion)
+static int nxt6000_set_inversion(struct nxt6000_config *fe, fe_spectral_inversion_t inversion)
 {
-
 	switch(inversion) {
 	
 		case INVERSION_OFF:
@@ -353,12 +306,10 @@
 			return -EINVAL;	
 	
 	}
-
 }
 
-static int nxt6000_set_transmission_mode(struct dvb_frontend *fe, fe_transmit_mode_t transmission_mode)
+static int nxt6000_set_transmission_mode(struct nxt6000_config *fe, fe_transmit_mode_t transmission_mode)
 {
-
 	int result;
 
 	switch(transmission_mode) {
@@ -383,14 +331,10 @@
 			return -EINVAL;
 	
 	}
-
 }
 
-static void nxt6000_setup(struct dvb_frontend *fe)
+static void nxt6000_setup(struct nxt6000_config *fe)
 {
-
-	struct nxt6000_config *nxt = FE2NXT(fe);
-
 	nxt6000_writereg(fe, RS_COR_SYNC_PARAM, SYNC_PARAM);
 	nxt6000_writereg(fe, BER_CTRL, /*(1 << 2) |*/ (0x01 << 1) | 0x01);
 	nxt6000_writereg(fe, VIT_COR_CTL, VIT_COR_RESYNC);
@@ -409,7 +353,7 @@
 	nxt6000_writereg(fe, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
 	nxt6000_writereg(fe, DIAG_CONFIG, TB_SET);
 	
-	if (nxt->clock_inversion)
+	if (fe->clock_inversion)
 		nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, CLKINVERSION);
 	else
 		nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0);
@@ -415,10 +359,9 @@
 		nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0);
 		
 	nxt6000_writereg(fe, TS_FORMAT, 0);
-
 }
 
-static void nxt6000_dump_status(struct dvb_frontend *fe)
+static void nxt6000_dump_status(struct nxt6000_config *fe)
 {
 	u8 val;
 
@@ -673,13 +567,12 @@
 	val = nxt6000_readreg(fe, RF_AGC_STATUS);
 
 	printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
-
 	printk("\n");
-	
 }
 
-static int nxt6000_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int nxt6000_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg)
 {
+	struct nxt6000_config *fe = (struct nxt6000_config *) f->data;
 
 	switch (cmd) {
 
@@ -769,17 +659,14 @@
 
 		case FE_SET_FRONTEND:
 		{
-			struct nxt6000_config *nxt = FE2NXT(fe);
 			struct dvb_frontend_parameters *param = (struct dvb_frontend_parameters *)arg;
 			int result;
 
-			switch(nxt->tuner_type) {
+			switch (fe->tuner_type) {
 			
 				case TUNER_TYPE_ALP510:
-
 					if ((result = alp510_set_tv_freq(fe, param->frequency)) < 0)
 						return result;
-						
 					break;
 
 				case TUNER_TYPE_SP5659:
@@ -826,42 +705,41 @@
 
 static u8 demod_addr_tbl[] = {0x14, 0x18, 0x24, 0x28};
 
-static int nxt6000_attach(struct dvb_i2c_bus *i2c, void **data)
+static struct i2c_client client_template;
+
+static int attach_adapter(struct i2c_adapter *adapter)
 {
+	struct i2c_client *client;
+	struct nxt6000_config *nxt;
 	u8 addr_nr;
-	u8 fe_count = 0;
-	struct nxt6000_config *pnxt;
-
-	dprintk("nxt6000: attach\n");
+	int ret;
 	
-	pnxt = kmalloc(sizeof(demod_addr_tbl)*sizeof(struct nxt6000_config), GFP_KERNEL);
-	if (NULL == pnxt) {
-		dprintk("nxt6000: no memory for private data.\n");
+	if ((nxt = kmalloc(sizeof(struct nxt6000_config), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
-	}
-	*data = pnxt;
+
+	memset(nxt, 0, sizeof(*nxt));
+	nxt->i2c = adapter;
 
 	for (addr_nr = 0; addr_nr < sizeof(demod_addr_tbl); addr_nr++) {
-		struct nxt6000_config *nxt = &pnxt[addr_nr];
 	
-		if (nxt6000_read(i2c, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE)
+		if (nxt6000_read(adapter, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE)
 			continue;
 
-		if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
+		if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) {
 			nxt->tuner_addr = 0xC0;
 			nxt->tuner_type = TUNER_TYPE_ALP510;
 			nxt->clock_inversion = 1;
 	
 			dprintk("nxt6000: detected TI ALP510 tuner at 0x%02X\n", nxt->tuner_addr);
 		
-		} else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC2) == 0) {
+		} else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC2) == 0) {
 			nxt->tuner_addr = 0xC2;
 			nxt->tuner_type = TUNER_TYPE_SP5659;
 			nxt->clock_inversion = 0;
 
 			dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt->tuner_addr);
 		
-		} else if (pll_test(i2c, demod_addr_tbl[addr_nr], 0xC0) == 0) {
+		} else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) {
 			nxt->tuner_addr = 0xC0;
 			nxt->tuner_type = TUNER_TYPE_SP5730;
 			nxt->clock_inversion = 0;
@@ -872,48 +750,99 @@
 			printk("nxt6000: unable to detect tuner\n");
 			continue;	
 		}
-		
-		nxt->demod_addr = demod_addr_tbl[addr_nr];
-	  
-		dprintk("nxt6000: attached at %d:%d\n", i2c->adapter->num, i2c->id);
-	
-		dvb_register_frontend(nxt6000_ioctl, i2c, (void *)nxt, &nxt6000_info);
-		
-		fe_count++;
 	}
 	
-	if (fe_count == 0) {
-		kfree(pnxt);
+	if (addr_nr == sizeof(demod_addr_tbl)) {
+		kfree(nxt);
 		return -ENODEV;
 	}
 	
-	return 0;
+	nxt->demod_addr = demod_addr_tbl[addr_nr];
+
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(nxt);
+		return -ENOMEM;
 }
 
-static void nxt6000_detach(struct dvb_i2c_bus *i2c, void *data)
-{
-	struct nxt6000_config *pnxt = (struct nxt6000_config *)data;
-	dprintk("nxt6000: detach\n");
-	dvb_unregister_frontend(nxt6000_ioctl, i2c);
-	kfree(pnxt);
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = demod_addr_tbl[addr_nr];
+	i2c_set_clientdata(client, (void *) nxt);
+
+	ret = i2c_attach_client(client);
+	if (ret) 
+		goto out;
+
+	BUG_ON(!nxt->dvb);
+
+	ret = dvb_register_frontend(nxt6000_ioctl, nxt->dvb, nxt, &nxt6000_info, THIS_MODULE);
+	if (ret) {
+		i2c_detach_client(client);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	kfree(client);
+	kfree(nxt);
+	return ret;
+}
+
+static int detach_client(struct i2c_client *client)
+{
+	struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client);
+	dvb_unregister_frontend_new(nxt6000_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
 }
 
-static __init int nxt6000_init(void)
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client);
 
-	dprintk("nxt6000: init\n");
+	switch (cmd) {
+	case FE_REGISTER:{
+			state->dvb = (struct dvb_adapter *) arg;
+			break;
+		}
+	case FE_UNREGISTER:{
+			state->dvb = NULL;
+			break;
+		}
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
 	
-	return dvb_register_i2c_device(THIS_MODULE, nxt6000_attach, nxt6000_detach);
+static struct i2c_driver driver = {
+	.owner = THIS_MODULE,
+	.name = "nxt6000",
+	.id = I2C_DRIVERID_DVBFE_NXT6000,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client = detach_client,
+	.command = command,
+};
 	
+static struct i2c_client client_template = {
+	I2C_DEVNAME("nxt6000"),
+	.flags = I2C_CLIENT_ALLOW_USE,
+	.driver = &driver,
+};
+
+static __init int nxt6000_init(void)
+{
+	return i2c_add_driver(&driver);
 }
 
 static __exit void nxt6000_exit(void)
 {
-
-	dprintk("nxt6000: cleanup\n");
-
-	dvb_unregister_i2c_device(nxt6000_attach);
-
+	if (i2c_del_driver(&driver))
+		printk("nxt6000: driver deregistration failed\n");
 }
 
 module_init(nxt6000_init);
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/sp887x.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/sp887x.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/sp887x.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/sp887x.c	2004-08-22 23:25:49.000000000 +0200
@@ -5,40 +5,36 @@
 /*
    This driver needs a copy of the Avermedia firmware. The version tested
    is part of the Avermedia DVB-T 1.3.26.3 Application. If the software is
-   installed in Windows the file will be in the /Program Files/AVerTV DVB-T/
+   installed in Windoze the file will be in the /Program Files/AVerTV DVB-T/
    directory and is called sc_main.mc. Alternatively it can "extracted" from
-   the install cab files. Copy this file to '/usr/lib/hotplug/firmware/sc_main.mc'.
+   the install cab files.
+   
+   Copy this file to '/usr/lib/hotplug/firmware/dvb-fe-sp887x.fw'.
+   
    With this version of the file the first 10 bytes are discarded and the
    next 0x4000 loaded. This may change in future versions.
  */
+#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/unistd.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
 
-#ifndef DVB_SP887X_FIRMWARE_FILE
-#define DVB_SP887X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/sc_main.mc"
-#endif
+#define FRONTEND_NAME "dvbfe_sp887x"
 
-static char *sp887x_firmware = DVB_SP887X_FIRMWARE_FILE;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
 
-#if 0
-#define dprintk(x...) printk(x)
-#else
-#define dprintk(x...)
-#endif
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 #if 0
 #define LOG(dir,addr,buf,len) 					\
@@ -53,9 +49,7 @@
 #define LOG(dir,addr,buf,len)
 #endif
 
-
-static
-struct dvb_frontend_info sp887x_info = {
+static struct dvb_frontend_info sp887x_info = {
 	.name = "Microtune MT7202DTF",
 	.type = FE_OFDM,
 	.frequency_min =  50500000,
@@ -67,18 +61,19 @@
                 FE_CAN_RECOVER
 };
 
-static int errno;
+struct sp887x_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
-static
-int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
+static int i2c_writebytes (struct i2c_adapter *i2c, u8 addr, u8 *buf, u8 len)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
 	int err;
 
 	LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
 
-	if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+	if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
 		printk ("%s: i2c write error (addr %02x, err == %i)\n",
 			__FUNCTION__, addr, err);
 		return -EREMOTEIO;
@@ -87,19 +82,15 @@
 	return 0;
 }
 
-
-
-static
-int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
+static int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
 	struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
 	int ret;
 
 	LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
 
-	if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) {
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) {
 		/**
 		 *  in case of soft reset we ignore ACK errors...
 		 */
@@ -116,11 +107,8 @@
 	return 0;
 }
 
-
-static
-u16 sp887x_readreg (struct dvb_frontend *fe, u16 reg)
+static u16 sp887x_readreg (struct i2c_adapter *i2c, u16 reg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	u8 b0 [] = { reg >> 8 , reg & 0xff };
 	u8 b1 [2];
 	int ret;
@@ -130,15 +118,13 @@
 	LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
 	LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
 
-	if ((ret = i2c->xfer(i2c, msg, 2)) != 2)
+	if ((ret = i2c_transfer(i2c, msg, 2)) != 2)
 		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
 
 	return (((b1[0] << 8) | b1[1]) & 0xfff);
 }
 
-
-static
-void sp887x_microcontroller_stop (struct dvb_frontend *fe)
+static void sp887x_microcontroller_stop (struct i2c_adapter *fe)
 {
 	dprintk("%s\n", __FUNCTION__);
 	sp887x_writereg(fe, 0xf08, 0x000);
@@ -148,9 +134,7 @@
 	sp887x_writereg(fe, 0xf00, 0x000);
 }
 
-
-static
-void sp887x_microcontroller_start (struct dvb_frontend *fe)
+static void sp887x_microcontroller_start (struct i2c_adapter *fe)
 {
 	dprintk("%s\n", __FUNCTION__);
 	sp887x_writereg(fe, 0xf08, 0x000);
@@ -160,9 +144,7 @@
 	sp887x_writereg(fe, 0xf00, 0x001);
 }
 
-
-static
-void sp887x_setup_agc (struct dvb_frontend *fe)
+static void sp887x_setup_agc (struct i2c_adapter *fe)
 {
 	/* setup AGC parameters */
 	dprintk("%s\n", __FUNCTION__);
@@ -182,72 +164,31 @@
 	sp887x_writereg(fe, 0x303, 0x000);
 }
 
-
 #define BLOCKSIZE 30
-
+#define FW_SIZE 0x4000
 /**
  *  load firmware and setup MPEG interface...
  */
-static
-int sp887x_initial_setup (struct dvb_frontend *fe)
+static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *fw)
 {
 	u8 buf [BLOCKSIZE+2];
-	unsigned char *firmware = NULL;
 	int i;
-	int fd;
-	int filesize;
-	int fw_size;
-	mm_segment_t fs;
+	int fw_size = fw->size;
+	unsigned char *mem = fw->data;
 
 	dprintk("%s\n", __FUNCTION__);
 
+	/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
+	if (fw_size < FW_SIZE+10)
+		return -ENODEV;
+
+	mem = fw->data + 10;
+
 	/* soft reset */
 	sp887x_writereg(fe, 0xf1a, 0x000);
 
 	sp887x_microcontroller_stop (fe);
 
-	fs = get_fs();
-
-	// Load the firmware
-	set_fs(get_ds());
-	fd = sys_open(sp887x_firmware, 0, 0);
-	if (fd < 0) {
-		printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
-		       sp887x_firmware);
-		return -EIO;
-	}
-	filesize = sys_lseek(fd, 0L, 2);
-	if (filesize <= 0) {
-		printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
-		       sp887x_firmware);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	fw_size = 0x4000;
-
-	// allocate buffer for it
-	firmware = vmalloc(fw_size);
-	if (firmware == NULL) {
-		printk(KERN_WARNING "%s: Out of memory loading firmware\n",
-		       __FUNCTION__);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	// read it!
-	// read the first 16384 bytes from the file
-	// ignore the first 10 bytes
-	sys_lseek(fd, 10, 0);
-	if (sys_read(fd, firmware, fw_size) != fw_size) {
-		printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
-		vfree(firmware);
-		sys_close(fd);
-		return -EIO;
-	}
-	sys_close(fd);
-	set_fs(fs);
-
 	printk ("%s: firmware upload... ", __FUNCTION__);
 
 	/* setup write pointer to -1 (end of memory) */
@@ -257,7 +198,7 @@
 	/* dummy write (wrap around to start of memory) */
 	sp887x_writereg(fe, 0x8f0a, 0x0000);
 
-	for (i=0; i<fw_size; i+=BLOCKSIZE) {
+	for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
 		int c = BLOCKSIZE;
 		int err;
 
@@ -270,18 +211,15 @@
 		buf[0] = 0xcf;
 		buf[1] = 0x0a;
 
-		memcpy(&buf[2], firmware + i, c);
+		memcpy(&buf[2], mem + i, c);
 
 		if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
 			printk ("failed.\n");
 			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
-			vfree(firmware);
 			return err;
 		}
 	}
 
-	vfree(firmware);
-
 	/* don't write RS bytes between packets */
 	sp887x_writereg(fe, 0xc13, 0x001);
 
@@ -312,8 +249,7 @@
  *  returns the actual tuned center frequency which can be used
  *  to initialise the AFC registers
  */
-static
-int tsa5060_setup_pll (struct dvb_frontend *fe, int freq)
+static int tsa5060_setup_pll (struct i2c_adapter *fe, int freq)
 {
 	u8 cfg, cpump, band_select;
 	u8 buf [4];
@@ -340,10 +276,7 @@
 	return (div * 166666 - 36000000);
 }
 
-
-
-static
-int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
 {
 	int known_parameters = 1;
 	
@@ -419,8 +351,7 @@
  *  estimates division of two 24bit numbers,
  *  derived from the ves1820/stv0299 driver code
  */
-static
-void divide (int n, int d, int *quotient_i, int *quotient_f)
+static void divide (int n, int d, int *quotient_i, int *quotient_f)
 {
 	unsigned int q, r;
 
@@ -438,9 +369,7 @@
 	}
 }
 
-
-static
-void sp887x_correct_offsets (struct dvb_frontend *fe,
+static void sp887x_correct_offsets (struct i2c_adapter *fe,
 			     struct dvb_frontend_parameters *p,
 			     int actual_freq)
 {
@@ -471,9 +400,7 @@
 	sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
 }
 
-
-static
-int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
+static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe,
 				      struct dvb_frontend_parameters *p)
 {
 	int actual_freq, err;
@@ -531,10 +458,11 @@
 	return 0;
 }
 
-
-static
-int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int sp887x_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg)
 {
+	struct sp887x_state *state = (struct sp887x_state *) f->data;
+	struct i2c_adapter *fe = state->i2c;
+
         switch (cmd) {
         case FE_GET_INFO:
 		memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
@@ -624,10 +552,6 @@
 		break;
 
         case FE_INIT:
-		if (fe->data == NULL) {	  /* first time initialisation... */
-			fe->data = (void*) ~0;
-			sp887x_initial_setup (fe);
-		}
 		/* enable TS output and interface pins */
 		sp887x_writereg(fe, 0xc18, 0x00d);
 		break;
@@ -635,9 +559,9 @@
 	case FE_GET_TUNE_SETTINGS:
 	{
 	        struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
-	        fesettings->min_delay_ms = 50;
-	        fesettings->step_size = 0;
-	        fesettings->max_drift = 0;
+	        fesettings->min_delay_ms = 350;
+	        fesettings->step_size = 166666*2;
+	        fesettings->max_drift = (166666*2)+1;
 	        return 0;
 	}	    
 
@@ -648,45 +572,135 @@
         return 0;
 }
 
+static struct i2c_client client_template;
 
-
-static
-int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter(struct i2c_adapter *adapter)
 {
+	struct i2c_client *client;
+	struct sp887x_state *state;
+	const struct firmware *fw;
+	int ret;
+
 	struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (i2c->xfer (i2c, &msg, 1) != 1)
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	if (NULL == (state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL))) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->i2c = adapter;
+
+	if (i2c_transfer (adapter, &msg, 1) != 1) {
+		kfree(state);
+		kfree(client);
                 return -ENODEV;
+	}
 
-	return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	i2c_set_clientdata(client, (void*)state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(client);
+		kfree(state);
+		return ret;
 }
 
+	/* request the firmware, this will block until someone uploads it */
+	printk("sp887x: waiting for firmware upload...\n");
+	ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev);
+	if (ret) {
+		printk("sp887x: no firmware upload (timeout or file not found?)\n");
+		goto out;
+	}
+
+	ret = sp887x_initial_setup(adapter, fw);
+	if (ret) {
+		printk("sp887x: writing firmware to device failed\n");
+		goto out;
+	}
+
+	ret = dvb_register_frontend(sp887x_ioctl, state->dvb, state,
+					&sp887x_info, THIS_MODULE);
+	if (ret) {
+		printk("sp887x: registering frontend to dvb-core failed.\n");
+		goto out;
+	}
 
-static
-void sp887x_detach (struct dvb_i2c_bus *i2c, void *data)
+	return 0;
+out:
+	release_firmware(fw);
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+	return ret;
+}
+
+static int detach_client(struct i2c_client *client)
 {
+	struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
-	dvb_unregister_frontend (sp887x_ioctl, i2c);
-}
 
+	dvb_unregister_frontend_new (sp887x_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
 
-static
-int __init init_sp887x (void)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
-	return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = (struct dvb_adapter*)arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_SP887X,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client 	= detach_client,
+	.command 	= command,
+};
 
-static
-void __exit exit_sp887x (void)
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
+
+static int __init init_sp887x(void)
 {
-	dprintk ("%s\n", __FUNCTION__);
-	dvb_unregister_i2c_device (sp887x_attach);
+	return i2c_add_driver(&driver);
 }
 
+static void __exit exit_sp887x(void)
+{
+	if (i2c_del_driver(&driver))
+		printk("sp887x: driver deregistration failed\n");
+}
 
 module_init(init_sp887x);
 module_exit(exit_sp887x);

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

* Re: [PATCH][2.6][9/14] add new frontend drivers 1/2
  2004-09-17 14:33               ` [PATCH][2.6][8/14] some more frontend drivers to converted to kernel i2c Michael Hunold
@ 2004-09-17 14:34                 ` Michael Hunold
  2004-09-17 14:36                   ` [PATCH][2.6][10/14] add new frontend drivers 2/2 Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 09-DVB-add-frontend-1-2.diff --]
[-- Type: text/plain, Size: 53992 bytes --]

- [DVB] add new driver for Zarlink DVB-T MT352 frontend
- [DVB] add new driver for Conexant 22702 DVB OFDM frontend 

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/Makefile linux-2.6.8.1-patched/drivers/media/dvb/frontends/Makefile
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/Makefile	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/Makefile	2004-03-05 17:43:49.000000000 +0100
@@ -18,3 +18,5 @@
 obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
+obj-$(CONFIG_DVB_MT352) += mt352.o
+
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt352.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.c
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt352.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.c	2004-08-18 19:52:17.000000000 +0200
@@ -0,0 +1,901 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *	 and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "mt352.h"
+
+#define FRONTEND_NAME "dvbfe_mt352"
+
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
+	} while (0)
+
+static int debug;
+static int force_card = -1;
+static int card_type = -1;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+//FIXME: Should be an array.
+module_param(force_card, int, 0444);
+MODULE_PARM_DESC(force_card, "Force card type.\n\t(0 == AVDVBT771, 1 == TUA6034, "
+		 "2 == TDTC9251DH01C).\n\tDefault is that AVDVBT771 is attempted "
+		 "to be autodetected,\n\tif you do not have this card, you must "
+		 "specify the card type here.");
+
+
+struct mt352_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
+
+#define mt352_write(ibuf, ilen)						\
+do {									\
+	struct i2c_msg msg = { .addr = I2C_MT352_ADDR, .flags = 0,	\
+			       .buf = ibuf, .len = ilen };		\
+	int err = i2c_transfer(i2c, &msg, 1);				\
+	if (err != 1) {							\
+		printk(KERN_WARNING					\
+		       "mt352_write() failed (err = %d)!\n", err);	\
+		return err;						\
+	}								\
+} while (0)
+
+// FIXME:
+static struct _tuner_info tuner_info [] = {
+	//AVERMEDIA 771 board
+	{
+	  .fe_frequency_min = 174000000,
+	  .fe_frequency_max = 862000000,
+	  .fe_frequency_stepsize = 83333,
+	  .coderate_hp_shift = 7,
+	  .coderate_lp_shift = 4,
+	  .constellation_shift = 13,
+	  .tx_mode_shift = 0,
+	  .guard_interval_shift = 2,
+	  .hierarchy_shift = 10,
+	  .read_reg_flag = I2C_M_NOSTART,
+	  .mt352_init = mt352_init_AVERMEDIA771,
+	  .mt352_charge_pump = mt352_cp_AVERMEDIA771,
+	  .mt352_band_select = mt352_bs_AVERMEDIA771
+	},
+	//TUA6034 tuner
+	{
+	  .fe_frequency_min = 174000000,
+	  .fe_frequency_max = 862000000,
+	  .fe_frequency_stepsize = 166667,
+	  .coderate_hp_shift = 9,
+	  .coderate_lp_shift = 6,
+	  .constellation_shift = 14,
+	  .tx_mode_shift = 1,
+	  .guard_interval_shift = 3,
+	  .hierarchy_shift = 12,
+	  .read_reg_flag = I2C_M_NOSTART,
+	  .mt352_init = mt352_init_TUA6034,
+	  .mt352_charge_pump = mt352_cp_TUA6034,
+	  .mt352_band_select = mt352_bs_TUA6034
+	},
+	//TDTC9251DH01C tuner
+	{
+	  .fe_frequency_min = 474000000,
+	  .fe_frequency_max = 858000000,
+	  .fe_frequency_stepsize = 166667,
+	  .coderate_hp_shift = 9,
+	  .coderate_lp_shift = 6,
+	  .constellation_shift = 4,
+	  .tx_mode_shift = 1,
+	  .guard_interval_shift = 3,
+	  .hierarchy_shift = 12,
+	  .read_reg_flag = 0,
+	  .mt352_init = mt352_init_TDTC9251DH01C,
+	  .mt352_charge_pump = mt352_cp_TDTC9251DH01C,
+	  .mt352_band_select = mt352_bs_TDTC9251DH01C
+	}
+};
+
+
+static struct dvb_frontend_info mt352_info = {
+	.name			= "DVB-T Zarlink MT352 demodulator driver",
+	.type			= FE_OFDM,
+/*
+	.frequency_min		= 0,
+	.frequency_max		= 0,
+	.frequency_stepsize	= 0,
+	.frequency_tolerance	= 0,
+	.symbol_rate_min	= 1000000,
+	.symbol_rate_max	= 45000000,
+	.symbol_rate_tolerance	= ???,
+*/
+	.notifier_delay		 = 0,
+	.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+		FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+		FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+		FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+		FE_CAN_MUTE_TS
+};
+
+static int mt352_init_TUA6034(struct i2c_adapter *i2c)
+{
+	static u8 mt352_reset [] = { RESET, 0x80 };
+	static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+	static u8 mt352_adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+	static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x19, 0xa0 };
+	static u8 mt352_acq_ctl [] = { ACQ_CTL, 0x50 };
+
+	mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(mt352_reset, sizeof(mt352_reset));
+	mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(mt352_acq_ctl, sizeof(mt352_acq_ctl));
+
+	mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+	return 0;
+}
+
+static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c)
+{
+	static u8 mt352_reset [] = { RESET, 0x80 };
+	static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+	static u8 mt352_adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+	static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+				       0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 mt352_acq_ctl [] = { ACQ_CTL, 0x50 };
+	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
+
+	mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(mt352_reset, sizeof(mt352_reset));
+	mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(mt352_acq_ctl, sizeof(mt352_acq_ctl));
+
+	mt352_write(mt352_agc_cfg,sizeof(mt352_agc_cfg));
+	udelay(2000);
+	mt352_write(mt352_av771_extra,sizeof(mt352_av771_extra));
+
+	return 0;
+}
+
+static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c)
+{
+	static u8 mt352_reset [] = { RESET, 0x80 };
+	static u8 mt352_clock_config [] = { CLOCK_CTL, 0x10, 0x2d };
+	static u8 mt352_adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+	static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x28, 0xa1 };
+	static u8 mt352_acq_ctl [] = { ACQ_CTL, 0x50 };
+
+	mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(mt352_reset, sizeof(mt352_reset));
+	mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(mt352_acq_ctl, sizeof(mt352_acq_ctl));
+
+	mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+	return 0;
+}
+
+static unsigned char mt352_cp_TUA6034(u32 freq)
+{
+	unsigned char cp = 0;
+
+	if (freq < 542)
+		cp = 0xbe;
+	else if (freq < 830)
+		cp = 0xf6;
+	else
+		cp = 0xfe;
+
+	return cp;
+}
+
+static unsigned char mt352_cp_AVERMEDIA771(u32 freq)
+{
+	unsigned char cp = 0;
+
+	if (freq < 150)
+		cp = 0xB4;
+	else if (freq < 173)
+		cp = 0xBC;
+	else if (freq < 250)
+		cp = 0xB4;
+	else if (freq < 400)
+		cp = 0xBC;
+	else if (freq < 420)
+		cp = 0xF4;
+	else if (freq < 470)
+		cp = 0xFC;
+	else if (freq < 600)
+		cp = 0xBC;
+	else if (freq < 730)
+		cp = 0xF4;
+	else
+		cp = 0xFC;
+
+	return cp;
+}
+
+static unsigned char mt352_cp_TDTC9251DH01C(u32 freq)
+{
+	return(0xcc);
+}
+
+static unsigned char mt352_bs_TUA6034(u32 freq)
+{
+	unsigned char bs = 0;
+
+	if (freq < 250)
+		bs = 0x01;
+	else
+		bs = 0x08;
+
+	return bs;
+}
+
+static unsigned char mt352_bs_AVERMEDIA771(u32 freq)
+{
+	unsigned char bs = 0;
+
+	if (freq < 150)
+		bs = 0x01;
+	else if (freq < 173)
+		bs = 0x01;
+	else if (freq < 250)
+		bs = 0x02;
+	else if (freq < 400)
+		bs = 0x02;
+	else if (freq < 420)
+		bs = 0x02;
+	else if (freq < 470)
+		bs = 0x02;
+	else if (freq < 600)
+		bs = 0x08;
+	else if (freq < 730)
+		bs = 0x08;
+	else
+		bs = 0x08;
+
+	return bs;
+}
+
+static unsigned char mt352_bs_TDTC9251DH01C(u32 freq)
+{
+	unsigned char bs = 0;
+
+	if ((freq >= 48) && (freq <= 154))      /* low band */
+		bs = 0x09;
+
+	if ((freq >= 161) && (freq <= 439))     /* medium band */
+		bs = 0x0a;
+
+	if ((freq >= 447) && (freq <= 863))     /* high band */
+		bs = 0x08;
+
+	return bs;
+}
+
+
+static int mt352_detect_avermedia_771(struct i2c_adapter *i2c)
+{
+	int i;
+	u8 reg;
+	u8 id[4];
+	const u8 pciid[4] = { 0x07, 0x71, 0x14, 0x61 };
+	struct i2c_msg msg[2] =
+	{
+		{
+			.addr = 0x50,
+			.flags = I2C_M_NOSTART,
+			.buf = &reg,
+			.len = 1
+		},
+		{
+			.addr = 0x50,
+			.flags = I2C_M_RD,
+			.len = 1
+		}
+	};
+
+	for (i = 0; i < 4; i++)
+	{
+		reg = i + 0xFC;
+		msg[1].buf = id + i;
+		if (i2c_transfer(i2c,msg,2) != 2)
+		{
+			return 0;
+		}
+	}
+
+	return *((u32 *) id) == *((u32 *) pciid);
+}
+
+static int mt352_init(struct i2c_adapter *i2c)
+{
+	/**
+	 *  all register write sequence have the register address of the
+	 *  first register in the first byte, thenafter the value to write
+	 *  into this and the following registers.
+	 *
+	 *
+	 *  We only write non-default settings, all default settings are
+	 *  restored by the full mt352_reset sequence.
+	 *
+	 *
+	 *  The optimal AGC target value and slope might vary from tuner
+	 *  type to tuner type, so check whether you need to adjust this one...
+	 **/
+
+	return(MT352_INIT(i2c));
+}
+
+static int mt352_sleep(struct i2c_adapter *i2c)
+{
+	static u8 mt352_softdown[] = { 0x89, 0x20, 0x08 };
+
+	mt352_write(mt352_softdown, sizeof(mt352_softdown));
+
+	return 0;
+}
+
+static int mt352_set_parameters(struct i2c_adapter *i2c,
+				struct dvb_frontend_parameters *param)
+{
+	unsigned char buf[14];
+	unsigned int tps = 0;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+	u32 freq = param->frequency / 1000000;
+	uint16_t tmp;
+
+	switch (op->code_rate_HP) {
+		case FEC_2_3:
+			tps |= (1 << CODERATE_HP_SHIFT);
+			break;
+		case FEC_3_4:
+			tps |= (2 << CODERATE_HP_SHIFT);
+			break;
+		case FEC_5_6:
+			tps |= (3 << CODERATE_HP_SHIFT);
+			break;
+		case FEC_7_8:
+			tps |= (4 << CODERATE_HP_SHIFT);
+			break;
+		case FEC_1_2:
+		case FEC_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->code_rate_LP) {
+		case FEC_2_3:
+			tps |= (1 <<  CODERATE_LP_SHIFT);
+			break;
+		case FEC_3_4:
+			tps |= (2 <<  CODERATE_LP_SHIFT);
+			break;
+		case FEC_5_6:
+			tps |= (3 <<  CODERATE_LP_SHIFT);
+			break;
+		case FEC_7_8:
+			tps |= (4 <<  CODERATE_LP_SHIFT);
+			break;
+		case FEC_1_2:
+		case FEC_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->constellation) {
+		case QPSK:
+			break;
+		case QAM_AUTO:
+		case QAM_16:
+			tps |= (1 << CONSTELLATION_SHIFT);
+			break;
+		case QAM_64:
+			tps |= (2 << CONSTELLATION_SHIFT);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+		case TRANSMISSION_MODE_AUTO:
+			break;
+		case TRANSMISSION_MODE_8K:
+			tps |= (1 << TX_MODE_SHIFT);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->guard_interval) {
+		case GUARD_INTERVAL_1_32:
+		case GUARD_INTERVAL_AUTO:
+			break;
+		case GUARD_INTERVAL_1_16:
+			tps |= (1 << GUARD_INTERVAL_SHIFT);
+			break;
+		case GUARD_INTERVAL_1_8:
+			tps |= (2 << GUARD_INTERVAL_SHIFT);
+			break;
+		case GUARD_INTERVAL_1_4:
+			tps |= (3 << GUARD_INTERVAL_SHIFT);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (op->hierarchy_information) {
+		case HIERARCHY_AUTO:
+		case HIERARCHY_NONE:
+			break;
+		case HIERARCHY_1:
+			tps |= (1 << HIERARCHY_SHIFT);
+			break;
+		case HIERARCHY_2:
+			tps |= (2 << HIERARCHY_SHIFT);
+			break;
+		case HIERARCHY_4:
+			tps |= (3 << HIERARCHY_SHIFT);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+
+	buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */
+
+	buf[1] = msb(tps);      /* TPS_GIVEN_(1|0) */
+	buf[2] = lsb(tps);
+
+	buf[3] = 0x50;
+
+	/**
+	 *  these settings assume 20.48MHz f_ADC, for other tuners you might
+	 *  need other values. See p. 33 in the MT352 Design Manual.
+	 */
+	if (op->bandwidth == BANDWIDTH_8_MHZ) {
+		buf[4] = 0x72;  /* TRL_NOMINAL_RATE_(1|0) */
+		buf[5] = 0x49;
+	} else if (op->bandwidth == BANDWIDTH_7_MHZ) {
+		buf[4] = 0x64;
+		buf[5] = 0x00;
+	} else {		/* 6MHz */
+		buf[4] = 0x55;
+		buf[5] = 0xb7;
+	}
+
+	buf[6] = 0x31;  /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */
+	buf[7] = 0x05;  /* see MT352 Design Manual page 32 for details */
+
+	buf[8] = I2C_TUNER_ADDR;
+
+	/**
+	 *  All the following settings are tuner module dependent,
+	 *  check the datasheet...
+	 */
+
+	/* here we assume 1/6MHz == 166.66kHz stepsize */
+	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+	tmp = ((param->frequency*3)/500000) + IF_FREQUENCYx6;
+
+	buf[9] = msb(tmp);      /* CHAN_START_(1|0) */
+	buf[10] = lsb(tmp);
+
+	buf[11] = MT352_CHARGE_PUMP(freq);
+	buf[12] = MT352_BAND_SELECT(freq);
+
+	buf[13] = 0x01; /* TUNER_GO!! */
+
+	mt352_write(buf, sizeof(buf));
+
+	return 0;
+}
+
+static u8 mt352_read_register(struct i2c_adapter *i2c, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = I2C_MT352_ADDR,
+				    .flags =  READ_REG_FLAG,
+				    .buf = b0, .len = 1 },
+				  { .addr = I2C_MT352_ADDR,
+				    .flags = I2C_M_RD,
+				    .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_WARNING
+		       "%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+	return b1[0];
+}
+
+
+static int mt352_get_parameters(struct i2c_adapter *i2c,
+				struct dvb_frontend_parameters *param)
+{
+	u16 tps;
+	u16 div;
+	u8 trl;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+	static const u8 tps_fec_to_api[8] =
+	{
+		FEC_1_2,
+		FEC_2_3,
+		FEC_3_4,
+		FEC_5_6,
+		FEC_7_8,
+		FEC_AUTO,
+		FEC_AUTO,
+		FEC_AUTO
+	};
+
+	if ( (mt352_read_register(i2c,0x00) & 0xC0) != 0xC0 )
+	{
+		return -EINVAL;
+	}
+
+	/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
+	 * the mt352 sometimes works with the wrong parameters
+	 */
+	tps = (mt352_read_register(i2c,	TPS_RECEIVED_1) << 8) | mt352_read_register(i2c, TPS_RECEIVED_0);
+	div = (mt352_read_register(i2c, CHAN_START_1) << 8) | mt352_read_register(i2c, CHAN_START_0);
+	trl = mt352_read_register(i2c, TRL_NOMINAL_RATE_1);
+
+	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+	switch ( (tps >> 13) & 3)
+	{
+		case 0:
+			op->constellation = QPSK;
+			break;
+		case 1:
+			op->constellation = QAM_16;
+			break;
+		case 2:
+			op->constellation = QAM_64;
+			break;
+		default:
+			op->constellation = QAM_AUTO;
+			break;
+	}
+
+	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K;
+
+	switch ( (tps >> 2) & 3)
+	{
+		case 0:
+			op->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case 1:
+			op->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case 2:
+			op->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case 3:
+			op->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			op->guard_interval = GUARD_INTERVAL_AUTO;
+			break;
+	}
+
+	switch ( (tps >> 10) & 7)
+	{
+		case 0:
+			op->hierarchy_information = HIERARCHY_NONE;
+			break;
+		case 1:
+			op->hierarchy_information = HIERARCHY_1;
+			break;
+		case 2:
+			op->hierarchy_information = HIERARCHY_2;
+			break;
+		case 3:
+			op->hierarchy_information = HIERARCHY_4;
+			break;
+		default:
+			op->hierarchy_information = HIERARCHY_AUTO;
+			break;
+	}
+
+	param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
+
+	if (trl == 0x72)
+	{
+		op->bandwidth = BANDWIDTH_8_MHZ;
+	}
+	else if (trl == 0x64)
+	{
+		op->bandwidth = BANDWIDTH_7_MHZ;
+	}
+	else
+	{
+		op->bandwidth = BANDWIDTH_6_MHZ;
+	}
+
+
+	if (mt352_read_register(i2c, STATUS_2) & 0x02)
+		param->inversion = INVERSION_OFF;
+	else
+		param->inversion = INVERSION_ON;
+
+	return 0;
+}
+
+
+static int mt352_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct mt352_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
+	u8 r,snr;
+	fe_status_t *status;
+	u16 signal;
+	struct dvb_frontend_tune_settings *fe_tune_settings;
+
+	switch (cmd) {
+	case FE_GET_INFO:
+		memcpy (arg, &mt352_info, sizeof(struct dvb_frontend_info));
+		break;
+
+	case FE_READ_STATUS:
+		status = arg;
+		*status = 0;
+		r = mt352_read_register (i2c, STATUS_0);
+		if (r & (1 << 4))
+			*status = FE_HAS_CARRIER;
+		if (r & (1 << 1))
+			*status |= FE_HAS_VITERBI;
+		if (r & (1 << 5))
+			*status |= FE_HAS_LOCK;
+
+		r = mt352_read_register (i2c, STATUS_1);
+		if (r & (1 << 1))
+			*status |= FE_HAS_SYNC;
+
+		r = mt352_read_register (i2c, STATUS_3);
+		if (r & (1 << 6))
+			*status |= FE_HAS_SIGNAL;
+
+		break;
+
+	case FE_READ_BER:
+		*((u32 *) arg) = (mt352_read_register (i2c, RS_ERR_CNT_2) << 16) |
+		       (mt352_read_register (i2c, RS_ERR_CNT_1) << 8) |
+		       (mt352_read_register (i2c, RS_ERR_CNT_0));
+		break;
+
+	case FE_READ_SIGNAL_STRENGTH:
+		signal = (mt352_read_register (i2c, AGC_GAIN_3) << 8) |
+			     (mt352_read_register (i2c, AGC_GAIN_2));
+		*((u16*) arg) = ~signal;
+		break;
+
+	case FE_READ_SNR:
+		snr = mt352_read_register (i2c, SNR);
+		*((u16*) arg) = (snr << 8) | snr;
+		break;
+
+	case FE_READ_UNCORRECTED_BLOCKS:
+		*(u32*) arg = (mt352_read_register (i2c,  RS_UBC_1) << 8) |
+			      (mt352_read_register (i2c,  RS_UBC_0));
+		break;
+
+	case FE_SET_FRONTEND:
+		return mt352_set_parameters (i2c,
+				 (struct dvb_frontend_parameters *) arg);
+
+	case FE_GET_FRONTEND:
+		return mt352_get_parameters (i2c,
+				 (struct dvb_frontend_parameters *) arg);
+
+	case FE_GET_TUNE_SETTINGS:
+		fe_tune_settings = (struct dvb_frontend_tune_settings *) arg;
+		fe_tune_settings->min_delay_ms = 800;
+		fe_tune_settings->step_size = 0;
+		fe_tune_settings->max_drift = 0;
+		break;
+
+	case FE_SLEEP:
+		return mt352_sleep(i2c);
+
+	case FE_INIT:
+		return mt352_init(i2c);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct i2c_client client_template;
+
+static int mt352_attach_adapter(struct i2c_adapter *i2c)
+{
+	struct mt352_state *state;
+	struct i2c_client *client;
+	static u8 mt352_reset_attach [] = { 0x50, 0xC0 };
+	int ret;
+
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		i2c->id, i2c->name);
+
+	/* set the proper MT352 frequency range */
+	mt352_info.frequency_min =  FE_FREQ_MIN;
+	mt352_info.frequency_max =  FE_FREQ_MAX;
+	mt352_info.frequency_stepsize =  FE_FREQ_STEPSIZE;
+
+	if ( !(state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	memset(state, 0, sizeof(struct mt352_state));
+	state->i2c = i2c;
+
+	if (mt352_detect_avermedia_771(i2c)) {
+		card_type = CARD_AVDVBT771;
+	} else if (force_card < 0) {
+		dprintk("Avermedia 771 not detected, maybe you should try the "
+			"'force_card' module parameter?.\n");
+		kfree(state);
+		return -ENODEV;
+	}
+
+	if (force_card > 0) {
+		if (card_type >= 0 && force_card != card_type)
+			printk(KERN_WARNING "dvbfe_mt352: Warning, overriding"
+					    " detected card.\n");
+		card_type = force_card;
+	}
+
+	if (mt352_read_register(i2c, CHIP_ID) != ID_MT352) {
+		kfree(state);
+		return -ENODEV;
+	}
+
+	if (card_type == CARD_AVDVBT771)
+		printk(KERN_INFO FRONTEND_NAME ": Setup for Avermedia 771.\n");
+	else if (card_type == CARD_TUA6034)
+		printk(KERN_INFO FRONTEND_NAME ": Setup for TUA6034.\n");
+	else if (card_type == CARD_TDTC9251DH01C)
+		printk(KERN_INFO FRONTEND_NAME ": Setup for TDTC9251DH01C.\n");
+
+	/* Do a "hard" reset */
+	mt352_write(mt352_reset_attach, sizeof(mt352_reset_attach));
+
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = i2c;
+	client->addr = 0; // XXX
+	i2c_set_clientdata(client, state);
+
+	if ((ret = i2c_attach_client(client))) {
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	if ((ret = dvb_register_frontend(mt352_ioctl, state->dvb, state,
+					     &mt352_info, THIS_MODULE))) {
+		i2c_detach_client(client);
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt352_detach_client(struct i2c_client *client)
+{
+	struct mt352_state *state = i2c_get_clientdata(client);
+
+	dvb_unregister_frontend_new (mt352_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
+
+static int mt352_command (struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct mt352_state *state = i2c_get_clientdata(client);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner 		= THIS_MODULE,
+	.name 		= FRONTEND_NAME,
+	.id 		= I2C_DRIVERID_DVBFE_MT352,
+	.flags 		= I2C_DF_NOTIFY,
+	.attach_adapter = mt352_attach_adapter,
+	.detach_client 	= mt352_detach_client,
+	.command 	= mt352_command,
+};
+
+static struct i2c_client client_template = {
+	.name		= FRONTEND_NAME,
+	.flags 		= I2C_CLIENT_ALLOW_USE,
+	.driver  	= &driver,
+};
+
+static int __init mt352_module_init(void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit mt352_module_exit(void)
+{
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "mt352: driver deregistration failed.\n");
+}
+
+module_init(mt352_module_init);
+module_exit(mt352_module_exit);
+
+MODULE_DESCRIPTION("DVB-T MT352 Zarlink");
+MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
+MODULE_LICENSE("GPL");
+
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt352.h linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.h
--- xx-linux-2.6.8.1/drivers/media/dvb/frontends/mt352.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.h	2004-07-16 20:20:10.000000000 +0200
@@ -0,0 +1,177 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *	 and Daniel Mack <daniel@qanu.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef _MT352_
+#define _MT352_
+
+#define I2C_MT352_ADDR  0x0f
+#define I2C_TUNER_ADDR  0xc2
+#define ID_MT352        0x13
+
+#define CARD_AVDVBT771	    0x00
+#define CARD_TUA6034	    0x01
+#define CARD_TDTC9251DH01C  0x02
+
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
+enum mt352_reg_addr {
+	STATUS_0           = 0x00,
+	STATUS_1           = 0x01,
+	STATUS_2           = 0x02,
+	STATUS_3           = 0x03,
+	STATUS_4           = 0x04,
+	INTERRUPT_0        = 0x05,
+	INTERRUPT_1        = 0x06,
+	INTERRUPT_2        = 0x07,
+	INTERRUPT_3        = 0x08,
+	SNR                = 0x09,
+	VIT_ERR_CNT_2      = 0x0A,
+	VIT_ERR_CNT_1      = 0x0B,
+	VIT_ERR_CNT_0      = 0x0C,
+	RS_ERR_CNT_2       = 0x0D,
+	RS_ERR_CNT_1       = 0x0E,
+	RS_ERR_CNT_0       = 0x0F,
+	RS_UBC_1           = 0x10,
+	RS_UBC_0           = 0x11,
+	AGC_GAIN_3         = 0x12,
+	AGC_GAIN_2         = 0x13,
+	AGC_GAIN_1         = 0x14,
+	AGC_GAIN_0         = 0x15,
+	FREQ_OFFSET_2      = 0x17,
+	FREQ_OFFSET_1      = 0x18,
+	FREQ_OFFSET_0      = 0x19,
+	TIMING_OFFSET_1    = 0x1A,
+	TIMING_OFFSET_0    = 0x1B,
+	CHAN_FREQ_1        = 0x1C,
+	CHAN_FREQ_0        = 0x1D,
+	TPS_RECEIVED_1     = 0x1E,
+	TPS_RECEIVED_0     = 0x1F,
+	TPS_CURRENT_1      = 0x20,
+	TPS_CURRENT_0      = 0x21,
+	TPS_CELL_ID_1      = 0x22,
+	TPS_CELL_ID_0      = 0x23,
+	TPS_MISC_DATA_2    = 0x24,
+	TPS_MISC_DATA_1    = 0x25,
+	TPS_MISC_DATA_0    = 0x26,
+	RESET              = 0x50,
+	TPS_GIVEN_1        = 0x51,
+	TPS_GIVEN_0        = 0x52,
+	ACQ_CTL            = 0x53,
+	TRL_NOMINAL_RATE_1 = 0x54,
+	TRL_NOMINAL_RATE_0 = 0x55,
+	INPUT_FREQ_1       = 0x56,
+	INPUT_FREQ_0       = 0x57,
+	TUNER_ADDR         = 0x58,
+	CHAN_START_1       = 0x59,
+	CHAN_START_0       = 0x5A,
+	CONT_1             = 0x5B,
+	CONT_0             = 0x5C,
+	TUNER_GO           = 0x5D,
+	STATUS_EN_0        = 0x5F,
+	STATUS_EN_1        = 0x60,
+	INTERRUPT_EN_0     = 0x61,
+	INTERRUPT_EN_1     = 0x62,
+	INTERRUPT_EN_2     = 0x63,
+	INTERRUPT_EN_3     = 0x64,
+	AGC_TARGET         = 0x67,
+	AGC_CTL            = 0x68,
+	CAPT_RANGE         = 0x75,
+	SNR_SELECT_1       = 0x79,
+	SNR_SELECT_0       = 0x7A,
+	RS_ERR_PER_1       = 0x7C,
+	RS_ERR_PER_0       = 0x7D,
+	CHIP_ID            = 0x7F,
+	CHAN_STOP_1        = 0x80,
+	CHAN_STOP_0        = 0x81,
+	CHAN_STEP_1        = 0x82,
+	CHAN_STEP_0        = 0x83,
+	FEC_LOCK_TIME      = 0x85,
+	OFDM_LOCK_TIME     = 0x86,
+	ACQ_DELAY          = 0x87,
+	SCAN_CTL           = 0x88,
+	CLOCK_CTL          = 0x89,
+	CONFIG             = 0x8A,
+	MCLK_RATIO         = 0x8B,
+	GPP_CTL            = 0x8C,
+	ADC_CTL_1          = 0x8E,
+	ADC_CTL_0          = 0x8F
+};
+
+struct _tuner_info {
+	__u32 fe_frequency_min;
+#define FE_FREQ_MIN tuner_info[card_type].fe_frequency_min
+
+	__u32 fe_frequency_max;
+#define FE_FREQ_MAX tuner_info[card_type].fe_frequency_max
+
+	__u32 fe_frequency_stepsize; //verificare se u32 e' corretto
+#define FE_FREQ_STEPSIZE  tuner_info[card_type].fe_frequency_stepsize
+
+	__u32 coderate_hp_shift; //verificare se u32 giusto
+#define CODERATE_HP_SHIFT tuner_info[card_type].coderate_hp_shift
+
+	__u32 coderate_lp_shift;
+#define CODERATE_LP_SHIFT tuner_info[card_type].coderate_lp_shift
+
+	int constellation_shift;
+#define CONSTELLATION_SHIFT tuner_info[card_type].constellation_shift
+
+	int tx_mode_shift;
+#define TX_MODE_SHIFT tuner_info[card_type].tx_mode_shift
+
+	int guard_interval_shift;
+#define GUARD_INTERVAL_SHIFT tuner_info[card_type].guard_interval_shift
+
+	int hierarchy_shift;
+#define HIERARCHY_SHIFT tuner_info[card_type].hierarchy_shift
+
+	int read_reg_flag;
+#define READ_REG_FLAG tuner_info[card_type].read_reg_flag
+
+	int (* mt352_init) (struct i2c_adapter *i2c);
+#define MT352_INIT tuner_info[card_type].mt352_init
+
+	unsigned char (* mt352_charge_pump) (u32 freq);
+#define MT352_CHARGE_PUMP tuner_info[card_type].mt352_charge_pump
+
+	unsigned char (* mt352_band_select) (u32 freq);
+#define MT352_BAND_SELECT tuner_info[card_type].mt352_band_select
+};
+
+static int mt352_init_TUA6034(struct i2c_adapter *i2c);
+static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c);
+static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c);
+static unsigned char mt352_cp_TUA6034(u32 freq);
+static unsigned char mt352_cp_AVERMEDIA771(u32 freq);
+static unsigned char mt352_cp_TDTC9251DH01C(u32 freq);
+static unsigned char mt352_bs_TUA6034(u32 freq);
+static unsigned char mt352_bs_AVERMEDIA771(u32 freq);
+static unsigned char mt352_bs_TDTC9251DH01C(u32 freq);
+static int mt352_detect_avermedia_771(struct i2c_adapter *i2c);
+
+#endif                          /* _MT352_ */
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/cx22702.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx22702.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/cx22702.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx22702.c	2004-09-17 12:25:15.000000000 +0200
@@ -0,0 +1,900 @@
+/*
+    Conexant 22702 DVB OFDM frontend driver
+
+    based on:
+        Alps TDMB7 DVB OFDM frontend driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+	  Holger Waechtler <holger@convergence.de>
+
+    Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/    
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+
+#define FRONTEND_NAME "dvbfe_cx22702"
+
+#define I2C_EEPROM_SLAVE_ADDR 0x50
+
+#define PLLTYPE_DTT7592 1
+#define PLLTYPE_DTT7595 2
+#define PLLTYPE_DTT7579 3
+
+static int debug = 0;
+
+#define dprintk	if (debug) printk
+
+static struct dvb_frontend_info cx22702_info = {
+	.name			= "CX22702 Demod Thomson 759x/7579 PLL",
+	.type			= FE_OFDM,
+	.frequency_min		= 177000000,
+	.frequency_max		= 858000000,
+	.frequency_stepsize	= 166666,
+	.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+	FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+	FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+	FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 
+	FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+};
+
+struct cx22702_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+	struct dvb_frontend_info cx22702_info;
+   	char pll_type;
+	int pll_addr;
+	int demod_addr;
+	u8 prevUCBlocks;
+};
+
+/* Register values to initialise the demod */
+static u8 init_tab [] = {
+	0x00, 0x00, /* Stop aquisition */
+	0x0B, 0x06,
+	0x09, 0x01,
+	0x0D, 0x41,
+	0x16, 0x32,
+	0x20, 0x0A,
+	0x21, 0x17,
+	0x24, 0x3e,
+	0x26, 0xff,
+	0x27, 0x10,
+	0x28, 0x00,
+	0x29, 0x00,
+	0x2a, 0x10,
+	0x2b, 0x00,
+	0x2c, 0x10,
+	0x2d, 0x00,
+	0x48, 0xd4,
+	0x49, 0x56,
+	0x6b, 0x1e,
+	0xc8, 0x02,
+	0xf8, 0x02,
+	0xf9, 0x00,
+	0xfa, 0x00,
+	0xfb, 0x00,
+	0xfc, 0x00,
+	0xfd, 0x00,
+};
+
+static struct i2c_client client_template;
+
+static int cx22702_writereg (struct i2c_adapter *i2c, int demod_addr, u8 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg, data };
+	struct i2c_msg msg = { .addr = demod_addr, .flags = 0, .buf = buf, .len = 2 };
+
+	ret = i2c_transfer(i2c, &msg, 1);
+
+	if (ret != 1) 
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			__FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 cx22702_readreg (struct i2c_adapter *i2c, int demod_addr, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = demod_addr, .flags = 0, .buf = b0, .len = 1 },
+		{ .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+        
+	ret = i2c_transfer(i2c, msg, 2);
+        
+	if (ret != 2) 
+		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+	return b1[0];
+}
+
+static int pll_readreg(struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 reg)
+{
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = pll_addr, .flags = 0,        .buf = b0, .len = 1 },
+		{ .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe); // Enable PLL bus
+	if (i2c_transfer(i2c, msg, 2) != 2) {
+		printk ("%s i2c pll request failed\n", __FUNCTION__);
+		cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
+		return -ENODEV;
+	}
+	cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
+
+	return b1[0];
+}
+
+static int pll_write (struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 data [4])
+{
+	int ret=0;
+	struct i2c_msg msg = { .addr = pll_addr, .flags = 0, .buf = data, .len = 4 };
+
+	cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe);  // Enable PLL bus
+	ret = i2c_transfer(i2c, &msg, 1);
+	cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
+
+	if (ret != 1)
+		printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static int pll_dtt759x_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth)
+{
+	int ret;
+
+	u32 div = (freq + 36166667) / 166666;
+
+	/* dividerhigh, dividerlow, control, bandwidth switch tuner args */
+	unsigned char buf [4] = {
+		(div >> 8) & 0x7f,
+		div & 0xff,
+		0x84,
+		0x00
+	};
+
+	if(freq < 470000000) {
+		buf[3] = 0x02;
+	} else {
+		buf[3] = 0x08;
+	}
+
+	if(bandwidth == BANDWIDTH_7_MHZ) {
+		buf[3] |= 0x10;
+	}
+
+	// Now compensate for the charge pump osc
+	if(freq <= 264000000) {
+		buf[2] = buf[2] | 0x30;
+	} else if (freq <= 735000000) {
+		buf[2] = buf[2] | 0x38;
+	} else if (freq <= 835000000) {
+		buf[2] = buf[2] | 0x70;
+	} else if (freq <= 896000000) {
+		buf[2] = buf[2] | 0x78;
+	}	
+   
+	dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div);
+   
+	ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf);
+	if(ret<0) {
+		dprintk ("%s: first pll_write failed\n",__FUNCTION__);
+		return ret;
+	}
+
+	/* Set the AGC during search */
+	buf[2]=(buf[2] & 0xc7) | 0x18;
+	buf[3]=0xa0;
+	ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
+	if(ret<0) {
+		dprintk ("%s: second pll_write failed\n",__FUNCTION__);
+		return ret;
+	}
+
+	/* Tuner needs a small amount of time */
+	msleep(100);
+
+	/* Set the AGC post-search */   
+	buf[3]=0x20;
+	ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
+	if(ret<0) {
+		dprintk ("%s: third pll_write failed\n",__FUNCTION__);
+		return ret;
+	}
+
+	return ret;
+
+}
+
+static int pll_dtt7579_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth)
+{
+	int ret;
+
+	u32 div = (freq + 36166667) / 166666;
+
+	/* dividerhigh, dividerlow */
+	unsigned char buf [4] = {
+		div >> 8,
+		div & 0xff,
+		0x00,
+		0x00
+	};
+
+	// FIXME: bandwidth setting unknown
+   
+	// Now compensate for the charge pump osc
+	if(freq <= 506000000) {
+		buf[2] = 0xb4;
+	   	buf[3] = 0x02;
+	} else if (freq <= 735000000) {
+   		buf[2] = 0xbc;
+	   	buf[3] = 0x08;
+	} else if (freq <= 835000000) {
+      		buf[2] = 0xf4;
+	   	buf[3] = 0x08;
+	} else if (freq <= 896000000) {
+		buf[2] = 0xfc;
+	   	buf[3] = 0x08;
+	}
+
+	dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div);
+
+	ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf);
+	if(ret<0) {
+		dprintk ("%s: first pll_write failed\n",__FUNCTION__);
+		return ret;
+	}
+
+	/* Set the AGC to search */
+	buf[2]=(buf[2] & 0xdc) | 0x9c;
+	buf[3]=0xa0;
+	ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
+	if(ret<0) {
+		dprintk ("%s: second pll_write failed\n",__FUNCTION__);
+		return ret;
+	}
+
+	return ret;
+
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int cx22702_init (struct i2c_adapter *i2c, struct cx22702_state *state)
+{
+	int i;
+
+	cx22702_writereg (i2c, state->demod_addr, 0x00, 0x02);
+
+	msleep(10);
+	
+	for (i=0; i<sizeof(init_tab); i+=2)
+		cx22702_writereg (i2c, state->demod_addr, init_tab[i], init_tab[i+1]);
+
+	return 0;	
+}
+
+static int cx22702_set_inversion (struct i2c_adapter *i2c, struct cx22702_state *state, int inversion)
+{
+	u8 val;
+
+	switch (inversion) {
+
+		case INVERSION_AUTO:
+			return -EOPNOTSUPP;
+
+		case INVERSION_ON:
+			val = cx22702_readreg (i2c, state->demod_addr, 0x0C);
+			return cx22702_writereg (i2c, state->demod_addr, 0x0C, val | 0x01);
+
+		case INVERSION_OFF:
+			val = cx22702_readreg (i2c, state->demod_addr, 0x0C);
+			return cx22702_writereg (i2c, state->demod_addr, 0x0C, val & 0xfe);
+
+		default:
+			return -EINVAL;
+
+	}
+
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state,
+			    struct dvb_frontend_parameters *p)
+{
+	u8 val;
+
+	/* set PLL */
+	switch(state->pll_type) {
+	case PLLTYPE_DTT7592:
+	case PLLTYPE_DTT7595:
+		pll_dtt759x_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth);
+		break;
+
+	case PLLTYPE_DTT7579:
+		pll_dtt7579_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth);
+		break;
+	}
+   
+	/* set inversion */
+	cx22702_set_inversion (i2c, state, p->inversion);
+
+	/* set bandwidth */
+	switch(p->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x20 );
+		break;
+	case BANDWIDTH_7_MHZ:
+		cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x10 );
+		break;
+	case BANDWIDTH_8_MHZ:
+		cx22702_writereg(i2c, state->demod_addr, 0x0C, cx22702_readreg(i2c, state->demod_addr, 0x0C) &0xcf );
+		break;
+	default:
+		dprintk ("%s: invalid bandwidth\n",__FUNCTION__);
+		return -EINVAL;
+	}
+
+   
+	p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
+     
+	/* use auto configuration? */
+	if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) || 
+	   (p->u.ofdm.constellation==QAM_AUTO) ||
+	   (p->u.ofdm.code_rate_HP==FEC_AUTO) || 
+	   (p->u.ofdm.code_rate_LP==FEC_AUTO) || 
+	   (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) || 
+	   (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
+
+		/* TPS Source - use hardware driven values */
+		cx22702_writereg(i2c, state->demod_addr, 0x06, 0x10);
+		cx22702_writereg(i2c, state->demod_addr, 0x07, 0x9);
+		cx22702_writereg(i2c, state->demod_addr, 0x08, 0xC1);
+		cx22702_writereg(i2c, state->demod_addr, 0x0B, cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc );
+		cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 );
+		cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01); /* Begin aquisition */
+		printk("%s: Autodetecting\n",__FUNCTION__);
+		return 0;
+	}
+
+   	/* manually programmed values */
+	val=0;
+	switch(p->u.ofdm.constellation) {
+		case   QPSK: val = (val&0xe7); break;
+		case QAM_16: val = (val&0xe7)|0x08; break;
+		case QAM_64: val = (val&0xe7)|0x10; break;
+		default:
+			dprintk ("%s: invalid constellation\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	switch(p->u.ofdm.hierarchy_information) {
+		case HIERARCHY_NONE: val = (val&0xf8); break;
+		case    HIERARCHY_1: val = (val&0xf8)|1; break;
+		case    HIERARCHY_2: val = (val&0xf8)|2; break;
+		case    HIERARCHY_4: val = (val&0xf8)|3; break;
+		default:
+			dprintk ("%s: invalid hierarchy\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	cx22702_writereg (i2c, state->demod_addr, 0x06, val);
+
+	val=0;
+	switch(p->u.ofdm.code_rate_HP) {
+		case FEC_NONE:
+		case FEC_1_2: val = (val&0xc7); break;
+		case FEC_2_3: val = (val&0xc7)|0x08; break;
+		case FEC_3_4: val = (val&0xc7)|0x10; break;
+		case FEC_5_6: val = (val&0xc7)|0x18; break;
+		case FEC_7_8: val = (val&0xc7)|0x20; break;
+		default:
+			dprintk ("%s: invalid code_rate_HP\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	switch(p->u.ofdm.code_rate_LP) {
+		case FEC_NONE:
+		case FEC_1_2: val = (val&0xf8); break;
+		case FEC_2_3: val = (val&0xf8)|1; break;
+		case FEC_3_4: val = (val&0xf8)|2; break;
+		case FEC_5_6: val = (val&0xf8)|3; break;
+		case FEC_7_8: val = (val&0xf8)|4; break;
+		default:
+			dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	cx22702_writereg (i2c, state->demod_addr, 0x07, val);
+
+	val=0;
+	switch(p->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_32: val = (val&0xf3); break;
+		case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break;
+		case  GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
+		case  GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break;
+		default:
+			dprintk ("%s: invalid guard_interval\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	switch(p->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
+		case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
+		default:
+			dprintk ("%s: invalid transmission_mode\n",__FUNCTION__);
+			return -EINVAL;
+	}
+	cx22702_writereg (i2c, state->demod_addr, 0x08, val);
+	cx22702_writereg(i2c, state->demod_addr, 0x0B, (cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc) | 0x02 );
+	cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 );
+
+	/* Begin channel aquisition */
+	cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01);
+
+	return 0;
+}
+
+/* Retrieve the demod settings */
+static int cx22702_get_tps (struct i2c_adapter *i2c, struct cx22702_state *state,
+			    struct dvb_ofdm_parameters *p)
+{
+	u8 val;
+
+	/* Make sure the TPS regs are valid */
+	if (!(cx22702_readreg(i2c, state->demod_addr, 0x0A) & 0x20))
+		return -EAGAIN;
+
+	val = cx22702_readreg (i2c, state->demod_addr, 0x01);
+	switch( (val&0x18)>>3) {
+		case 0: p->constellation =   QPSK; break;
+		case 1: p->constellation = QAM_16; break;
+		case 2: p->constellation = QAM_64; break;
+	}
+	switch( val&0x07 ) {
+		case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+		case 1: p->hierarchy_information =    HIERARCHY_1; break;
+		case 2: p->hierarchy_information =    HIERARCHY_2; break;
+		case 3: p->hierarchy_information =    HIERARCHY_4; break;
+	}
+
+
+	val = cx22702_readreg (i2c, state->demod_addr, 0x02);
+	switch( (val&0x38)>>3 ) {
+		case 0: p->code_rate_HP = FEC_1_2; break;
+		case 1: p->code_rate_HP = FEC_2_3; break;
+		case 2: p->code_rate_HP = FEC_3_4; break;
+		case 3: p->code_rate_HP = FEC_5_6; break;
+		case 4: p->code_rate_HP = FEC_7_8; break;
+	}
+	switch( val&0x07 ) {
+		case 0: p->code_rate_LP = FEC_1_2; break;
+		case 1: p->code_rate_LP = FEC_2_3; break;
+		case 2: p->code_rate_LP = FEC_3_4; break;
+		case 3: p->code_rate_LP = FEC_5_6; break;
+		case 4: p->code_rate_LP = FEC_7_8; break;
+	}
+
+
+	val = cx22702_readreg (i2c, state->demod_addr, 0x03);
+	switch( (val&0x0c)>>2 ) {
+		case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+		case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+		case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
+		case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+	}
+	switch( val&0x03 ) {
+		case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+		case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+	}
+
+	return 0;
+}
+
+static int cx22702_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct cx22702_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
+	u8 reg0A;
+	u8 reg23;
+	u8 ucblocks;
+
+	switch (cmd) {
+		case FE_GET_INFO:
+			memcpy (arg, &state->cx22702_info, sizeof(struct dvb_frontend_info));
+			break;
+
+		case FE_READ_STATUS:
+		{
+			fe_status_t *status = (fe_status_t *) arg;
+
+			*status = 0;
+
+			reg0A = cx22702_readreg (i2c, state->demod_addr, 0x0A);
+			reg23 = cx22702_readreg (i2c, state->demod_addr, 0x23);
+
+			dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
+				,__FUNCTION__,reg0A,reg23);
+
+			if(reg0A & 0x10) {
+				*status |= FE_HAS_LOCK;
+				*status |= FE_HAS_VITERBI;
+				*status |= FE_HAS_SYNC;
+			}
+
+			if(reg0A & 0x20) 
+				*status |= FE_HAS_CARRIER;
+
+			if(reg23 < 0xf0) 
+				*status |= FE_HAS_SIGNAL;
+
+			break;
+
+		}
+
+		case FE_READ_BER:
+			if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) {
+				/* Realtime statistics */
+				*((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
+					| (cx22702_readreg (i2c, state->demod_addr, 0xDF)&0x7F);
+			} else {
+				/* Averagtine statistics */
+				*((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
+					| cx22702_readreg (i2c, state->demod_addr, 0xDF);
+			}
+			break;
+
+		case FE_READ_SIGNAL_STRENGTH:
+		{
+			u16 ss = cx22702_readreg (i2c, state->demod_addr, 0x23);
+			*((u16*) arg) = ss;
+			break;
+		}
+
+		/* We don't have an register for this */
+		/* We'll take the inverse of the BER register */
+		case FE_READ_SNR:
+		{
+			u16 rs_ber=0;
+			if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) {
+				/* Realtime statistics */
+				rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
+					| (cx22702_readreg (i2c, state->demod_addr, 0xDF)& 0x7F);
+			} else {
+				/* Averagine statistics */
+				rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 8
+					| cx22702_readreg (i2c, state->demod_addr, 0xDF);
+			}
+			*((u16*) arg) = ~rs_ber;
+			break;
+		}
+
+		case FE_READ_UNCORRECTED_BLOCKS: 
+			/* RS Uncorrectable Packet Count then reset */
+			ucblocks = cx22702_readreg (i2c, state->demod_addr, 0xE3);
+			if (state->prevUCBlocks < ucblocks) *((u32*) arg) = (ucblocks - state->prevUCBlocks);
+			else *((u32*) arg) = state->prevUCBlocks - ucblocks;
+	   		state->prevUCBlocks = ucblocks;
+			break;
+
+		case FE_SET_FRONTEND:
+		{
+			struct dvb_frontend_parameters *p = arg;
+			int ret;
+
+			if((ret=cx22702_set_tps (i2c, state, p))<0) {
+				dprintk ("%s: set_tps failed ret=%d\n",__FUNCTION__,ret);
+				return ret;
+			}
+			break;
+		}
+
+		case FE_GET_FRONTEND:
+		{
+			struct dvb_frontend_parameters *p = arg;
+			u8 reg0C = cx22702_readreg (i2c, state->demod_addr, 0x0C);
+		
+			p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+			return cx22702_get_tps (i2c, state, &p->u.ofdm);
+		}
+
+		case FE_INIT:
+			return cx22702_init (i2c, state);
+
+		default:
+			return -EOPNOTSUPP;
+	};
+
+	return 0;
+}
+
+/* Validate the eeprom contents, make sure content look ok.
+   Get the eeprom data. */
+static int cx22702_validate_eeprom(struct i2c_adapter *i2c, int* minfreq, int* pll_type, int* pll_addr, int* demod_addr)
+{
+	u8 b0 [] = { 0 };
+	u8 b1 [128];
+	u32 model=0;
+	u8 tuner=0;
+	int i,j;
+
+	struct i2c_msg msg [] = {
+		{ .addr = I2C_EEPROM_SLAVE_ADDR, .flags = 0,        .buf = b0, .len = 1 },
+		{ .addr = I2C_EEPROM_SLAVE_ADDR, .flags = I2C_M_RD, .buf = b1, .len = 128 }
+	};
+
+	if (i2c_transfer(i2c, msg, 2) != 2) {
+		printk ("%s i2c eeprom request failed\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	if(debug) {
+		dprintk ("i2c eeprom content:\n");
+		j=0;
+		for(i=0;i<128;i++) {
+			dprintk("%02x ",b1[i]);
+			if(j++==16) {
+				dprintk("\n");
+				j=0;
+			}
+		}
+ 		dprintk("\n");
+	}
+
+	if( (b1[8]!=0x84) || (b1[10]!=0x00) ) {
+		printk ("%s eeprom content is not valid\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	/* Make sure we support the board model */
+	model = b1[0x1f] << 24 | b1[0x1e] << 16 | b1[0x1d] << 8 | b1[0x1c];
+	switch(model) {
+		case 90002:
+		case 90500:
+		case 90501:
+			dprintk ("%s: Model #%d\n",__FUNCTION__,model);
+			break;	
+		default:
+			printk ("%s: Unknown model #%d not supported\n",__FUNCTION__,model);
+			return -ENODEV;	
+	}
+
+	/* Make sure we support the tuner */
+	tuner = b1[0x2d];
+	switch(tuner) {
+		case 0x4B:
+			dprintk ("%s: Tuner Thomson DTT 7595\n",__FUNCTION__);
+			*minfreq = 177000000;
+			*pll_type = PLLTYPE_DTT7595;
+			break;	
+		case 0x4C:
+			dprintk ("%s: Tuner Thomson DTT 7592\n",__FUNCTION__);
+			*minfreq = 474000000;
+			*pll_type = PLLTYPE_DTT7592;
+			break;	
+		default:
+			printk ("%s: Unknown tuner 0x%02x not supported\n",__FUNCTION__,tuner);
+			return -ENODEV;	
+	}
+	*pll_addr = 0x61;
+	*demod_addr = 0x43;   
+	return 0;
+}
+
+
+/* Validate the demod, make sure we understand the hardware */
+static int cx22702_validate_demod(struct i2c_adapter *i2c, int demod_addr)
+{
+	u8 b0 [] = { 0x1f };
+	u8 b1 [] = { 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = demod_addr, .flags = 0,        .buf = b0, .len = 1 },
+		{ .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	if (i2c_transfer(i2c, msg, 2) != 2) {
+		printk ("%s i2c demod request failed\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	if( (b1[0]!=0x3) ) {
+		printk ("%s i2c demod type 0x(%02x) not known\n", __FUNCTION__,b1[0]);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Validate the tuner PLL, make sure we understand the hardware */
+static int cx22702_validate_pll(struct i2c_adapter *i2c, int pll_addr, int demod_addr)
+{
+	int result=0;
+
+	if( (result=pll_readreg(i2c,pll_addr,demod_addr,0xc2)) < 0)
+		return result;
+
+	if( (result >= 0) && (result&0x30) )
+		return 0;
+
+	return result;
+}
+
+/* Check we can see the I2c clients */
+static int cx22702_attach_adapter(struct i2c_adapter *adapter)
+{
+	struct cx22702_state *state;
+	struct i2c_client *client;
+	int ret;
+	int minfreq;
+	int pll_type;
+	int pll_addr;
+	int demod_addr;
+
+	if (0 == (adapter->class & I2C_CLASS_TV_DIGITAL)) {
+		dprintk("Ignoring adapter 0x%x:%s (no digital tv card).\n",
+			adapter->id, adapter->name);
+		return 0;
+	}
+
+	dprintk("Trying to attach to adapter 0x%x:%s.\n",
+		adapter->id, adapter->name);
+
+	if (!strcmp(adapter->name, "Conexant DVB-T reference design")) {
+	   	printk("cx22702: Detected Conexant DVB-T card - PLL Thomson DTT7579\n");
+		pll_type = PLLTYPE_DTT7579;
+		pll_addr = 0x60;
+		demod_addr = 0x43;
+		minfreq = 177000000; // guess
+	} else {
+		// default to Hauppauge Nova-T for the moment
+	   	printk("cx22702: Detected Hauppauge Nova-T DVB-T - PLL Thomson DTT759x\n");
+		ret=cx22702_validate_eeprom(adapter, &minfreq, &pll_type, &pll_addr, &demod_addr);
+		if(ret < 0)
+			return ret;
+	}
+
+	ret=cx22702_validate_demod(adapter, demod_addr);
+	if(ret < 0)
+		return ret;
+
+	ret=cx22702_validate_pll(adapter, pll_addr, demod_addr);
+	if(ret < 0)
+		return ret;
+
+	if ( !(state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL)) )
+		return -ENOMEM;
+
+	memset(state, 0, sizeof(struct cx22702_state));
+	state->i2c = adapter;
+	memcpy(&state->cx22702_info, &cx22702_info, sizeof(struct dvb_frontend_info));   
+	state->cx22702_info.frequency_min = minfreq;
+	state->pll_type = pll_type;
+	state->pll_addr = pll_addr; 
+	state->demod_addr = demod_addr;
+
+	if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = state->demod_addr;
+	i2c_set_clientdata(client, state);
+   
+	if ((ret = i2c_attach_client(client))) {
+		printk("cx22702: attach failed %i\n", ret);
+		kfree(client);
+		kfree(state);
+		return ret;
+	}
+	return 0;	
+}
+
+static int cx22702_detach_client(struct i2c_client *client)
+{
+	struct cx22702_state *state = i2c_get_clientdata(client);
+
+	if (NULL != state->dvb) {
+		dvb_unregister_frontend (cx22702_ioctl, state->dvb);
+		state->dvb = NULL;
+	}
+	i2c_detach_client(client);
+	kfree(client);
+	return 0;
+}
+
+static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct cx22702_state *state = i2c_get_clientdata(client);
+	int rc;
+
+	switch(cmd) {
+	case FE_REGISTER:
+		if (NULL != state->dvb)
+			break;
+		state->dvb = arg;
+		rc = dvb_register_frontend(cx22702_ioctl, state->dvb, state,
+					   &state->cx22702_info, THIS_MODULE);
+		if (0 != rc) {
+			printk("cx22702: dvb_register_frontend failed with rc=%d\n",rc);
+			state->dvb = NULL;
+			return rc;
+		}
+		break;
+	case FE_UNREGISTER:
+		if (NULL == state->dvb)
+			break;
+		dvb_unregister_frontend (cx22702_ioctl, state->dvb);
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner = THIS_MODULE,
+	.name  = FRONTEND_NAME,
+	.id = I2C_DRIVERID_DVBFE_CX22702,
+	.flags = I2C_DF_NOTIFY,
+	.attach_adapter = cx22702_attach_adapter,
+	.detach_client = cx22702_detach_client,
+	.command = command,
+};
+
+static struct i2c_client client_template = {
+	.name = FRONTEND_NAME,
+	.flags = I2C_CLIENT_ALLOW_USE,
+	.driver = &driver,
+};
+
+static int __init init_cx22702 (void)
+{
+	return i2c_add_driver(&driver);
+}
+
+static void __exit exit_cx22702 (void)
+{
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "cx22702: driver deregistration failed.\n");
+}
+
+module_init (init_cx22702);
+module_exit (exit_cx22702);
+
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+MODULE_DESCRIPTION("CX22702 / Thomson DTT 759x / Thomson DTT 7579 PLL DVB Frontend driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+

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

* Re: [PATCH][2.6][10/14] add new frontend drivers 2/2
  2004-09-17 14:34                 ` [PATCH][2.6][9/14] add new frontend drivers 1/2 Michael Hunold
@ 2004-09-17 14:36                   ` Michael Hunold
  2004-09-17 14:37                     ` [PATCH][2.6][11/14] new DVB driver Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:36 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 10-DVB-add-frontend-2-2.diff --]
[-- Type: text/plain, Size: 48107 bytes --]

- [DVB] add new driver for mobile DVB-T demodulator DiBcom 3000-MB
- [DVB] add new drivers to Makefile

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dib3000mb.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/dib3000mb.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dib3000mb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dib3000mb.c	2004-09-17 12:25:15.000000000 +0200
@@ -0,0 +1,857 @@
+/*
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB 
+ * DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 
+ * based on GPL code from DibCom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * Acknowledgements
+ * 
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+
+#include "dib3000mb.h"
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk_new(level,args...) \
+	do { if ((debug & level)) { printk(args); } } while (0)
+
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore (|-able)).");
+#else
+#define dprintk_new(args...)
+#endif
+
+#define deb_info(args...) dprintk_new(0x01,args)
+#define deb_xfer(args...) dprintk_new(0x02,args)
+#define deb_alot(args...) dprintk_new(0x04,args)
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000-MB DVB-T frontend"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+struct dib3000mb_state {
+	struct i2c_client *i2c;
+	struct dvb_adapter *dvb;
+	u16 manufactor_id;
+	u16 device_id;
+};
+
+static struct dvb_frontend_info dib3000mb_info = {
+	.name			= "DiBcom 3000-MB DVB-T frontend",
+	.type 			= FE_OFDM,
+	.frequency_min 		= 44250000,
+	.frequency_max 		= 867250000,
+	.frequency_stepsize	= 62500,
+	.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | 
+			FE_CAN_GUARD_INTERVAL_AUTO | 
+			FE_CAN_HIERARCHY_AUTO,
+};
+
+
+#define rd(reg) dib3000mb_read_reg(state->i2c,reg)
+#define wr(reg,val) if (dib3000mb_write_reg(state->i2c,reg,val)) \
+	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+#define wr_foreach(a,v) { int i; \
+	deb_alot("sizeof: %d %d\n",sizeof(a),sizeof(v));\
+	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+		wr(a[i],v[i]); \
+}
+
+static u16 dib3000mb_read_reg(struct i2c_client *i2c, u16 reg)
+{
+	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+	u8 rb[2]; 
+	struct i2c_msg msg[] = {
+		{ .addr = i2c->addr, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = i2c->addr, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+	deb_alot("reading from i2c bus (reg: %d)\n",reg);
+
+	if (i2c_transfer(i2c->adapter,msg,2) != 2)
+		deb_alot("i2c read error\n");
+
+	return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000mb_write_reg(struct i2c_client *i2c,u16 reg, u16 val)
+{
+	u8 b[] = { 
+		(reg >> 8) & 0xff, reg & 0xff, 
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg[] = { { .addr = i2c->addr, .flags = 0, .buf = b, .len = 4 } };
+	deb_alot("writing to i2c bus (reg: %d, val: %d)\n",reg,val);
+
+	return i2c_transfer(i2c->adapter,msg,1) != 1 ? -EREMOTEIO : 0 ;
+}
+
+static int dib3000mb_tuner_thomson_cable_eu(struct dib3000mb_state *state,
+		u32 freq)
+{
+	u32 tfreq = (freq + 36125000) / 62500;
+	unsigned int addr;
+	int vu,p0,p1,p2;
+	
+	if (freq > 403250000)
+		vu = 1, p2 = 1, p1 = 0, p0 = 1;
+	else if (freq > 115750000)
+		vu = 0, p2 = 1, p1 = 1, p0 = 0;
+	else if (freq > 44250000)
+		vu = 0, p2 = 0, p1 = 1, p0 = 1;
+	else 
+		return -EINVAL;
+	/* TODO better solution for i2c->addr handling */
+	addr = state->i2c->addr;
+	state->i2c->addr = DIB3000MB_TUNER_ADDR_DEFAULT;
+	wr(tfreq & 0x7fff,(0x8e << 8) + ((vu << 7) | (p2 << 2) | (p1 << 1) | p0) );
+	state->i2c->addr = addr;
+	
+	return 0;
+}
+
+static int dib3000mb_get_frontend(struct dib3000mb_state *state, 
+		struct dvb_frontend_parameters *fep)
+{
+	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+	fe_code_rate_t *cr;
+	u16 tps_val;
+	int inv_test1,inv_test2;
+	u32 dds_val, threshold = 0x800000;
+	
+	if (!rd(DIB3000MB_REG_TPS_LOCK)) 
+		return -EINVAL;
+
+	dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
+	if (dds_val & threshold)
+		inv_test1 = 0;
+	else if (dds_val == threshold) 
+		inv_test1 = 1;
+	else 
+		inv_test1 = 2;
+
+	dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
+	if (dds_val & threshold)
+		inv_test2 = 0;
+	else if (dds_val == threshold) 
+		inv_test2 = 1;
+	else 
+		inv_test2 = 2;
+	
+	fep->inversion = 
+		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0))
+					||
+		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
+
+	deb_info("inversion %d %d, %d\n",inv_test2,inv_test1, fep->inversion);
+	
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
+		case DIB3000MB_QAM_QPSK:
+			deb_info("QPSK ");
+			ofdm->constellation = QPSK;
+			break;
+		case DIB3000MB_QAM_QAM16:
+			deb_info("QAM16 ");
+			ofdm->constellation = QAM_16;
+			break;
+		case DIB3000MB_QAM_QAM64:
+			deb_info("QAM64 ");
+			ofdm->constellation = QAM_64;
+			break;
+		default:
+			err("Unexpected constellation returned by TPS (%d)",tps_val);
+			break;
+ 	}
+	deb_info("TPS: %d\n",tps_val);
+
+	if (rd(DIB3000MB_REG_TPS_HRCH)) {
+		deb_info("HRCH ON\n");
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
+		cr = &ofdm->code_rate_LP;
+		ofdm->code_rate_HP = FEC_NONE;
+		
+		switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
+			case DIB3000MB_VIT_ALPHA_OFF:
+				deb_info("HIERARCHY_NONE ");
+				ofdm->hierarchy_information = HIERARCHY_NONE;
+				break;
+			case DIB3000MB_VIT_ALPHA_1:
+				deb_info("HIERARCHY_1 ");
+				ofdm->hierarchy_information = HIERARCHY_1;
+				break;
+			case DIB3000MB_VIT_ALPHA_2:
+				deb_info("HIERARCHY_2 ");
+				ofdm->hierarchy_information = HIERARCHY_2;
+				break;
+			case DIB3000MB_VIT_ALPHA_4:
+				deb_info("HIERARCHY_4 ");
+				ofdm->hierarchy_information = HIERARCHY_4;
+				break;
+			default:
+				err("Unexpected ALPHA value returned by TPS (%d)",tps_val);
+		}	
+		deb_info("TPS: %d\n",tps_val);
+	} else {
+		deb_info("HRCH OFF\n");
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
+		cr = &ofdm->code_rate_HP;
+		ofdm->code_rate_LP = FEC_NONE;
+		ofdm->hierarchy_information = HIERARCHY_NONE;
+	}
+
+	switch (tps_val) {
+		case DIB3000MB_FEC_1_2:
+			deb_info("FEC_1_2 ");
+			*cr = FEC_1_2;
+			break;
+		case DIB3000MB_FEC_2_3:
+			deb_info("FEC_2_3 ");
+			*cr = FEC_2_3;
+			break;
+		case DIB3000MB_FEC_3_4:
+			deb_info("FEC_3_4 ");
+			*cr = FEC_3_4;
+			break;
+		case DIB3000MB_FEC_5_6:
+			deb_info("FEC_5_6 ");
+			*cr = FEC_4_5;
+			break;
+		case DIB3000MB_FEC_7_8:
+			deb_info("FEC_7_8 ");
+			*cr = FEC_7_8;
+			break;
+		default:
+			err("Unexpected FEC returned by TPS (%d)",tps_val);
+			break;
+	}
+	deb_info("TPS: %d\n",tps_val);
+	
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
+		case DIB3000MB_GUARD_TIME_1_32:
+			deb_info("GUARD_INTERVAL_1_32 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case DIB3000MB_GUARD_TIME_1_16:
+			deb_info("GUARD_INTERVAL_1_16 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case DIB3000MB_GUARD_TIME_1_8:
+			deb_info("GUARD_INTERVAL_1_8 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case DIB3000MB_GUARD_TIME_1_4:
+			deb_info("GUARD_INTERVAL_1_4 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			err("Unexpected Guard Time returned by TPS (%d)",tps_val);
+			break;
+	}
+	deb_info("TPS: %d\n",tps_val);
+	
+	switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
+		case DIB3000MB_FFT_2K:
+			deb_info("TRANSMISSION_MODE_2K ");
+			ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case DIB3000MB_FFT_8K:
+			deb_info("TRANSMISSION_MODE_8K ");
+			ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			err("unexpected transmission mode return by TPS (%d)",tps_val);
+	}
+	deb_info("TPS: %d\n",tps_val);
+	return 0;
+}
+
+static int dib3000mb_set_frontend(struct dib3000mb_state *state,
+		struct dvb_frontend_parameters *fep, int tuner);
+
+static int dib3000mb_fe_read_search_status(struct dib3000mb_state *state) 
+{
+	u16 irq;
+	struct dvb_frontend_parameters fep;
+	
+	irq = rd(DIB3000MB_REG_AS_IRQ_PENDING);
+
+	if (irq & 0x02) {
+		if (rd(DIB3000MB_REG_LOCK2_VALUE) & 0x01) {
+			if (dib3000mb_get_frontend(state,&fep) == 0) {
+				deb_info("reading tuning data from frontend succeeded.\n");
+				return dib3000mb_set_frontend(state,&fep,0) == 0;
+			} else {
+				deb_info("reading tuning data failed -> tuning failed.\n");
+				return 0;
+			}
+		} else {
+			deb_info("AS IRQ was pending, but LOCK2 was not & 0x01.\n");
+			return 0;
+		}
+	} else if (irq & 0x01) {
+		deb_info("Autosearch failed.\n");
+		return 0;
+	}
+
+	return -1;
+}
+
+static int dib3000mb_set_frontend(struct dib3000mb_state *state,
+		struct dvb_frontend_parameters *fep, int tuner)
+{
+	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+	fe_code_rate_t fe_cr;
+	int search_state,seq;
+	
+	if (tuner) {
+		wr(DIB3000MB_REG_TUNER,
+				DIB3000MB_ACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) );
+		dib3000mb_tuner_thomson_cable_eu(state,fep->frequency);
+		
+		/* wait for tuner */
+		msleep(1);
+		wr(DIB3000MB_REG_TUNER, 
+				DIB3000MB_DEACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) );
+
+		switch (ofdm->bandwidth) {
+			case BANDWIDTH_8_MHZ:
+			case BANDWIDTH_AUTO:
+				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+				break;
+			case BANDWIDTH_7_MHZ:
+				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[1]);
+				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_7mhz);
+				break;
+			case BANDWIDTH_6_MHZ:
+				wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[0]);
+				wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_6mhz);
+				break;
+			default:
+				err("unkown bandwidth value.");
+				return -EINVAL;
+				break;
+		}
+	}	
+	wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+
+	switch (ofdm->transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+			wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_2K);
+			break;
+		case TRANSMISSION_MODE_8K:
+			wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_8K);
+			break;
+		case TRANSMISSION_MODE_AUTO:
+			wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_AUTO);
+			break;
+		default:
+			return -EINVAL;
+	}
+	
+	switch (ofdm->guard_interval) {
+		case GUARD_INTERVAL_1_32:
+			wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_32);
+			break;
+		case GUARD_INTERVAL_1_16:
+			wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_16);
+			break;
+		case GUARD_INTERVAL_1_8:
+			wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_8);
+			break;
+		case GUARD_INTERVAL_1_4:
+			wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_4);
+			break;
+		case GUARD_INTERVAL_AUTO:
+			wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_AUTO);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (fep->inversion) {
+		case INVERSION_OFF:
+			wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_OFF);
+			break;
+		case INVERSION_AUTO:
+		case INVERSION_ON:
+			wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_ON);
+			break;
+		default:
+			return -EINVAL;
+	}
+	
+	switch (ofdm->constellation) {
+		case QPSK:
+			wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QPSK);
+			break;
+		case QAM_16:
+			wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM16);
+			break;
+		case QAM_64:
+			wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM64);
+			break;
+		case QAM_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}
+	
+	switch (ofdm->hierarchy_information) {
+		case HIERARCHY_NONE:
+		case HIERARCHY_1:
+			wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_1);
+			break;
+		case HIERARCHY_2:
+			wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_2);
+			break;
+		case HIERARCHY_4:
+			wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_4);
+			break; 
+		case HIERARCHY_AUTO:
+			wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO);
+			break;
+		default:
+			return -EINVAL;
+	}
+	
+	if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+		wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_OFF);
+		wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP);
+		fe_cr = ofdm->code_rate_HP;
+	} else {
+		wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_ON);
+		wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_LP);
+		fe_cr = ofdm->code_rate_LP;
+	}
+			
+	switch (fe_cr) {
+		case FEC_1_2:
+			wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2);
+			break;
+		case FEC_2_3:
+			wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_2_3);
+			break;
+		case FEC_3_4:
+			wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_3_4);
+			break;
+		case FEC_5_6:
+			wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_5_6);
+			break;
+		case FEC_7_8:
+			wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_7_8);
+			break;
+		case FEC_NONE:
+		case FEC_AUTO:
+			break;
+		default:
+			return -EINVAL;
+	}	
+	
+	seq = dib3000mb_seq
+		[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
+		[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
+		[fep->inversion == INVERSION_AUTO];
+
+	deb_info("seq? %d\n",seq);
+	
+	wr(DIB3000MB_REG_SEQ,seq);
+	
+	wr(DIB3000MB_REG_ISI,seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
+
+	if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
+		if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_2K_1_8);
+		} else {
+			wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_DEFAULT);
+		}
+		
+		wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_2K);
+	} else {
+		wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_DEFAULT);
+	}
+
+	wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_MOBILE_MODE,DIB3000MB_MOBILE_MODE_OFF);
+		
+	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_high);
+	
+	wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_ACTIVATE);
+
+	wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AGC+DIB3000MB_RESTART_CTRL);
+	wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+	
+	/* wait for AGC lock */
+	msleep(70);
+
+	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+	
+	/* something has to be auto searched */ 
+	if (ofdm->constellation == QAM_AUTO ||
+		ofdm->hierarchy_information == HIERARCHY_AUTO ||
+		fe_cr == FEC_AUTO || 
+		fep->inversion == INVERSION_AUTO) {
+		
+		deb_info("autosearch enabled.\n");	
+		
+		wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
+		
+		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH);
+		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+		
+		while ((search_state = dib3000mb_fe_read_search_status(state)) < 0);
+		
+		return search_state ? 0 : -EINVAL;
+	} else {
+		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
+		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+		msleep(70);
+	}
+	return 0;
+}
+
+
+static int dib3000mb_fe_init(struct dib3000mb_state *state,int mobile_mode)
+{
+	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
+	
+	wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
+	
+	wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE);
+	wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE_RST);
+	
+	wr(DIB3000MB_REG_CLOCK,DIB3000MB_CLOCK_DEFAULT);
+	
+	wr(DIB3000MB_REG_ELECT_OUT_MODE,DIB3000MB_ELECT_OUT_MODE_ON);
+
+	wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_RESERVED);
+	wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO);
+	
+	wr(DIB3000MB_REG_DDS_FREQ_MSB,DIB3000MB_DDS_FREQ_MSB);
+	wr(DIB3000MB_REG_DDS_FREQ_LSB,DIB3000MB_DDS_FREQ_LSB);
+
+	wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+
+	wr_foreach(dib3000mb_reg_impulse_noise,
+			dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
+	
+	wr_foreach(dib3000mb_reg_agc_gain,dib3000mb_default_agc_gain);
+
+	wr(DIB3000MB_REG_PHASE_NOISE,DIB3000MB_PHASE_NOISE_DEFAULT);
+
+	wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
+	
+	wr_foreach(dib3000mb_reg_lock_duration,dib3000mb_default_lock_duration);
+
+	wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+
+	wr(DIB3000MB_REG_LOCK0_MASK,DIB3000MB_LOCK0_DEFAULT);
+	wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+	wr(DIB3000MB_REG_LOCK2_MASK,DIB3000MB_LOCK2_DEFAULT);
+	wr(DIB3000MB_REG_SEQ,dib3000mb_seq[1][1][1]);
+		
+	wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+	
+	wr(DIB3000MB_REG_UNK_68,DIB3000MB_UNK_68);
+	wr(DIB3000MB_REG_UNK_69,DIB3000MB_UNK_69);
+	wr(DIB3000MB_REG_UNK_71,DIB3000MB_UNK_71);
+	wr(DIB3000MB_REG_UNK_77,DIB3000MB_UNK_77);
+	wr(DIB3000MB_REG_UNK_78,DIB3000MB_UNK_78);
+	wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
+	wr(DIB3000MB_REG_UNK_92,DIB3000MB_UNK_92);
+	wr(DIB3000MB_REG_UNK_96,DIB3000MB_UNK_96);
+	wr(DIB3000MB_REG_UNK_97,DIB3000MB_UNK_97);
+	wr(DIB3000MB_REG_UNK_106,DIB3000MB_UNK_106);
+	wr(DIB3000MB_REG_UNK_107,DIB3000MB_UNK_107);
+	wr(DIB3000MB_REG_UNK_108,DIB3000MB_UNK_108);
+	wr(DIB3000MB_REG_UNK_122,DIB3000MB_UNK_122);
+	wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
+	wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2);
+	wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP);
+	wr(DIB3000MB_REG_BERLEN,DIB3000MB_BERLEN_DEFAULT);
+
+	wr_foreach(dib3000mb_reg_filter_coeffs,dib3000mb_filter_coeffs);
+
+	wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_ON);
+	wr(DIB3000MB_REG_MULTI_DEMOD_MSB,DIB3000MB_MULTI_DEMOD_MSB);
+	wr(DIB3000MB_REG_MULTI_DEMOD_LSB,DIB3000MB_MULTI_DEMOD_LSB);
+
+	wr(DIB3000MB_REG_OUTPUT_MODE,DIB3000MB_OUTPUT_MODE_SLAVE);
+
+	wr(DIB3000MB_REG_FIFO_142,DIB3000MB_FIFO_142);
+	wr(DIB3000MB_REG_MPEG2_OUT_MODE,DIB3000MB_MPEG2_OUT_MODE_188);
+	wr(DIB3000MB_REG_FIFO_144,DIB3000MB_FIFO_144);
+	wr(DIB3000MB_REG_FIFO,DIB3000MB_FIFO_INHIBIT);
+	wr(DIB3000MB_REG_FIFO_146,DIB3000MB_FIFO_146);
+	wr(DIB3000MB_REG_FIFO_147,DIB3000MB_FIFO_147);
+	
+	wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);	
+	return 0;
+}
+
+static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat)
+{
+	*stat = 0;
+	*stat |= rd(DIB3000MB_REG_AGC_LOCK) ? FE_HAS_SIGNAL : 0;
+	*stat |= rd(DIB3000MB_REG_CARRIER_LOCK) ? FE_HAS_CARRIER : 0;
+	*stat |= rd(DIB3000MB_REG_VIT_LCK) ? FE_HAS_VITERBI : 0;
+	*stat |= rd(DIB3000MB_REG_TS_SYNC_LOCK) ? FE_HAS_SYNC : 0;
+	*stat |= *stat ? FE_HAS_LOCK : 0;
+
+	deb_info("actual status is %2x\n",*stat);
+	
+	deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
+			rd(DIB3000MB_REG_TPS_LOCK),
+			rd(DIB3000MB_REG_TPS_QAM), 
+			rd(DIB3000MB_REG_TPS_HRCH),
+			rd(DIB3000MB_REG_TPS_VIT_ALPHA),
+			rd(DIB3000MB_REG_TPS_CODE_RATE_HP),
+			rd(DIB3000MB_REG_TPS_CODE_RATE_LP), 
+			rd(DIB3000MB_REG_TPS_GUARD_TIME),
+			rd(DIB3000MB_REG_TPS_FFT),
+			rd(DIB3000MB_REG_TPS_CELL_ID));
+
+	//*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	return 0;
+}
+
+static int dib3000mb_read_ber(struct dib3000mb_state *state,u32 *ber)
+{
+	*ber = 
+		(((rd(DIB3000MB_REG_BER_MSB) << 16) & 0x1f) | rd(DIB3000MB_REG_BER_LSB) ) /
+		 100000000;
+	return 0;
+}
+
+static int dib3000mb_signal_strength(struct dib3000mb_state *state, u16 *strength)
+{
+//	*stength = DIB3000MB_REG_SIGNAL_POWER 
+	return 0;
+}
+
+static int dib3000mb_sleep(struct dib3000mb_state *state)
+{
+	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
+	return 0;
+}
+
+static int dib3000mb_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	struct dib3000mb_state *state = fe->data;
+	int ret = 0;		
+	switch (cmd) {
+		case FE_GET_INFO:
+			deb_info("FE_GET_INFO\n");
+			memcpy(arg, &dib3000mb_info, sizeof(struct dvb_frontend_info));
+			break;
+
+		case FE_READ_STATUS: 
+			deb_info("FE_READ_STATUS\n");
+			ret = dib3000mb_read_status(state,(fe_status_t *)arg);
+			break;
+
+		case FE_READ_BER:
+			deb_info("FE_READ_BER\n");
+			ret = dib3000mb_read_ber(state,(u32 *)arg);
+			break;
+
+		case FE_READ_SIGNAL_STRENGTH:
+			deb_info("FE_READ_SIG_STRENGTH\n");
+			ret = dib3000mb_signal_strength(state,(u16 *) arg);
+			break;
+
+		case FE_READ_SNR:
+			deb_info("FE_READ_SNR\n");
+			break;
+
+		case FE_READ_UNCORRECTED_BLOCKS: 
+			deb_info("FE_READ_UNCORRECTED_BLOCKS\n");
+			break;
+
+		case FE_SET_FRONTEND:
+			deb_info("FE_SET_FRONTEND\n");
+			ret = dib3000mb_set_frontend(state,(struct dvb_frontend_parameters *) arg,1);
+			break;
+
+		case FE_GET_FRONTEND:
+			deb_info("FE_GET_FRONTEND\n");
+			ret = dib3000mb_get_frontend(state,(struct dvb_frontend_parameters *) arg);
+			break;
+
+		case FE_SLEEP:
+			deb_info("FE_SLEEP\n");
+			ret = dib3000mb_sleep(state);
+			break;
+
+		case FE_INIT:
+			deb_info("FE_INIT\n");
+			ret = dib3000mb_fe_init(state,0);
+			break;
+
+		case FE_SET_TONE:
+		case FE_SET_VOLTAGE:
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+	}
+	return 0;
+} 
+
+static struct i2c_client client_template;
+
+static int dib3000mb_attach_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_client *client;
+	struct dib3000mb_state *state;
+	int ret = -ENOMEM;
+
+	deb_info("i2c probe with adapter '%s'.\n",adapter->name);
+	
+	if ((state = kmalloc(sizeof(struct dib3000mb_state),GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	
+
+	if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL)
+		goto i2c_kmalloc_err;
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+
+	client->adapter = adapter;
+	client->addr = 0x10; 
+	state->i2c = client;
+	
+	i2c_set_clientdata(client,state);
+
+	state->manufactor_id = dib3000mb_read_reg(client, DIB3000MB_REG_MANUFACTOR_ID);
+	state->device_id = dib3000mb_read_reg(client,DIB3000MB_REG_DEVICE_ID);
+	if (state->manufactor_id == 0x01b3 && state->device_id == 0x3000) 
+		info("found a DiBCom (0x%04x) 3000-MB DVB-T frontend (ver: %x).",
+				state->manufactor_id, state->device_id);
+	else {
+		err("did not found a DiBCom 3000-MB.");
+		ret = -ENODEV;
+		goto probe_err;
+	}
+	
+	if ((ret = i2c_attach_client(client))) 
+		goto i2c_attach_err;
+
+	if (state->dvb == NULL) 
+		goto i2c_attach_err;
+
+	if ((ret = dvb_register_frontend(dib3000mb_ioctl, state->dvb, state,
+					     &dib3000mb_info, THIS_MODULE)))
+		goto dvb_fe_err;
+	
+	
+	goto success;
+dvb_fe_err:
+	i2c_detach_client(client);
+i2c_attach_err:
+probe_err:
+	kfree(client);
+i2c_kmalloc_err:
+	kfree(state);
+	return ret;
+success:
+	return 0;
+}
+
+
+static int dib3000mb_detach_client(struct i2c_client *client)
+{
+	struct dib3000mb_state *state = i2c_get_clientdata(client);
+
+	deb_info("i2c detach\n");
+
+	dvb_unregister_frontend(dib3000mb_ioctl, state->dvb);
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+
+	return 0;
+}
+
+static int dib3000mb_command(struct i2c_client *client,
+			      unsigned int cmd, void *arg)
+{
+	struct dib3000mb_state *state = i2c_get_clientdata(client);
+	deb_info("i2c command.\n");
+	switch(cmd) {
+		case FE_REGISTER:
+			state->dvb = arg;
+			break;
+		case FE_UNREGISTER:
+			state->dvb = NULL;
+			break;
+		default:
+			return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= "dib3000mb",
+	.id			= I2C_DRIVERID_DVBFE_DIB3000MB,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= dib3000mb_attach_adapter,
+	.detach_client	= dib3000mb_detach_client,
+	.command	= dib3000mb_command,
+};
+
+static struct i2c_client client_template = {
+	.name		= "dib3000mb",
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
+
+/* module stuff */
+static int __init dib3000mb_init(void)
+{
+	deb_info("debugging level: %d\n",debug);
+	return i2c_add_driver(&driver);
+}
+
+static void __exit dib3000mb_exit(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init (dib3000mb_init);
+module_exit (dib3000mb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dib3000mb.h linux-2.6.8.1-patched/drivers/media/dvb/frontends/dib3000mb.h
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dib3000mb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dib3000mb.h	2004-09-13 09:37:20.000000000 +0200
@@ -0,0 +1,657 @@
+/*
+ * dib3000mb.h
+ * 
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * 
+ * for more information see dib3000mb.c .
+ */
+
+#ifndef __DIB3000MB_H_INCLUDED__
+#define __DIB3000MB_H_INCLUDED__
+
+/* info and err, taken from usb.h, if there is anything available like by default,
+ * please change !
+ */
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+
+/* register addresses and some of their default values */
+
+/* restart subsystems */
+#define DIB3000MB_REG_RESTART			(     0)
+
+#define DIB3000MB_RESTART_OFF			(     0)
+#define DIB3000MB_RESTART_AUTO_SEARCH		(1 << 1)
+#define DIB3000MB_RESTART_CTRL				(1 << 2)
+#define DIB3000MB_RESTART_AGC				(1 << 3)
+
+/* FFT size */
+#define DIB3000MB_REG_FFT				(     1)
+#define DIB3000MB_FFT_2K					(     0)
+#define DIB3000MB_FFT_8K					(     1)
+#define DIB3000MB_FFT_AUTO					(     1)
+
+/* Guard time */
+#define DIB3000MB_REG_GUARD_TIME		(     2)
+#define DIB3000MB_GUARD_TIME_1_32			(     0)
+#define DIB3000MB_GUARD_TIME_1_16			(     1)
+#define DIB3000MB_GUARD_TIME_1_8			(     2)
+#define DIB3000MB_GUARD_TIME_1_4			(     3)
+#define DIB3000MB_GUARD_TIME_AUTO			(     0)
+
+/* QAM */
+#define DIB3000MB_REG_QAM				(     3)
+#define DIB3000MB_QAM_QPSK					(     0)
+#define DIB3000MB_QAM_QAM16					(     1)
+#define DIB3000MB_QAM_QAM64					(     2)
+#define DIB3000MB_QAM_RESERVED				(     3)
+
+/* Alpha coefficient high priority Viterbi algorithm */
+#define DIB3000MB_REG_VIT_ALPHA			(     4)
+#define DIB3000MB_VIT_ALPHA_OFF				(     0)
+#define DIB3000MB_VIT_ALPHA_1				(     1)
+#define DIB3000MB_VIT_ALPHA_2				(     2)
+#define DIB3000MB_VIT_ALPHA_4				(     4)
+#define DIB3000MB_VIT_ALPHA_AUTO			(     7)
+
+/* spectrum inversion */
+#define DIB3000MB_REG_DDS_INV			(     5)
+#define DIB3000MB_DDS_INV_OFF				(     0)
+#define DIB3000MB_DDS_INV_ON				(     1)
+
+/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ 
+#define DIB3000MB_REG_DDS_FREQ_MSB		(     6)
+#define DIB3000MB_REG_DDS_FREQ_LSB		(     7)
+#define DIB3000MB_DDS_FREQ_MSB				(   178)
+#define DIB3000MB_DDS_FREQ_LSB				(  8990)
+
+/* timing frequency (carrier spacing) */
+#define DIB3000MB_REG_TIMING_FREQ_MSB	(     8)
+#define DIB3000MB_REG_TIMING_FREQ_LSB	(     9)
+
+static u16 dib3000mb_reg_timing_freq[] = {
+	DIB3000MB_REG_TIMING_FREQ_MSB, DIB3000MB_REG_TIMING_FREQ_LSB 
+};
+static u16 dib3000mb_timing_freq[][2] = {
+	{ 126 , 48873 }, /* 6 MHz */
+	{ 147 , 57019 }, /* 7 MHz */ 
+	{ 168 , 65164 }, /* 8 MHz */
+};
+
+/* impulse noise parameter */
+#define DIB3000MB_REG_IMPNOISE_10		(    10)
+#define DIB3000MB_REG_IMPNOISE_11		(    11)
+#define DIB3000MB_REG_IMPNOISE_12		(    12)
+#define DIB3000MB_REG_IMPNOISE_13		(    13)
+#define DIB3000MB_REG_IMPNOISE_14		(    14)
+#define DIB3000MB_REG_IMPNOISE_15		(    15)
+/* 36 ??? */
+#define DIB3000MB_REG_IMPNOISE_36		(    36)
+
+enum dib3000mb_impulse_noise_type {
+	DIB3000MB_IMPNOISE_OFF,
+	DIB3000MB_IMPNOISE_MOBILE,
+	DIB3000MB_IMPNOISE_FIXED,
+	DIB3000MB_IMPNOISE_DEFAULT
+};
+
+static u16 dib3000mb_reg_impulse_noise[] = {
+ DIB3000MB_REG_IMPNOISE_10, DIB3000MB_REG_IMPNOISE_11, 
+ DIB3000MB_REG_IMPNOISE_12, DIB3000MB_REG_IMPNOISE_15,
+ DIB3000MB_REG_IMPNOISE_36
+};
+
+static u16 dib3000mb_impulse_noise_values[][5] = {
+	{ 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
+	{ 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
+	{ 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
+	{ 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
+};
+
+/* 
+ * Dual Automatic-Gain-Control 
+ * - gains RF in tuner (AGC1) 
+ * - gains IF after filtering (AGC2)
+ */
+
+/* also from 16 to 18 */
+#define DIB3000MB_REG_AGC_GAIN_19		(    19)
+#define DIB3000MB_REG_AGC_GAIN_20		(    20)
+#define DIB3000MB_REG_AGC_GAIN_21		(    21)
+#define DIB3000MB_REG_AGC_GAIN_22		(    22)
+#define DIB3000MB_REG_AGC_GAIN_23		(    23)
+#define DIB3000MB_REG_AGC_GAIN_24		(    24)
+#define DIB3000MB_REG_AGC_GAIN_25		(    25)
+#define DIB3000MB_REG_AGC_GAIN_26		(    26)
+#define DIB3000MB_REG_AGC_GAIN_27		(    27)
+#define DIB3000MB_REG_AGC_GAIN_28		(    28)
+#define DIB3000MB_REG_AGC_GAIN_29		(    29)
+#define DIB3000MB_REG_AGC_GAIN_30		(    30)
+#define DIB3000MB_REG_AGC_GAIN_31		(    31)
+#define DIB3000MB_REG_AGC_GAIN_32		(    32)
+
+static u16 dib3000mb_reg_agc_gain[] = {
+  DIB3000MB_REG_AGC_GAIN_19, DIB3000MB_REG_AGC_GAIN_20, DIB3000MB_REG_AGC_GAIN_21,
+  DIB3000MB_REG_AGC_GAIN_22, DIB3000MB_REG_AGC_GAIN_23, DIB3000MB_REG_AGC_GAIN_24,
+  DIB3000MB_REG_AGC_GAIN_25, DIB3000MB_REG_AGC_GAIN_26, DIB3000MB_REG_AGC_GAIN_27,
+  DIB3000MB_REG_AGC_GAIN_28, DIB3000MB_REG_AGC_GAIN_29, DIB3000MB_REG_AGC_GAIN_30,
+  DIB3000MB_REG_AGC_GAIN_31, DIB3000MB_REG_AGC_GAIN_32 };
+  
+static u16 dib3000mb_default_agc_gain[] =
+	{ 0x0001, 52429,   623, 128, 166, 195, 61,   /* RF ??? */
+	  0x0001, 53766, 38011,   0,  90,  33, 23 }; /* IF ??? */
+
+/* phase noise */
+#define DIB3000MB_REG_PHASE_NOISE_33		(    33)
+#define DIB3000MB_REG_PHASE_NOISE_34		(    34)
+#define DIB3000MB_REG_PHASE_NOISE_35		(    35)
+#define DIB3000MB_REG_PHASE_NOISE_36		(    36)
+#define DIB3000MB_REG_PHASE_NOISE_37		(    37)
+#define DIB3000MB_REG_PHASE_NOISE_38		(    38)
+
+/* DIB3000MB_REG_PHASE_NOISE_36 is set when setting the impulse noise */
+static u16 dib3000mb_reg_phase_noise[] = {
+	DIB3000MB_REG_PHASE_NOISE_33, DIB3000MB_REG_PHASE_NOISE_34, DIB3000MB_REG_PHASE_NOISE_35,
+	DIB3000MB_REG_PHASE_NOISE_37, DIB3000MB_REG_PHASE_NOISE_38
+};
+
+static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
+
+/* lock duration */
+#define DIB3000MB_REG_LOCK_DURATION_39	(    39)
+#define DIB3000MB_REG_LOCK_DURATION_40	(    40)
+
+static u16 dib3000mb_reg_lock_duration[] = {
+	DIB3000MB_REG_LOCK_DURATION_39, DIB3000MB_REG_LOCK_DURATION_40
+};
+
+static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
+
+/* AGC loop bandwidth */
+
+#define DIB3000MB_REG_AGC_BW_43			(    43)
+#define DIB3000MB_REG_AGC_BW_44			(    44)
+#define DIB3000MB_REG_AGC_BW_45			(    45)
+#define DIB3000MB_REG_AGC_BW_46			(    46)
+#define DIB3000MB_REG_AGC_BW_47			(    47)
+#define DIB3000MB_REG_AGC_BW_48			(    48)
+#define DIB3000MB_REG_AGC_BW_49			(    49)
+#define DIB3000MB_REG_AGC_BW_50			(    50)
+
+static u16 dib3000mb_reg_agc_bandwidth[] = {
+	DIB3000MB_REG_AGC_BW_43, DIB3000MB_REG_AGC_BW_44, DIB3000MB_REG_AGC_BW_45, 
+	DIB3000MB_REG_AGC_BW_46, DIB3000MB_REG_AGC_BW_47, DIB3000MB_REG_AGC_BW_48,
+	DIB3000MB_REG_AGC_BW_49, DIB3000MB_REG_AGC_BW_50
+};
+
+static u16 dib3000mb_agc_bandwidth_low[]  = 
+	{ 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
+static u16 dib3000mb_agc_bandwidth_high[] = 
+	{ 2349,  5, 2349,  5, 2586, 2, 2586, 2 };
+
+/* 
+ * lock0 definition (coff_lock) 
+ */
+#define DIB3000MB_REG_LOCK0_MASK		(    51)
+#define DIB3000MB_LOCK0_DEFAULT				(     4)
+
+/*
+ * lock1 definition (cpil_lock)
+ * for auto search 
+ * which values hide behind the lock masks 
+ */
+#define DIB3000MB_REG_LOCK1_MASK		(    52)
+#define DIB3000MB_LOCK1_SEARCH_4			(0x0004)
+#define DIB3000MB_LOCK1_SEARCH_2048			(0x0800)
+#define DIB3000MB_LOCK1_DEFAULT				(0x0001)
+
+/*
+ * lock2 definition (fec_lock) */
+#define DIB3000MB_REG_LOCK2_MASK		(    53)
+#define DIB3000MB_LOCK2_DEFAULT				(0x0080)
+
+/* 
+ * SEQ ? what was that again ... :) 
+ * changes when, inversion, guard time and fft is
+ * either automatically detected or not
+ */
+#define DIB3000MB_REG_SEQ				(    54)
+
+/* all values have been set manually */
+static u16 dib3000mb_seq[2][2][2] = 	/* fft,gua,   inv   */
+	{ /* fft */ 
+		{ /* gua */ 
+			{ 0, 1 },					/*  0   0   { 0,1 } */
+			{ 3, 9 },					/*  0   1   { 0,1 } */
+		},
+		{ 
+			{ 2, 5 },					/*  1   0   { 0,1 } */
+			{ 6, 11 },					/*  1   1   { 0,1 } */
+		}
+	};
+
+/* bandwidth */
+#define DIB3000MB_REG_BW_55				(    55)
+#define DIB3000MB_REG_BW_56				(    56)
+#define DIB3000MB_REG_BW_57				(    57)
+#define DIB3000MB_REG_BW_58				(    58)
+#define DIB3000MB_REG_BW_59				(    59)
+#define DIB3000MB_REG_BW_60				(    60)
+#define DIB3000MB_REG_BW_61				(    61)
+#define DIB3000MB_REG_BW_62				(    62)
+#define DIB3000MB_REG_BW_63				(    63)
+#define DIB3000MB_REG_BW_64				(    64)
+#define DIB3000MB_REG_BW_65				(    65)
+#define DIB3000MB_REG_BW_66				(    66)
+#define DIB3000MB_REG_BW_67				(    67)
+
+static u16 dib3000mb_reg_bandwidth[] = {
+	DIB3000MB_REG_BW_55, DIB3000MB_REG_BW_56, DIB3000MB_REG_BW_57, 
+	DIB3000MB_REG_BW_58, DIB3000MB_REG_BW_59, DIB3000MB_REG_BW_60,
+	DIB3000MB_REG_BW_61, DIB3000MB_REG_BW_62, DIB3000MB_REG_BW_63,
+	DIB3000MB_REG_BW_64, DIB3000MB_REG_BW_65, DIB3000MB_REG_BW_66, 
+	DIB3000MB_REG_BW_67
+};
+
+static u16 dib3000mb_bandwidth_6mhz[] = 
+	{ 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_7mhz[] =
+	{ 0, 28, 64421,  96, 39973, 483,  3255, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_8mhz[] =
+	{ 0, 25, 23600,  84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
+
+#define DIB3000MB_REG_UNK_68				(    68)
+#define DIB3000MB_UNK_68						(     0)
+
+#define DIB3000MB_REG_UNK_69				(    69)
+#define DIB3000MB_UNK_69						(     0)
+
+#define DIB3000MB_REG_UNK_71				(    71)
+#define DIB3000MB_UNK_71						(     0)
+
+#define DIB3000MB_REG_UNK_77				(    77)
+#define DIB3000MB_UNK_77						(     6)
+
+#define DIB3000MB_REG_UNK_78				(    78)
+#define DIB3000MB_UNK_78						(0x0080)
+
+/* isi */
+#define DIB3000MB_REG_ISI				(    79)
+#define DIB3000MB_ISI_ACTIVATE				(     0)
+#define DIB3000MB_ISI_INHIBIT				(     1)
+
+/* sync impovement */
+#define DIB3000MB_REG_SYNC_IMPROVEMENT	(    84)
+#define DIB3000MB_SYNC_IMPROVE_2K_1_8		(     3)
+#define DIB3000MB_SYNC_IMPROVE_DEFAULT		(     0)
+
+/* phase noise compensation inhibition */
+#define DIB3000MB_REG_PHASE_NOISE		(    87)
+#define DIB3000MB_PHASE_NOISE_DEFAULT	(     0)
+
+#define DIB3000MB_REG_UNK_92				(    92)
+#define DIB3000MB_UNK_92						(0x0080)
+
+#define DIB3000MB_REG_UNK_96				(    96)
+#define DIB3000MB_UNK_96						(0x0010)
+
+#define DIB3000MB_REG_UNK_97				(    97)
+#define DIB3000MB_UNK_97						(0x0009)
+
+/* mobile mode ??? */
+#define DIB3000MB_REG_MOBILE_MODE		(   101)
+#define DIB3000MB_MOBILE_MODE_ON				(     1)
+#define DIB3000MB_MOBILE_MODE_OFF			(     0)
+
+#define DIB3000MB_REG_UNK_106			(   106)
+#define DIB3000MB_UNK_106					(0x0080)
+
+#define DIB3000MB_REG_UNK_107			(   107)
+#define DIB3000MB_UNK_107					(0x0080)
+
+#define DIB3000MB_REG_UNK_108			(   108)
+#define DIB3000MB_UNK_108					(0x0080)
+
+/* fft ??? */
+#define DIB3000MB_REG_UNK_121			(   121)
+#define DIB3000MB_UNK_121_2K				(     7)
+#define DIB3000MB_UNK_121_DEFAULT			(     5)
+
+#define DIB3000MB_REG_UNK_122			(   122)
+#define DIB3000MB_UNK_122					(  2867)
+
+/* QAM for mobile mode */
+#define DIB3000MB_REG_MOBILE_MODE_QAM	(   126)
+#define DIB3000MB_MOBILE_MODE_QAM_64			(     3)
+#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16	(     1)
+#define DIB3000MB_MOBILE_MODE_QAM_OFF		(     0)
+
+/* 
+ * data diversity when having more than one chip on-board
+ * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
+ */
+#define DIB3000MB_REG_DATA_IN_DIVERSITY		(   127)
+#define DIB3000MB_DATA_DIVERSITY_IN_OFF			(     0)
+#define DIB3000MB_DATA_DIVERSITY_IN_ON			(     2)
+
+/* vit hrch */
+#define DIB3000MB_REG_VIT_HRCH			(   128)
+#define DIB3000MB_VIT_HRCH_ON				(     1)
+#define DIB3000MB_VIT_HRCH_OFF				(     0)
+
+/* vit code rate */
+#define DIB3000MB_REG_VIT_CODE_RATE		(   129)
+
+/* forward error correction code rates */
+#define DIB3000MB_FEC_1_2					(     0)
+#define DIB3000MB_FEC_2_3					(     1)
+#define DIB3000MB_FEC_3_4					(     2)
+#define DIB3000MB_FEC_4_5					(     3)
+#define DIB3000MB_FEC_5_6					(     4)
+#define DIB3000MB_FEC_7_8					(     5)
+
+/* vit select hp */
+#define DIB3000MB_REG_VIT_HP			(   130)
+#define DIB3000MB_VIT_LP					(     0)
+#define DIB3000MB_VIT_HP					(     1)
+
+/* time frame for Bit-Error-Rate calculation */
+#define DIB3000MB_REG_BERLEN			(   135)
+#define DIB3000MB_BERLEN_LONG				(     0)
+#define DIB3000MB_BERLEN_DEFAULT			(     1)
+#define DIB3000MB_BERLEN_MEDIUM				(     2)
+#define DIB3000MB_BERLEN_SHORT				(     3)
+
+/* 142 - 152 FIFO parameters 
+ * which is what ?
+ */
+
+#define DIB3000MB_REG_FIFO_142			(   142)
+#define DIB3000MB_FIFO_142					(     0)
+
+/* MPEG2 TS output mode */
+#define DIB3000MB_REG_MPEG2_OUT_MODE	(   143)
+#define DIB3000MB_MPEG2_OUT_MODE_204		(     0)
+#define DIB3000MB_MPEG2_OUT_MODE_188		(     1)
+
+#define DIB3000MB_REG_FIFO_144			(   144)
+#define DIB3000MB_FIFO_144					(     1)
+
+#define DIB3000MB_REG_FIFO				(   145)
+#define DIB3000MB_FIFO_INHIBIT				(     1)
+#define DIB3000MB_FIFO_ACTIVATE				(     0)
+
+#define DIB3000MB_REG_FIFO_146			(   146)
+#define DIB3000MB_FIFO_146					(     3)
+
+#define DIB3000MB_REG_FIFO_147			(   147)
+#define DIB3000MB_FIFO_147					(0x0100)
+
+/* 
+ * pidfilter 
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. Necessary because of the limited USB1.1 bandwidth.
+ */
+#define DIB3000MB_REG_FILTER_PID_0		(   153)
+#define DIB3000MB_REG_FILTER_PID_1		(   154)
+#define DIB3000MB_REG_FILTER_PID_2		(   155)
+#define DIB3000MB_REG_FILTER_PID_3		(   156)
+#define DIB3000MB_REG_FILTER_PID_4		(   157)
+#define DIB3000MB_REG_FILTER_PID_5		(   158)
+#define DIB3000MB_REG_FILTER_PID_6		(   159)
+#define DIB3000MB_REG_FILTER_PID_7		(   160)
+#define DIB3000MB_REG_FILTER_PID_8		(   161)
+#define DIB3000MB_REG_FILTER_PID_9		(   162)
+#define DIB3000MB_REG_FILTER_PID_10		(   163)
+#define DIB3000MB_REG_FILTER_PID_11		(   164)
+#define DIB3000MB_REG_FILTER_PID_12		(   165)
+#define DIB3000MB_REG_FILTER_PID_13		(   166)
+#define DIB3000MB_REG_FILTER_PID_14		(   167)
+#define DIB3000MB_REG_FILTER_PID_15		(   168)
+
+#define DIB3000MB_ACTIVATE_FILTERING			(0x2000)
+
+/*
+ * output mode
+ * USB devices have to use 'slave'-mode
+ * see also DIB3000MB_REG_ELECT_OUT_MODE
+ */
+#define DIB3000MB_REG_OUTPUT_MODE		(   169)
+#define DIB3000MB_OUTPUT_MODE_GATED_CLK		(     0)
+#define DIB3000MB_OUTPUT_MODE_CONT_CLK		(     1)
+#define DIB3000MB_OUTPUT_MODE_SERIAL		(     2)
+#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY	(     5)
+#define DIB3000MB_OUTPUT_MODE_SLAVE			(     6)
+
+/* irq event mask */
+#define DIB3000MB_REG_IRQ_EVENT_MASK		(   170)
+#define DIB3000MB_IRQ_EVENT_MASK				(     0)
+
+/* filter coefficients */
+#define DIB3000MB_REG_FILTER_COEF_171	(   171)
+#define DIB3000MB_REG_FILTER_COEF_172	(   172)
+#define DIB3000MB_REG_FILTER_COEF_173	(   173)
+#define DIB3000MB_REG_FILTER_COEF_174	(   174)
+#define DIB3000MB_REG_FILTER_COEF_175	(   175)
+#define DIB3000MB_REG_FILTER_COEF_176	(   176)
+#define DIB3000MB_REG_FILTER_COEF_177	(   177)
+#define DIB3000MB_REG_FILTER_COEF_178	(   178)
+#define DIB3000MB_REG_FILTER_COEF_179	(   179)
+#define DIB3000MB_REG_FILTER_COEF_180	(   180)
+#define DIB3000MB_REG_FILTER_COEF_181	(   181)
+#define DIB3000MB_REG_FILTER_COEF_182	(   182)
+#define DIB3000MB_REG_FILTER_COEF_183	(   183)
+#define DIB3000MB_REG_FILTER_COEF_184	(   184)
+#define DIB3000MB_REG_FILTER_COEF_185	(   185)
+#define DIB3000MB_REG_FILTER_COEF_186	(   186)
+#define DIB3000MB_REG_FILTER_COEF_187	(   187)
+#define DIB3000MB_REG_FILTER_COEF_188	(   188)
+#define DIB3000MB_REG_FILTER_COEF_189	(   189)
+#define DIB3000MB_REG_FILTER_COEF_190	(   190)
+#define DIB3000MB_REG_FILTER_COEF_191	(   191)
+#define DIB3000MB_REG_FILTER_COEF_192	(   192)
+#define DIB3000MB_REG_FILTER_COEF_193	(   193)
+#define DIB3000MB_REG_FILTER_COEF_194	(   194)
+
+static u16 dib3000mb_reg_filter_coeffs[] = {
+	DIB3000MB_REG_FILTER_COEF_171, DIB3000MB_REG_FILTER_COEF_172, DIB3000MB_REG_FILTER_COEF_173,
+	DIB3000MB_REG_FILTER_COEF_174, DIB3000MB_REG_FILTER_COEF_175, DIB3000MB_REG_FILTER_COEF_176,
+	DIB3000MB_REG_FILTER_COEF_177, DIB3000MB_REG_FILTER_COEF_178, DIB3000MB_REG_FILTER_COEF_179,
+	DIB3000MB_REG_FILTER_COEF_180, DIB3000MB_REG_FILTER_COEF_181, DIB3000MB_REG_FILTER_COEF_182,
+	DIB3000MB_REG_FILTER_COEF_183, DIB3000MB_REG_FILTER_COEF_184, DIB3000MB_REG_FILTER_COEF_185,
+	DIB3000MB_REG_FILTER_COEF_186,                                DIB3000MB_REG_FILTER_COEF_188,
+	DIB3000MB_REG_FILTER_COEF_189, DIB3000MB_REG_FILTER_COEF_190, DIB3000MB_REG_FILTER_COEF_191,
+	DIB3000MB_REG_FILTER_COEF_192,                                DIB3000MB_REG_FILTER_COEF_194
+};
+
+static u16 dib3000mb_filter_coeffs[] = {
+	 226,  160,   29, 
+ 	 979,  998,   19,  
+	  22, 1019, 1006, 
+	1022,   12,    6, 
+	1017, 1017,    3,  
+	   6,       1019,
+	1021,    2,    3,
+	   1,          0,
+};
+
+/* 
+ * mobile algorithm (when you are moving with your device) 
+ * but not faster than 90 km/h
+ */
+#define DIB3000MB_REG_MOBILE_ALGO		(   195)
+#define DIB3000MB_MOBILE_ALGO_ON			(     0)
+#define DIB3000MB_MOBILE_ALGO_OFF			(     1)
+
+/* multiple demodulators algorithm */
+#define DIB3000MB_REG_MULTI_DEMOD_MSB	(   206)
+#define DIB3000MB_REG_MULTI_DEMOD_LSB	(   207)
+
+/* terminator, no more demods */
+#define DIB3000MB_MULTI_DEMOD_MSB			( 32767)
+#define DIB3000MB_MULTI_DEMOD_LSB			(  4095)
+
+/* bring the device into a known  */
+#define DIB3000MB_REG_RESET_DEVICE		(  1024)
+#define DIB3000MB_RESET_DEVICE				(0x812c)
+#define DIB3000MB_RESET_DEVICE_RST			(     0)
+
+/* identification registers, manufactor an the device */
+#define DIB3000MB_REG_MANUFACTOR_ID		(  1025)
+#define DIB3000MB_MANUFACTOR_ID_DIBCOM		(0x01B3)
+
+#define DIB3000MB_REG_DEVICE_ID			(  1026)
+#define DIB3000MB_DEVICE_ID					(0x3000)
+
+/* hardware clock configuration */
+#define DIB3000MB_REG_CLOCK				(  1027)
+#define DIB3000MB_CLOCK_DEFAULT				(0x9000)
+#define DIB3000MB_CLOCK_DIVERSITY			(0x92b0)
+
+/* power down config */
+#define DIB3000MB_REG_POWER_CONTROL		(  1028)
+#define DIB3000MB_POWER_DOWN				(     1)
+#define DIB3000MB_POWER_UP					(     0)
+
+/* electrical output mode */
+#define DIB3000MB_REG_ELECT_OUT_MODE	(  1029)
+#define DIB3000MB_ELECT_OUT_MODE_OFF		(     0)
+#define DIB3000MB_ELECT_OUT_MODE_ON			(     1)
+
+/* set the tuner i2c address */
+#define DIB3000MB_REG_TUNER				(  1089)
+#define DIB3000MB_TUNER_ADDR_DEFAULT		(   194)
+#define DIB3000MB_ACTIVATE_TUNER_XFER(a)	(0xffff & (a << 7))
+#define DIB3000MB_DEACTIVATE_TUNER_XFER(a)	(0xffff & ((a << 7) + 0x80)) 
+
+/* monitoring registers (read only) */
+
+/* agc loop locked (size: 1) */
+#define DIB3000MB_REG_AGC_LOCK			(   324)
+
+/* agc power (size: 16) */
+#define DIB3000MB_REG_AGC_POWER			(   325)
+
+/* agc1 value (16) */
+#define DIB3000MB_REG_AGC1_VALUE		(   326)
+
+/* agc2 value (16) */
+#define DIB3000MB_REG_AGC2_VALUE		(   327)
+
+/* total RF power (16), can be used for signal strength */
+#define DIB3000MB_REG_RF_POWER			(   328)
+
+/* dds_frequency with offset (24) */
+#define DIB3000MB_REG_DDS_VALUE_MSB		(   339)
+#define DIB3000MB_REG_DDS_VALUE_LSB		(   340)
+
+/* timing offset signed (24) */
+#define DIB3000MB_REG_TIMING_OFFSET_MSB	(   341)
+#define DIB3000MB_REG_TIMING_OFFSET_LSB	(   342)
+
+/* fft start position (13) */
+#define DIB3000MB_REG_FFT_WINDOW_POS	(   353)
+
+/* carriers locked (1) */
+#define DIB3000MB_REG_CARRIER_LOCK		(   355)
+
+/* noise power (24) */
+#define DIB3000MB_REG_NOISE_POWER_MSB	(   372)
+#define DIB3000MB_REG_NOISE_POWER_LSB	(   373)
+
+#define DIB3000MB_REG_MOBILE_NOISE_MSB	(   374)
+#define DIB3000MB_REG_MOBILE_NOISE_LSB	(   375)
+
+/* 
+ * signal power (16), this and the above can be 
+ * used to calculate the signal/noise - ratio
+ */
+#define DIB3000MB_REG_SIGNAL_POWER		(   380)
+
+/* mer (24) */
+#define DIB3000MB_REG_MER_MSB			(   381)
+#define DIB3000MB_REG_MER_LSB			(   382)
+
+/*
+ * Transmission Parameter Signalling (TPS) 
+ * the following registers can be used to get TPS-information.
+ * The values are according to the DVB-T standard.
+ */
+
+/* TPS locked (1) */
+#define DIB3000MB_REG_TPS_LOCK			(   394)
+
+/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
+#define DIB3000MB_REG_TPS_QAM			(   398)
+
+/* hierarchy from TPS (1) */
+#define DIB3000MB_REG_TPS_HRCH			(   399)
+
+/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
+#define DIB3000MB_REG_TPS_VIT_ALPHA		(   400)
+
+/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
+#define DIB3000MB_REG_TPS_CODE_RATE_HP	(   401)
+
+/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
+#define DIB3000MB_REG_TPS_CODE_RATE_LP	(   402)
+
+/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
+#define DIB3000MB_REG_TPS_GUARD_TIME	(   403)
+
+/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
+#define DIB3000MB_REG_TPS_FFT			(   404)
+
+/* cell id from TPS (16) */
+#define DIB3000MB_REG_TPS_CELL_ID		(   406)
+
+/* TPS (68) */
+#define DIB3000MB_REG_TPS_1				(   408)
+#define DIB3000MB_REG_TPS_2				(   409)
+#define DIB3000MB_REG_TPS_3				(   410)
+#define DIB3000MB_REG_TPS_4				(   411)
+#define DIB3000MB_REG_TPS_5				(   412)
+
+/* bit error rate (before RS correction) (21) */
+#define DIB3000MB_REG_BER_MSB			(   414)
+#define DIB3000MB_REG_BER_LSB			(   415)
+
+/* packet error rate (uncorrected TS packets) (16) */
+#define DIB3000MB_REG_PACKET_ERROR_RATE	(   417)
+
+/* packet error count (16) */
+#define DIB3000MB_REG_PACKET_ERROR_COUNT	(   420)
+
+/* viterbi locked (1) */
+#define DIB3000MB_REG_VIT_LCK			(   421)
+
+/* viterbi inidcator (16) */
+#define DIB3000MB_REG_VIT_INDICATOR		(   422)
+
+/* transport stream sync lock (1) */
+#define DIB3000MB_REG_TS_SYNC_LOCK		(   423)
+
+/* transport stream RS lock (1) */ 
+#define DIB3000MB_REG_TS_RS_LOCK		(   424)
+
+/* lock mask 0 value (1) */
+#define DIB3000MB_REG_LOCK0_VALUE		(   425)
+
+/* lock mask 1 value (1) */
+#define DIB3000MB_REG_LOCK1_VALUE		(   426)
+
+/* lock mask 2 value (1) */
+#define DIB3000MB_REG_LOCK2_VALUE		(   427)
+
+/* interrupt pending for auto search */
+#define DIB3000MB_REG_AS_IRQ_PENDING	(   434)
+
+#endif
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/Makefile linux-2.6.8.1-patched/drivers/media/dvb/frontends/Makefile
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/Makefile	2004-09-17 12:26:33.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/Makefile	2004-09-15 10:26:44.000000000 +0200
@@ -12,6 +12,7 @@
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
 obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
 obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -19,4 +20,5 @@
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
 obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_CX22702) += cx22702.o
 

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

* Re: [PATCH][2.6][11/14] new DVB driver
  2004-09-17 14:36                   ` [PATCH][2.6][10/14] add new frontend drivers 2/2 Michael Hunold
@ 2004-09-17 14:37                     ` Michael Hunold
  2004-09-17 14:39                       ` [PATCH][2.6][12/14] misc. driver updates Michael Hunold
  0 siblings, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:37 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 11-DVB-new-driver-dibusb.diff --]
[-- Type: text/plain, Size: 29871 bytes --]

- [DVB] new driver for mobile USB Budget DVB-T devices, thanks to Patrick Boettcher

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/dvb-dibusb.c linux-2.6.8.1-patched/drivers/media/dvb/dibusb/dvb-dibusb.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/dvb-dibusb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/dibusb/dvb-dibusb.c	2004-09-17 11:51:57.000000000 +0200
@@ -0,0 +1,719 @@
+/*
+ * Driver for mobile USB Budget DVB-T devices based on reference 
+ * design made by DiBcom (http://www.dibcom.fr/)
+ * 
+ * dvb-dibusb.c
+ * 
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 
+ * based on GPL code from DiBcom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ * 
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * Acknowledgements
+ * 
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dib3000mb frontend) are based.
+ *
+ *  TODO
+ *   - probing for i2c addresses, it is possible, that they have been changed 
+ *     by the vendor
+ * 
+ * see Documentation/dvb/README.dibusb for more information
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#include "dvb-dibusb.h"
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk_new(level,args...) \
+	    do { if ((debug & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l) if (debug) {\
+	int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
+	for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
+	deb_xfer("\n");\
+}
+
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore (|-able)).");
+#else
+#define dprintk_new(args...)
+#define debug_dump(b,l)
+#endif
+
+#define deb_info(args...) dprintk_new(0x01,args)
+#define deb_xfer(args...) dprintk_new(0x02,args)
+#define deb_alot(args...) dprintk_new(0x04,args)
+
+/* Version information */
+#define DRIVER_VERSION "0.0"
+#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+/* USB Driver stuff */
+	
+/* table of devices that work with this driver */
+static struct usb_device_id dibusb_table [] = {
+	{ USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_PREFW_ID) },
+	{ USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_ID) },
+	{ USB_DEVICE(USB_IMC_NETWORKS_VENDOR_ID, USB_VP7041_PRODUCT_PREFW_ID) },
+	{ USB_DEVICE(USB_IMC_NETWORKS_VENDOR_ID, USB_VP7041_PRODUCT_ID) },
+	{ USB_DEVICE(USB_KWORLD_VENDOR_ID, USB_VSTREAM_PRODUCT_PREFW_ID) },
+	{ USB_DEVICE(USB_KWORLD_VENDOR_ID, USB_VSTREAM_PRODUCT_ID) },
+	{ USB_DEVICE(USB_DIBCOM_VENDOR_ID, USB_DIBCOM_PRODUCT_PREFW_ID) },
+	{ USB_DEVICE(USB_DIBCOM_VENDOR_ID, USB_DIBCOM_PRODUCT_ID) },
+	{ USB_DEVICE(USB_ULTIMA_ELECTRONIC_ID, USB_ULTIMA_ELEC_PROD_PREFW_ID) },
+	{ USB_DEVICE(USB_ULTIMA_ELECTRONIC_ID, USB_ULTIMA_ELEC_PROD_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dibusb_table);
+
+static int dibusb_readwrite_usb(struct usb_dibusb *dib, 
+		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	int actlen,ret = -ENOMEM;
+
+	if (wbuf == NULL || wlen == 0)
+		return -EINVAL;
+
+/*	if (dib->disconnecting)
+		return -EINVAL;*/
+
+	if ((ret = down_interruptible(&dib->usb_sem)))
+		return ret;
+
+	debug_dump(wbuf,wlen);
+		
+	ret = usb_bulk_msg(dib->udev,COMMAND_PIPE,
+			wbuf,wlen,&actlen,DIBUSB_I2C_TIMEOUT);
+		
+	if (ret)
+		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
+	else
+		ret = actlen != wlen ? -1 : 0;
+
+	/* an answer is expected */
+	if (!ret && rbuf && rlen) {
+		ret = usb_bulk_msg(dib->udev,RESULT_PIPE,rbuf,rlen,
+				&actlen,DIBUSB_I2C_TIMEOUT);
+
+		if (ret)
+			err("recv bulk message failed: %d",ret);
+		else {
+			deb_alot("rlen: %d\n",rlen);
+			debug_dump(rbuf,actlen);
+		}
+	}
+	
+	up(&dib->usb_sem);
+	return ret;
+}
+
+static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+	return dibusb_readwrite_usb(dib,buf,len,NULL,0);
+}
+
+static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, 
+		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+	/* write only ? */
+	int wo = (rbuf == NULL || rlen == 0), 
+		len = 2 + wlen + (wo ? 0 : 2);
+
+	deb_alot("wo: %d, wlen: %d, len: %d\n",wo,wlen,len);
+	
+	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+	sndbuf[1] = (addr & 0xfe) | (wo ? 0 : 1);
+
+	memcpy(&sndbuf[2],wbuf,wlen);
+	
+	if (!wo) {
+		sndbuf[wlen+2] = (rlen >> 8) & 0xff;
+		sndbuf[wlen+3] = rlen & 0xff;
+	}
+	
+	return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen);
+}
+
+/*
+ * DVB stuff 
+ */
+
+static struct dibusb_pid * dibusb_get_free_pid(struct usb_dibusb *dib)
+{
+	int i;
+	unsigned long flags;
+	struct dibusb_pid *dpid = NULL;
+
+	spin_lock_irqsave(&dib->pid_list_lock,flags);
+	for (i=0; i < DIBUSB_MAX_PIDS; i++)
+		if (!dib->pid_list[i].active) {
+			dpid = dib->pid_list + i;
+			dpid->active = 1;
+			break;
+		}
+	spin_unlock_irqrestore(&dib->pid_list_lock,flags);
+	return dpid;
+}
+
+static int dibusb_start_xfer(struct usb_dibusb *dib)
+{
+	u8 b[4] = { 
+		(DIB3000MB_REG_FIFO >> 8) & 0xff,
+		(DIB3000MB_REG_FIFO) & 0xff,
+		(DIB3000MB_FIFO_ACTIVATE >> 8) & 0xff,
+		(DIB3000MB_FIFO_ACTIVATE) & 0xff
+	};
+	return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
+}
+
+static int dibusb_stop_xfer(struct usb_dibusb *dib)
+{
+	u8 b[4] = { 
+		(DIB3000MB_REG_FIFO >> 8) & 0xff,
+		(DIB3000MB_REG_FIFO) & 0xff,
+		(DIB3000MB_FIFO_INHIBIT >> 8) & 0xff,
+		(DIB3000MB_FIFO_INHIBIT) & 0xff
+	};
+	return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
+}
+
+static int dibusb_set_pid(struct dibusb_pid *dpid)
+{
+	u16 pid = dpid->pid | (dpid->active ? DIB3000MB_ACTIVATE_FILTERING : 0);
+	u8 b[4] = { 
+		(dpid->reg >> 8) & 0xff,
+		(dpid->reg) & 0xff,
+		(pid >> 8) & 0xff,
+		(pid) & 0xff
+	};
+	
+	return dibusb_i2c_msg(dpid->dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
+}
+
+static void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+	struct usb_dibusb *dib = urb->context;
+
+	if (!dib->streaming)
+		return;
+
+	if (urb->status == 0) {
+		deb_info("URB return len: %d\n",urb->actual_length);
+		if (urb->actual_length % 188)
+			deb_info("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
+		dvb_dmx_swfilter_packets(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length/188);
+	}
+
+	if (dib->streaming)
+		usb_submit_urb(urb,GFP_KERNEL);
+}
+
+
+static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+//	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
+	struct dibusb_pid *dpid;
+	int ret = 0;
+
+	deb_info("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+
+	if ((dpid = dibusb_get_free_pid(dib)) == NULL) {
+		err("no free pid in list.");
+		return -ENODEV;
+	}
+	dvbdmxfeed->priv = dpid;
+	dpid->pid = dvbdmxfeed->pid;
+
+	dibusb_set_pid(dpid);
+
+	if (0 == dib->feed_count++) {
+		usb_fill_bulk_urb( dib->buf_urb, dib->udev, DATA_PIPE,
+			dib->buffer, 8192, dibusb_urb_complete, dib);
+		dib->buf_urb->transfer_flags = 0;
+		dib->buf_urb->timeout = 0;
+
+		if ((ret = usb_submit_urb(dib->buf_urb,GFP_KERNEL))) {
+			dibusb_stop_xfer(dib);
+			err("could not submit buffer urb.");
+			return ret;
+		}
+		
+		if ((ret = dibusb_start_xfer(dib)))
+			return ret;
+
+		dib->streaming = 1;
+	}
+	return 0;
+}
+
+static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
+	struct dibusb_pid *dpid = (struct dibusb_pid *) dvbdmxfeed->priv;
+
+	deb_info("stopfeed pid: 0x%04x, feedtype: %d",dvbdmxfeed->pid, dvbdmxfeed->type);
+
+	if (dpid == NULL)
+		err("channel in dmxfeed->priv was NULL");
+	else {
+		dpid->active = 0;
+		dpid->pid = 0;
+		dibusb_set_pid(dpid);
+	}
+
+	if (--dib->feed_count == 0) {
+		dib->streaming = 0;
+		usb_unlink_urb(dib->buf_urb);
+		dibusb_stop_xfer(dib);
+	}		
+	return 0;
+}
+
+/*
+ * firmware transfers
+ */
+
+/*
+ * do not use this, just a workaround for a bug, 
+ * which will never occur :).
+ */
+static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_REQ_INTR_READ };
+	return dibusb_write_usb(dib,b,1);
+}
+
+/*
+ * TODO: a tasklet should run with a delay of 1/10 second
+ * and fill an appropriate event device ?
+ */
+static int dibusb_read_remote_control(struct usb_dibusb *dib) 
+{
+	u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
+	int ret;
+	if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) 
+		return ret;
+
+	return 0;
+}
+
+/*
+ * ioctl for the firmware 
+ */
+static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
+{
+	u8 b[34];
+	int size = plen > 32 ? 32 : plen;
+	b[0] = DIBUSB_REQ_SET_IOCTL;
+	b[1] = cmd;
+	memcpy(&b[2],param,size);
+
+	return dibusb_write_usb(dib,b,2+size);
+}
+
+/*
+ * ioctl for power control
+ */
+static int dibusb_hw_sleep(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
+	return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+}
+
+static int dibusb_hw_wakeup(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
+	return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+}
+
+/*
+ * I2C
+ */
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+	struct usb_dibusb *dib = i2c_get_adapdata(adap);
+	int i;
+
+	if (down_interruptible(&dib->i2c_sem) < 0) 
+		return -EAGAIN;
+	
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,
+						msg[i+1].buf,msg[i+1].len) < 0)
+				break;
+			i++;
+		} else 
+			if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
+				break;
+	}
+	
+	up(&dib->i2c_sem);
+	return i;	
+}
+
+static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static int dibusb_i2c_client_register (struct i2c_client *i2c)
+{
+	struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter);
+	if (i2c->driver->command)
+		return i2c->driver->command(i2c,FE_REGISTER,dib->adapter);
+	return 0;
+}
+
+static int dibusb_i2c_client_unregister (struct i2c_client *i2c)
+{
+	struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter);
+	if (i2c->driver->command)
+		return i2c->driver->command(i2c,FE_UNREGISTER,dib->adapter);
+	return 0;
+}
+
+static struct i2c_algorithm dibusb_algo = {
+	.name			= "DiBcom USB i2c algorithm",
+	.id				= I2C_ALGO_BIT,
+	.master_xfer	= dibusb_i2c_xfer,
+	.functionality	= dibusb_i2c_func,
+};
+
+static int dibusb_dvb_init(struct usb_dibusb *dib)
+{
+	int ret;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
+    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) {
+#else
+    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC , 
+			THIS_MODULE)) < 0) {
+#endif
+		deb_info("dvb_register_adapter failed: error %d", ret);
+		goto err;
+	}
+
+	strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+	dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+	dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+	dib->i2c_adap.algo 		= &dibusb_algo;
+	dib->i2c_adap.algo_data = NULL;
+	dib->i2c_adap.id		= I2C_ALGO_BIT;
+	dib->i2c_adap.client_register   = dibusb_i2c_client_register,
+	dib->i2c_adap.client_unregister = dibusb_i2c_client_unregister,
+	
+	i2c_set_adapdata(&dib->i2c_adap, dib);
+	
+	if ((i2c_add_adapter(&dib->i2c_adap) < 0)) {
+		err("could not add i2c adapter");
+		goto err_i2c;
+	}
+
+	dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+
+	dib->demux.priv = (void *)dib;
+	dib->demux.filternum = DIBUSB_MAX_PIDS;
+	dib->demux.feednum = DIBUSB_MAX_PIDS;
+	dib->demux.start_feed = dibusb_start_feed;
+	dib->demux.stop_feed = dibusb_stop_feed;
+	dib->demux.write_to_decoder = NULL;
+	if ((ret = dvb_dmx_init(&dib->demux)) < 0) {
+		err("dvb_dmx_init failed: error %d",ret);
+		goto err_dmx;
+	}
+
+	dib->dmxdev.filternum = dib->demux.filternum;
+	dib->dmxdev.demux = &dib->demux.dmx;
+	dib->dmxdev.capabilities = 0;
+	if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) {
+		err("dvb_dmxdev_init failed: error %d",ret);
+		goto err_dmx_dev;
+	}
+
+	dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx);
+	
+	goto success;
+err_dmx_dev:
+	dvb_dmx_release(&dib->demux);
+err_dmx:
+	i2c_del_adapter(&dib->i2c_adap);
+err_i2c:
+	dvb_unregister_adapter(dib->adapter);
+err:
+	return ret;
+success:
+	return 0;
+}
+
+static int dibusb_dvb_exit(struct usb_dibusb *dib)
+{
+	deb_info("unregistering DVB part\n");
+	dvb_net_release(&dib->dvb_net);
+	dib->demux.dmx.close(&dib->demux.dmx);
+	dvb_dmxdev_release(&dib->dmxdev);
+	dvb_dmx_release(&dib->demux);
+	i2c_del_adapter(&dib->i2c_adap);
+	dvb_unregister_adapter(dib->adapter);
+
+	return 0;
+}
+
+static int dibusb_exit(struct usb_dibusb *dib)
+{
+	usb_free_urb(dib->buf_urb);
+	pci_free_consistent(NULL,8192,dib->buffer,dib->dma_handle);
+	return 0;
+}
+
+static int dibusb_init(struct usb_dibusb *dib)
+{
+	int ret,i;
+	sema_init(&dib->usb_sem, 1);
+	sema_init(&dib->i2c_sem, 1);
+	
+	/*
+	 * when reloading the driver w/o replugging the device 
+	 * a timeout occures, this helps
+	 */
+	usb_clear_halt(dib->udev,COMMAND_PIPE);
+	usb_clear_halt(dib->udev,RESULT_PIPE);
+	usb_clear_halt(dib->udev,DATA_PIPE);
+
+	/* dibusb_reset_cpu(dib); */
+
+	dib->buffer = pci_alloc_consistent(NULL,8192, &dib->dma_handle);
+	memset(dib->buffer,0,8192);
+	if (!(dib->buf_urb = usb_alloc_urb(0,GFP_KERNEL))) {
+		dibusb_exit(dib);
+		return -ENOMEM;
+	}
+	
+	for (i=0; i < DIBUSB_MAX_PIDS; i++) {
+		dib->pid_list[i].reg = i+DIB3000MB_REG_FIRST_PID;
+		dib->pid_list[i].pid = 0;
+		dib->pid_list[i].active = 0;
+		dib->pid_list[i].dib = dib;
+	}
+
+	dib->streaming = 0;
+	dib->feed_count = 0;
+	
+	if ((ret = dibusb_dvb_init(dib))) {
+		dibusb_exit(dib);
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * load a firmware packet to the device 
+ */
+static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
+{
+	return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+			0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+}
+
+static int dibusb_loadfirmware(struct usb_device *udev,
+		struct dibusb_device *dibdev) 
+{
+	const struct firmware *fw = NULL;
+	u16 addr;
+	u8 *b,*p;
+	int ret = 0,i;
+
+	for (i = 0; i < sizeof(valid_firmware_filenames)/sizeof(const char*); i++) {
+		if ((ret = request_firmware(&fw, valid_firmware_filenames[i], &udev->dev)) == 0) {
+			info("using firmware file (%s).",valid_firmware_filenames[i]);
+			break;
+		}
+		deb_info("tried to find '%s' firmware - unsuccessful. (%d)\n",
+				valid_firmware_filenames[i],ret);
+	}
+		
+	if (fw == NULL) {
+		err("did not find a valid firmware file. "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems.");
+		return -EINVAL;
+	} 
+	p = kmalloc(fw->size,GFP_KERNEL);	
+	if (p != NULL) {
+		u8 reset;
+		/*
+		 * you cannot use the fw->data as buffer for 
+		 * usb_control_msg, a new buffer has to be
+		 * created
+		 */
+		memcpy(p,fw->data,fw->size);
+
+		/* stop the CPU */
+		reset = 1;
+		if ((ret = dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1)) != 1) 
+			err("could not stop the USB controller CPU.");
+		for(i = 0; p[i+3] == 0 && i < fw->size; ) { 
+			b = (u8 *) &p[i];
+			addr = *((u16 *) &b[1]);
+
+			ret = dibusb_writemem(udev,addr,&b[4],b[0]);
+		
+			if (ret != b[0]) {
+				err("error while transferring firmware "
+					"(transferred size: %d, block size: %d)",
+					ret,b[1]);
+				ret = -EINVAL;
+				break;
+			}
+			i += 5 + b[0];
+		}
+		/* restart the CPU */
+		reset = 0;
+		if ((ret = dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1)) != 1) 
+			err("could not restart the USB controller CPU.");
+
+		kfree(p);
+		ret = 0;
+	} else { 
+		ret = -ENOMEM;
+	}
+	release_firmware(fw);
+
+	return ret;
+}
+
+/*
+ * USB 
+ */
+static int dibusb_probe(struct usb_interface *intf, 
+		const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_dibusb *dib = NULL;
+	struct dibusb_device *dibdev = NULL;
+	
+	int ret = -ENOMEM,i,cold=0;
+
+	for (i = 0; i < DIBUSB_SUPPORTED_DEVICES; i++)
+		if (dibusb_devices[i].cold_product_id == udev->descriptor.idProduct || 
+			dibusb_devices[i].warm_product_id == udev->descriptor.idProduct) {
+			dibdev = &dibusb_devices[i];
+			
+			cold = dibdev->cold_product_id == udev->descriptor.idProduct;
+			
+			if (cold)
+				info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
+			else
+				info("found a '%s' in warm state.",dibdev->name);
+		}
+	
+	if (dibdev == NULL) {
+		err("something went very wrong, "
+				"unknown product ID: %.4x",udev->descriptor.idProduct);
+		return -ENODEV;
+	}
+	
+	if (cold)
+		ret = dibusb_loadfirmware(udev,dibdev);
+	else {
+		dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
+		if (dib == NULL) {
+			err("no memory");
+			return ret;
+		}
+		memset(dib,0,sizeof(struct usb_dibusb));
+		
+		dib->udev = udev;
+		dib->dibdev = dibdev;
+		
+		usb_set_intfdata(intf, dib);
+
+		ret = dibusb_init(dib);
+	}
+	
+	if (ret == 0)
+		info("%s successfully initialized and connected.",dibdev->name);
+	else 
+		info("%s error while loading driver (%d)",dibdev->name,ret);
+	return ret;
+}
+
+static void dibusb_disconnect(struct usb_interface *intf)
+{
+	struct usb_dibusb *dib = usb_get_intfdata(intf);
+	const char *name = DRIVER_DESC;
+	
+	usb_set_intfdata(intf,NULL);
+	if (dib != NULL) {
+		name = dib->dibdev->name;
+		dibusb_dvb_exit(dib);
+		dibusb_exit(dib);
+		kfree(dib);
+	}
+	info("%s successfully deinitialized and disconnected.",name);
+	
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dibusb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "dvb_dibusb",
+	.probe 		= dibusb_probe,
+	.disconnect = dibusb_disconnect,
+	.id_table 	= dibusb_table,
+};
+
+/* module stuff */
+static int __init usb_dibusb_init(void)
+{
+	int result;
+	if ((result = usb_register(&dibusb_driver))) {
+		err("usb_register failed. Error number %d",result);
+		return result;
+	}
+	
+	return 0;
+}
+
+static void __exit usb_dibusb_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&dibusb_driver);
+}
+
+module_init (usb_dibusb_init);
+module_exit (usb_dibusb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/dvb-dibusb.h linux-2.6.8.1-patched/drivers/media/dvb/dibusb/dvb-dibusb.h
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/dvb-dibusb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/dibusb/dvb-dibusb.h	2004-09-13 23:28:47.000000000 +0200
@@ -0,0 +1,175 @@
+/*
+ * dvb-dibusb.h
+ * 
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ *
+ * for more information see dvb-dibusb.c .
+ */
+
+#ifndef __DVB_DIBUSB_H__
+#define __DVB_DIBUSB_H__
+
+/* Vendor IDs */
+#define USB_TWINHAN_VENDOR_ID			0x1822
+#define USB_IMC_NETWORKS_VENDOR_ID		0x13d3
+#define USB_KWORLD_VENDOR_ID			0xeb1a
+#define USB_DIBCOM_VENDOR_ID			0x10b8
+#define USB_ULTIMA_ELECTRONIC_ID		0x05d8
+
+/* Product IDs before loading the firmware */
+#define USB_VP7041_PRODUCT_PREFW_ID		0x3201
+#define USB_VSTREAM_PRODUCT_PREFW_ID	0x17de
+#define USB_DIBCOM_PRODUCT_PREFW_ID		0x0bb8
+#define USB_ULTIMA_ELEC_PROD_PREFW_ID	0x8105
+
+/* product ID afterwards */
+#define USB_VP7041_PRODUCT_ID			0x3202
+#define USB_VSTREAM_PRODUCT_ID			0x17df
+#define USB_DIBCOM_PRODUCT_ID			0x0bb9
+#define USB_ULTIMA_ELEC_PROD_ID			0x8106
+
+/* CS register start/stop the usb controller cpu */
+#define DIBUSB_CPU_CSREG				0x7F92
+
+// 0x10 is the I2C address of the first demodulator on the board
+#define DIBUSB_DEMOD_I2C_ADDR_DEFAULT	0x10
+#define DIBUSB_I2C_TIMEOUT 				HZ*5
+
+#define DIBUSB_MAX_PIDS					16
+
+#define DIB3000MB_REG_FIRST_PID			(   153)
+
+struct usb_dibusb;
+
+struct dibusb_pid {
+	u16 reg;
+	u16 pid;
+	int active;
+	struct usb_dibusb *dib;
+};
+
+struct usb_dibusb {
+	/* usb */
+	struct usb_device * udev;
+
+	struct dibusb_device * dibdev;
+
+	int streaming;
+	int feed_count;
+	struct urb *buf_urb;
+	u8 *buffer;
+	dma_addr_t dma_handle;
+	
+	spinlock_t pid_list_lock;
+	struct dibusb_pid pid_list[DIBUSB_MAX_PIDS];
+
+	/* I2C */
+	struct i2c_adapter i2c_adap;
+	struct i2c_client i2c_client;
+
+	/* locking */
+	struct semaphore usb_sem;
+	struct semaphore i2c_sem;
+
+	/* dvb */
+	struct dvb_adapter *adapter;
+	struct dmxdev dmxdev;
+	struct dvb_demux demux;
+	struct dvb_net dvb_net;
+};
+
+
+struct dibusb_device {
+	u16 cold_product_id;
+	u16 warm_product_id;
+	u8 demod_addr;
+	const char *name;
+};
+
+/* static array of valid firmware names, the best one first */
+static const char * valid_firmware_filenames[] = {
+	"dvb-dibusb-5.0.0.11.fw",
+};
+
+#define DIBUSB_SUPPORTED_DEVICES	4
+
+/* USB Driver stuff */
+static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
+	{	.cold_product_id = USB_VP7041_PRODUCT_PREFW_ID, 
+		.warm_product_id = USB_VP7041_PRODUCT_ID,
+		.name = "Twinhan VisionDTV USB-Ter/HAMA USB DVB-T device", 
+		.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
+	},
+	{	.cold_product_id = USB_VSTREAM_PRODUCT_PREFW_ID,
+		.warm_product_id = USB_VSTREAM_PRODUCT_ID,
+		.name = "KWorld V-Stream XPERT DTV - DVB-T USB",
+		.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
+	},
+	{	.cold_product_id = USB_DIBCOM_PRODUCT_PREFW_ID,
+		.warm_product_id = USB_DIBCOM_PRODUCT_ID,
+		.name = "DiBcom USB reference design",
+		.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
+	},
+	{
+ 		.cold_product_id = USB_ULTIMA_ELEC_PROD_PREFW_ID,
+		.warm_product_id = USB_ULTIMA_ELEC_PROD_ID,
+		.name = "Ultima Electronic/Artec T1 USB TVBOX",
+		.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
+	}, 
+};
+
+#define COMMAND_PIPE	usb_sndbulkpipe(dib->udev, 0x01)
+#define RESULT_PIPE		usb_rcvbulkpipe(dib->udev, 0x81)
+#define DATA_PIPE		usb_rcvbulkpipe(dib->udev, 0x82)
+/* 
+ * last endpoint 0x83 only used for chaining the buffers 
+ * of the endpoints in the cypress 
+ */
+#define CHAIN_PIPE_DO_NOT_USE	usb_rcvbulkpipe(dib->udev, 0x83)
+
+/* types of first byte of each buffer */
+
+#define DIBUSB_REQ_START_READ			0x00
+#define DIBUSB_REQ_START_DEMOD			0x01
+#define DIBUSB_REQ_I2C_READ  			0x02
+#define DIBUSB_REQ_I2C_WRITE 			0x03
+
+/* prefix for reading the current RC key */
+#define DIBUSB_REQ_POLL_REMOTE			0x04
+
+/* 0x05 0xXX */
+#define DIBUSB_REQ_SET_STREAMING_MODE	0x05
+
+/* interrupt the internal read loop, when blocking */
+#define DIBUSB_REQ_INTR_READ		   	0x06
+
+/* IO control 
+ * 0x07 <cmd 1 byte> <param 32 bytes>
+ */ 
+#define DIBUSB_REQ_SET_IOCTL			0x07
+
+/* IOCTL commands */
+
+/* change the power mode in firmware */ 
+#define DIBUSB_IOCTL_CMD_POWER_MODE		0x00
+#define DIBUSB_IOCTL_POWER_SLEEP			0x00
+#define DIBUSB_IOCTL_POWER_WAKEUP			0x01
+
+
+/* 
+ * values from the demodulator which are needed in
+ * the usb driver as well 
+ */
+
+#define DIB3000MB_REG_FIFO              (   145)
+#define DIB3000MB_FIFO_INHIBIT              (     1)
+#define DIB3000MB_FIFO_ACTIVATE             (     0)
+
+#define DIB3000MB_ACTIVATE_FILTERING            (0x2000)
+
+#endif
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/dibusb/Kconfig
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/dibusb/Kconfig	2004-09-13 23:28:47.000000000 +0200
@@ -0,0 +1,31 @@
+config DVB_DIBUSB
+	tristate "Twinhan/KWorld/Hama/Artec USB DVB-T devices"
+	depends on DVB_CORE && USB
+	select FW_LOADER
+	help
+	  Support for USB 1.1 DVB-T devices based on a reference design made by 
+	  DiBcom (http://www.dibcom.fr).
+
+	  Devices supported by this driver:
+
+	    Twinhan VisionPlus VisionDTV USB-Ter (VP7041)
+	    KWorld V-Stream XPERT DTV - DVB-T USB
+	    Hama DVB-T USB-Box
+	    DiBcom reference device (non-public)
+	    Ultima Electronic/Artec T1 USB TVBOX
+
+	  The VP7041 seems to be identical to "CTS Portable" (Chinese 
+	  Television System).
+
+	  These devices can be understood as budget ones, they "only" deliver
+	  the MPEG data.
+
+	  Currently all known copies of the DiBcom reference design have the DiBcom 3000MB 
+	  frontend onboard. Please enable and load this one manually in order to use this
+	  device.
+	  
+	  A firmware is needed to use the device. See Documentation/dvb/README.dibusb
+	  details.
+
+	  Say Y if you own such a device and want to use it. You should build it as
+	  a module.
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/Makefile linux-2.6.8.1-patched/drivers/media/dvb/dibusb/Makefile
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dibusb/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.8.1-patched/drivers/media/dvb/dibusb/Makefile	2004-09-07 20:14:10.000000000 +0200
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/Makefile linux-2.6.8.1-patched/drivers/media/dvb/Makefile
--- linux-2.6.8.1-dvb1/drivers/media/dvb/Makefile	2004-09-15 15:34:22.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/Makefile	2004-09-15 10:26:44.000000000 +0200
@@ -2,5 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/
-
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/Kconfig linux-2.6.8.1-patched/drivers/media/dvb/frontends/Kconfig
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/Kconfig	2004-09-17 12:26:24.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/Kconfig	2004-09-15 10:26:44.000000000 +0200
@@ -63,13 +63,9 @@
 	help
  	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
-	  This driver needs a copy of the Avermedia firmware. The version tested
-	  is part of the Avermedia DVB-T 1.3.26.3 Application. If the software is
-	  installed in Windoze the file will be in the /Program Files/AVerTV DVB-T/
-	  directory and is called sc_main.mc. Alternatively it can "extracted" from
-	  the install cab files.
-   
-   	  Copy this file to '/usr/lib/hotplug/firmware/dvb-fe-sp887x.fw'.
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
@@ -81,9 +77,9 @@
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
-	  This driver needs a copy of the firmware file from the Haupauge
-	  Windoze driver. Copy 'Sc_main.mc' to
-	  '/usr/lib/hotplug/firmware/dvb-fe-tdlb7.fw'.
+	  This driver needs external firmware. Please use the command
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+	  download/extract it, and then copy it to /usr/lib/hotplug/firmware.
 
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
@@ -99,6 +95,16 @@
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
+config DVB_CX22702
+ 	tristate "Conexant cx22702 demodulator (OFDM)"
+ 	depends on DVB_CORE
+ 	help
+ 	  A DVB-T tuner module. Say Y when you want to support this frontend.
+ 
+ 	  If you don't know what tuner module is soldered on your
+ 	  DVB adapter simply enable all supported frontends, the
+ 	  right one will get autodetected.
+
 config DVB_GRUNDIG_29504_401
 	tristate "Grundig 29504-401 based"
 	depends on DVB_CORE
@@ -115,6 +121,11 @@
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
+	  This driver needs external firmware. Please use the commands
+	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+  	  "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+	  download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+
 	  If you don't know what tuner module is soldered on your 
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
@@ -139,6 +150,21 @@
 	  DVB adapter simply enable all supported frontends, the
 	  right one will get autodetected.
 
+config DVB_DIB3000MB
+	tristate "DiBcom 3000-MB" 
+	depends on DVB_CORE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+	 
+	  Used on USB-powered devices. You should also say Y to DVB_DIBUSB 
+	  (DiBcom USB DVB-T Adapter) to support the actual device, 
+	  this is "only" the frontend/tuner.
+	 
+	  If you don't know what tuner module is soldered on your
+	  DVB adapter simply enable all supported frontends, the
+	  right one will get autodetected.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 

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

* Re: [PATCH][2.6][12/14] misc. driver updates
  2004-09-17 14:37                     ` [PATCH][2.6][11/14] new DVB driver Michael Hunold
@ 2004-09-17 14:39                       ` Michael Hunold
  2004-09-17 14:40                         ` [PATCH][2.6][13/14] dvb frontend updates Michael Hunold
  2004-09-20 11:11                         ` [PATCH][2.6][12.1/14] DVB: add kernel message classifiers Philipp Matthias Hahn
  0 siblings, 2 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:39 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 12-DVB-misc-driver-updates.diff --]
[-- Type: text/plain, Size: 72491 bytes --]

- [DVB] av7110: convert MODULE_PARM() to module_param(), replace home-brewn waiting stuff in osd code with wait_event_interruptible_timeout()
- [DVB] av7110: put a semaphore around osd calls to make sure they're properly serialized, timeout variable in arm_thread() must be int, not unsigned long
- [DVB] av7110: add additional OSD window types (patch by Jeremy Jones), new ioctl OSD_GET_CAPABILITY/OSD_CAP_MEMSIZE; returns size of OSD memory
- [DVB] av7110: put audio/video initialization into separate function init_av7110_av(); call this function after system initialization and after arm crash to restore the previous state; thanks to Soeren Sonnenburg <bugreports@nn7.de> for this patch.
- [DVB] av7110, budget, ttusb-budget: remove dvb i2c remains, support kernel i2c
- [DVB] av7110, budget: use msleep() instead of my_wait(), thanks to Kernel Janitors/Nishanth Aravamudan <nacc@us.ibm.com>
- [DVB] av7110, budget: fix videodev has no release callback
- [DVB] av7110: more sparse annotiations
- [DVB] budget: add support for TerraTec Cinergy 1200 DVB-S
- [DVB] budget: fix race condition in irq handler
- [DVB] skystar2, av7110, ttusb-budget, budget: make i2c client_(un)register() functions static

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_av.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_av.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_av.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_av.c	2004-08-18 19:52:18.000000000 +0200
@@ -37,14 +37,10 @@
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
 #include "av7110.h"
 #include "av7110_hw.h"
 #include "av7110_av.h"
 #include "av7110_ipack.h"
-#include "dvb_functions.h"
 
 /* MPEG-2 (ISO 13818 / H.222.0) stream types */
 #define PROG_STREAM_MAP  0xBC
@@ -292,6 +286,9 @@
 
 	DEB_EE(("av7110: %p\n", av7110));
 
+	av7110->mixer.volume_left = volleft;
+	av7110->mixer.volume_right = volright;
+
 	switch (av7110->adac_type) {
 	case DVB_ADAC_TI:
 		volleft = (volleft * 256) / 1036;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.c	2004-08-18 19:52:18.000000000 +0200
@@ -41,6 +41,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/kernel.h>
+#include <linux/moduleparam.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -50,18 +51,14 @@
 #include <linux/vmalloc.h>
 #include <linux/firmware.h>
 #include <linux/crc32.h>
+#include <linux/i2c.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
 
 #include <linux/dvb/frontend.h>
 
-#include "dvb_i2c.h"
 #include "dvb_frontend.h"
-#include "dvb_functions.h"
-
-
-	#define DEBUG_VARIABLE av7110_debug
 
 #include "ttpci-eeprom.h"
 #include "av7110.h"
@@ -70,26 +67,93 @@
 #include "av7110_ca.h"
 #include "av7110_ipack.h"
 
-
-static void restart_feeds(struct av7110 *av7110);
-
-int av7110_debug = 0;
-
+static int av7110_debug;
 static int vidmode=CVBS_RGB_OUT;
 static int pids_off;
 static int adac=DVB_ADAC_TI;
-static int hw_sections = 0;
-static int rgb_on = 0;
+static int hw_sections;
+static int rgb_on;
+static int volume = 255;
+
+module_param_named(debug, av7110_debug, int, 0644);
+MODULE_PARM_DESC(av7110_debug, "Turn on/off debugging (default:off).");
+module_param(vidmode, int, 0444);
+MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
+module_param(pids_off, int, 0444);
+MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
+module_param(adac, int, 0444);
+MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
+module_param(hw_sections, int, 0444);
+MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");
+module_param(rgb_on, int, 0444);
+MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"
+		" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB");
+module_param(volume, int, 0444);
+MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
+
+static void restart_feeds(struct av7110 *av7110);
 
 int av7110_num = 0;
 
+static void init_av7110_av(struct av7110 *av7110)
+{
+	struct saa7146_dev *dev=av7110->dev;
+
+	/* set internal volume control to maximum */
+	av7110->adac_type = DVB_ADAC_TI;
+	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+
+	av7710_set_video_mode(av7110, vidmode);
+
+	/* handle different card types */
+	/* remaining inits according to card and frontend type */
+	av7110->has_analog_tuner = 0;
+	av7110->current_input = 0;
+	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+		printk ("av7110(%d): Crystal audio DAC detected\n",
+			av7110->dvb_adapter->num);
+		av7110->adac_type = DVB_ADAC_CRYSTAL;
+		i2c_writereg(av7110, 0x20, 0x01, 0xd2);
+		i2c_writereg(av7110, 0x20, 0x02, 0x49);
+		i2c_writereg(av7110, 0x20, 0x03, 0x00);
+		i2c_writereg(av7110, 0x20, 0x04, 0x00);
+
+	/**
+	 * some special handling for the Siemens DVB-C cards...
+	 */
+	} else if (0 == av7110_init_analog_module(av7110)) {
+		/* done. */
+	}
+	else if (dev->pci->subsystem_vendor == 0x110a) {
+		printk("av7110(%d): DVB-C w/o analog module detected\n",
+			av7110->dvb_adapter->num);
+		av7110->adac_type = DVB_ADAC_NONE;
+	}
+	else {
+		av7110->adac_type = adac;
+		printk("av7110(%d): adac type set to %d\n",
+			av7110->dvb_adapter->num, av7110->adac_type);
+	}
+
+	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
+		// switch DVB SCART on
+		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
+		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+		if (rgb_on)
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
+		//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
+	}
+
+	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+	av7110_setup_irc_config(av7110, 0);
+}
 
 static void recover_arm(struct av7110 *av7110)
 {
 	DEB_EE(("av7110: %p\n",av7110));
 
 	av7110_bootarm(av7110);
-        dvb_delay(100); 
+	msleep(100);
         restart_feeds(av7110);
 	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
@@ -106,12 +170,16 @@
 static int arm_thread(void *data)
 {
 	struct av7110 *av7110 = data;
-	unsigned long timeout;
         u16 newloops = 0;
+	int timeout;
 
 	DEB_EE(("av7110: %p\n",av7110));
 	
-	dvb_kernel_thread_setup ("arm_mon");
+        lock_kernel ();
+        daemonize ("arm_mon");
+        sigfillset (&current->blocked);
+        unlock_kernel ();
+
 	av7110->arm_thread = current;
 
 	while (1) {
@@ -135,6 +203,9 @@
 				av7110->dvb_adapter->num);
 
 			arm_error(av7110);
+			av7710_set_video_mode(av7110, vidmode);
+
+			init_av7110_av(av7110);
 
                         if (down_interruptible(&av7110->dcomlock))
                                 break;
@@ -638,6 +709,8 @@
 
 	if (cmd == OSD_SEND_CMD)
 		return av7110_osd_cmd(av7110, (osd_cmd_t *) parg);
+	if (cmd == OSD_GET_CAPABILITY)
+		return av7110_osd_capability(av7110, (osd_cap_t *) parg);
 
 	return -EINVAL;
         }
@@ -1203,19 +1275,17 @@
 int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
 {
 	u8 msg[2] = { reg, val };
-	struct dvb_i2c_bus *i2c = av7110->i2c_bus;
 	struct i2c_msg msgs;
 	
 	msgs.flags = 0;
 	msgs.addr = id / 2;
 	msgs.len = 2;
 	msgs.buf = msg;
-	return i2c->xfer(i2c, &msgs, 1);
+	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
 }
 
 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 {
-	struct dvb_i2c_bus *i2c = av7110->i2c_bus;
 	u8 mm1[] = {0x00};
 	u8 mm2[] = {0x00};
 	struct i2c_msg msgs[2];
@@ -1226,17 +1296,11 @@
 	mm1[0] = reg;
 	msgs[0].len = 1; msgs[1].len = 1;
 	msgs[0].buf = mm1; msgs[1].buf = mm2;
-	i2c->xfer(i2c, msgs, 2);
+	i2c_transfer(&av7110->i2c_adap, msgs, 2);
 
 	return mm2[0];
 }
 
-static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[], int num)
-{
-	struct saa7146_dev *dev = i2c->data;
-	return saa7146_i2c_transfer(dev, msgs, num, 6);
-}
-
 /****************************************************************************
  * INITIALIZATION
  ****************************************************************************/
@@ -1310,13 +1374,25 @@
 	/* request the av7110 firmware, this will block until someone uploads it */
 	ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev);
 	if (ret) {
-		printk("dvb-ttpci: cannot request firmware!\n");
+		if (ret == -ENOENT) {
+			printk(KERN_ERR "dvb-ttpci: could not load firmware,"
+			       " file not found: dvb-ttpci-01.fw\n");
+			printk(KERN_ERR "dvb-ttpci: usually this should be in"
+			       " /usr/lib/hotplug/firmware\n");
+			printk(KERN_ERR "dvb-ttpci: and can be downloaded here"
+			       " http://www.linuxtv.org/download/dvb/firmware/\n");
+		} else
+			printk(KERN_ERR "dvb-ttpci: cannot request firmware"
+			       " (error %i)\n", ret);
 		return -EINVAL;
 	}
+
 	if (fw->size <= 200000) {
 		printk("dvb-ttpci: this firmware is way too small.\n");
+		release_firmware(fw);
 		return -EINVAL;
 	}
+
 	/* check if the firmware is available */
 	av7110->bin_fw = (unsigned char*) vmalloc(fw->size);
 	if (NULL == av7110->bin_fw) {
@@ -1321,8 +1397,10 @@
 	av7110->bin_fw = (unsigned char*) vmalloc(fw->size);
 	if (NULL == av7110->bin_fw) {
 		DEB_D(("out of memory\n"));
+		release_firmware(fw);
 		return -ENOMEM;
 	}
+
 	memcpy(av7110->bin_fw, fw->data, fw->size);
 	av7110->size_fw = fw->size;
 	if ((ret = check_firmware(av7110)))
@@ -1327,10 +1405,34 @@
 	av7110->size_fw = fw->size;
 	if ((ret = check_firmware(av7110)))
 		vfree(av7110->bin_fw);
+
+	release_firmware(fw);
 	return ret;
 }
 #endif
 
+int client_register(struct i2c_client *client)
+{
+	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
+	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+
+	/* fixme: check for "type" (ie. frontend type) */
+	if (client->driver->command)
+		return client->driver->command(client, FE_REGISTER, av7110->dvb_adapter);
+	return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
+	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+
+	/* fixme: check for "type" (ie. frontend type) */
+	if (client->driver->command)
+		return client->driver->command(client, FE_UNREGISTER, av7110->dvb_adapter);
+	return 0;
+}
+
 static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
 {
 	struct av7110 *av7110 = NULL;
@@ -1361,18 +1463,26 @@
 	   get recognized before the main driver is fully loaded */
 	saa7146_write(dev, GPIO_CTRL, 0x500000);
 
-	saa7146_i2c_adapter_prepare(dev, NULL, 0, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
+	av7110->i2c_adap = (struct i2c_adapter) {
+		.client_register = client_register,
+		.client_unregister = client_unregister,
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+		.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+		.class = I2C_CLASS_TV_DIGITAL,
+#endif
+	};
+	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 
-	av7110->i2c_bus = dvb_register_i2c_bus (master_xfer, dev,
-						av7110->dvb_adapter, 0);
+	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
 
-	if (!av7110->i2c_bus) {
+	if (i2c_add_adapter(&av7110->i2c_adap) < 0) {
 		dvb_unregister_adapter (av7110->dvb_adapter);
 		kfree(av7110);
 		return -ENOMEM;
 	}
 
-	ttpci_eeprom_parse_mac(av7110->i2c_bus);
+	ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac);
 
 	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 	saa7146_write(dev, BCS_CTRL, 0x80400040);
@@ -1399,6 +1509,7 @@
 
         /* default OSD window */
         av7110->osdwin=1;
+	sema_init(&av7110->osd_sema, 1);
 
         /* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);
@@ -1443,54 +1554,12 @@
 		goto err2;
 	}
 
-	/* set internal volume control to maximum */
-	av7110->adac_type = DVB_ADAC_TI;
-	av7110_set_volume(av7110, 0xff, 0xff);
-
-	av7710_set_video_mode(av7110, vidmode);
-
-	/* handle different card types */
-	/* remaining inits according to card and frontend type */
-	av7110->has_analog_tuner = 0;
-	av7110->current_input = 0;
-	if (i2c_writereg(av7110, 0x20, 0x00, 0x00)==1) {
-		printk ("av7110(%d): Crystal audio DAC detected\n",
-			av7110->dvb_adapter->num);
-		av7110->adac_type = DVB_ADAC_CRYSTAL;
-		i2c_writereg(av7110, 0x20, 0x01, 0xd2);
-		i2c_writereg(av7110, 0x20, 0x02, 0x49);
-		i2c_writereg(av7110, 0x20, 0x03, 0x00);
-		i2c_writereg(av7110, 0x20, 0x04, 0x00);
-	
-	/**
-	 * some special handling for the Siemens DVB-C cards...
-	 */
-	} else if (0 == av7110_init_analog_module(av7110)) {
-		/* done. */
-	}
-	else if (dev->pci->subsystem_vendor == 0x110a) {
-		printk("av7110(%d): DVB-C w/o analog module detected\n",
-			av7110->dvb_adapter->num);
-		av7110->adac_type = DVB_ADAC_NONE;
-	}
-	else {
-		av7110->adac_type = adac;
-		printk("av7110(%d): adac type set to %d\n",
-			av7110->dvb_adapter->num, av7110->adac_type);
-		}
-
-	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
-		// switch DVB SCART on
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
-		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
-		if (rgb_on)
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
-		//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
-	}
+	/* set initial volume in mixer struct */
+	av7110->mixer.volume_left  = volume;
+	av7110->mixer.volume_right = volume;
 	
-	av7110_set_volume(av7110, 0xff, 0xff);
+	init_av7110_av(av7110);
 
-	av7110_setup_irc_config (av7110, 0);
 	av7110_register(av7110);
 	
 	/* special case DVB-C: these cards have an analog tuner
@@ -1510,13 +1579,12 @@
 	av7110->arm_rmmod = 1;
 	wake_up_interruptible(&av7110->arm_wait);
 	while (av7110->arm_thread)
-		dvb_delay(1);
+		msleep(1);
 err2:
 	av7110_ca_exit(av7110);
 	av7110_av_exit(av7110);
 err:
-	dvb_unregister_i2c_bus (master_xfer,av7110->i2c_bus->adapter,
-				av7110->i2c_bus->id);
+	i2c_del_adapter(&av7110->i2c_adap);
 
 	dvb_unregister_adapter (av7110->dvb_adapter);
 
@@ -1546,7 +1614,7 @@
 	wake_up_interruptible(&av7110->arm_wait);
 
 	while (av7110->arm_thread)
-		dvb_delay(1);
+		msleep(1);
 
 	dvb_unregister(av7110);
 	
@@ -1563,7 +1631,8 @@
 	pci_free_consistent(saa->pci, 8192, av7110->debi_virt,
 			    av7110->debi_bus);
 
-	dvb_unregister_i2c_bus (master_xfer,av7110->i2c_bus->adapter, av7110->i2c_bus->id);
+	i2c_del_adapter(&av7110->i2c_adap);
+
 	dvb_unregister_adapter (av7110->dvb_adapter);
 
 	av7110_num--;
@@ -1602,7 +1671,7 @@
 MAKE_AV7110_INFO(fs_1_5, "Siemens cable card PCI rev1.5");
 MAKE_AV7110_INFO(fs_1_3, "Siemens/Technotrend/Hauppauge PCI rev1.3");
 MAKE_AV7110_INFO(tt_1_6, "Technotrend/Hauppauge PCI rev1.3 or 1.6");
-MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1");
+MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1 or 2.2");
 MAKE_AV7110_INFO(tt_t,	 "Technotrend/Hauppauge PCI DVB-T");
 MAKE_AV7110_INFO(unkwn0, "Technotrend/Hauppauge PCI rev?(unknown0)?");
 MAKE_AV7110_INFO(unkwn1, "Technotrend/Hauppauge PCI rev?(unknown1)?");
@@ -1684,15 +1753,3 @@
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(av7110_debug,"i");
-MODULE_PARM(vidmode,"i");
-MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
-MODULE_PARM(pids_off,"i");
-MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
-MODULE_PARM(adac,"i");
-MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
-MODULE_PARM(hw_sections, "i");
-MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");
-MODULE_PARM(rgb_on, "i");
-MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"
-		" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_ca.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_ca.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_ca.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_ca.c	2004-08-18 19:52:18.000000000 +0200
@@ -38,13 +38,8 @@
 #include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
-#include "dvb_i2c.h"
 #include "av7110.h"
 #include "av7110_hw.h"
-#include "dvb_functions.h"
 
 
 void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110.h linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.h
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.h	2004-08-18 19:52:18.000000000 +0200
@@ -4,13 +4,12 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/netdevice.h>
+#include <linux/i2c.h>
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
 #endif
 
-#include <media/saa7146_vv.h>
-
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
 #include <linux/dvb/dmx.h>
@@ -26,6 +25,7 @@
 #include "dvb_net.h"
 #include "dvb_ringbuffer.h"
 
+#include <media/saa7146_vv.h>
 
 #define MAXFILT 32
 
@@ -60,12 +60,13 @@
         struct dvb_device       dvb_dev;
         struct dvb_net               dvb_net;
 
-	struct video_device	v4l_dev;
-	struct video_device	vbi_dev;
+	struct video_device	*v4l_dev;
+	struct video_device	*vbi_dev;
 
         struct saa7146_dev	*dev;
 
-	struct dvb_i2c_bus	*i2c_bus;	
+	struct i2c_adapter	i2c_adap;
+
 	char			*card_name;
 
 	/* support for analog module of dvb-c */
@@ -127,7 +128,7 @@
 
         int                     osdwin;      /* currently active window */
         u16                     osdbpp[8];
-
+	struct semaphore	osd_sema;
 
         /* CA */
 
@@ -187,6 +188,7 @@
         struct dvb_ringbuffer    ci_rbuffer;
         struct dvb_ringbuffer    ci_wbuffer;
 
+	struct audio_mixer	mixer;
 
         struct dvb_adapter       *dvb_adapter;
         struct dvb_device        *video_dev;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_hw.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_hw.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_hw.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_hw.c	2004-08-18 19:44:05.000000000 +0200
@@ -38,12 +38,8 @@
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
 #include "av7110.h"
 #include "av7110_hw.h"
-#include "dvb_functions.h"
 
 /****************************************************************************
  * DEBI functions
@@ -106,7 +102,7 @@
 	saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
 
 	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-	dvb_delay(30);	/* the firmware needs some time to initialize */
+	msleep(30);	/* the firmware needs some time to initialize */
 
 	ARM_ResetMailBox(av7110);
 
@@ -268,7 +264,7 @@
 		return -1;
 	}
 	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-	dvb_delay(30);	/* the firmware needs some time to initialize */
+	msleep(30);	/* the firmware needs some time to initialize */
 
 	//ARM_ClearIrq(av7110);
 	ARM_ResetMailBox(av7110);
@@ -302,7 +298,7 @@
 
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 			printk(KERN_ERR "%s: timeout waiting for COMMAND idle\n", __FUNCTION__);
 			return -1;
@@ -312,7 +308,7 @@
 #ifndef _NOHANDSHAKE
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
 			return -1;
@@ -322,7 +318,7 @@
 
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2) & OSDQFull) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_OSD)) {
 			printk(KERN_ERR "%s: timeout waiting for !OSDQFull\n", __FUNCTION__);
 			return -1;
@@ -341,7 +337,7 @@
 #ifdef COM_DEBUG
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 			printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n",
 			       __FUNCTION__);
@@ -458,7 +454,7 @@
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
 #ifdef _NOHANDSHAKE
-		dvb_delay(1);
+		msleep(1);
 #endif
 		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 			printk("%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
@@ -470,7 +466,7 @@
 #ifndef _NOHANDSHAKE
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
 			up(&av7110->dcomlock);
@@ -630,7 +626,7 @@
 		return -ERESTARTSYS;
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_OSD)) {
 			printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
@@ -654,7 +650,7 @@
 
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_OSD)) {
 			printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
 			       __FUNCTION__);
@@ -665,7 +661,7 @@
 #ifndef _NOHANDSHAKE
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
-		dvb_delay(1);
+		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
 			printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n",
 			       __FUNCTION__);
@@ -721,7 +717,7 @@
 }
 
 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
-				  enum av7110_window_display_type disptype,
+				  osd_raw_window_t disptype,
 				  u16 width, u16 height)
 {
 	return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
@@ -732,8 +728,8 @@
 static enum av7110_osd_palette_type bpp2pal[8] = {
 	Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
 };
-static enum av7110_window_display_type bpp2bit[8] = {
-	BITMAP1, BITMAP2, 0, BITMAP4, 0, 0, 0, BITMAP8
+static osd_raw_window_t bpp2bit[8] = {
+	OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
 };
 
 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
@@ -743,32 +739,26 @@
 	int i;
 	int d, delta;
 	u8 c;
-	DECLARE_WAITQUEUE(wait, current);
+	int ret;
 
 	DEB_EE(("av7110: %p\n", av7110));
 
-	if (av7110->bmp_state == BMP_LOADING) {
-		add_wait_queue(&av7110->bmpq, &wait);
-		while (1) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (av7110->bmp_state != BMP_LOADING
-			    || signal_pending(current))
-				break;
-			schedule();
-		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&av7110->bmpq, &wait);
-	}
-	if (av7110->bmp_state == BMP_LOADING)
+	ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
+	if (ret == -ERESTARTSYS || ret == 0) {
+		printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__);
+		av7110->bmp_state = BMP_NONE;
 		return -1;
+	}
+	BUG_ON (av7110->bmp_state == BMP_LOADING);
+
 	av7110->bmp_state = BMP_LOADING;
-	if	(format == BITMAP8) {
+	if	(format == OSD_BITMAP8) {
 		bpp=8; delta = 1;
-	} else if (format == BITMAP4) {
+	} else if (format == OSD_BITMAP4) {
 		bpp=4; delta = 2;
-	} else if (format == BITMAP2) {
+	} else if (format == OSD_BITMAP2) {
 		bpp=2; delta = 4;
-	} else if (format == BITMAP1) {
+	} else if (format == OSD_BITMAP1) {
 		bpp=1; delta = 8;
 	} else {
 		av7110->bmp_state = BMP_NONE;
@@ -786,7 +776,7 @@
 			return -1;
 		}
 	}
-	if (format != BITMAP8) {
+	if (format != OSD_BITMAP8) {
 		for (i = 0; i < dx * dy / delta; i++) {
 			c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
 			for (d = delta - 2; d >= 0; d--) {
@@ -802,27 +792,22 @@
 
 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	int ret;
 
 	DEB_EE(("av7110: %p\n", av7110));
 
-       if (av7110->bmp_state == BMP_NONE)
+	BUG_ON (av7110->bmp_state == BMP_NONE);
+
+	ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
+	if (ret == -ERESTARTSYS || ret == 0) {
+		printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__);
+		av7110->bmp_state = BMP_NONE;
 		return -1;
-	if (av7110->bmp_state == BMP_LOADING) {
-		add_wait_queue(&av7110->bmpq, &wait);
-		while (1) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (av7110->bmp_state != BMP_LOADING
-			    || signal_pending(current))
-				break;
-			schedule();
 		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&av7110->bmpq, &wait);
-	}
-	if (av7110->bmp_state == BMP_LOADED)
+
+	BUG_ON (av7110->bmp_state != BMP_LOADED);
+
 		return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
-	return -1;
 }
 
 static inline int ReleaseBitmap(struct av7110 *av7110)
@@ -865,18 +850,22 @@
 		  color, ((blend >> 4) & 0x0f));
 }
 
-static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
+static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
 {
        int i;
        int length = last - first + 1;
 
        if (length * 4 > DATA_BUFF3_SIZE)
-	       return -1;
+	       return -EINVAL;
 
        for (i = 0; i < length; i++) {
-	       u32 blend = (colors[i] & 0xF0000000) >> 4;
-	       u32 yuv = blend ? RGB2YUV(colors[i] & 0xFF, (colors[i] >> 8) & 0xFF,
-					 (colors[i] >> 16) & 0xFF) | blend : 0;
+	       u32 color, blend, yuv;
+
+	       if (get_user(color, colors + i))
+		       return -EFAULT;
+	       blend = (color & 0xF0000000) >> 4;
+	       yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+				     (color >> 16) & 0xFF) | blend : 0;
 	       yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
 	       wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
        }
@@ -922,10 +911,19 @@
 
 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
 {
+	int ret;
+	
+	ret = down_interruptible(&av7110->osd_sema);
+	if (ret)
+		return -ERESTARTSYS;
+
+	/* stupid, but OSD functions don't provide a return code anyway */
+	ret = 0;
+	
 	switch (dc->cmd) {
 	case OSD_Close:
 		DestroyOSDWindow(av7110, av7110->osdwin);
-		return 0;
+		goto out;
 	case OSD_Open:
 		av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
 		CreateOSDWindow(av7110, av7110->osdwin,
@@ -935,90 +933,84 @@
 			MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
 			SetColorBlend(av7110, av7110->osdwin);
 		}
-		return 0;
+		goto out;
 	case OSD_Show:
 		MoveWindowRel(av7110, av7110->osdwin, 0, 0);
-		return 0;
+		goto out;
 	case OSD_Hide:
 		HideWindow(av7110, av7110->osdwin);
-		return 0;
+		goto out;
 	case OSD_Clear:
 		DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
-		return 0;
+		goto out;
 	case OSD_Fill:
 		DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
-		return 0;
+		goto out;
 	case OSD_SetColor:
 		OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
-		return 0;
+		goto out;
 	case OSD_SetPalette:
 	{
-		int len = dc->x0-dc->color+1;
-		void *buf;
-		if (len <= 0)
-			return 0;
-
-		buf = kmalloc(len * 4, GFP_KERNEL);
-		if (!buf)
-			return -ENOMEM;
-
-		if (copy_from_user(buf, dc->data, len * 4)) {
-			kfree(buf);
-			return -EFAULT;
+		if (FW_VERSION(av7110->arm_app) >= 0x2618) {
+			ret = OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0);
+			goto out;
+		} else {
+			int i, len = dc->x0-dc->color+1;
+			u8 *colors = (u8 *)dc->data;
+			u8 r, g, b, blend;
+
+			for (i = 0; i<len; i++) {
+				if (get_user(r, colors + i * 4) ||
+				    get_user(g, colors + i * 4 + 1) ||
+				    get_user(b, colors + i * 4 + 2) ||
+				    get_user(blend, colors + i * 4 + 3)) {
+					ret = -EFAULT;
+					goto out;
 		}
-
-		if (FW_VERSION(av7110->arm_app) >= 0x2618)
-			OSDSetPalette(av7110, buf, dc->color, dc->x0);
-		else {
-			int i;
-			u8 *colors = buf;
-
-			for (i = 0; i<len; i++)
-				OSDSetColor(av7110, dc->color + i,
-					colors[i * 4], colors[i * 4 + 1],
-					colors[i * 4 + 2], colors[i * 4 + 3]);
+				OSDSetColor(av7110, dc->color + i, r, g, b, blend);
 		}
-		kfree(buf);
-		return 0;
+		}
+		ret = 0;
+		goto out;
 	}
 	case OSD_SetTrans:
-		return 0;
+		goto out;
 	case OSD_SetPixel:
 		DrawLine(av7110, av7110->osdwin,
 			 dc->x0, dc->y0, 0, 0, dc->color);
-		return 0;
+		goto out;
 	case OSD_GetPixel:
-		return 0;
-
+		goto out;
 	case OSD_SetRow:
 		dc->y1 = dc->y0;
 		/* fall through */
 	case OSD_SetBlock:
 		OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
-		return 0;
-
+		goto out;
 	case OSD_FillRow:
 		DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
 			  dc->x1-dc->x0+1, dc->y1, dc->color);
-		return 0;
+		goto out;
 	case OSD_FillBlock:
 		DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
 			  dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
-		return 0;
+		goto out;
 	case OSD_Line:
 		DrawLine(av7110, av7110->osdwin,
 			 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
-		return 0;
+		goto out;
 	case OSD_Query:
-		return 0;
+		goto out;
 	case OSD_Test:
-		return 0;
+		goto out;
 	case OSD_Text:
 	{
 		char textbuf[240];
 
-		if (strncpy_from_user(textbuf, dc->data, 240) < 0)
-			return -EFAULT;
+		if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
+			ret = -EFAULT;
+			goto out;
+		}
 		textbuf[239] = 0;
 		if (dc->x1 > 3)
 			dc->x1 = 3;
@@ -1026,16 +1018,55 @@
 			(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
 		FlushText(av7110);
 		WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
-		return 0;
+		goto out;
 	}
 	case OSD_SetWindow:
-		if (dc->x0 < 1 || dc->x0 > 7)
-			return -EINVAL;
+		if (dc->x0 < 1 || dc->x0 > 7) {
+			ret = -EINVAL;
+			goto out;
+		}
 		av7110->osdwin = dc->x0;
-		return 0;
+		goto out;
 	case OSD_MoveWindow:
 		MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
 		SetColorBlend(av7110, av7110->osdwin);
+		goto out;
+	case OSD_OpenRaw:
+		if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
+			av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
+		}
+		else {
+			av7110->osdbpp[av7110->osdwin] = 0;
+		}
+		CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+		if (!dc->data) {
+			MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+			SetColorBlend(av7110, av7110->osdwin);
+		}
+		goto out;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	up(&av7110->osd_sema);
+	return ret;
+}
+
+int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
+{
+        switch (cap->cmd) {
+        case OSD_CAP_MEMSIZE:
+                if (FW_4M_SDRAM(av7110->arm_app))
+                        cap->val = 1000000;
+                else
+                        cap->val = 92000;
 		return 0;
 	default:
 		return -EINVAL;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_hw.h linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_hw.h
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_hw.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_hw.h	2004-07-27 14:36:01.000000000 +0200
@@ -39,29 +39,6 @@
 	Pal8Bit =  256	   /* 256 colors for 16 bit palette */
 };
 
-enum av7110_window_display_type {
-	BITMAP1,	   /* 1 bit bitmap */
-	BITMAP2,	   /* 2 bit bitmap */
-	BITMAP4,	   /* 4 bit bitmap */
-	BITMAP8,	   /* 8 bit bitmap */
-	BITMAP1HR,	   /* 1 Bit bitmap half resolution */
-	BITMAP2HR,	   /* 2 bit bitmap half resolution */
-	BITMAP4HR,	   /* 4 bit bitmap half resolution */
-	BITMAP8HR,	   /* 8 bit bitmap half resolution */
-	YCRCB422,	   /* 4:2:2 YCRCB Graphic Display */
-	YCRCB444,	   /* 4:4:4 YCRCB Graphic Display */
-	YCRCB444HR,	   /* 4:4:4 YCRCB graphic half resolution */
-	VIDEOTSIZE,	   /* True Size Normal MPEG Video Display */
-	VIDEOHSIZE,	   /* MPEG Video Display Half Resolution */
-	VIDEOQSIZE,	   /* MPEG Video Display Quarter Resolution */
-	VIDEODSIZE,	   /* MPEG Video Display Double Resolution */
-	VIDEOTHSIZE,	   /* True Size MPEG Video Display Half Resolution */
-	VIDEOTQSIZE,	   /* True Size MPEG Video Display Quarter Resolution*/
-	VIDEOTDSIZE,	   /* True Size MPEG Video Display Double Resolution */
-	VIDEONSIZE,	   /* Full Size MPEG Video Display */
-	CURSOR		   /* Cursor */
-};
-
 /* switch defines */
 #define SB_GPIO 3
 #define SB_OFF	SAA7146_GPIO_OUTLO  /* SlowBlank off (TV-Mode) */
@@ -388,6 +365,7 @@
 extern int av7110_bootarm(struct av7110 *av7110);
 extern int av7110_firmversion(struct av7110 *av7110);
 #define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
+#define FW_4M_SDRAM(arm_app)      ((arm_app) & 0x40000000)
 #define FW_VERSION(arm_app)	  ((arm_app) & 0x0000FFFF)
 
 extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
@@ -495,7 +473,7 @@
 
 static int inline audcom(struct av7110 *av7110, u32 com)
 {
-	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 4,
+	return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
 			     (com>>16), (com&0xffff));
 }
 
@@ -510,6 +488,7 @@
 
 #ifdef CONFIG_DVB_AV7110_OSD
 extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
+extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
 #endif /* CONFIG_DVB_AV7110_OSD */
 
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_ir.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_ir.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_ir.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_ir.c	2004-07-31 02:05:46.000000000 +0200
@@ -1,23 +1,21 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/input.h>
 #include <linux/proc_fs.h>
 #include <asm/bitops.h>
 
 #include "av7110.h"
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "input_fake.h"
-#endif
-
-
 #define UP_TIMEOUT (HZ/4)
 
-static int av7110_ir_debug = 0;
+static int av7110_ir_debug;
 
-#define dprintk(x...)  do { if (av7110_ir_debug) printk (x); } while (0)
+module_param_named(debug_ir, av7110_ir_debug, int, 0644);
+MODULE_PARM_DESC(av7110_ir_debug, "Turn on/off IR debugging (default:off).");
 
+#define dprintk(x...)  do { if (av7110_ir_debug) printk (x); } while (0)
 
 static struct input_dev input_dev;
 
@@ -205,6 +198,7 @@
 
 void __exit av7110_ir_exit (void)
 {
+	del_timer_sync(&keyup_timer);
 	remove_proc_entry ("av7110_ir", NULL);
 	av7110_unregister_irc_handler (av7110_emit_key);
 	input_unregister_device(&input_dev);
@@ -213,6 +207,3 @@
 //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
 //MODULE_LICENSE("GPL");
 
-MODULE_PARM(av7110_ir_debug,"i");
-MODULE_PARM_DESC(av7110_ir_debug, "enable AV7110 IR receiver debug messages");
-
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_v4l.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_v4l.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_v4l.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110_v4l.c	2004-08-18 19:52:18.000000000 +0200
@@ -35,23 +35,16 @@
 #include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
-#include "dvb_i2c.h"
 #include "av7110.h"
 #include "av7110_hw.h"
 #include "av7110_av.h"
-#include "dvb_functions.h"
-
 
 int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
 {
 	u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
-	struct dvb_i2c_bus *i2c = av7110->i2c_bus;
 	struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
 
-	if (i2c->xfer(i2c, &msgs, 1) != 1) {
+	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
 		printk("av7110(%d): %s(%u = %u) failed\n",
 		       av7110->dvb_adapter->num, __FUNCTION__, reg, val);
 		return -EIO;
@@ -63,13 +56,12 @@
 {
 	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
 	u8 msg2[2];
-	struct dvb_i2c_bus *i2c = av7110->i2c_bus;
 	struct i2c_msg msgs[2] = {
 		{ .flags = 0,	     .addr = 0x40, .len = 3, .buf = msg1 },
 		{ .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 }
 	};
 
-	if (i2c->xfer(i2c, msgs, 2) != 2) {
+	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
 		printk("av7110(%d): %s(%u) failed\n",
 		       av7110->dvb_adapter->num, __FUNCTION__, reg);
 		return -EIO;
@@ -517,7 +507,7 @@
 	printk("av7110(%d): DVB-C analog module detected, initializing MSP3400\n",
 		av7110->dvb_adapter->num);
 	av7110->adac_type = DVB_ADAC_MSP;
-	dvb_delay(100); // the probing above resets the msp...
+	msleep(100); // the probing above resets the msp...
 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
 	printk("av7110(%d): MSP3400 version 0x%04x 0x%04x\n",
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-av.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-av.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-av.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-av.c	2004-08-18 19:44:05.000000000 +0200
@@ -30,14 +30,12 @@
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
-#include <media/saa7146_vv.h>
-
 #include "budget.h"
-#include "dvb_functions.h"
+#include <media/saa7146_vv.h>
 
 struct budget_av {
 	struct budget budget;
-	struct video_device vd;
+	struct video_device *vd;
 	int cur_input;
 	int has_saa7113;
 };
@@ -47,7 +45,7 @@
  ****************************************************************************/
 
 
-static u8 i2c_readreg (struct dvb_i2c_bus *i2c, u8 id, u8 reg)
+static u8 i2c_readreg (struct i2c_adapter *i2c, u8 id, u8 reg)
 {
 	u8 mm1[] = {0x00};
 	u8 mm2[] = {0x00};
@@ -60,12 +58,12 @@
 	msgs[0].len = 1; msgs[1].len = 1;
 	msgs[0].buf = mm1; msgs[1].buf = mm2;
 
-	i2c->xfer(i2c, msgs, 2);
+	i2c_transfer(i2c, msgs, 2);
 
 	return mm2[0];
 }
 
-static int i2c_readregs(struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 *buf, u8 len)
+static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 *buf, u8 len)
 {
         u8 mm1[] = { reg };
         struct i2c_msg msgs[2] = {
@@ -73,8 +71,9 @@
 		{ .addr = id/2, .flags = I2C_M_RD, .buf = buf, .len = len }
 	};
 
-        if (i2c->xfer(i2c, msgs, 2) != 2)
+        if (i2c_transfer(i2c, msgs, 2) != 2)
 		return -EIO;
+
 	return 0;
 }
 
@@ -79,7 +78,7 @@
 }
 
 
-static int i2c_writereg (struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 val)
+static int i2c_writereg (struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
 {
         u8 msg[2]={ reg, val }; 
         struct i2c_msg msgs;
@@ -88,7 +87,7 @@
         msgs.addr=id/2;
         msgs.len=2;
         msgs.buf=msg;
-        return i2c->xfer (i2c, &msgs, 1);
+        return i2c_transfer(i2c, &msgs, 1);
 }
 
 
@@ -127,7 +126,7 @@
 	struct budget *budget = &budget_av->budget;
 	const u8 *data = saa7113_tab;
 
-        if (i2c_writereg (budget->i2c_bus, 0x4a, 0x01, 0x08) != 1) {
+        if (i2c_writereg (&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
                 DEB_D(("saa7113: not found on KNC card\n"));
                 return -ENODEV;
         }
@@ -135,12 +134,12 @@
         INFO(("saa7113: detected and initializing\n"));
 
 	while (*data != 0xff) {
-                i2c_writereg(budget->i2c_bus, 0x4a, *data, *(data+1));
+                i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data+1));
                 data += 2;
         }
 
 	DEB_D(("saa7113: status=%02x\n",
-	      i2c_readreg(budget->i2c_bus, 0x4a, 0x1f)));
+	      i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)));
 
 	return 0;
 }
@@ -154,11 +153,11 @@
 		return -ENODEV;
 
 	if (input == 1) {
-		i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7);
-		i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
 	} else if (input == 0) {
-		i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc0);
-		i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x00);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
+		i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
 	} else
 		return -EINVAL;
 
@@ -177,7 +176,7 @@
 	if ( 1 == budget_av->has_saa7113 ) {
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
 
-	dvb_delay(200);
+		msleep(200);
 
 	saa7146_unregister_device (&budget_av->vd, dev);
 	}
@@ -201,7 +200,7 @@
 
 	DEB_EE(("dev: %p\n",dev));
 
-	if (bi->type != BUDGET_KNC1) {
+	if (bi->type != BUDGET_KNC1 && bi->type != BUDGET_CIN1200) {
 		return -ENODEV;
 	}
 
@@ -210,13 +209,13 @@
 
 	memset(budget_av, 0, sizeof(struct budget_av));
 
+	dev->ext_priv = budget_av;
+
 	if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) {
 		kfree(budget_av);
 		return err;
 	}
 
-	dev->ext_priv = budget_av;
-
 	/* knc1 initialization */
 	saa7146_write(dev, DD1_STREAM_B, 0x04000000);
 	saa7146_write(dev, DD1_INIT, 0x07000600);
@@ -225,7 +224,7 @@
 	//test_knc_ci(av7110);
 
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
-	dvb_delay(500);
+	msleep(500);
 
 	if ( 0 == saa7113_init(budget_av) ) {
 		budget_av->has_saa7113 = 1;
@@ -259,7 +258,7 @@
 	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 
 	mac = budget_av->budget.dvb_adapter->proposed_mac;
-	if (i2c_readregs(budget_av->budget.i2c_bus, 0xa0, 0x30, mac, 6)) {
+	if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
 		printk("KNC1-%d: Could not read MAC from KNC1 card\n",
 				budget_av->budget.dvb_adapter->num);
 		memset(mac, 0, 6);
@@ -361,9 +360,11 @@
 
 
 MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1);
+MAKE_BUDGET_INFO(cin1200, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200);
 
 static struct pci_device_id pci_tbl [] = {
 	MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56),
+	MAKE_EXTENSION_PCI(cin1200, 0x153b, 0x1154),
 	{
 		.vendor    = 0,
 	}
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget.c	2004-08-18 19:52:18.000000000 +0200
@@ -35,7 +35,6 @@
  */
 
 #include "budget.h"
-#include "dvb_functions.h"
 
 static void Set22K (struct budget *budget, int state)
 {
@@ -100,7 +99,7 @@
 			udelay(12500);
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
 		}
-		dvb_delay(20);
+		msleep(20);
 	}
 
 	return 0;
@@ -202,6 +201,8 @@
 
 	DEB_EE(("dev:%p, info:%p, budget:%p\n",dev,info,budget));
 
+	dev->ext_priv = budget;
+
 	if ((err = ttpci_budget_init (budget, dev, info))) {
 		printk("==> failed\n");
 		kfree (budget);
@@ -215,8 +216,6 @@
 	dvb_add_frontend_ioctls (budget->dvb_adapter,
 				 budget_diseqc_ioctl, NULL, budget);
 
-	dev->ext_priv = budget;
-
 	return 0;
 }
 
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-ci.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-ci.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-ci.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-ci.c	2004-08-18 19:52:18.000000000 +0200
@@ -38,13 +38,8 @@
 #include <linux/input.h>
 #include <linux/spinlock.h>
 
-#include "dvb_functions.h"
 #include "dvb_ca_en50221.h"
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "input_fake.h"
-#endif
-
 #define DEBIADDR_IR		0x1234
 #define DEBIADDR_CICONTROL	0x0000
 #define DEBIADDR_CIVERSION	0x4000
@@ -326,7 +321,7 @@
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
 	budget_ci->slot_status = SLOTSTATUS_RESET;
 	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
-	dvb_delay(1);
+	msleep(1);
 	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
 
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
@@ -372,14 +367,13 @@
 	// ensure we don't get spurious IRQs during initialisation
 	if (!budget_ci->budget.ci_present) return;
 
+	// read the CAM status
 	flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
+	if (flags & CICONTROL_CAMDETECT) {
 
-	// always set the GPIO mode back to "normal", in case the card is
-	// yanked at an inopportune moment
+		// GPIO should be set to trigger on falling edge if a CAM is present
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
 
-	if (flags & CICONTROL_CAMDETECT) {
-
 		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
 			// CAM insertion IRQ
 			budget_ci->slot_status = SLOTSTATUS_PRESENT;
@@ -395,7 +389,15 @@
 			dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
 		}
 	} else {
+
+		// trigger on rising edge if a CAM is not present - when a CAM is inserted, we
+		// only want to get the IRQ when it sets READY. If we trigger on the falling edge,
+		// the CAM might not actually be ready yet.
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+
+	   	// generate a CAM removal IRQ if we haven't already
 		if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
+			// CAM removal IRQ
 			budget_ci->slot_status = SLOTSTATUS_NONE;
 			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
 		}
@@ -446,7 +448,11 @@
 
 	// Setup CI slot IRQ
 	tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+	if (budget_ci->slot_status != SLOTSTATUS_NONE) {
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
+	} else {
+		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
+	}
 	saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
 	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
 
@@ -475,7 +481,7 @@
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
 	tasklet_kill(&budget_ci->ciintf_irq_tasklet);
 	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
-	dvb_delay(1);
+	msleep(1);
 	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
 
 	// disable TS data stream to CI interface
@@ -520,20 +526,19 @@
 	spin_lock_init(&budget_ci->debilock);
 	budget_ci->budget.ci_present = 0;
 
+	dev->ext_priv = budget_ci;
+
 	if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
 		kfree (budget_ci);
 		return err;
 	}
 
-	dev->ext_priv = budget_ci;
-
 	tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
 		      (unsigned long) budget_ci);
 
 	msp430_ir_init (budget_ci);
 
-	// UNCOMMENT TO TEST CI INTERFACE
-//	ciintf_init(budget_ci);
+	ciintf_init(budget_ci);
 
 	return 0;
 }
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-core.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-core.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget-core.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-core.c	2004-08-18 18:01:48.000000000 +0200
@@ -34,10 +34,15 @@
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
+#include <linux/moduleparam.h>
+
 #include "budget.h"
 #include "ttpci-eeprom.h"
 
-int budget_debug = 0;
+static int budget_debug;
+
+module_param_named(debug, budget_debug, int, 0644);
+MODULE_PARM_DESC(budget_debug, "Turn on/off budget debugging (default:off).");
 
 /****************************************************************************
  * TT budget / WinTV Nova
@@ -258,13 +263,26 @@
         dvb_dmx_release(&budget->demux);
 }
 
-
-static int master_xfer (struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[], int num)
+/* fixme: can this be unified among all saa7146 based dvb cards? */
+int client_register(struct i2c_client *client)
 {
-	struct saa7146_dev *dev = i2c->data;
-	return saa7146_i2c_transfer(dev, msgs, num, 6);
+	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
+	struct budget *budget = (struct budget*)dev->ext_priv;
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_REGISTER, budget->dvb_adapter);
+	return 0;
 }
 
+int client_unregister(struct i2c_client *client)
+{
+	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
+	struct budget *budget = (struct budget*)dev->ext_priv;
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_UNREGISTER, budget->dvb_adapter);
+	return 0;
+}
 
 int ttpci_budget_init (struct budget *budget,
 		       struct saa7146_dev* dev,
@@ -301,17 +319,27 @@
 	if (bi->type != BUDGET_FS_ACTIVY)
 		saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
 	
-	saa7146_i2c_adapter_prepare(dev, NULL, 0, SAA7146_I2C_BUS_BIT_RATE_120);
+	budget->i2c_adap = (struct i2c_adapter) {
+		.client_register = client_register,
+		.client_unregister = client_unregister,
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+		.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+		.class = I2C_CLASS_TV_DIGITAL,
+#endif
+	};
+	
+	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
-	budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev,
-						budget->dvb_adapter, 0);
+	saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
+	strcpy(budget->i2c_adap.name, budget->card->name);
 
-	if (!budget->i2c_bus) {
+	if (i2c_add_adapter(&budget->i2c_adap) < 0) {
 		dvb_unregister_adapter (budget->dvb_adapter);
 		return -ENOMEM;
 	}
 
-	ttpci_eeprom_parse_mac(budget->i2c_bus);
+	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac);
 
 	if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) {
 		ret = -ENOMEM;
@@ -334,12 +362,11 @@
 		return 0;
 	}
 err:
+	i2c_del_adapter(&budget->i2c_adap);
+
 	if (budget->grabbing)
 		vfree(budget->grabbing);
 
-	dvb_unregister_i2c_bus (master_xfer,budget->i2c_bus->adapter,
-				budget->i2c_bus->id);
-
 	dvb_unregister_adapter (budget->dvb_adapter);
 
 	return ret;
@@ -354,8 +381,7 @@
 
 	budget_unregister (budget);
 
-	dvb_unregister_i2c_bus (master_xfer, budget->i2c_bus->adapter,
-				budget->i2c_bus->id);
+	i2c_del_adapter(&budget->i2c_adap);
 
 	dvb_unregister_adapter (budget->dvb_adapter);
 
@@ -402,7 +428,5 @@
 EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
 EXPORT_SYMBOL_GPL(budget_debug);
 
-MODULE_PARM(budget_debug,"i");
 MODULE_LICENSE("GPL");
 
-
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget.h linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget.h
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/budget.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget.h	2004-08-18 19:52:18.000000000 +0200
@@ -1,9 +1,6 @@
 #ifndef __BUDGET_DVB__
 #define __BUDGET_DVB__
 
-#include <media/saa7146.h>
-
-#include "dvb_i2c.h"
 #include "dvb_frontend.h"
 #include "dvbdev.h"
 #include "demux.h"
@@ -12,6 +9,8 @@
 #include "dvb_filter.h"
 #include "dvb_net.h"
 
+#include <media/saa7146.h>
+
 extern int budget_debug;
 
 struct budget_info {
@@ -28,7 +27,7 @@
 
         struct saa7146_dev	*dev;
 
-	struct dvb_i2c_bus	*i2c_bus;	
+	struct i2c_adapter	i2c_adap;	
 	struct budget_info	*card;
 
 	unsigned char		*grabbing;
@@ -79,6 +78,7 @@
 #define BUDGET_KNC1		   2
 #define BUDGET_PATCH		   3
 #define BUDGET_FS_ACTIVY	   4
+#define BUDGET_CIN1200		   5
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/ttpci-eeprom.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/ttpci-eeprom.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/ttpci-eeprom.c	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/ttpci-eeprom.c	2004-08-18 19:52:18.000000000 +0200
@@ -35,9 +35,8 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/i2c.h>
 
-#include "dvb_i2c.h"
-#include "dvb_functions.h"
 
 #if 1
 #define dprintk(x...) do { printk(x); } while (0)
@@ -85,7 +84,7 @@
         return 0;
 }
 
-static int ttpci_eeprom_read_encodedMAC(struct dvb_i2c_bus *i2c, u8 * encodedMAC)
+static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC)
 {
 	int ret;
 	u8 b0[] = { 0xcc };
@@ -97,7 +96,7 @@
 
 	/* dprintk("%s\n", __FUNCTION__); */
 
-	ret = i2c->xfer(i2c, msg, 2);
+	ret = i2c_transfer(adapter, msg, 2);
 
 	if (ret != 2)		/* Assume EEPROM isn't there */
 		return (-ENODEV);
@@ -106,36 +105,34 @@
 }
 
 
-int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c)
+int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
 {
 	int ret, i;
 	u8 encodedMAC[20];
 	u8 decodedMAC[6];
 
-	ret = ttpci_eeprom_read_encodedMAC(i2c, encodedMAC);
+	ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC);
 
 	if (ret != 0) {		/* Will only be -ENODEV */
 		dprintk("Couldn't read from EEPROM: not there?\n");
-		memset(i2c->adapter->proposed_mac, 0, 6);
+		memset(proposed_mac, 0, 6);
 		return ret;
 	}
 
 	ret = getmac_tt(decodedMAC, encodedMAC);
 	if( ret != 0 ) {
-		dprintk("%s adapter %i failed MAC signature check\n",
-			i2c->adapter->name, i2c->adapter->num);
+		dprintk("adapter failed MAC signature check\n");
 		dprintk("encoded MAC from EEPROM was " );
 		for(i=0; i<19; i++) {
 			dprintk( "%.2x:", encodedMAC[i]);
 		}
 		dprintk("%.2x\n", encodedMAC[19]);
-		memset(i2c->adapter->proposed_mac, 0, 6);
+		memset(proposed_mac, 0, 6);
 		return ret;
 	}
 
-	memcpy(i2c->adapter->proposed_mac, decodedMAC, 6);
-	dprintk("%s adapter %i has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-		i2c->adapter->name, i2c->adapter->num,
+	memcpy(proposed_mac, decodedMAC, 6);
+	dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
 		decodedMAC[0], decodedMAC[1], decodedMAC[2],
 		decodedMAC[3], decodedMAC[4], decodedMAC[5]);
 	return 0;
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttpci/ttpci-eeprom.h linux-2.6.8.1-patched/drivers/media/dvb/ttpci/ttpci-eeprom.h
--- xx-linux-2.6.8.1/drivers/media/dvb/ttpci/ttpci-eeprom.h	2004-07-19 19:40:04.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/ttpci-eeprom.h	2004-05-03 13:15:31.000000000 +0200
@@ -25,8 +25,9 @@
 #ifndef __TTPCI_EEPROM_H__
 #define __TTPCI_EEPROM_H__
 
-#include "dvb_i2c.h"
+#include <linux/types.h>
+#include <linux/i2c.h>
 
-extern int ttpci_eeprom_parse_mac(struct dvb_i2c_bus *i2c);
+extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac);
 
 #endif
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c linux-2.6.8.1-patched/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2004-08-24 16:05:26.000000000 +0200
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
 #include <linux/time.h>
@@ -28,8 +29,6 @@
 #include <linux/dvb/dmx.h>
 #include <linux/pci.h>
 
-#include "dvb_functions.h"
-
 /*
   TTUSB_HWSECTIONS:
     the DSP supports filtering in hardware, however, since the "muxstream"
@@ -49,7 +48,10 @@
     this unless the device doesn't load at all. > 2 for bandwidth statistics.
 */
 
-static int debug = 0;
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
 #define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)
 
@@ -80,6 +82,8 @@
 	struct dvb_adapter *adapter;
 	struct usb_device *dev;
 
+	struct i2c_adapter i2c_adap;	
+
 	int disconnecting;
 	int iso_streaming;
 
@@ -242,10 +246,9 @@
 	return rcv_len;
 }
 
-static int ttusb_i2c_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg msg[],
-		   int num)
+static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num)
 {
-	struct ttusb *ttusb = i2c->data;
+	struct ttusb *ttusb = i2c_get_adapdata(adapter);
 	int i = 0;
 	int inc;
 
@@ -514,7 +517,7 @@
 
 static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct ttusb *ttusb = fe->i2c->data;
+	struct ttusb *ttusb = fe->before_after_data;
 
 	switch (cmd) {
 	case FE_SET_VOLTAGE:
@@ -787,7 +790,7 @@
 			ttusb_process_frame(ttusb, data, len);
 		}
 	}
-	usb_submit_urb(urb, GFP_KERNEL);
+	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
 static void ttusb_free_iso_urbs(struct ttusb *ttusb)
@@ -822,7 +825,7 @@
 
 		if (!
 		    (urb =
-		     usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_KERNEL))) {
+		     usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
 			ttusb_free_iso_urbs(ttusb);
 			return -ENOMEM;
 		}
@@ -880,7 +883,7 @@
 	}
 
 	for (i = 0; i < ISO_BUF_COUNT; i++) {
-		if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_KERNEL))) {
+		if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) {
 			ttusb_stop_iso_xfer(ttusb);
 			printk
 			    ("%s: failed urb submission (%i: err = %i)!\n",
@@ -1068,6 +1071,38 @@
 };
 #endif
 
+u32 functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ttusb_dec_algo = {
+	.name		= "ttusb dec i2c algorithm",
+	.id		= I2C_ALGO_BIT,
+	.master_xfer	= master_xfer,
+	.functionality	= functionality,
+};
+
+int client_register(struct i2c_client *client)
+{
+	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_REGISTER, ttusb->adapter);
+
+	return 0;
+}
+
+int client_unregister(struct i2c_client *client)
+{
+	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+
+	if (client->driver->command)
+		return client->driver->command(client, FE_UNREGISTER, ttusb->adapter);
+
+	return 0;
+}
+
 static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *udev;
@@ -1078,17 +1113,6 @@
 
 	udev = interface_to_usbdev(intf);
 
-	/* Device has already been reset; its configuration was chosen.
-	 * If this fault happens, use a hotplug script to choose the
-	 * right configuration (write bConfigurationValue in sysfs).
-	 */
-	if (udev->actconfig->desc.bConfigurationValue != 1) {
-		dev_err(&intf->dev, "device config is #%d, need #1\n",
-			udev->actconfig->desc.bConfigurationValue);
-		return -ENODEV;
-	}
-
-
         if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV;
 
 	if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL)))
@@ -1117,7 +1141,29 @@
 
 	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
 
-	dvb_register_i2c_bus(ttusb_i2c_xfer, ttusb, ttusb->adapter, 0);
+	/* i2c */
+	memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
+	strcpy(ttusb->i2c_adap.name, "TTUSB DEC");
+
+	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
+
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+	ttusb->i2c_adap.class 	    	  = I2C_ADAP_CLASS_TV_DIGITAL;
+#else
+	ttusb->i2c_adap.class 	    	  = I2C_CLASS_TV_DIGITAL;
+#endif
+	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
+	ttusb->i2c_adap.algo_data         = NULL;
+	ttusb->i2c_adap.id                = I2C_ALGO_BIT;
+	ttusb->i2c_adap.client_register   = client_register;
+	ttusb->i2c_adap.client_unregister = client_unregister;
+	
+	result = i2c_add_adapter(&ttusb->i2c_adap);
+	if (result) {
+		dvb_unregister_adapter (ttusb->adapter);
+		return result;
+	}
+
 	dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
 				ttusb);
 
@@ -1137,9 +1183,10 @@
 	ttusb->dvb_demux.write_to_decoder = NULL;
 
 	if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) {
-		printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n",
-		       result);
-		goto err;
+		printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
+		i2c_del_adapter(&ttusb->i2c_adap);
+		dvb_unregister_adapter (ttusb->adapter);
+		return -ENODEV;
 	}
 //FIXME dmxdev (nur WAS?)
 	ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
@@ -1150,15 +1197,20 @@
 		printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
 		       result);
 		dvb_dmx_release(&ttusb->dvb_demux);
-		goto err;
+		i2c_del_adapter(&ttusb->i2c_adap);
+		dvb_unregister_adapter (ttusb->adapter);
+		return -ENODEV;
 	}
 
-	if (dvb_net_init
-	    (ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
+	if (dvb_net_init(ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
 		printk("ttusb_dvb: dvb_net_init failed!\n");
+		dvb_dmxdev_release(&ttusb->dmxdev);
+		dvb_dmx_release(&ttusb->dvb_demux);
+		i2c_del_adapter(&ttusb->i2c_adap);
+		dvb_unregister_adapter (ttusb->adapter);
+		return -ENODEV;
 	}
 
-      err:
 #if 0
 	ttusb->stc_devfs_handle =
 	    devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME,
@@ -1187,7 +1238,7 @@
 	dvb_dmxdev_release(&ttusb->dmxdev);
 	dvb_dmx_release(&ttusb->dvb_demux);
 
-	dvb_unregister_i2c_bus(ttusb_i2c_xfer, ttusb->adapter, 0);
+	i2c_del_adapter(&ttusb->i2c_adap);
 	dvb_unregister_adapter(ttusb->adapter);
 
 	ttusb_free_iso_urbs(ttusb);
@@ -1234,9 +1285,6 @@
 module_init(ttusb_init);
 module_exit(ttusb_exit);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug or not");
-
 MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
 MODULE_DESCRIPTION("TTUSB DVB Driver");
 MODULE_LICENSE("GPL");
diff -uraNwB xx-linux-2.6.8.1/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- xx-linux-2.6.8.1/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2004-08-23 09:34:58.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2004-08-18 19:52:18.000000000 +0200
@@ -22,10 +22,12 @@
 #include <asm/semaphore.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
+#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/firmware.h>
 #if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
@@ -37,13 +39,17 @@
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
-#include "dvb_i2c.h"
 #include "dvb_filter.h"
 #include "dvb_frontend.h"
 #include "dvb_net.h"
 
-static int debug = 0;
-static int output_pva = 0;
+static int debug;
+static int output_pva;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+module_param(output_pva, int, 0444);
+MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
 
 #define dprintk	if (debug) printk
 
@@ -95,7 +101,6 @@
 	struct dmxdev			dmxdev;
 	struct dvb_demux		demux;
 	struct dmx_frontend		frontend;
-	struct dvb_i2c_bus		i2c_bus;
 	struct dvb_net			dvb_net;
 	struct dvb_frontend_info	*frontend_info;
 	int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
@@ -1100,7 +1104,7 @@
 				 	       &dec->iso_dma_handle);
 
 	memset(dec->iso_buffer, 0,
-	       sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)));
+	       ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));
 
 	for (i = 0; i < ISO_BUF_COUNT; i++) {
 		struct urb *urb;
@@ -1600,7 +1603,7 @@
 				p->u.qam.symbol_rate);
 			dprintk("            inversion->%d\n", p->inversion);
 
-		freq = htonl(p->frequency * 1000 +
+		freq = htonl(p->frequency +
 		       (dec->hi_band ? LOF_HI : LOF_LO));
 			memcpy(&b[4], &freq, sizeof(u32));
 			sym_rate = htonl(p->u.qam.symbol_rate);
@@ -1628,9 +1631,18 @@
 		dprintk("%s: FE_INIT\n", __FUNCTION__);
 		break;
 
-	case FE_DISEQC_SEND_MASTER_CMD:
+	case FE_DISEQC_SEND_MASTER_CMD: {
+		u8 b[] = { 0x00, 0xff, 0x00, 0x00,
+			   0x00, 0x00, 0x00, 0x00,
+			   0x00, 0x00 };
+		struct dvb_diseqc_master_cmd *cmd = arg;
+		memcpy(&b[4], cmd->msg, cmd->msg_len);
 		dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
+		ttusb_dec_send_command(dec, 0x72,
+				       sizeof(b) - (6 - cmd->msg_len), b,
+				       NULL, NULL);
 		break;
+	}
 
 	case FE_DISEQC_SEND_BURST:
 		dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
@@ -1669,15 +1680,13 @@
 
 static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
 {
-	dec->i2c_bus.adapter = dec->adapter;
-
-	dvb_register_frontend(dec->frontend_ioctl, &dec->i2c_bus, (void *)dec,
-			      dec->frontend_info);
+	int ret;
+	ret = dvb_register_frontend(dec->frontend_ioctl, dec->adapter, dec, dec->frontend_info, THIS_MODULE);
 }
 
 static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
 {
-	dvb_unregister_frontend(dec->frontend_ioctl, &dec->i2c_bus);
+	dvb_unregister_frontend_new(dec->frontend_ioctl, dec->adapter);
 }
 
 static void ttusb_dec_init_filters(struct ttusb_dec *dec)
@@ -1840,7 +1849,3 @@
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-MODULE_PARM(output_pva, "i");
-MODULE_PARM_DESC(output_pva, "Output PVA from dvr device");
diff -uraNwB xx-linux-2.6.8.1/include/linux/dvb/osd.h linux-2.6.8.1-patched/include/linux/dvb/osd.h
--- xx-linux-2.6.8.1/include/linux/dvb/osd.h	2004-08-23 09:35:38.000000000 +0200
+++ linux-2.6.8.1-patched/include/linux/dvb/osd.h	2004-08-09 13:26:27.000000000 +0200
@@ -94,6 +94,7 @@
   OSD_Text,       // (x0,y0,size,color,text)
   OSD_SetWindow, //  (x0) set window with number 0<x0<8 as current
   OSD_MoveWindow, //  move current window to (x0, y0)  
+  OSD_OpenRaw,	// Open other types of OSD windows
 } OSD_Command;
 
 typedef struct osd_cmd_s {
@@ -106,8 +107,39 @@
         void __user *data;
 } osd_cmd_t;
 
+/* OSD_OpenRaw: set 'color' to desired window type */
+typedef enum {
+        OSD_BITMAP1,           /* 1 bit bitmap */
+        OSD_BITMAP2,           /* 2 bit bitmap */
+        OSD_BITMAP4,           /* 4 bit bitmap */
+        OSD_BITMAP8,           /* 8 bit bitmap */
+        OSD_BITMAP1HR,         /* 1 Bit bitmap half resolution */
+        OSD_BITMAP2HR,         /* 2 bit bitmap half resolution */
+        OSD_BITMAP4HR,         /* 4 bit bitmap half resolution */
+        OSD_BITMAP8HR,         /* 8 bit bitmap half resolution */
+        OSD_YCRCB422,          /* 4:2:2 YCRCB Graphic Display */
+        OSD_YCRCB444,          /* 4:4:4 YCRCB Graphic Display */
+        OSD_YCRCB444HR,        /* 4:4:4 YCRCB graphic half resolution */
+        OSD_VIDEOTSIZE,        /* True Size Normal MPEG Video Display */
+        OSD_VIDEOHSIZE,        /* MPEG Video Display Half Resolution */
+        OSD_VIDEOQSIZE,        /* MPEG Video Display Quarter Resolution */
+        OSD_VIDEODSIZE,        /* MPEG Video Display Double Resolution */
+        OSD_VIDEOTHSIZE,       /* True Size MPEG Video Display Half Resolution */
+        OSD_VIDEOTQSIZE,       /* True Size MPEG Video Display Quarter Resolution*/
+        OSD_VIDEOTDSIZE,       /* True Size MPEG Video Display Double Resolution */
+        OSD_VIDEONSIZE,        /* Full Size MPEG Video Display */
+        OSD_CURSOR             /* Cursor */
+} osd_raw_window_t;
+
+typedef struct osd_cap_s {
+        int  cmd;
+#define OSD_CAP_MEMSIZE         1  /* memory size */
+        long val;
+} osd_cap_t;
+
 
 #define OSD_SEND_CMD       _IOW('o', 160, osd_cmd_t)
+#define OSD_GET_CAPABILITY      _IOR('o', 161, osd_cap_t)
 
 #endif
 
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/b2c2/skystar2.c linux-2.6.8.1-patched/drivers/media/dvb/b2c2/skystar2.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/b2c2/skystar2.c	2004-09-17 12:26:13.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/b2c2/skystar2.c	2004-09-01 12:19:01.000000000 +0200
@@ -2236,7 +2236,7 @@
 }
 
 
-int client_register(struct i2c_client *client)
+static int client_register(struct i2c_client *client)
 {
 	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
 
@@ -2247,7 +2247,7 @@
 	return 0;
 }
 
-int client_unregister(struct i2c_client *client)
+static int client_unregister(struct i2c_client *client)
 {
 	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
 
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c linux-2.6.8.1-patched/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2004-09-17 12:26:39.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	2004-09-01 12:19:01.000000000 +0200
@@ -1083,7 +1083,7 @@
 	.functionality	= functionality,
 };
 
-int client_register(struct i2c_client *client)
+static int client_register(struct i2c_client *client)
 {
 	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
 
@@ -1093,7 +1093,7 @@
 	return 0;
 }
 
-int client_unregister(struct i2c_client *client)
+static int client_unregister(struct i2c_client *client)
 {
 	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
 
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/budget-core.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-core.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/budget-core.c	2004-09-17 12:26:39.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-core.c	2004-09-01 12:19:01.000000000 +0200
@@ -264,7 +264,7 @@
 }
 
 /* fixme: can this be unified among all saa7146 based dvb cards? */
-int client_register(struct i2c_client *client)
+static int client_register(struct i2c_client *client)
 {
 	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
 	struct budget *budget = (struct budget*)dev->ext_priv;
@@ -274,7 +274,7 @@
 	return 0;
 }
 
-int client_unregister(struct i2c_client *client)
+static int client_unregister(struct i2c_client *client)
 {
 	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
 	struct budget *budget = (struct budget*)dev->ext_priv;
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/av7110.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/av7110.c	2004-09-17 12:26:39.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/av7110.c	2004-09-17 12:35:37.000000000 +0200
@@ -1412,7 +1411,8 @@
 }
 #endif
 
-int client_register(struct i2c_client *client)
+
+static int client_register(struct i2c_client *client)
 {
 	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
 	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
@@ -1423,7 +1423,7 @@
 	return 0;
 }
 
-int client_unregister(struct i2c_client *client)
+static int client_unregister(struct i2c_client *client)
 {
 	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
 	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/budget-ci.c linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-ci.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttpci/budget-ci.c	2004-09-17 12:26:39.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttpci/budget-ci.c	2004-09-01 12:19:01.000000000 +0200
@@ -74,14 +74,15 @@
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	u32 result = 0;
+        unsigned long flags;
 
 	if (count > 4 || count <= 0)
 		return 0;
 
-	spin_lock(&budget_ci->debilock);
+	spin_lock_irqsave(&budget_ci->debilock, flags);
 
 	if (saa7146_wait_for_debi_done(saa) < 0) {
-		spin_unlock(&budget_ci->debilock);
+		spin_unlock_irqrestore(&budget_ci->debilock, flags);
 		return 0;
 	}
 
@@ -96,21 +97,22 @@
 	result = saa7146_read(saa, 0x88);
 	result &= (0xffffffffUL >> ((4 - count) * 8));
 
-	spin_unlock(&budget_ci->debilock);
+	spin_unlock_irqrestore(&budget_ci->debilock, flags);
 	return result;
 }
 
 static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value)
 {
 	struct saa7146_dev *saa = budget_ci->budget.dev;
+        unsigned long flags;
 
 	if (count > 4 || count <= 0)
 		return 0;
 
-	spin_lock(&budget_ci->debilock);
+	spin_lock_irqsave(&budget_ci->debilock, flags);
 
 	if (saa7146_wait_for_debi_done(saa) < 0) {
-		spin_unlock(&budget_ci->debilock);
+		spin_unlock_irqrestore(&budget_ci->debilock, flags);
 		return 0;
 	}
 
@@ -123,7 +125,7 @@
 
 	saa7146_wait_for_debi_done(saa);
 
-	spin_unlock(&budget_ci->debilock);
+	spin_unlock_irqrestore(&budget_ci->debilock, flags);
 	return 0;
 }
 

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

* Re: [PATCH][2.6][13/14] dvb frontend updates
  2004-09-17 14:39                       ` [PATCH][2.6][12/14] misc. driver updates Michael Hunold
@ 2004-09-17 14:40                         ` Michael Hunold
  2004-09-17 14:42                           ` [PATCH][2.6][14/14] follow saa7146 changes in other drivers Michael Hunold
  2004-09-20 11:11                         ` [PATCH][2.6][12.1/14] DVB: add kernel message classifiers Philipp Matthias Hahn
  1 sibling, 1 reply; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 13-DVB-frontend-updates.diff --]
[-- Type: text/plain, Size: 25857 bytes --]

- [DVB] all: replace dvb_unregister_frontend_new() with dvb_unregister_frontend()
- [DVB] sp887x: fix firmware download, patch by Jose Alberto Reguero
- [DVB] tda1004x: add firmware loading via firmware_class()
- [DVB] dvb_frontend: without hierachical coding, code_rate_LP is irrelevant, so we tolerate the otherwise invalid FEC_NONE setting
- [DVB] ves1x93: fixed dropouts on older DVB cards, fix tuning issues (Andreas Share / Gregoire Favre), 

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_ksyms.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ksyms.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_ksyms.c	2004-09-17 12:26:16.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_ksyms.c	2004-08-24 17:54:22.000000000 +0200
@@ -24,7 +24,7 @@
 EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
 EXPORT_SYMBOL(dvb_register_frontend);
-EXPORT_SYMBOL(dvb_unregister_frontend_new);
+EXPORT_SYMBOL(dvb_unregister_frontend);
 EXPORT_SYMBOL(dvb_add_frontend_ioctls);
 EXPORT_SYMBOL(dvb_remove_frontend_ioctls);
 EXPORT_SYMBOL(dvb_add_frontend_notifier);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/alps_tdlb7.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdlb7.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/alps_tdlb7.c	2004-09-17 12:26:19.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdlb7.c	2004-09-01 12:19:01.000000000 +0200
@@ -19,15 +19,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
-
 /* 
-    This driver needs a copy of the firmware file from the Technotrend
-    Windoze driver.
-
-    This page is worth a look:
-    http://www.heise.de/ct/ftp/projekte/vdr/firmware.shtml
-    
-    Copy 'Sc_main.mc'  to '/usr/lib/hotplug/firmware/dvb-fe-tdlb7-2.16.fw'.
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
 */  
 #define SP887X_DEFAULT_FIRMWARE "dvb-fe-tdlb7-2.16.fw"
 
@@ -690,7 +683,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend_new (tdlb7_ioctl, state->dvb);
+	dvb_unregister_frontend (tdlb7_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/alps_tdmb7.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdmb7.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/alps_tdmb7.c	2004-09-17 12:26:19.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/alps_tdmb7.c	2004-08-24 17:54:22.000000000 +0200
@@ -470,7 +467,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend_new (tdmb7_ioctl, state->dvb);
+	dvb_unregister_frontend (tdmb7_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/at76c651.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/at76c651.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/at76c651.c	2004-09-17 12:26:19.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/at76c651.c	2004-08-24 17:54:22.000000000 +0200
@@ -514,7 +508,7 @@
 {
 	struct at76c651_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new(at76c651_ioctl, state->dvb);
+	dvb_unregister_frontend(at76c651_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/cx24110.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx24110.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/cx24110.c	2004-09-17 12:26:19.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/cx24110.c	2004-08-24 17:54:22.000000000 +0200
@@ -708,7 +708,7 @@
 {
 	struct cx24110_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new(cx24110_ioctl, state->dvb);
+	dvb_unregister_frontend(cx24110_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dst.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dst.c	2004-09-17 12:26:19.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dst.c	2004-08-24 17:54:22.000000000 +0200
@@ -1193,7 +1190,7 @@
 {
 	struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
 	
-	dvb_unregister_frontend_new(dst_ioctl, state->dvb);
+	dvb_unregister_frontend(dst_ioctl, state->dvb);
 
 	device_remove_file(&client->dev, &dev_attr_client_type);
 	device_remove_file(&client->dev, &dev_attr_client_flags);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dvb_dummy_fe.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/dvb_dummy_fe.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/dvb_dummy_fe.c	2004-09-17 12:26:24.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/dvb_dummy_fe.c	2004-08-24 17:54:22.000000000 +0200
@@ -207,7 +207,7 @@
 {
 	struct dvb_adapter *dvb = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new(dvbdummyfe_ioctl, dvb);
+	dvb_unregister_frontend(dvbdummyfe_ioctl, dvb);
 	i2c_detach_client(client);
 	kfree(client);
 	return 0;
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/grundig_29504-401.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-401.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/grundig_29504-401.c	2004-09-17 12:26:24.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-401.c	2004-08-24 17:54:22.000000000 +0200
@@ -684,7 +684,7 @@
 {
 	struct l64781_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new(l64781_ioctl, state->dvb);
+	dvb_unregister_frontend(l64781_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/grundig_29504-491.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-491.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/grundig_29504-491.c	2004-09-17 12:26:24.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/grundig_29504-491.c	2004-08-24 17:54:22.000000000 +0200
@@ -492,7 +490,7 @@
 {
 	struct tda8083_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new (tda8083_ioctl, state->dvb);
+	dvb_unregister_frontend (tda8083_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/mt312.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt312.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/mt312.c	2004-09-17 12:26:24.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt312.c	2004-08-24 17:54:22.000000000 +0200
@@ -845,7 +845,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend_new (mt312_ioctl, state->dvb);
+	dvb_unregister_frontend (mt312_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/mt352.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/mt352.c	2004-09-17 12:26:33.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/mt352.c	2004-08-24 17:54:22.000000000 +0200
@@ -840,7 +840,7 @@
 {
 	struct mt352_state *state = i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new (mt352_ioctl, state->dvb);
+	dvb_unregister_frontend (mt352_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/nxt6000.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/nxt6000.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/nxt6000.c	2004-09-17 12:26:29.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/nxt6000.c	2004-08-24 17:54:22.000000000 +0200
@@ -872,7 +791,7 @@
 static int detach_client(struct i2c_client *client)
 {
 	struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client);
-	dvb_unregister_frontend_new(nxt6000_ioctl, state->dvb);
+	dvb_unregister_frontend(nxt6000_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/sp887x.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/sp887x.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/sp887x.c	2004-09-17 12:26:29.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/sp887x.c	2004-09-01 12:19:01.000000000 +0200
@@ -3,16 +3,9 @@
 */
 
 /*
-   This driver needs a copy of the Avermedia firmware. The version tested
-   is part of the Avermedia DVB-T 1.3.26.3 Application. If the software is
-   installed in Windoze the file will be in the /Program Files/AVerTV DVB-T/
-   directory and is called sc_main.mc. Alternatively it can "extracted" from
-   the install cab files.
-   
-   Copy this file to '/usr/lib/hotplug/firmware/dvb-fe-sp887x.fw'.
-   
-   With this version of the file the first 10 bytes are discarded and the
-   next 0x4000 loaded. This may change in future versions.
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
  */
 #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
@@ -202,8 +195,8 @@
 		int c = BLOCKSIZE;
 		int err;
 
-		if (i+c > fw_size)
-			c = fw_size - i;
+		if (i+c > FW_SIZE)
+			c = FW_SIZE - i;
 
 		/* bit 0x8000 in address is set to enable 13bit mode */
 		/* bit 0x4000 enables multibyte read/write transfers */
@@ -650,7 +641,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend_new (sp887x_ioctl, state->dvb);
+	dvb_unregister_frontend (sp887x_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/stv0299.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/stv0299.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/stv0299.c	2004-09-17 12:26:18.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/stv0299.c	2004-09-17 12:35:36.000000000 +0200
@@ -1414,7 +1414,7 @@
 {
 	struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
 
-	dvb_unregister_frontend_new (uni0299_ioctl, state->dvb);
+	dvb_unregister_frontend (uni0299_ioctl, state->dvb);
 	i2c_detach_client(client);
 	kfree(client);
 	kfree(state);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/tda1004x.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/tda1004x.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/tda1004x.c	2004-09-17 12:26:18.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/tda1004x.c	2004-09-01 12:19:01.000000000 +0200
@@ -19,20 +19,14 @@
      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
    */
-
 /*
-    This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
-	windows driver.
-
-    Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
-    be added reasonably painlessly.
-
-    Windows driver URL: http://www.technotrend.de/
-
-	wget http://www.technotrend.de/new/215/TTweb_215a_budget_20_05_2003.zip
-	unzip -j TTweb_215a_budget_20_05_2003.zip Software/Oem/PCI/App/ttlcdacc.dll
+ * This driver needs external firmware. Please use the commands
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
 */
-#define TDA1004X_DEFAULT_FIRMWARE "tda1004x.bin"
+#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
+#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -181,32 +174,6 @@
 	int dspVersion;
 };
 
-struct fwinfo {
-	int file_size;
-	int fw_offset;
-	int fw_size;
-};
-
-static struct fwinfo tda10045h_fwinfo[] = {
-	{
-		.file_size = 286720,
-		.fw_offset = 0x34cc5,
-		.fw_size = 30555
-	},
-};
-
-static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
-
-static struct fwinfo tda10046h_fwinfo[] = {
-	{
-		.file_size = 286720,
-		.fw_offset = 0x3c4f9,
-		.fw_size = 24479
-	}
-};
-
-static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);
-
 static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int data)
 {
 	int ret;
@@ -403,22 +370,6 @@
 	return 0;
 	}
 
-static int tda1004x_find_extraction_params(struct fwinfo* fwInfo, int fwInfoCount, int size)
-{
-	int fwinfo_idx;
-
-        for (fwinfo_idx = 0; fwinfo_idx < fwInfoCount; fwinfo_idx++) {
-		if (fwInfo[fwinfo_idx].file_size == size)
-			break;
-	}
-        if (fwinfo_idx >= fwInfoCount) {
-		printk("tda1004x: Unsupported firmware uploaded.\n");
-		return -EIO;
-	}
-
-	return fwinfo_idx;
-	}
-
 static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_state *state)
 {
 	u8 data1, data2;
@@ -438,14 +389,18 @@
         }
 
 
-static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, const struct firmware *fw)
+static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
 {
-	int index;
 	int ret;
+	const struct firmware *fw;
 
-	index = tda1004x_find_extraction_params(tda10045h_fwinfo, tda10045h_fwinfo_count, fw->size);
-	if (index < 0)
-		return index;
+	/* request the firmware, this will block until someone uploads it */
+	printk("tda1004x: waiting for firmware upload...\n");
+	ret = request_firmware(&fw, TDA10045_DEFAULT_FIRMWARE, &client->dev);
+	if (ret) {
+		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+	   	return ret;
+	}
 
 	/* set some valid bandwith parameters before uploading */
 
@@ -458,7 +413,7 @@
 	/* set parameters */
 	tda10045h_set_bandwidth(i2c, state, BANDWIDTH_8_MHZ);
 
-	ret = tda1004x_do_upload(i2c, state, fw->data + tda10045h_fwinfo[index].fw_offset, tda10045h_fwinfo[index].fw_size);
+	ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
 	if (ret)
 		return ret;
 
@@ -473,15 +428,19 @@
 	return 0;
 	}
 
-static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, const struct firmware *fw)
+static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
 {
 	unsigned long timeout;
-	int index;
 	int ret;
+	const struct firmware *fw;
 
-	index = tda1004x_find_extraction_params(tda10046h_fwinfo, tda10046h_fwinfo_count, fw->size);
-	if (index < 0)
-		return index;
+	/* request the firmware, this will block until someone uploads it */
+	printk("tda1004x: waiting for firmware upload...\n");
+	ret = request_firmware(&fw, TDA10046_DEFAULT_FIRMWARE, &client->dev);
+	if (ret) {
+		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+   	   	return ret;
+	}
 
 	/* set some valid bandwith parameters before uploading */
 
@@ -498,7 +457,7 @@
 	tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
 	tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
 
-	ret = tda1004x_do_upload(i2c, state, fw->data + tda10046h_fwinfo[index].fw_offset, tda10046h_fwinfo[index].fw_size);
+	ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
 	if (ret)
 		return ret;
 
@@ -814,7 +771,9 @@
         if ((tmp = tda1004x_set_frequency(i2c, tda_state, fe_params)) < 0)
 		return tmp;
 
-        // hardcoded to use auto as much as possible
+	// Hardcoded to use auto as much as possible
+	// The TDA10045 is very unreliable if AUTO mode is _not_ used. I have not
+	// yet tested the TDA10046 to see if this issue has been fixed
         fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
         fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
         fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
@@ -1452,7 +1411,6 @@
 {
 	struct i2c_client *client;
 	struct tda1004x_state *state;
-	const struct firmware *fw;
 	int ret;
 
 	dprintk ("%s\n", __FUNCTION__);
@@ -1489,21 +1447,13 @@
 	// upload firmware
 	BUG_ON(!state->dvb);
 
-	/* request the firmware, this will block until someone uploads it */
-	printk("tda1004x: waiting for firmware upload...\n");
-	ret = request_firmware(&fw, TDA1004X_DEFAULT_FIRMWARE, &client->dev);
-	if (ret) {
-		printk("tda1004x: no firmware upload (timeout or file not found?)\n");
-		goto out;
-	}
-
 	switch(state->fe_type) {
         case FE_TYPE_TDA10045H:
 		state->dspCodeCounterReg = TDA10045H_FWPAGE;
 		state->dspCodeInReg =  TDA10045H_CODE_IN;
 		state->dspVersion = 0x2c;
 
-		ret = tda10045_fwupload(adapter, state, fw);
+		ret = tda10045_fwupload(adapter, state, client);
 		if (ret) {
 			printk("tda1004x: firmware upload failed\n");
 			goto out;
@@ -1518,7 +1468,7 @@
 		state->dspCodeInReg =  TDA10046H_CODE_IN;
 		state->dspVersion = 0x20;
 
-		ret = tda10046_fwupload(adapter, state, fw);
+		ret = tda10046_fwupload(adapter, state, client);
 		if (ret) {
 			printk("tda1004x: firmware upload failed\n");
 			goto out;
@@ -1551,7 +1501,7 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend_new (tda1004x_ioctl, state->dvb);
+	dvb_unregister_frontend (tda1004x_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_frontend.c linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_frontend.c	2004-09-17 12:26:16.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.c	2004-09-01 12:19:01.000000000 +0200
@@ -762,6 +763,13 @@
 			fe->parameters.inversion = INVERSION_AUTO;
 			fetunesettings.parameters.inversion = INVERSION_AUTO;
 		}
+		if (fe->info->type == FE_OFDM) {
+			/* without hierachical coding code_rate_LP is irrelevant,
+			 * so we tolerate the otherwise invalid FEC_NONE setting */
+			if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+			    fe->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+				fe->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
+		}
 
 		/* get frontend-specific tuning settings */
 		if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS,
@@ -1180,7 +1186,7 @@
 	return 0;
 }
 
-int dvb_unregister_frontend_new (int (*ioctl) (struct dvb_frontend *frontend,
+int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
 					   unsigned int cmd, void *arg),
 			     struct dvb_adapter *dvb_adapter)
 {
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_frontend.h linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.h
--- linux-2.6.8.1-dvb1/drivers/media/dvb/dvb-core/dvb_frontend.h	2004-09-17 12:26:16.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/dvb-core/dvb_frontend.h	2004-09-17 12:35:35.000000000 +0200
@@ -42,6 +45,8 @@
 #define I2C_DRIVERID_DVBFE_ALPS_TDMB7	I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_AT76C651	I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_CX24110	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX22702	I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_DIB3000MB	I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_DST		I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_DUMMY	I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_L64781	I2C_DRIVERID_EXP2
@@ -102,7 +107,7 @@
 		       struct module *module);
 
 extern int
-dvb_unregister_frontend_new (int (*ioctl) (struct dvb_frontend *frontend,
+dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
 				       unsigned int cmd, void *arg),
 			 struct dvb_adapter *dvb_adapter);
 
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/ves1820.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1820.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/ves1820.c	2004-09-17 12:26:18.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1820.c	2004-08-24 17:54:22.000000000 +0200
@@ -578,7 +575,7 @@
 static int detach_client(struct i2c_client *client)
 {
 	struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
-	dvb_unregister_frontend_new(ves1820_ioctl, state->dvb);
+	dvb_unregister_frontend(ves1820_ioctl, state->dvb);
 	device_remove_file(&client->dev, &dev_attr_client_name);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/ves1x93.c linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1x93.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/frontends/ves1x93.c	2004-09-17 12:26:18.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/frontends/ves1x93.c	2004-09-15 10:26:45.000000000 +0200
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include "dvb_frontend.h"
 
@@ -48,7 +49,7 @@
 	.type			= FE_QPSK,
 	.frequency_min		= 950000,
 	.frequency_max		= 2150000,
-	.frequency_stepsize	= 250,           /* kHz for QPSK frontends */
+	.frequency_stepsize	= 125,		 /* kHz for QPSK frontends */
 	.frequency_tolerance	= 29500,
 	.symbol_rate_min	= 1000000,
 	.symbol_rate_max	= 45000000,
@@ -170,10 +171,26 @@
  *   set up the downconverter frequency divisor for a
  *   reference clock comparision frequency of 125 kHz.
  */
-static int sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq, u8 pwr)
+static int sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
+	u8 pwr = 0;
+   	u8 buf[4];
         u32 div = (freq + 479500) / 125;
-	u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x95, (pwr << 5) | 0x30 };
+   
+	if (freq > 2000000) pwr = 3;
+	else if (freq > 1800000) pwr = 2;
+	else if (freq > 1600000) pwr = 1;
+	else if (freq > 1200000) pwr = 0;
+	else if (freq >= 1100000) pwr = 1;
+	else pwr = 2;
+
+   	buf[0] = (div >> 8) & 0x7f;
+   	buf[1] = div & 0xff;
+   	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+   	buf[3] = (pwr << 6) | 0x30;
+   	
+   	// NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
 
 	return tuner_write (i2c, buf, sizeof(buf));
 }
@@ -195,10 +212,10 @@
 }
 
 
-static int tuner_set_tv_freq (struct i2c_adapter *i2c, u32 freq, u8 pwr)
+static int tuner_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 	if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI))
-		return sp5659_set_tv_freq (i2c, freq, pwr);
+		return sp5659_set_tv_freq (i2c, freq);
 	else if (demod_type == DEMOD_VES1993)
 		return tsa5059_set_tv_freq (i2c, freq);
 
@@ -252,17 +269,10 @@
 
 static int ves1x93_clr_bit (struct i2c_adapter *i2c)
 {
+	msleep(10);
         ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe);
         ves1x93_writereg (i2c, 0, init_1x93_tab[0]);
-	msleep(5);
-	return 0;
-}
-
-static int ves1x93_init_aquire (struct i2c_adapter *i2c)
-{
-        ves1x93_writereg (i2c, 3, 0x00);
-	ves1x93_writereg (i2c, 3, init_1x93_tab[3]);
-	msleep(5);
+	msleep(50);
 	return 0;
 }
 
@@ -414,26 +423,6 @@
 	return 0;
 }
 
-
-static int ves1x93_afc (struct i2c_adapter *i2c, u32 freq, u32 srate)
-{
-	int afc;
-
-	afc = ((int)((ves1x93_readreg (i2c, 0x0a) << 1) & 0xff))/2;
-	afc = (afc * (int)(srate/1000/8))/16;
-    
-	if (afc) {
-	
-		freq -= afc;
-
-		tuner_set_tv_freq (i2c, freq, 0);
-
-		ves1x93_init_aquire (i2c);
-	}
-       
-	return 0;
-}
-
 static int ves1x93_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
 {
 	switch (voltage) {
@@ -464,6 +453,21 @@
 		fe_status_t *status = arg;
 		u8 sync = ves1x93_readreg (i2c, 0x0e);
 
+		/*
+		 * The ves1893 sometimes returns sync values that make no sense,
+		 * because, e.g., the SIGNAL bit is 0, while some of the higher
+		 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
+		 * Tests showed that the the VITERBI and SYNC bits are returned
+		 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
+		 * If such a case occurs, we read the value again, until we get a
+		 * valid value.
+		 */
+		int maxtry = 10; /* just for safety - let's not get stuck here */
+		while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
+			msleep(10);
+			sync = ves1x93_readreg (i2c, 0x0e);
+		}
+
 		*status = 0;
 
 		if (sync & 1)
@@ -525,11 +529,10 @@
         {
 		struct dvb_frontend_parameters *p = arg;
 
-		tuner_set_tv_freq (i2c, p->frequency, 0);
+		tuner_set_tv_freq (i2c, p->frequency);
 		ves1x93_set_inversion (i2c, p->inversion);
 		ves1x93_set_fec (i2c, p->u.qpsk.fec_inner);
 		ves1x93_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
-		ves1x93_afc (i2c, p->frequency, p->u.qpsk.symbol_rate);	    
 		state->inversion = p->inversion;
                 break;
         }
@@ -650,7 +653,7 @@
 static int detach_client(struct i2c_client *client)
 {
 	struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client);
-	dvb_unregister_frontend_new(ves1x93_ioctl, state->dvb);
+	dvb_unregister_frontend(ves1x93_ioctl, state->dvb);
 	i2c_detach_client(client);
 	BUG_ON(state->dvb);
 	kfree(client);
diff -uraNwB linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- linux-2.6.8.1-dvb1/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2004-09-17 12:26:39.000000000 +0200
+++ linux-2.6.8.1-patched/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2004-08-24 17:54:22.000000000 +0200
@@ -1689,7 +1686,7 @@
 
 static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
 {
-	dvb_unregister_frontend_new(dec->frontend_ioctl, dec->adapter);
+	dvb_unregister_frontend(dec->frontend_ioctl, dec->adapter);
 }
 
 static void ttusb_dec_init_filters(struct ttusb_dec *dec)

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

* Re: [PATCH][2.6][14/14] follow saa7146 changes in other drivers
  2004-09-17 14:40                         ` [PATCH][2.6][13/14] dvb frontend updates Michael Hunold
@ 2004-09-17 14:42                           ` Michael Hunold
  0 siblings, 0 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-17 14:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Linux Kernel Mailing List, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 14-V4L-follow-changes-in-saa7146.diff --]
[-- Type: text/plain, Size: 4167 bytes --]

- [V4L] mxb, dpc7146, hexium_orion, hexium_gemini: follow latest changes in saa7146 driver

Signed-off-by: Michael Hunold <hunold@linuxtv.org>

diff -ura a/drivers/media/video/dpc7146.c linux-2.6.8.1-dvb2/drivers/media/video/dpc7146.c
--- a/drivers/media/video/dpc7146.c	2004-09-17 14:35:42.000000000 +0200
+++ linux-2.6.8.1-dvb2/drivers/media/video/dpc7146.c	2004-09-17 14:40:49.000000000 +0200
@@ -79,8 +79,8 @@
 
 struct dpc
 {
-	struct video_device	video_dev;
-	struct video_device	vbi_dev;
+	struct video_device	*video_dev;
+	struct video_device	*vbi_dev;
 
 	struct i2c_adapter	i2c_adapter;	
 	struct i2c_client	*saa7111a;
@@ -106,7 +106,11 @@
 	   video port pins should be enabled here ?! */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
+	dpc->i2c_adapter = (struct i2c_adapter) {
+		.class = I2C_CLASS_TV_ANALOG,
+		.name = "dpc7146",
+	};
+	saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&dpc->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(dpc);
diff -ura a/drivers/media/video/hexium_gemini.c linux-2.6.8.1-dvb2/drivers/media/video/hexium_gemini.c
--- a/drivers/media/video/hexium_gemini.c	2004-09-17 14:35:36.000000000 +0200
+++ linux-2.6.8.1-dvb2/drivers/media/video/hexium_gemini.c	2004-09-17 14:43:36.000000000 +0200
@@ -78,7 +78,8 @@
 struct hexium
 {
 	int type;
-	struct video_device	video_dev;
+	
+	struct video_device	*video_dev;
 	struct i2c_adapter	i2c_adapter;
 		
 	int 		cur_input;	/* current input */
@@ -250,7 +251,11 @@
 	/* enable i2c-port pins */
 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
+	hexium->i2c_adapter = (struct i2c_adapter) {
+		.class = I2C_CLASS_TV_ANALOG,
+		.name = "hexium gemini",
+	};
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(hexium);
diff -ura a/drivers/media/video/hexium_orion.c linux-2.6.8.1-dvb2/drivers/media/video/hexium_orion.c
--- a/drivers/media/video/hexium_orion.c	2004-09-17 14:35:36.000000000 +0200
+++ linux-2.6.8.1-dvb2/drivers/media/video/hexium_orion.c	2004-09-17 14:43:54.000000000 +0200
@@ -68,8 +68,9 @@
 struct hexium
 {
 	int type;
-	struct video_device	video_dev;
+	struct video_device	*video_dev;
 	struct i2c_adapter	i2c_adapter;	
+
 	int cur_input;	/* current input */
 };
 
@@ -237,7 +238,11 @@
 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
-	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
+	hexium->i2c_adapter = (struct i2c_adapter) {
+		.class = I2C_CLASS_TV_ANALOG,
+		.name = "hexium orion",
+	};
+	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(hexium);
diff -ura a/drivers/media/video/mxb.c linux-2.6.8.1-dvb2/drivers/media/video/mxb.c
--- a/drivers/media/video/mxb.c	2004-09-17 14:35:32.000000000 +0200
+++ linux-2.6.8.1-dvb2/drivers/media/video/mxb.c	2004-09-17 14:44:17.000000000 +0200
@@ -128,8 +128,8 @@
 
 struct mxb
 {
-	struct video_device	video_dev;
-	struct video_device	vbi_dev;
+	struct video_device	*video_dev;
+	struct video_device	*vbi_dev;
 
 	struct i2c_adapter	i2c_adapter;	
 
@@ -183,7 +183,12 @@
 	}
 	memset(mxb, 0x0, sizeof(struct mxb));	
 
-	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
+	mxb->i2c_adapter = (struct i2c_adapter) {
+		.class = I2C_CLASS_TV_ANALOG,
+		.name = "mxb",
+	};
+	
+	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 	if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
 		DEB_S(("cannot register i2c-device. skipping.\n"));
 		kfree(mxb);

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

* Re: [PATCH][2.6][4/14] dvb core update
  2004-09-17 14:27       ` [PATCH][2.6][4/14] dvb core update Michael Hunold
  2004-09-17 14:29         ` [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3 Michael Hunold
@ 2004-09-17 14:58         ` Jesper Juhl
  2004-09-17 15:35           ` Linus Torvalds
  2004-09-17 15:58           ` Alan Cox
  2004-09-17 15:28         ` Richard B. Johnson
  2 siblings, 2 replies; 23+ messages in thread
From: Jesper Juhl @ 2004-09-17 14:58 UTC (permalink / raw)
  To: Michael Hunold; +Cc: Linus Torvalds, Linux Kernel Mailing List, Andrew Morton

On Fri, 17 Sep 2004, Michael Hunold wrote:

> Date: Fri, 17 Sep 2004 16:27:45 +0200
> From: Michael Hunold <hunold@linuxtv.org>
> To: Linus Torvalds <torvalds@osdl.org>
> Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
>     Andrew Morton <akpm@osdl.org>
> Subject: Re: [PATCH][2.6][4/14] dvb core update
> 
> 

[...]

> - [DVB] convert C++ comments to C comments

It seems you missed a few, and the patch adds a few itself :  
 
> @@ -662,19 +670,9 @@
>          // sanity check

[...]
 
> +				// no need to poll if the CAM supports IRQs

[...]

> +				// poll mode

[...]

>  	FE_NEEDS_BENDING              = 0x20000000, // frontend requires frequency bending
>  	FE_CAN_RECOVER                = 0x40000000, // frontend can recover from a cable unplug automatically
>  	FE_CAN_MUTE_TS                = 0x80000000  // frontend can stop spurious TS data output

And I'll bet there are probably more if I could be bothered to check the 
actual files.

Besides, didn't C99 make C++ style comments valid for C code as well?  
Does CodingStyle have any oppinion on this?


--
Jesper Juhl <juhl-lkml@dif.dk>



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

* Re: [PATCH][2.6][4/14] dvb core update
  2004-09-17 14:27       ` [PATCH][2.6][4/14] dvb core update Michael Hunold
  2004-09-17 14:29         ` [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3 Michael Hunold
  2004-09-17 14:58         ` [PATCH][2.6][4/14] dvb core update Jesper Juhl
@ 2004-09-17 15:28         ` Richard B. Johnson
  2 siblings, 0 replies; 23+ messages in thread
From: Richard B. Johnson @ 2004-09-17 15:28 UTC (permalink / raw)
  To: Michael Hunold; +Cc: Linux Kernel Mailing List, Andrew Morton

On Fri, 17 Sep 2004, Michael Hunold wrote:

FYI       '//' are now (since 1998) 'C' comments as well as 'C++'


Cheers,
Dick Johnson
Penguin : Linux version 2.4.26 on an i686 machine (5570.56 BogoMips).
            Note 96.31% of all statistics are fiction.


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

* Re: [PATCH][2.6][4/14] dvb core update
  2004-09-17 14:58         ` [PATCH][2.6][4/14] dvb core update Jesper Juhl
@ 2004-09-17 15:35           ` Linus Torvalds
  2004-09-17 15:58           ` Alan Cox
  1 sibling, 0 replies; 23+ messages in thread
From: Linus Torvalds @ 2004-09-17 15:35 UTC (permalink / raw)
  To: Jesper Juhl; +Cc: Michael Hunold, Linux Kernel Mailing List, Andrew Morton



On Fri, 17 Sep 2004, Jesper Juhl wrote:
> 
> Besides, didn't C99 make C++ style comments valid for C code as well?  
> Does CodingStyle have any oppinion on this?

We've allowed C++ comments for a longish time as far as I can tell. They 
are very common, all over the tree according to a quick grep. Admittedly 
they are more common in certain driver setups than in "general code", but 
I don't think there is really any reason (other than maintainer 
preferences) to convert one into the other.

		Linus

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

* Re: [PATCH][2.6][4/14] dvb core update
  2004-09-17 14:58         ` [PATCH][2.6][4/14] dvb core update Jesper Juhl
  2004-09-17 15:35           ` Linus Torvalds
@ 2004-09-17 15:58           ` Alan Cox
  1 sibling, 0 replies; 23+ messages in thread
From: Alan Cox @ 2004-09-17 15:58 UTC (permalink / raw)
  To: Jesper Juhl
  Cc: Michael Hunold, Linus Torvalds, Linux Kernel Mailing List, Andrew Morton

On Gwe, 2004-09-17 at 15:58, Jesper Juhl wrote:
> And I'll bet there are probably more if I could be bothered to check the 
> actual files.

Lots of drivers use C++^WBCPL comments  (C++ just borrowed them)

> Besides, didn't C99 make C++ style comments valid for C code as well?  

Yes and this leads to such fun as

	x = 4 //**/
		-1;

	if(x == 3)
		printf("New C compiler\n");



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

* Re: [PATCH][2.6][0/14] DVB subsystem update
  2004-09-17 14:20 [PATCH][2.6][0/14] DVB subsystem update Michael Hunold
  2004-09-17 14:22 ` [PATCH][2.6][1/14] update saa7146 driver Michael Hunold
@ 2004-09-17 23:41 ` Andrew Morton
  2004-09-20 11:42   ` Michael Hunold
  1 sibling, 1 reply; 23+ messages in thread
From: Andrew Morton @ 2004-09-17 23:41 UTC (permalink / raw)
  To: Michael Hunold; +Cc: torvalds, linux-kernel

Michael Hunold <hunold@linuxtv.org> wrote:
>
> here comes a patchset consisting of 14 patches bringing the in-kernel 
> DVB subsystem in sync with the LinuxTV.org CVS driver.

I'm getting lots of rejects from these.  At the fifth patch I gave up.  The
rejects appear to be against stock 2.6.9-rc2.

Please regenerate these patches and double-check that they apply to latest
-linus tree.  Or against next -mm if they are dependent upon Gerd's
patches:

v4l-msp3400-cleanup.patch
v4l-tuner-update.patch
v4l-bttv-update.patch
v4l-dvb-cx88-driver-update.patch


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

* Re: [PATCH][2.6][12.1/14] DVB: add kernel message classifiers
  2004-09-17 14:39                       ` [PATCH][2.6][12/14] misc. driver updates Michael Hunold
  2004-09-17 14:40                         ` [PATCH][2.6][13/14] dvb frontend updates Michael Hunold
@ 2004-09-20 11:11                         ` Philipp Matthias Hahn
  2004-09-20 16:46                           ` Michael Hunold
  1 sibling, 1 reply; 23+ messages in thread
From: Philipp Matthias Hahn @ 2004-09-20 11:11 UTC (permalink / raw)
  To: Michael Hunold; +Cc: Linux Kernel Mailing List

Hello Michael!

On Fri, Sep 17, 2004 at 04:39:23PM +0200, Michael Hunold wrote:
> - [DVB] av7110: convert MODULE_PARM() to module_param(), replace home-brewn waiting stuff in osd code with wait_event_interruptible_timeout()
> - [DVB] av7110, budget: use msleep() instead of my_wait(), thanks to Kernel Janitors/Nishanth Aravamudan <nacc@us.ibm.com>
> 
> Signed-off-by: Michael Hunold <hunold@linuxtv.org>

Could you please apply the following patch on top, which adds
kernel message classifiers to printk()-calls in av7110_av.c

If you don't to apply the whole patch, please at least remove those two
printk() calls in av7110_ioctl() line 267 and 270, because on my Siemens
DVB-C 1.6 they are printed every second and fill up syslog! (BTW: Stereo
detection never worked for me)

Signed-off-by: Philipp Matthias Hahn <pmhahn@titan.lahn.de>

--- linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_v4l.c~	2004-06-16 09:29:23.000000000 +0200
+++ linux-2.6.8.1/drivers/media/dvb/ttpci/av7110_v4l.c	2004-09-20 12:58:16.000000000 +0200
@@ -51,7 +51,7 @@ int msp_writereg(struct av7110 *av7110, 
 	struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
 
 	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
-		printk("av7110(%d): %s(%u = %u) failed\n",
+		printk(KERN_ERR "av7110(%d): %s(%u = %u) failed\n",
 		       av7110->dvb_adapter->num, __FUNCTION__, reg, val);
 		return -EIO;
 	}
@@ -68,7 +68,7 @@ int msp_readreg(struct av7110 *av7110, u
 	};
 
 	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
-		printk("av7110(%d): %s(%u) failed\n",
+		printk(KERN_ERR "av7110(%d): %s(%u) failed\n",
 		       av7110->dvb_adapter->num, __FUNCTION__, reg);
 		return -EIO;
 	}
@@ -194,7 +194,7 @@ int av7110_dvb_c_switch(struct saa7146_f
 		source = SAA7146_HPS_SOURCE_PORT_B;
 		sync = SAA7146_HPS_SYNC_PORT_B;
 		memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
-		printk("av7110: switching to analog TV\n");
+		printk(KERN_INFO "av7110: switching to analog TV\n");
 		msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
 		msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
 		msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
@@ -207,7 +207,7 @@ int av7110_dvb_c_switch(struct saa7146_f
 		source = SAA7146_HPS_SOURCE_PORT_A;
 		sync = SAA7146_HPS_SYNC_PORT_A;
 		memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
-		printk("av7110: switching DVB mode\n");
+		printk(KERN_INFO "av7110: switching DVB mode\n");
 		msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
 		msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
 		msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
@@ -218,10 +218,10 @@ int av7110_dvb_c_switch(struct saa7146_f
 
 	/* hmm, this does not do anything!? */
 	if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
-		printk("ADSwitch error\n");
+		printk(KERN_ERROR "ADSwitch error\n");
 
 	if (ves1820_writereg(dev, 0x0f, band))
-		printk("setting band in demodulator failed.\n");
+		printk(KERN_ERROR "setting band in demodulator failed.\n");
 	saa7146_set_hps_source_and_sync(dev, source, sync);
 
 	if (vv->ov_suspend != NULL) {
@@ -264,10 +264,10 @@ int av7110_ioctl(struct saa7146_fh *fh, 
 
 		// FIXME: standard / stereo detection is still broken
 		msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
-printk("VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
+		printk(KERN_DEBUG "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
 
 		msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
-		printk("VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
+		printk(KERN_DEBUG "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
 		stereo = (s8)(stereo_det >> 8);
 		if (stereo > 0x10) {
 			/* stereo */
@@ -418,7 +418,7 @@ printk("VIDIOC_G_TUNER: msp3400 TV stand
 		break;
 	}
 	default:
-		printk("no such ioctl\n");
+		printk(KERN_ERR "no such ioctl\n");
 		return -ENOIOCTLCMD;
 	}
 	return 0;
@@ -512,13 +512,13 @@ int av7110_init_analog_module(struct av7
 	    || i2c_writereg(av7110, 0x80, 0x0, 0) != 1)
 		return -ENODEV;
 
-	printk("av7110(%d): DVB-C analog module detected, initializing MSP3400\n",
+	printk(KERN_INFO "av7110(%d): DVB-C analog module detected, initializing MSP3400\n",
 		av7110->dvb_adapter->num);
 	av7110->adac_type = DVB_ADAC_MSP;
 	msleep(100); // the probing above resets the msp...
 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
-	printk("av7110(%d): MSP3400 version 0x%04x 0x%04x\n",
+	printk(KERN_INFO "av7110(%d): MSP3400 version 0x%04x 0x%04x\n",
 		av7110->dvb_adapter->num, version1, version2);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
@@ -537,7 +537,7 @@ int av7110_init_analog_module(struct av7
 		/* init the saa7113 */
 		while (*i != 0xff) {
 			if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
-				printk("av7110(%d): saa7113 initialization failed",
+				printk(KERN_ERR "av7110(%d): saa7113 initialization failed",
 						av7110->dvb_adapter->num);
 				break;
 			}

-- 
  / /  (_)__  __ ____  __ Philipp Hahn
 / /__/ / _ \/ // /\ \/ /
/____/_/_//_/\_,_/ /_/\_\ pmhahn@titan.lahn.de

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

* Re: [PATCH][2.6][0/14] DVB subsystem update
  2004-09-17 23:41 ` [PATCH][2.6][0/14] DVB subsystem update Andrew Morton
@ 2004-09-20 11:42   ` Michael Hunold
  0 siblings, 0 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-20 11:42 UTC (permalink / raw)
  To: Andrew Morton; +Cc: torvalds, linux-kernel

Hi,

On 18.09.2004 01:41, Andrew Morton wrote:
> I'm getting lots of rejects from these.  At the fifth patch I gave up.  The
> rejects appear to be against stock 2.6.9-rc2.

The patchset was against 2.6.8(.1), the rejects come from the janitor 
cleanups for msleep() in the saa7146 driver and from the 
sys_read()/errno mess in the frontend drivers, which loaded the firmware 
directly.

> Please regenerate these patches and double-check that they apply to latest
> -linus tree.  Or against next -mm if they are dependent upon Gerd's
> patches:

I'll send you a new patchset against 2.6.9-rc2-mm1 in private right now. 
  The patches have been adopted or re-generated to fit against your 
latest tree, so I don't post them in public any more.

CU
Michael.

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

* Re: [PATCH][2.6][12.1/14] DVB: add kernel message classifiers
  2004-09-20 11:11                         ` [PATCH][2.6][12.1/14] DVB: add kernel message classifiers Philipp Matthias Hahn
@ 2004-09-20 16:46                           ` Michael Hunold
  0 siblings, 0 replies; 23+ messages in thread
From: Michael Hunold @ 2004-09-20 16:46 UTC (permalink / raw)
  To: Philipp Matthias Hahn; +Cc: Linux Kernel Mailing List

Hi,

> Could you please apply the following patch on top, which adds
> kernel message classifiers to printk()-calls in av7110_av.c
> 
> If you don't to apply the whole patch, please at least remove those two
> printk() calls in av7110_ioctl() line 267 and 270, because on my Siemens
> DVB-C 1.6 they are printed every second and fill up syslog! (BTW: Stereo
> detection never worked for me)

I've taken the time and reworked the debug message logic in the av7110 
driver. It depended on the saa7146 driver and used horrible macros 
anyway, so I converted them alltogether.

I'll try to get this into 2.6.9 as well.

CU
Michael.

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

end of thread, other threads:[~2004-09-20 16:57 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-09-17 14:20 [PATCH][2.6][0/14] DVB subsystem update Michael Hunold
2004-09-17 14:22 ` [PATCH][2.6][1/14] update saa7146 driver Michael Hunold
2004-09-17 14:24   ` [PATCH][2.6][2/14] documentation update Michael Hunold
2004-09-17 14:26     ` [PATCH][2.6][3/14] dvb-bt8xx and skystar2 driver update Michael Hunold
2004-09-17 14:27       ` [PATCH][2.6][4/14] dvb core update Michael Hunold
2004-09-17 14:29         ` [PATCH][2.6][5/14] convert frontend drivers to kernel i2c 1/3 Michael Hunold
2004-09-17 14:30           ` [PATCH][2.6][6/14] convert frontend drivers to kernel i2c 2/3 Michael Hunold
2004-09-17 14:32             ` [PATCH][2.6][7/14] convert frontend drivers to kernel i2c 3/3 Michael Hunold
2004-09-17 14:33               ` [PATCH][2.6][8/14] some more frontend drivers to converted to kernel i2c Michael Hunold
2004-09-17 14:34                 ` [PATCH][2.6][9/14] add new frontend drivers 1/2 Michael Hunold
2004-09-17 14:36                   ` [PATCH][2.6][10/14] add new frontend drivers 2/2 Michael Hunold
2004-09-17 14:37                     ` [PATCH][2.6][11/14] new DVB driver Michael Hunold
2004-09-17 14:39                       ` [PATCH][2.6][12/14] misc. driver updates Michael Hunold
2004-09-17 14:40                         ` [PATCH][2.6][13/14] dvb frontend updates Michael Hunold
2004-09-17 14:42                           ` [PATCH][2.6][14/14] follow saa7146 changes in other drivers Michael Hunold
2004-09-20 11:11                         ` [PATCH][2.6][12.1/14] DVB: add kernel message classifiers Philipp Matthias Hahn
2004-09-20 16:46                           ` Michael Hunold
2004-09-17 14:58         ` [PATCH][2.6][4/14] dvb core update Jesper Juhl
2004-09-17 15:35           ` Linus Torvalds
2004-09-17 15:58           ` Alan Cox
2004-09-17 15:28         ` Richard B. Johnson
2004-09-17 23:41 ` [PATCH][2.6][0/14] DVB subsystem update Andrew Morton
2004-09-20 11:42   ` Michael Hunold

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).