public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] fix RPS init race
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 2/9] support pinnacle pctv-sat, clean-ups Johannes Stezenbach
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] saa7146: explicitely disable RPS tasks in saa7146_init_one()

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/common/saa7146_core.c linux-2.6.11-rc2-dvb/drivers/media/common/saa7146_core.c
--- linux-2.6.11-rc2/drivers/media/common/saa7146_core.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/common/saa7146_core.c	2005-01-20 19:56:37.000000000 +0100
@@ -380,8 +380,8 @@
 	/* disable all irqs */
 	saa7146_write(dev, IER, 0);
 
-	/* shut down all dma transfers */
-	saa7146_write(dev, MC1, 0x00ff0000);
+	/* shut down all dma transfers and rps tasks */
+	saa7146_write(dev, MC1, 0x30ff0000);
 
 	/* clear out any rps-signals pending */
 	saa7146_write(dev, MC2, 0xf8000000);


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

* [PATCH 0/9] 2.6.11-rc2 DVB update
@ 2005-01-22 17:34 Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 1/9] fix RPS init race Johannes Stezenbach
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

Hi Linus,

this is the usual batch of DVB updates from linuxtv.org CVS.
The patches were prepared by Michael Hunold, I just rediffed
them to apply cleanly against 2.6.11-rc2, and submit
them on his behalf this time.

I realize it is actually a bit late in the 2.6.11 release
cycle but I hope they can be included in 2.6.11 anyway, as
they don't touch anything outside the DVB subsystem.
If not I will factor out the important bug fixes and
resubmit them.

1 saa7146	fix possible RPS init race
2 bt8xx		support pinnacle pctv-sat, clean-ups
3 dibusb	refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones
4 misc		support nxt2002 frontend, misc skystar2 fixes
5 dvb-core	add ATSC support, misc fixes
6 dib3000	refactoring
7 frontends	nxt2002: add ATSC support, misc fixes
8 ttpci		dvb-ttpci: fix SMP race, budget: fix init race, misc fixes

Johannes


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

* [PATCH 2/9] support pinnacle pctv-sat, clean-ups
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 1/9] fix RPS init race Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 3/9] refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones Johannes Stezenbach
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] dvb-bt8xx: add support for pinnacle pctv-sat, patch by Peter Hettkamp and Adam Szalkowski
- [DVB] dvb-bt8xx: minor code cleanups, patch by Arne Ahrend
- [DVB] dvb-bt8xx: make sure to compile all necessary frontend modules, remove misleading comment

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/bt8xx/dvb-bt8xx.c linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- linux-2.6.11-rc2/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/dvb-bt8xx.c	2005-01-20 19:56:37.000000000 +0100
@@ -181,6 +181,70 @@
 	.pll_set = thomson_dtt7579_pll_set,
 };
 
+static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+   u32 freq = params->frequency;
+   
+   int i, a, n, pump; 
+   u32 band, pll;
+   
+   
+   u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
+               1576000,1718000,1856000,2036000,2150000};
+   u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
+               0x00102000,0x00104000,0x00108000,0x00110000,
+               0x00120000,0x00140000};
+   
+#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
+        printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
+        
+        /* This is really the bit driving the tuner chip cx24108 */
+        
+        if(freq<950000) freq=950000; /* kHz */
+        if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */
+        
+        /* decide which VCO to use for the input frequency */
+        for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
+        printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
+        band=bandsel[i];
+        /* the gain values must be set by SetSymbolrate */
+        /* compute the pll divider needed, from Conexant data sheet,
+           resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
+           depending on the divider bit. It is set to /4 on the 2 lowest 
+           bands  */
+        n=((i<=2?2:1)*freq*10L)/(XTAL/100);
+        a=n%32; n/=32; if(a==0) n--;
+        pump=(freq<(osci[i-1]+osci[i])/2);
+        pll=0xf8000000|
+            ((pump?1:2)<<(14+11))|
+            ((n&0x1ff)<<(5+11))|
+            ((a&0x1f)<<11);
+        /* everything is shifted left 11 bits to left-align the bits in the
+           32bit word. Output to the tuner goes MSB-aligned, after all */
+        printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
+        cx24110_pll_write(fe,band);
+        /* set vga and vca to their widest-band settings, as a precaution.
+           SetSymbolrate might not be called to set this up */
+        cx24110_pll_write(fe,0x500c0000);
+        cx24110_pll_write(fe,0x83f1f800);
+        cx24110_pll_write(fe,pll);
+/*        writereg(client,0x56,0x7f);*/
+
+	return 0;
+}
+
+static int pinnsat_pll_init(struct dvb_frontend* fe)
+{
+   return 0;
+}
+
+
+static struct cx24110_config pctvsat_config = {
+
+	.demod_address = 0x55,
+	.pll_init = pinnsat_pll_init,
+	.pll_set = cx24108_pll_set,
+};
 
 
 static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -220,7 +284,7 @@
 	return request_firmware(fw, name, &bt->bt->dev->dev);
 }
 
-struct sp887x_config microtune_mt7202dtf_config = {
+static struct sp887x_config microtune_mt7202dtf_config = {
 
 	.demod_address = 0x70,
 	.pll_set = microtune_mt7202dtf_pll_set,
@@ -387,6 +451,13 @@
 			break;
 		}
 		break;
+	
+	case BTTV_PINNACLESAT:
+		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			break;
+		}
+		break;
 	}
 
 	if (card->fe == NULL) {
@@ -510,7 +581,14 @@
 
 	switch(sub->core->type)
 	{
-/*	case BTTV_PINNACLESAT: UNDEFINED HARDWARE */
+	case BTTV_PINNACLESAT:
+		card->gpio_mode = 0x0400c060;
+		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
+		              BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
+		card->op_sync_orin = 0;
+		card->irq_err_ignore = 0;
+		break;
+		
 #ifdef BTTV_DVICO_DVBT_LITE
 	case BTTV_DVICO_DVBT_LITE:
 #endif
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/bt8xx/dvb-bt8xx.h linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/dvb-bt8xx.h
--- linux-2.6.11-rc2/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/dvb-bt8xx.h	2005-01-20 19:56:37.000000000 +0100
@@ -22,6 +22,9 @@
  *
  */
 
+#ifndef DVB_BT8XX_H
+#define DVB_BT8XX_H
+
 #include <linux/i2c.h>
 #include "dvbdev.h"
 #include "dvb_net.h"
@@ -30,6 +33,7 @@
 #include "sp887x.h"
 #include "dst.h"
 #include "nxt6000.h"
+#include "cx24110.h"
 
 struct dvb_bt8xx_card {
 	struct semaphore lock;
@@ -50,3 +54,5 @@
 				
 	struct dvb_frontend* fe;
 };
+
+#endif /* DVB_BT8XX_H */
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/bt8xx/Kconfig linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/Kconfig
--- linux-2.6.11-rc2/drivers/media/dvb/bt8xx/Kconfig	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/bt8xx/Kconfig	2005-01-20 19:56:37.000000000 +0100
@@ -3,6 +3,8 @@
 	depends on DVB_CORE && PCI && VIDEO_BT848
 	select DVB_MT352
 	select DVB_SP887X
+	select DVB_NXT6000
+	select DVB_CX24110
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
 	  the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
@@ -11,8 +13,5 @@
 	  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.
 


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

* [PATCH 3/9] refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 1/9] fix RPS init race Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 2/9] support pinnacle pctv-sat, clean-ups Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 4/9] support nxt2002 frontend, misc skystar2 fixes Johannes Stezenbach
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] dvb-dibusb: refactoring of the dibusb driver, support for device clones
        from Yakumo/HAMA/Typhoon/HanfTek, update the documentation

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

diff -uraNwB linux-2.6.11-rc2/Documentation/dvb/README.dibusb linux-2.6.11-rc2-dvb/Documentation/dvb/README.dibusb
--- linux-2.6.11-rc2/Documentation/dvb/README.dibusb	2005-01-20 19:55:06.000000000 +0100
+++ linux-2.6.11-rc2-dvb/Documentation/dvb/README.dibusb	2005-01-20 19:56:37.000000000 +0100
@@ -26,7 +26,7 @@
 - HAMA DVB-T USB device
 	http://www.hama.de/portal/articleId*110620/action*2598
 
-- CTS Portable (Chinese Television System)
+- CTS Portable (Chinese Television System) (2)
 	http://www.2cts.tv/ctsportable/
 
 - Unknown USB DVB-T device with vendor ID Hyper-Paltek
@@ -46,16 +46,16 @@
 
 Others:
 -------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235)
+- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner) 
 	http://82.161.246.249/products-tvbox.html
 
-- Compro Videomate DVB-U2000 - DVB-T USB
+- Compro Videomate DVB-U2000 - DVB-T USB (2)
 	http://www.comprousa.com/products/vmu2000.htm
 
 - Grandtec USB DVB-T
 	http://www.grand.com.tw/
 
-- Avermedia AverTV DVBT USB
+- Avermedia AverTV DVBT USB (2)
 	http://www.avermedia.com/
 
 - DiBcom USB DVB-T reference device (non-public)
@@ -63,16 +63,33 @@
 
 Supported devices USB2.0
 ========================
-- Twinhan MagicBox II
+- Twinhan MagicBox II (2)
 	http://www.twinhan.com/product_terrestrial_7.asp
 
-- Yakumo DVB-T mobile
+- Hanftek UMT-010 (1)
+	http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
+
+- Typhoon/Yakumo/HAMA DVB-T mobile USB2.0 (1)
 	http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
 
+- Artec T1 USB TVBOX (FX2) (2)
+
 - DiBcom USB2.0 DVB-T reference device (non-public)
 
+1) It is working almost.
+2) No test reports received yet. 
+
 
 0. NEWS:
+  2004-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
+             - first almost working version for HanfTek UMT-010
+             - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek
+  2004-01-10 - refactoring completed, now everything is very delightful
+             - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
+               Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich. 
+  2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
+  2004-12-26 - refactored the dibusb-driver, splitted into separate files
+             - i2c-probing enabled
   2004-12-06 - possibility for demod i2c-address probing
              - new usb IDs (Compro,Artec)
   2004-11-23 - merged changes from DiB3000MC_ver2.1
@@ -115,13 +132,15 @@
 
 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, 2.6.9 .
+it is working with 2.6.7 and above.
 
 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 :).
 
+The driver is included in the kernel since Linux 2.6.10.
+
 1.1. Firmware
 
 The USB driver needs to download a firmware to start working.
@@ -155,9 +174,13 @@
 first have a look, which debug level are available:
 
 modinfo dib3000mb
+modinfo dib3000-common
+modinfo dib3000mc
 modinfo dvb-dibusb
 
+modprobe dib3000-common debug=<level>
 modprobe dib3000mb debug=<level>
+modprobe dib3000mc debug=<level>
 modprobe dvb-dibusb debug=<level>
 
 should do the trick.
@@ -168,13 +191,11 @@
 
 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).
+in vdr (at least the USB2.0 one) is working. 
 
 2. Known problems and bugs
 
-TODO:
-- signal-quality and strength calculations
+- none this time
 
 2.1. Adding support for devices 
 
@@ -202,9 +223,10 @@
 maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
 This is not enough for receiving the complete transport stream of a
 DVB-T channel (which can be about 16 MBit/s). Normally this is not a
-problem, if you only want to watch TV, but watching a channel while
-recording another channel on the same frequency simply does not work.
-This applies to all USB1.1 DVB-T devices.
+problem, if you only want to watch TV (this does not apply for HDTV),
+but watching a channel while recording another channel on the same 
+frequency simply does not work. This applies to all USB1.1 DVB-T 
+devices, not only dibusb)
 
 A special problem of the dibusb for the USB1.1 is, that the USB control
 IC has a problem with write accesses while having MPEG2-streaming
@@ -218,14 +240,20 @@
 these features is maybe a solution. Additionally this behaviour of VDR exceeds
 the USB1.1 bandwidth.
 
+Update:
+For the USB1.1 and VDR some work has been done (patches and comments are still 
+very welcome). Maybe the problem is solved in the meantime because I now use
+the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
+linux-dvb software filter is able to get the best of the garbled TS.
+
 2.3. 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.
+    providing specs, code and help, on which the dvb-dibusb, dib3000mb and 
+    dib3000mc are based.
 
    David Matthews for identifying a new device type (Artec T1 with AN2235)
     and for extending dibusb with remote control event handling. Thank you.
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-core.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-core.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-core.c	2005-01-13 14:24:12.000000000 +0100
@@ -0,0 +1,471 @@
+/*
+ * Driver for mobile USB Budget DVB-T devices based on reference 
+ * design made by DiBcom (http://www.dibcom.fr/)
+ * 
+ * dvb-dibusb-core.c
+ * 
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ * Remote control code added by David Matthews (dm@prolingua.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, version 2.
+ *
+ * Acknowledgements
+ * 
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
+ * 
+ * see Documentation/dvb/README.dibusb for more information
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/moduleparam.h>
+
+/* debug */
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able)).");
+#endif
+
+int pid_parse;
+module_param(pid_parse, int, 0644);
+MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
+
+int rc_query_interval;
+module_param(rc_query_interval, int, 0644);
+MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
+
+/* Vendor IDs */
+#define USB_VID_ANCHOR						0x0547
+#define USB_VID_AVERMEDIA					0x14aa
+#define USB_VID_COMPRO						0x185b
+#define USB_VID_COMPRO_UNK					0x145f
+#define USB_VID_CYPRESS						0x04b4
+#define USB_VID_DIBCOM						0x10b8
+#define USB_VID_EMPIA						0xeb1a
+#define USB_VID_GRANDTEC					0x5032
+#define USB_VID_HYPER_PALTEK				0x1025
+#define USB_VID_HANFTEK						0x15f4
+#define USB_VID_IMC_NETWORKS				0x13d3
+#define USB_VID_TWINHAN						0x1822
+#define USB_VID_ULTIMA_ELECTRONIC			0x05d8
+
+/* Product IDs */
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD		0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM		0x0002
+#define USB_PID_COMPRO_DVBU2000_COLD		0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM		0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD	0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM	0x010d
+#define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
+#define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
+#define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
+#define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD		0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD		0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM		0x0fa1
+#define USB_PID_KWORLD_VSTREAM_COLD			0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM			0x17df
+#define USB_PID_TWINHAN_VP7041_COLD			0x3201
+#define USB_PID_TWINHAN_VP7041_WARM			0x3202
+#define USB_PID_ULTIMA_TVBOX_COLD			0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM			0x8106
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD	0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM	0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD	0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD		0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD	0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM	0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD		0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM		0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD		0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM		0x0025
+#define USB_PID_YAKUMO_DTT200U_COLD			0x0201
+#define USB_PID_YAKUMO_DTT200U_WARM			0x0301
+
+/* USB Driver stuff
+ * table of devices that this driver is working with
+ *
+ * ATTENTION: Never ever change the order of this table, the particular 
+ * devices depend on this order 
+ *
+ * Each entry is used as a reference in the device_struct. Currently this is 
+ * the only non-redundant way of assigning USB ids to actual devices I'm aware 
+ * of, because there is only one place in the code where the assignment of 
+ * vendor and product id is done, here.
+ */
+static struct usb_device_id dib_table [] = {
+/* 00 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 02 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_COLD) },
+
+/* the following device is actually not supported, but when loading the 
+ * correct firmware (ie. its usb ids will change) everything works fine then 
+ */
+/* 03 */	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_WARM) },
+
+/* 04 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
+/* 05 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
+/* 06 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
+/* 07 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
+/* 08 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
+/* 09 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_COLD) },
+/* 10 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_WARM) },
+/* 11 */	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_COLD) },
+/* 12 */	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_WARM) },
+/* 13 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
+/* 14 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
+/* 15 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
+/* 16 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_WARM) },
+/* 17 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_COLD) },
+/* 18 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_WARM) },
+/* 19 */	{ USB_DEVICE(USB_VID_IMC_NETWORKS,	USB_PID_TWINHAN_VP7041_COLD) },
+/* 20 */	{ USB_DEVICE(USB_VID_IMC_NETWORKS,	USB_PID_TWINHAN_VP7041_WARM) },
+/* 21 */	{ USB_DEVICE(USB_VID_TWINHAN, 		USB_PID_TWINHAN_VP7041_COLD) },
+/* 22 */	{ USB_DEVICE(USB_VID_TWINHAN, 		USB_PID_TWINHAN_VP7041_WARM) },
+/* 23 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 24 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 25 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 26 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 27 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+	
+/* 28 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_COLD) },
+/* 29 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_WARM) },
+
+/* 
+ * activate the following define when you have one of the devices and want to 
+ * build it from build-2.6 in dvb-kernel
+ */
+// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES 
+#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 31 */	{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
+/* 32 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
+/* 33 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_DIBCOM_ANCHOR_2135_COLD) },
+#endif
+			{ }		/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dib_table);
+
+static struct dibusb_usb_controller dibusb_usb_ctrl[] = {
+	{ .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
+	{ .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
+	{ .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
+};
+
+struct dibusb_tuner dibusb_tuner[] = {
+	{ DIBUSB_TUNER_CABLE_THOMSON, 
+	  0x61 
+	},
+	{ DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
+	  0x60 
+	},
+	{ DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
+	  0x61
+	},
+	{ DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
+	  0x60
+	},
+};
+
+static struct dibusb_demod dibusb_demod[] = {
+	{ DIBUSB_DIB3000MB,
+	  16,
+	  { 0x8, 0 },
+	},
+	{ DIBUSB_DIB3000MC,
+	  32,
+	  { 0x9, 0xa, 0xb, 0xc }, 
+	},
+	{ DIBUSB_MT352,
+	  254,
+	  { 0xf, 0 }, 
+	},
+};
+
+static struct dibusb_device_class dibusb_device_classes[] = {
+	{ .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
+	  .firmware = "dvb-dibusb-5.0.0.11.fw",
+	  .pipe_cmd = 0x01, .pipe_data = 0x02, 
+	  .urb_count = 3, .urb_buffer_size = 4096,
+	  DIBUSB_RC_NEC_PROTOCOL,
+	  &dibusb_demod[DIBUSB_DIB3000MB],
+	  &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+	},
+	{ DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
+	  "dvb-dibusb-an2235-1.fw",
+	  0x01, 0x02, 
+	  3, 4096,
+	  DIBUSB_RC_NEC_PROTOCOL,
+	  &dibusb_demod[DIBUSB_DIB3000MB],
+	  &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+	},
+	{ DIBUSB2_0,&dibusb_usb_ctrl[2],
+	  "dvb-dibusb-6.0.0.5.fw",
+	  0x01, 0x06, 
+	  3, 188*210,
+	  DIBUSB_RC_NEC_PROTOCOL,
+	  &dibusb_demod[DIBUSB_DIB3000MC],
+	  &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
+	},
+	{ UMT2_0, &dibusb_usb_ctrl[2],
+	  "dvb-dibusb-umt-1.fw",
+	  0x01, 0x02, 
+	  15, 188*21,
+	  DIBUSB_RC_NO,
+	  &dibusb_demod[DIBUSB_MT352],
+//	  &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5],
+	  &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
+	},
+};
+
+static struct dibusb_usb_device dibusb_devices[] = {
+	{	"TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[19], &dib_table[21], NULL},
+		{ &dib_table[20], &dib_table[22], NULL},
+	},
+	{	"KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[11], NULL },
+		{ &dib_table[12], NULL },
+	},
+	{	"Grandtec USB1.1 DVB-T",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[13], &dib_table[15], NULL },
+		{ &dib_table[14], &dib_table[16], NULL },
+	},
+	{	"DiBcom USB1.1 DVB-T reference design (MOD3000)",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[7],  NULL },
+		{ &dib_table[8],  NULL },
+	},
+	{	"Artec T1 USB1.1 TVBOX with AN2135",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[23], NULL },
+		{ &dib_table[24], NULL },
+	},
+	{	"Artec T1 USB1.1 TVBOX with AN2235",
+		&dibusb_device_classes[DIBUSB1_1_AN2235],
+		{ &dib_table[25], NULL },
+		{ &dib_table[26], NULL },
+	},
+	{	"Avermedia AverTV DVBT USB1.1",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[0],  NULL },
+		{ &dib_table[1],  NULL },
+	},
+	{	"Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[4], &dib_table[6], NULL},
+		{ &dib_table[5], NULL },
+	},
+	{	"Unkown USB1.1 DVB-T device ???? please report the name to the author",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[17], NULL },
+		{ &dib_table[18], NULL },
+	},
+	{	"DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+		&dibusb_device_classes[DIBUSB2_0],
+		{ &dib_table[9],  NULL },
+		{ &dib_table[10], NULL },
+	},
+	{	"Artec T1 USB2.0 TVBOX (please report the warm ID)",
+		&dibusb_device_classes[DIBUSB2_0],
+		{ &dib_table[27], NULL },
+		{ NULL },
+	},
+	{	"AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0",
+		&dibusb_device_classes[UMT2_0],
+		{ &dib_table[2], NULL },
+		{ NULL },
+	},	
+	{	"Hanftek UMT-010 DVB-T USB2.0",
+		&dibusb_device_classes[UMT2_0],
+		{ &dib_table[28], NULL },
+		{ &dib_table[29], NULL },
+	},	
+#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+	{	"Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
+		&dibusb_device_classes[DIBUSB1_1_AN2235],
+		{ &dib_table[30], NULL },
+		{ NULL },
+	},
+	{	"Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
+		&dibusb_device_classes[DIBUSB2_0],
+		{ &dib_table[31], NULL },
+		{ &dib_table[32], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
+	},
+	{	"DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
+		&dibusb_device_classes[DIBUSB1_1],
+		{ &dib_table[33], NULL },
+		{ NULL },
+	},
+#endif
+};
+
+static int dibusb_exit(struct usb_dibusb *dib)
+{
+	deb_info("init_state before exiting everything: %x\n",dib->init_state);
+	dibusb_remote_exit(dib);
+	dibusb_fe_exit(dib);
+	dibusb_i2c_exit(dib);
+	dibusb_pid_list_exit(dib);
+	dibusb_dvb_exit(dib);
+	dibusb_urb_exit(dib);
+	deb_info("init_state should be zero now: %x\n",dib->init_state);
+	dib->init_state = DIBUSB_STATE_INIT;
+	kfree(dib);
+	return 0;
+}
+
+static int dibusb_init(struct usb_dibusb *dib)
+{
+	int ret = 0;
+	sema_init(&dib->usb_sem, 1);
+	sema_init(&dib->i2c_sem, 1);
+
+	dib->init_state = DIBUSB_STATE_INIT;
+	
+	if ((ret = dibusb_urb_init(dib)) ||
+		(ret = dibusb_dvb_init(dib)) || 
+		(ret = dibusb_pid_list_init(dib)) ||
+		(ret = dibusb_i2c_init(dib))) {
+		dibusb_exit(dib);
+		return ret;
+	}
+
+	if ((ret = dibusb_fe_init(dib)))
+		err("could not initialize a frontend.");
+	
+	if ((ret = dibusb_remote_init(dib)))
+		err("could not initialize remote control.");
+	
+	return 0;
+}
+
+static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
+{
+	int i,j;
+	*cold = -1;
+	for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
+		for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
+			deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
+			if (dibusb_devices[i].cold_ids[j]->idVendor == udev->descriptor.idVendor &&
+				dibusb_devices[i].cold_ids[j]->idProduct == udev->descriptor.idProduct) {
+				*cold = 1;
+				return &dibusb_devices[i];
+			}
+		}
+
+		for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
+			deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
+			if (dibusb_devices[i].warm_ids[j]->idVendor == udev->descriptor.idVendor &&
+				dibusb_devices[i].warm_ids[j]->idProduct == udev->descriptor.idProduct) {
+				*cold = 0;
+				return &dibusb_devices[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+ * 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_usb_device *dibdev = NULL;
+	
+	int ret = -ENOMEM,cold=0;
+
+	if ((dibdev = dibusb_find_device(udev,&cold)) == NULL) {
+		err("something went very wrong, "
+				"unknown product ID: %.4x",udev->descriptor.idProduct);
+		return -ENODEV;
+	}
+	
+	if (cold == 1) {
+		info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
+		ret = dibusb_loadfirmware(udev,dibdev);
+	} else {
+		info("found a '%s' in warm state.",dibdev->name);
+		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 && dib->dibdev != NULL) {
+		name = dib->dibdev->name;
+		dibusb_exit(dib);
+	}
+	info("%s successfully deinitialized and disconnected.",name);
+	
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+struct usb_driver dibusb_driver = {
+	.owner		= THIS_MODULE,
+	.name		= DRIVER_DESC,
+	.probe 		= dibusb_probe,
+	.disconnect = dibusb_disconnect,
+	.id_table 	= dib_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.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c	2005-01-13 14:24:12.000000000 +0100
@@ -0,0 +1,205 @@
+/*
+ * dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices 
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for initializing and handling the 
+ * linux-dvb API.
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/usb.h>
+#include <linux/version.h>
+
+static u32 urb_compl_count;
+
+/*
+ * MPEG2 TS DVB stuff 
+ */
+void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+	struct usb_dibusb *dib = urb->context;
+	int ret;
+
+	deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
+			urb->actual_length);
+
+	urb_compl_count++;
+	if (urb_compl_count % 500 == 0)
+		deb_info("%d urbs completed so far.\n",urb_compl_count);
+
+	switch (urb->status) {
+		case 0:         /* success */
+		case -ETIMEDOUT:    /* NAK */
+			break;
+		case -ECONNRESET:   /* unlink */
+		case -ENOENT:
+		case -ESHUTDOWN:
+			return;
+		default:        /* error */
+			warn("urb completition error %d.", urb->status);
+	}
+
+	if (dib->feedcount > 0) {
+		deb_ts("URB return len: %d\n",urb->actual_length);
+		if (urb->actual_length % 188) 
+			deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
+
+		/* Francois recommends to drop not full-filled packets, even if they may 
+		 * contain valid TS packets, at least for USB1.1
+		 *
+		 * if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) */
+		if (dib->init_state & DIBUSB_STATE_DVB)
+			dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
+		else
+			deb_ts("URB dropped because of the " 
+					"actual_length or !dvb_is_ready (%d).\n",dib->init_state & DIBUSB_STATE_DVB);
+	} else 
+		deb_ts("URB dropped because of feedcount.\n");
+
+	ret = usb_submit_urb(urb,GFP_ATOMIC);
+	deb_ts("urb resubmitted, (%d)\n",ret);
+}
+
+static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) 
+{
+	struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
+	int newfeedcount;
+	
+	if (dib == NULL)
+		return -ENODEV;
+
+	newfeedcount = dib->feedcount + (onoff ? 1 : -1);
+
+	/* 
+	 * stop feed before setting a new pid if there will be no pid anymore 
+	 */
+//	if ((dib->dibdev->parm->firmware_bug && dib->feedcount) || 
+	if (newfeedcount == 0) {
+		deb_ts("stop feeding\n");
+		if (dib->xfer_ops.fifo_ctrl != NULL) {
+			if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
+				err("error while inhibiting fifo.");
+				return -ENODEV;
+			}
+		}
+	}
+	
+	dib->feedcount = newfeedcount;
+
+	/* get a free pid from the list and activate it on the device
+	 * specific pid_filter
+	 */
+	if (dib->pid_parse)
+		dibusb_ctrl_pid(dib,dvbdmxfeed,onoff);
+
+	/* 
+	 * start the feed, either if there is the firmware bug or 
+	 * if this was the first pid to set and there is still a pid for 
+	 * reception.
+	 */
+	
+//	if ((dib->dibdev->parm->firmware_bug)
+	if (dib->feedcount == onoff && dib->feedcount > 0) {
+
+		deb_ts("controlling pid parser\n");
+		if (dib->xfer_ops.pid_parse != NULL) {
+			if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
+				err("could not handle pid_parser");
+			}
+		}
+		
+		deb_ts("start feeding\n");
+		if (dib->xfer_ops.fifo_ctrl != NULL) {
+			if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
+				err("error while enabling fifo.");
+				return -ENODEV;
+			}
+		}
+		dibusb_streaming(dib,1);
+	}
+	return 0;
+}
+
+static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+	return dibusb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+	return dibusb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dibusb_dvb_init(struct usb_dibusb *dib)
+{
+	int ret;
+
+	urb_compl_count = 0;
+
+#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;
+	}
+	dib->adapter->priv = dib;
+	
+/* i2c is done in dibusb_i2c_init */
+	
+	dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+
+	dib->demux.priv = (void *)dib;
+	/* get pidcount from demod */
+	dib->demux.feednum = dib->demux.filternum = 255;
+	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:
+	dvb_unregister_adapter(dib->adapter);
+err:
+	return ret;
+success:
+	dib->init_state |= DIBUSB_STATE_DVB;
+	return 0;
+}
+
+int dibusb_dvb_exit(struct usb_dibusb *dib)
+{
+	if (dib->init_state & DIBUSB_STATE_DVB) {
+		dib->init_state &= ~DIBUSB_STATE_DVB;
+		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);
+		dvb_unregister_adapter(dib->adapter);
+	}
+	return 0;
+}
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c	2005-01-13 14:24:12.000000000 +0100
@@ -0,0 +1,598 @@
+/*
+ * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices 
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for attaching, initializing of an appropriate
+ * demodulator/frontend. I2C-stuff is also located here.
+ * 
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/usb.h>
+
+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);
+	
+	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+	sndbuf[1] = (addr << 1) | (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);
+}
+
+/*
+ * I2C master xfer function
+ */
+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;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+	
+	for (i = 0; i < num; i++) {
+		/* write/read request */
+		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+			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 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_general_demod_init(struct dvb_frontend *fe);
+static u8 dibusb_general_pll_addr(struct dvb_frontend *fe);
+static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]);
+static int dibusb_general_pll_set(struct dvb_frontend *fe, 
+		struct dvb_frontend_parameters* params, u8 pll_buf[5]);
+
+static struct mt352_config mt352_hanftek_umt_010_config = {
+	.demod_address = 0x1e,
+	.demod_init = dibusb_general_demod_init,
+   	.pll_set = dibusb_general_pll_set,
+};
+
+static int dibusb_tuner_quirk(struct usb_dibusb *dib) 
+{
+	switch (dib->dibdev->dev_cl->id) {
+		case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */
+		case DIBUSB1_1_AN2235: { /* actually its this device, but in warm state they are indistinguishable */
+			struct dibusb_tuner *t;
+			u8 b[2] = { 0,0 } ,b2[1];
+			struct i2c_msg msg[2] = {
+				{ .flags = 0, .buf = b, .len = 2 },
+				{ .flags = I2C_M_RD, .buf = b2, .len = 1},
+			};
+			
+			t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5];
+			
+			msg[0].addr = msg[1].addr = t->pll_addr;
+		
+			if (dib->xfer_ops.tuner_pass_ctrl != NULL)
+				dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr);
+			dibusb_i2c_xfer(&dib->i2c_adap,msg,2);
+			if (dib->xfer_ops.tuner_pass_ctrl != NULL)
+				dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr);
+
+			if (b2[0] == 0xfe)
+				info("this device has the Thomson Cable onboard. Which is default.");
+			else {
+				dib->tuner = t;
+				info("this device has the Panasonic ENV77H11D5 onboard.");
+			}
+			break;	
+		}
+		default:
+			break;
+	}
+	return 0;
+}
+
+/* there is a ugly pid_filter in the firmware of the umt devices, it is accessible 
+ * by i2c address 0x8. Don't know how to deactivate it and how many rows it has.
+ */
+static int dibusb_umt_pid_control(struct dvb_frontend *fe, int index, int pid, int onoff)
+{
+	struct usb_dibusb *dib = fe->dvb->priv;
+	u8 b[3];
+	b[0] = index;
+	if (onoff) {
+		b[1] = (pid >> 8) & 0xff;
+		b[2] = pid & 0xff;
+	} else {
+		b[1] = 0;
+		b[2] = 0;
+	}
+	dibusb_i2c_msg(dib, 0x8, b, 3, NULL,0);
+	dibusb_set_streaming_mode(dib,0);
+	dibusb_set_streaming_mode(dib,1);
+	return 0;
+}
+
+int dibusb_fe_init(struct usb_dibusb* dib)
+{
+	struct dib3000_config demod_cfg;
+	int i;
+	
+	if (dib->init_state & DIBUSB_STATE_I2C) { 
+		for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) && 
+				dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) {
+
+			demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
+			demod_cfg.pll_addr = dibusb_general_pll_addr;
+			demod_cfg.pll_set = dibusb_general_pll_set;
+			demod_cfg.pll_init = dibusb_general_pll_init;
+
+			switch (dib->dibdev->dev_cl->demod->id) {
+				case DIBUSB_DIB3000MB:
+					dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
+				break;
+				case DIBUSB_DIB3000MC:
+					dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
+				break;
+				case DIBUSB_MT352:
+					mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
+					dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
+					dib->xfer_ops.pid_ctrl = dibusb_umt_pid_control;
+				break;
+			}
+			if (dib->fe != NULL) {
+				info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]);
+				break;
+			}
+		}
+		if (dib->fe->ops->sleep != NULL)
+			dib->fe_sleep = dib->fe->ops->sleep;
+		dib->fe->ops->sleep = dibusb_hw_sleep;
+
+		if (dib->fe->ops->init != NULL ) 
+			dib->fe_init = dib->fe->ops->init;
+		dib->fe->ops->init = dibusb_hw_wakeup;
+	
+		/* setting the default tuner */ 
+		dib->tuner = dib->dibdev->dev_cl->tuner;
+
+		/* check which tuner is mounted on this device, in case this is unsure */
+		dibusb_tuner_quirk(dib);
+	}
+	if (dib->fe == NULL) {
+		err("A frontend driver was not found for device '%s'.",
+		       dib->dibdev->name);
+		return -ENODEV;
+	} else {
+		if (dvb_register_frontend(dib->adapter, dib->fe)) {
+			err("Frontend registration failed.");
+			if (dib->fe->ops->release)
+				dib->fe->ops->release(dib->fe);
+			dib->fe = NULL;
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+int dibusb_fe_exit(struct usb_dibusb *dib)
+{
+	if (dib->fe != NULL)
+		dvb_unregister_frontend(dib->fe);
+	return 0;
+}
+
+int dibusb_i2c_init(struct usb_dibusb *dib)
+{
+	int ret = 0;
+
+	dib->adapter->priv = dib;
+
+	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;
+	
+	i2c_set_adapdata(&dib->i2c_adap, dib);
+	
+	if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0)
+		err("could not add i2c adapter");
+	
+	dib->init_state |= DIBUSB_STATE_I2C;
+
+	return ret;
+}
+
+int dibusb_i2c_exit(struct usb_dibusb *dib)
+{
+	if (dib->init_state & DIBUSB_STATE_I2C)
+		i2c_del_adapter(&dib->i2c_adap);
+	dib->init_state &= ~DIBUSB_STATE_I2C;
+	return 0;
+}
+
+
+/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */
+static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
+{
+	u32 tfreq = (fep->frequency + 36125000) / 62500;
+	int vu,p0,p1,p2;
+
+	if (fep->frequency > 403250000)
+		vu = 1, p2 = 1, p1 = 0, p0 = 1;
+	else if (fep->frequency > 115750000)
+		vu = 0, p2 = 1, p1 = 1, p0 = 0;
+	else if (fep->frequency > 44250000)
+		vu = 0, p2 = 0, p1 = 1, p0 = 1;
+	else
+		return -EINVAL;
+
+	pllbuf[0] = (tfreq >> 8) & 0x7f;
+	pllbuf[1] = tfreq & 0xff;
+   	pllbuf[2] = 0x8e;
+   	pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
+	return 0;
+}
+
+static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
+{
+	u32 freq = fep->frequency;
+	u32 tfreq = ((freq + 36125000)*6 + 500000) / 1000000;
+	u8 TA, T210, R210, ctrl1, cp210, p4321;
+	if (freq > 858000000) {
+		err("frequency cannot be larger than 858 MHz.");
+		return -EINVAL;
+	}
+	
+	// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
+	TA = 1;
+	T210 = 0;
+	R210 = 0x2;
+	ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
+
+// ********    CHARGE PUMP CONFIG vs RF FREQUENCIES     *****************
+	if (freq < 470000000) 
+		cp210 = 2;  // VHF Low and High band ch E12 to E4 to E12
+	else if (freq < 526000000) 
+		cp210 = 4;  // UHF band Ch E21 to E27
+	else // if (freq < 862000000) 
+		cp210 = 5;  // UHF band ch E28 to E69
+
+//*********************    BW select  *******************************
+	if (freq < 153000000) 
+		p4321  = 1; // BW selected for VHF low
+	else if (freq < 470000000) 
+		p4321  = 2; // BW selected for VHF high E5 to E12
+	else // if (freq < 862000000) 
+		p4321  = 4; // BW selection for UHF E21 to E69
+
+	pllbuf[0] = (tfreq >> 8) & 0xff;
+	pllbuf[1] = (tfreq >> 0) & 0xff;
+	pllbuf[2] = 0xff & ctrl1;
+	pllbuf[3] =  (cp210 << 5) | (p4321);
+
+	return 0;
+}
+
+/*
+ *            	            7	6		5	4	3	2	1	0
+ * Address Byte             1	1		0	0	0	MA1	MA0	R/~W=0
+ *
+ * Program divider byte 1   0	n14		n13	n12	n11	n10	n9	n8
+ * Program divider byte 2	n7	n6		n5	n4	n3	n2	n1	n0
+ *
+ * Control byte 1           1	T/A=1	T2	T1	T0	R2	R1	R0
+ *                          1	T/A=0	0	0	ATC	AL2	AL1	AL0
+ * 
+ * Control byte 2           CP2	CP1		CP0	BS5	BS4	BS3	BS2	BS1
+ * 
+ * MA0/1 = programmable address bits
+ * R/~W  = read/write bit (0 for writing)
+ * N14-0 = programmable LO frequency
+ * 
+ * T/A   = test AGC bit (0 = next 6 bits AGC setting, 
+ *                       1 = next 6 bits test and reference divider ratio settings)
+ * T2-0  = test bits
+ * R2-0  = reference divider ratio and programmable frequency step
+ * ATC   = AGC current setting and time constant
+ *         ATC = 0: AGC current = 220nA, AGC time constant = 2s
+ *         ATC = 1: AGC current = 9uA, AGC time constant = 50ms
+ * AL2-0 = AGC take-over point bits
+ * CP2-0 = charge pump current
+ * BS5-1 = PMOS ports control bits;
+ *             BSn = 0 corresponding port is off, high-impedance state (at power-on)
+ *             BSn = 1 corresponding port is on
+ */
+
+
+static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4])
+{
+	pllbuf[0] = 0x0b;
+	pllbuf[1] = 0xf5;
+	pllbuf[2] = 0x85;
+	pllbuf[3] = 0xab;
+	return 0;
+}
+
+static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4])
+{
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = fep->frequency + 36166000;
+	if (tuner_frequency < 87000000)
+		return -EINVAL;
+	else if (tuner_frequency < 130000000)
+		cp = 3;
+	else if (tuner_frequency < 160000000)
+		cp = 5;
+	else if (tuner_frequency < 200000000)
+		cp = 6;
+	else if (tuner_frequency < 290000000)
+		cp = 3;
+	else if (tuner_frequency < 420000000)
+		cp = 5;
+	else if (tuner_frequency < 480000000)
+		cp = 6;
+	else if (tuner_frequency < 620000000)
+		cp = 3;
+	else if (tuner_frequency < 830000000)
+		cp = 5;
+	else if (tuner_frequency < 895000000)
+		cp = 7;
+	else
+		return -EINVAL;
+
+	// determine band
+	if (fep->frequency < 49000000)
+		return -EINVAL;
+	else if (fep->frequency < 161000000)
+		band = 1;
+	else if (fep->frequency < 444000000)
+		band = 2;
+	else if (fep->frequency < 861000000)
+		band = 4;
+	else
+		return -EINVAL;
+
+	// setup PLL filter
+	switch (fep->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:
+		case BANDWIDTH_7_MHZ:
+			filter = 0;
+			break;
+		case BANDWIDTH_8_MHZ:
+			filter = 1;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	// calculate divisor
+	// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+	tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000;
+
+	// setup tuner buffer
+	pllbuf[0] = (tuner_frequency >> 8) & 0x7f;
+	pllbuf[1] = tuner_frequency & 0xff;
+	pllbuf[2] = 0xca;
+	pllbuf[3] = (cp << 5) | (filter << 3) | band;
+	return 0;
+}
+
+/*
+ *            	            7	6	5	4	3	2	1	0
+ * Address Byte             1	1	0	0	0	MA1	MA0	R/~W=0
+ *
+ * Program divider byte 1   0	n14	n13	n12	n11	n10	n9	n8
+ * Program divider byte 2	n7	n6	n5	n4	n3	n2	n1	n0
+ *
+ * Control byte             1	CP	T2	T1	T0	RSA	RSB	OS
+ * 
+ * Band Switch byte         X	X	X	P4	P3	P2	P1	P0
+ *
+ * Auxiliary byte           ATC	AL2	AL1	AL0	0	0	0	0
+ *
+ * Address: MA1	MA0	Address
+ *          0	0	c0
+ *          0	1	c2 (always valid)
+ *          1	0	c4
+ *          1	1	c6
+ *
+ *
+ * 
+ */
+
+static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4]) 
+{
+	u32 div;
+	u8 p3210, p4;
+
+#define TUNER_MUL 62500
+
+	div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+
+	if (fep->frequency < 174500000) 
+		p3210 = 1; // not supported by the tdtp_e102p
+	else if (fep->frequency < 230000000) // VHF
+		p3210 = 2;
+	else 
+		p3210 = 4;
+
+	if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+		p4 = 0;
+	else 
+		p4 = 1;
+		
+	pllbuf[0] = (div >> 8) & 0x7f;
+	pllbuf[1] = div & 0xff;
+	pllbuf[2] = 0xce;
+	pllbuf[3] = (p4 << 4) | p3210;
+
+	return 0;
+}
+
+static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
+{
+	static u8 mt352_clock_config[] = { 0x89, 0xb0, 0x2d };
+	static u8 mt352_reset[] = { 0x50, 0x80 };
+	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg[] = { 0x67, 0x14, 0x22 };
+	static u8 mt352_sec_agc_cfg[] = { 0x69, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x40, 0x40 };
+
+	static u8 mt352_unk [] = { 0xb5, 0x7a };
+
+	static u8 mt352_acq_ctl[] = { 0x53, 0x5f };
+	static u8 mt352_input_freq_1[] = { 0x56, 0xf1, 0x05 };
+	
+//	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
+	
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+	mt352_write(fe, mt352_sec_agc_cfg, sizeof(mt352_sec_agc_cfg));
+
+	mt352_write(fe, mt352_unk, sizeof(mt352_unk));
+	
+	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
+	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
+	
+//	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int dibusb_general_demod_init(struct dvb_frontend *fe)
+{
+	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+	switch (dib->dibdev->dev_cl->id) {
+		case UMT2_0:
+			return lg_tdtp_e102p_mt352_demod_init(fe);
+		default: /* other device classes do not have device specific demod inits */
+			break;
+	}
+	return 0;
+}
+
+static u8 dibusb_general_pll_addr(struct dvb_frontend *fe)
+{
+	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+	return dib->tuner->pll_addr;
+}
+
+static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4])
+{
+	if (pll_buf == NULL) {
+		struct i2c_msg msg = { 
+			.addr = dib->tuner->pll_addr, 
+			.flags = 0, 
+			.buf = buf, 
+			.len = sizeof(buf) 
+		};
+		if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
+			return -EIO;
+		msleep(1);
+	} else {
+		pll_buf[0] = dib->tuner->pll_addr << 1;
+		memcpy(&pll_buf[1],buf,4);
+	}
+
+	return 0;
+}
+
+static int dibusb_general_pll_init(struct dvb_frontend *fe, 
+		u8 pll_buf[5])
+{
+	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+	u8 buf[4];
+	int ret=0;
+	switch (dib->tuner->id) {
+		case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
+			ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf);
+			break;
+		default:
+			break;
+	}
+	
+	if (ret)
+		return ret;
+
+	return dibusb_pll_i2c_helper(dib,pll_buf,buf);
+}
+
+static int dibusb_general_pll_set(struct dvb_frontend *fe, 
+		struct dvb_frontend_parameters *fep, u8 pll_buf[5])
+{
+	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+	u8 buf[4];
+	int ret=0;
+
+	switch (dib->tuner->id) {
+		case DIBUSB_TUNER_CABLE_THOMSON: 
+			ret = thomson_cable_eu_pll_set(fep, buf); 
+			break;
+		case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5:
+			ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf);
+			break;
+		case DIBUSB_TUNER_CABLE_LG_TDTP_E102P:
+			ret = lg_tdtp_e102p_tua6034(fep, buf); 
+			break;
+		case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
+			ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf);
+			break;
+		default:
+			warn("no pll programming routine found for tuner %d.\n",dib->tuner->id);
+			ret = -ENODEV;
+			break;
+	}
+	
+	if (ret)
+		return ret;
+	
+	return dibusb_pll_i2c_helper(dib,pll_buf,buf);
+}
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c	2005-01-07 12:49:57.000000000 +0100
@@ -0,0 +1,85 @@
+/*
+ * dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices 
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for downloading the firmware to the device.
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/firmware.h>
+#include <linux/usb.h>
+
+/*
+ * 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);
+}
+
+int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
+{
+	const struct firmware *fw = NULL;
+	u16 addr;
+	u8 *b,*p;
+	int ret = 0,i;
+	
+	if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
+		err("did not find a valid firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+			dibdev->dev_cl->firmware);
+		return ret;
+	}
+	
+	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,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1)) != 1) 
+			err("could not stop the USB controller CPU.");
+		for(i = 0; p[i+3] == 0 && i < fw->size; ) { 
+			b = (u8 *) &p[i];
+			addr = *((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[0]);
+				ret = -EINVAL;
+				break;
+			}
+			i += 5 + b[0];
+		}
+		/* length in ret */
+		if (ret > 0)
+			ret = 0;
+		/* restart the CPU */
+		reset = 0;
+		if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) {
+			err("could not restart the USB controller CPU.");
+			ret = -EINVAL;
+		}
+
+		kfree(p);
+	} else { 
+		ret = -ENOMEM;
+	}
+	release_firmware(fw);
+
+	return ret;
+}
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb.h linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb.h
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb.h	2005-01-20 19:54:06.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb.h	2005-01-20 19:56:37.000000000 +0100
@@ -1,15 +1,14 @@
 /*
  * dvb-dibusb.h
  *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 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 .
+ * for more information see dvb-dibusb-core.c .
  */
-
 #ifndef __DVB_DIBUSB_H__
 #define __DVB_DIBUSB_H__
 
@@ -13,281 +12,160 @@
 #ifndef __DVB_DIBUSB_H__
 #define __DVB_DIBUSB_H__
 
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/usb.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
 #include "dib3000.h"
+#include "mt352.h"
+
+/* debug */
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(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");\
+}
+
+/* module parameters - declared in -core.c */
+extern int debug;
+
+#else
+#define dprintk(args...)
+#define debug_dump(b,l)
+#endif
+
+/* Version information */
+#define DRIVER_VERSION "0.3"
+#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+/* module parameters - declared in -core.c */
+extern int pid_parse;
+extern int rc_query_interval;
+
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_xfer(args...) dprintk(0x02,args)
+#define deb_alot(args...) dprintk(0x04,args)
+#define deb_ts(args...)   dprintk(0x08,args)
+#define deb_err(args...)  dprintk(0x10,args)
+#define deb_rc(args...)   dprintk(0x20,args)
+
+/* generic log methods - taken from usb.h */
+#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)
+
+struct dibusb_usb_controller {
+	const char *name;       /* name of the usb controller */
+	u16 cpu_cs_register;    /* needs to be restarted, when the firmware has been downloaded. */
+};
 
 typedef enum {
 	DIBUSB1_1 = 0,
-	DIBUSB2_0,
 	DIBUSB1_1_AN2235,
-} dibusb_type;
+	DIBUSB2_0,
+	UMT2_0,
+} dibusb_class_t;
 
-static const char * dibusb_fw_filenames1_1[] = {
-	"dvb-dibusb-5.0.0.11.fw"
-};
+typedef enum {
+	DIBUSB_TUNER_CABLE_THOMSON = 0,
+	DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
+	DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
+	DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
+} dibusb_tuner_t;
 
-static const char * dibusb_fw_filenames1_1_an2235[] = {
-	"dvb-dibusb-an2235-1.fw"
-};
+typedef enum {
+	DIBUSB_DIB3000MB = 0,
+	DIBUSB_DIB3000MC,
+	DIBUSB_MT352,
+} dibusb_demodulator_t;
 
-static const char * dibusb_fw_filenames2_0[] = {
-	"dvb-dibusb-6.0.0.5.fw"
-};
+typedef enum {
+	DIBUSB_RC_NO = 0,
+	DIBUSB_RC_NEC_PROTOCOL = 1,
+} dibusb_remote_t;
 
-struct dibusb_device_parameter {
-	dibusb_type type;
-	u8 demod_addr;
-	const char **fw_filenames;
-	const char *usb_controller;
-	u16 usb_cpu_csreg;
-
-	int num_urbs;
-	int urb_buf_size;
-	int default_size;
-	int firmware_bug;
-
-	int cmd_pipe;
-	int result_pipe;
-	int data_pipe;
-};
+struct dibusb_tuner {
+	dibusb_tuner_t id;
 
-static struct dibusb_device_parameter dibusb_dev_parm[3] = {
-	{	.type = DIBUSB1_1,
-		.demod_addr = 0x10,
-		.fw_filenames = dibusb_fw_filenames1_1,
-		.usb_controller = "Cypress AN2135",
-		.usb_cpu_csreg = 0x7f92,
-
-		.num_urbs = 3,
-		.urb_buf_size = 4096,
-		.default_size = 188*21,
-		.firmware_bug = 1,
-
-		.cmd_pipe = 0x01,
-		.result_pipe = 0x81,
-		.data_pipe = 0x82,
-	},
-	{	.type = DIBUSB2_0,
-		.demod_addr = 0x18,
-		.fw_filenames = dibusb_fw_filenames2_0,
-		.usb_controller = "Cypress FX2",
-		.usb_cpu_csreg = 0xe600,
-
-		.num_urbs = 3,
-		.urb_buf_size = 40960,
-		.default_size = 188*210,
-		.firmware_bug = 0,
-
-		.cmd_pipe = 0x01,
-		.result_pipe = 0x81,
-		.data_pipe = 0x86,
-	},
-	{	.type = DIBUSB1_1_AN2235,
-		.demod_addr = 0x10,
-		.fw_filenames = dibusb_fw_filenames1_1_an2235,
-		.usb_controller = "Cypress CY7C64613 (AN2235)",
-		.usb_cpu_csreg = 0x7f92,
-
-		.num_urbs = 3,
-		.urb_buf_size = 4096,
-		.default_size = 188*21,
-		.firmware_bug = 1,
-
-		.cmd_pipe = 0x01,
-		.result_pipe = 0x81,
-		.data_pipe = 0x82,
-	}
+	u8 pll_addr;       /* tuner i2c address */
 };
+extern struct dibusb_tuner dibusb_tuner[];
 
-struct dibusb_device {
-	const char *name;
-	u16 cold_product_id;
-	u16 warm_product_id;
-	struct dibusb_device_parameter *parm;
-};
+#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4
+struct dibusb_demod {
+	dibusb_demodulator_t id;
 
-/* Vendor IDs */
-#define USB_VID_ANCHOR						0x0547
-#define USB_VID_AVERMEDIA					0x14aa
-#define USB_VID_COMPRO						0x185b
-#define USB_VID_COMPRO_UNK					0x145f
-#define USB_VID_CYPRESS						0x04b4
-#define USB_VID_DIBCOM						0x10b8
-#define USB_VID_EMPIA						0xeb1a
-#define USB_VID_GRANDTEC					0x5032
-#define USB_VID_HYPER_PALTEK				0x1025
-#define USB_VID_IMC_NETWORKS				0x13d3
-#define USB_VID_TWINHAN						0x1822
-#define USB_VID_ULTIMA_ELECTRONIC			0x05d8
-
-/* Product IDs */
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD		0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM		0x0002
-#define USB_PID_COMPRO_DVBU2000_COLD		0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM		0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD	0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM	0x010d
-#define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
-#define USB_PID_DIBCOM_MOD3000_WARM			0x0bb9
-#define USB_PID_DIBCOM_MOD3001_COLD			0x0bc6
-#define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
-#define USB_PID_GRANDTEC_DVBT_USB_COLD		0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM		0x0fa1
-#define USB_PID_KWORLD_VSTREAM_COLD			0x17de
-#define USB_PID_KWORLD_VSTREAM_WARM			0x17df
-#define USB_PID_TWINHAN_VP7041_COLD			0x3201
-#define USB_PID_TWINHAN_VP7041_WARM			0x3202
-#define USB_PID_ULTIMA_TVBOX_COLD			0x8105
-#define USB_PID_ULTIMA_TVBOX_WARM			0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD	0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM	0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD	0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD		0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD	0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM	0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD		0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM		0x005f
-#define USB_PID_YAKUMO_DTT200U_COLD			0x0201
-#define USB_PID_YAKUMO_DTT200U_WARM			0x0301
-
-#define DIBUSB_SUPPORTED_DEVICES	15
-
-/* USB Driver stuff */
-static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
-	{	.name = "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
-		.cold_product_id = USB_PID_TWINHAN_VP7041_COLD,
-		.warm_product_id = USB_PID_TWINHAN_VP7041_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
-		.cold_product_id = USB_PID_KWORLD_VSTREAM_COLD,
-		.warm_product_id = USB_PID_KWORLD_VSTREAM_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Grandtec USB1.1 DVB-T/DiBcom USB1.1 DVB-T reference design (MOD3000)",
-		.cold_product_id = USB_PID_DIBCOM_MOD3000_COLD,
-		.warm_product_id = USB_PID_DIBCOM_MOD3000_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Artec T1 USB1.1 TVBOX with AN2135",
-		.cold_product_id = USB_PID_ULTIMA_TVBOX_COLD,
-		.warm_product_id = USB_PID_ULTIMA_TVBOX_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Artec T1 USB1.1 TVBOX with AN2235",
-		.cold_product_id = USB_PID_ULTIMA_TVBOX_AN2235_COLD,
-		.warm_product_id = USB_PID_ULTIMA_TVBOX_AN2235_WARM,
-		.parm = &dibusb_dev_parm[2],
-	},
-	{	.name = "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
-		.cold_product_id = USB_PID_ULTIMA_TVBOX_ANCHOR_COLD,
-		.warm_product_id = 0, /* undefined, this design becomes USB_PID_DIBCOM_MOD3000_WARM in warm state */
-		.parm = &dibusb_dev_parm[2],
-	},
-	{	.name = "Artec T1 USB2.0 TVBOX (please report the warm ID)",
-		.cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_COLD,
-		.warm_product_id = 0, /* don't know, it is most likely that the device will get another USB ID in warm state */
-		.parm = &dibusb_dev_parm[1],
-	},
-	{	.name = "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
-		.cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_COLD,
-		.warm_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_WARM, /* undefined, it could be that the device will get another USB ID in warm state */
-		.parm = &dibusb_dev_parm[1],
-	},
-	{	.name = "Compro Videomate DVB-U2000 - DVB-T USB1.1",
-		.cold_product_id = USB_PID_COMPRO_DVBU2000_COLD,
-		.warm_product_id = USB_PID_COMPRO_DVBU2000_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Compro Videomate DVB-U2000 - DVB-T USB1.1 (really ?? please report the name!)",
-		.cold_product_id = USB_PID_COMPRO_DVBU2000_UNK_COLD,
-		.warm_product_id = USB_PID_COMPRO_DVBU2000_UNK_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Unkown USB1.1 DVB-T device ???? please report the name to the author",
-		.cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD,
-		.warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
-		.cold_product_id = USB_PID_DIBCOM_MOD3001_COLD,
-		.warm_product_id = USB_PID_DIBCOM_MOD3001_WARM,
-		.parm = &dibusb_dev_parm[1],
-	},
-	{	.name = "Grandtec DVB-T USB1.1",
-		.cold_product_id = USB_PID_GRANDTEC_DVBT_USB_COLD,
-		.warm_product_id = USB_PID_GRANDTEC_DVBT_USB_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Avermedia AverTV DVBT USB1.1",
-		.cold_product_id = USB_PID_AVERMEDIA_DVBT_USB_COLD,
-		.warm_product_id = USB_PID_AVERMEDIA_DVBT_USB_WARM,
-		.parm = &dibusb_dev_parm[0],
-	},
-	{	.name = "Yakumo DVB-T mobile USB2.0",
-		.cold_product_id = USB_PID_YAKUMO_DTT200U_COLD,
-		.warm_product_id = USB_PID_YAKUMO_DTT200U_WARM,
-		.parm = &dibusb_dev_parm[1],
-	}
+	int pid_filter_count;                       /* counter of the internal pid_filter */
+	u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */
 };
 
-/* USB Driver stuff */
-/* table of devices that work with this driver */
-static struct usb_device_id dibusb_table [] = {
-	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_AVERMEDIA_DVBT_USB_WARM)},
-	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
-	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
-	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
-	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
-	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_COLD) },
-	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3001_WARM) },
-	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_COLD) },
-	{ USB_DEVICE(USB_VID_EMPIA,			USB_PID_KWORLD_VSTREAM_WARM) },
-	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
-	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
-	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
-	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_WARM) },
-	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_COLD) },
-	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_WARM) },
-	{ USB_DEVICE(USB_VID_IMC_NETWORKS,	USB_PID_TWINHAN_VP7041_COLD) },
-	{ USB_DEVICE(USB_VID_IMC_NETWORKS,	USB_PID_TWINHAN_VP7041_WARM) },
-	{ USB_DEVICE(USB_VID_TWINHAN, 		USB_PID_TWINHAN_VP7041_COLD) },
-	{ USB_DEVICE(USB_VID_TWINHAN, 		USB_PID_TWINHAN_VP7041_WARM) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
-	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_COLD) },
-	{ USB_DEVICE(USB_VID_AVERMEDIA,		USB_PID_YAKUMO_DTT200U_WARM) },
-	{ USB_DEVICE(USB_PID_COMPRO_DVBU2000_UNK_COLD, USB_VID_COMPRO_UNK) },
-	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+#define DIBUSB_MAX_TUNER_NUM 2
+struct dibusb_device_class {
+	dibusb_class_t id;
 
-/*
- * activate the following define when you have one of the devices and want to
- * build it from build-2.6 in dvb-kernel
- */
-// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-	{ USB_DEVICE(USB_VID_CYPRESS,		USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
-	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
-#endif
-	{ }                 /* Terminating entry */
+	const struct dibusb_usb_controller *usb_ctrl; /* usb controller */
+	const char *firmware;                         /* valid firmware filenames */
+
+	int pipe_cmd;                                 /* command pipe (read/write) */
+	int pipe_data;                                /* data pipe */
+	
+	int urb_count;                                /* number of data URBs to be submitted */
+	int urb_buffer_size;                          /* the size of the buffer for each URB */
+
+	dibusb_remote_t remote_type;                  /* does this device have a ir-receiver */
+
+	struct dibusb_demod *demod;                   /* which demodulator is mount */
+	struct dibusb_tuner *tuner;                   /* which tuner can be found here */
 };
 
-MODULE_DEVICE_TABLE (usb, dibusb_table);
+#define DIBUSB_ID_MAX_NUM 15
+struct dibusb_usb_device {
+	const char *name;                                 /* real name of the box */
+	struct dibusb_device_class *dev_cl;               /* which dibusb_device_class is this device part of */
 
-#define DIBUSB_I2C_TIMEOUT 				HZ*5
+	struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */
+	struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */
+};
+
+/* a PID for the pid_filter list, when in use */
+struct dibusb_pid
+{
+	int index;
+	u16 pid;
+	int active;
+};
 
 struct usb_dibusb {
 	/* usb */
 	struct usb_device * udev;
 
-	struct dibusb_device * dibdev;
+	struct dibusb_usb_device * dibdev;
+
+#define DIBUSB_STATE_INIT       0x000
+#define DIBUSB_STATE_URB_LIST   0x001
+#define DIBUSB_STATE_URB_BUF    0x002
+#define DIBUSB_STATE_URB_SUBMIT 0x004 
+#define DIBUSB_STATE_DVB        0x008
+#define DIBUSB_STATE_I2C        0x010
+#define DIBUSB_STATE_REMOTE		0x020
+#define DIBUSB_STATE_PIDLIST    0x040
+	int init_state;
 
 	int feedcount;
 	int pid_parse;
-	struct dib3000_xfer_ops xfer_ops;
+	struct dib_fe_xfer_ops xfer_ops;
+
+	struct dibusb_tuner *tuner;
 
 	struct urb **urb_list;
 	u8 *buffer;
@@ -295,49 +173,137 @@
 
 	/* I2C */
 	struct i2c_adapter i2c_adap;
-	struct i2c_client i2c_client;
 
 	/* locking */
 	struct semaphore usb_sem;
 	struct semaphore i2c_sem;
 
+	/* pid filtering */
+	spinlock_t pid_list_lock;
+	struct dibusb_pid *pid_list;
+	
 	/* dvb */
-	int dvb_is_ready;
 	struct dvb_adapter *adapter;
 	struct dmxdev dmxdev;
 	struct dvb_demux demux;
 	struct dvb_net dvb_net;
 	struct dvb_frontend* fe;
 
+	int (*fe_sleep) (struct dvb_frontend *);
+	int (*fe_init) (struct dvb_frontend *);
+
 	/* remote control */
 	struct input_dev rc_input_dev;
 	struct work_struct rc_query_work;
 	int rc_input_event;
 };
 
+/* commonly used functions in the separated files */
+
+/* dvb-dibusb-firmware.c */
+int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev);
+
+/* dvb-dibusb-remote.c */
+int dibusb_remote_exit(struct usb_dibusb *dib);
+int dibusb_remote_init(struct usb_dibusb *dib);
+
+/* dvb-dibusb-fe-i2c.c */
+int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, 
+		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen);
+int dibusb_fe_init(struct usb_dibusb* dib);
+int dibusb_fe_exit(struct usb_dibusb *dib);
+int dibusb_i2c_init(struct usb_dibusb *dib);
+int dibusb_i2c_exit(struct usb_dibusb *dib);
+
+/* dvb-dibusb-dvb.c */
+void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs);
+int dibusb_dvb_init(struct usb_dibusb *dib);
+int dibusb_dvb_exit(struct usb_dibusb *dib);
+
+/* dvb-dibusb-usb.c */
+int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
+	u16 rlen);
+
+int dibusb_hw_wakeup(struct dvb_frontend *);
+int dibusb_hw_sleep(struct dvb_frontend *);
+int dibusb_set_streaming_mode(struct usb_dibusb *,u8);
+int dibusb_streaming(struct usb_dibusb *,int);
+
+int dibusb_urb_init(struct usb_dibusb *);
+int dibusb_urb_exit(struct usb_dibusb *);
+
+/* dvb-dibusb-pid.c */
+int dibusb_pid_list_init(struct usb_dibusb *dib);
+void dibusb_pid_list_exit(struct usb_dibusb *dib);
+int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff);
+
+/* i2c and transfer stuff */
+#define DIBUSB_I2C_TIMEOUT				HZ*5
+
+/* 
+ * protocol of all dibusb related devices
+ */
 
-/* types of first byte of each buffer */
+/* 
+ * bulk msg to/from endpoint 0x01
+ *
+ * general structure:
+ * request_byte parameter_bytes
+ */
 
 #define DIBUSB_REQ_START_READ			0x00
 #define DIBUSB_REQ_START_DEMOD			0x01
+
+/* 
+ * i2c read 
+ * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
+ * bulk read:  byte_buffer (length_word bytes)
+ */
 #define DIBUSB_REQ_I2C_READ  			0x02
+ 
+/*
+ * i2c write
+ * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
+ */
 #define DIBUSB_REQ_I2C_WRITE 			0x03
 
-/* prefix for reading the current RC key */
+/* 
+ * polling the value of the remote control 
+ * bulk write: 0x04
+ * bulk read:  byte_buffer (5 bytes) 
+ *
+ * first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
+ */
 #define DIBUSB_REQ_POLL_REMOTE			0x04
 
 #define DIBUSB_RC_NEC_EMPTY				0x00
 #define DIBUSB_RC_NEC_KEY_PRESSED		0x01
 #define DIBUSB_RC_NEC_KEY_REPEATED		0x02
 
-/* 0x05 0xXX */
+/* streaming mode:
+ * bulk write: 0x05 mode_byte 
+ *
+ * mode_byte is mostly 0x00
+ */
 #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>
+/* io control
+ * 0x07 cmd_byte param_bytes
+ *
+ * param_bytes can be up to 32 bytes
+ *
+ * cmd_byte function    parameter name 
+ * 0x00     power mode
+ *                      0x00      sleep
+ *                      0x01      wakeup
+ *
+ * 0x01     enable streaming 
+ * 0x02     disable streaming
+ *
+ *
  */
 #define DIBUSB_REQ_SET_IOCTL			0x07
 
@@ -348,4 +314,8 @@
 #define DIBUSB_IOCTL_POWER_SLEEP			0x00
 #define DIBUSB_IOCTL_POWER_WAKEUP			0x01
 
+/* modify streaming of the FX2 */
+#define DIBUSB_IOCTL_CMD_ENABLE_STREAM	0x01
+#define DIBUSB_IOCTL_CMD_DISABLE_STREAM	0x02
+
 #endif
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-pid.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-pid.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-pid.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-pid.c	2005-01-13 14:24:13.000000000 +0100
@@ -0,0 +1,80 @@
+/*
+ * dvb-dibusb-pid.c is part of the driver for mobile USB Budget DVB-T devices 
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for initializing and handling the internal
+ * pid-list. This pid-list mirrors the information currently stored in the
+ * devices pid-list.
+ */
+#include "dvb-dibusb.h"
+
+int dibusb_pid_list_init(struct usb_dibusb *dib)
+{
+	int i;
+	dib->pid_list = kmalloc(sizeof(struct dibusb_pid) * dib->dibdev->dev_cl->demod->pid_filter_count,GFP_KERNEL);
+	if (dib->pid_list == NULL)
+		return -ENOMEM;
+
+	deb_xfer("initializing %d pids for the pid_list.\n",dib->dibdev->dev_cl->demod->pid_filter_count);
+	
+	dib->pid_list_lock = SPIN_LOCK_UNLOCKED;
+	memset(dib->pid_list,0,dib->dibdev->dev_cl->demod->pid_filter_count*(sizeof(struct dibusb_pid)));
+	for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++) {
+		dib->pid_list[i].index = i;
+		dib->pid_list[i].pid = 0;
+		dib->pid_list[i].active = 0;
+	}
+
+	dib->init_state |= DIBUSB_STATE_PIDLIST;
+	return 0;
+}
+
+void dibusb_pid_list_exit(struct usb_dibusb *dib)
+{
+	if (dib->init_state & DIBUSB_STATE_PIDLIST)
+		kfree(dib->pid_list);
+	dib->init_state &= ~DIBUSB_STATE_PIDLIST;
+}
+
+/* fetch a pid from pid_list and set it on or off */
+int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff)
+{
+	int i,ret = -1;
+	unsigned long flags;
+	u16 pid = dvbdmxfeed->pid;
+
+	if (onoff) {
+		spin_lock_irqsave(&dib->pid_list_lock,flags);
+		for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++)
+			if (!dib->pid_list[i].active) {
+				dib->pid_list[i].pid = pid;
+				dib->pid_list[i].active = 1;
+				ret = i;
+				break;
+			}
+		dvbdmxfeed->priv = &dib->pid_list[ret];
+		spin_unlock_irqrestore(&dib->pid_list_lock,flags);
+		
+		if (dib->xfer_ops.pid_ctrl != NULL) 
+			dib->xfer_ops.pid_ctrl(dib->fe,dib->pid_list[ret].index,dib->pid_list[ret].pid,1);
+	} else {
+		struct dibusb_pid *dpid = dvbdmxfeed->priv;
+		
+		if (dib->xfer_ops.pid_ctrl != NULL) 
+			dib->xfer_ops.pid_ctrl(dib->fe,dpid->index,0,0);
+		
+		dpid->pid = 0;
+		dpid->active = 0;
+		ret = dpid->index;
+	}
+	
+	/* a free pid from the list */
+	deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
+
+	return ret;
+}
+
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-remote.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-remote.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-remote.c	2005-01-09 16:50:44.000000000 +0100
@@ -0,0 +1,197 @@
+/*
+ * dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for handling the event device on the software
+ * side and the remote control on the hardware side.
+ */
+#include "dvb-dibusb.h"
+
+/* Table to map raw key codes to key events.  This should not be hard-wired
+   into the kernel.  */
+static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
+{
+	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
+	{ 0x00, 0xff, 0x16, KEY_POWER },
+	{ 0x00, 0xff, 0x10, KEY_MUTE },
+	{ 0x00, 0xff, 0x03, KEY_1 },
+	{ 0x00, 0xff, 0x01, KEY_2 },
+	{ 0x00, 0xff, 0x06, KEY_3 },
+	{ 0x00, 0xff, 0x09, KEY_4 },
+	{ 0x00, 0xff, 0x1d, KEY_5 },
+	{ 0x00, 0xff, 0x1f, KEY_6 },
+	{ 0x00, 0xff, 0x0d, KEY_7 },
+	{ 0x00, 0xff, 0x19, KEY_8 },
+	{ 0x00, 0xff, 0x1b, KEY_9 },
+	{ 0x00, 0xff, 0x15, KEY_0 },
+	{ 0x00, 0xff, 0x05, KEY_CHANNELUP },
+	{ 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
+	{ 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
+	{ 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
+	{ 0x00, 0xff, 0x11, KEY_RECORD },
+	{ 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+	{ 0x00, 0xff, 0x14, KEY_PLAY },
+	{ 0x00, 0xff, 0x1a, KEY_STOP },
+	{ 0x00, 0xff, 0x40, KEY_REWIND },
+	{ 0x00, 0xff, 0x12, KEY_FASTFORWARD },
+	{ 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+	{ 0x00, 0xff, 0x4c, KEY_PAUSE },
+	{ 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+	{ 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
+	{ 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
+	{ 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
+	{ 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
+	{ 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
+	{ 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
+	{ 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
+	/* Key codes for the KWorld/ADSTech/JetWay remote. */
+	{ 0x86, 0x6b, 0x12, KEY_POWER },
+	{ 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
+	{ 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
+	{ 0x86, 0x6b, 0x0b, KEY_EPG },
+	{ 0x86, 0x6b, 0x10, KEY_MUTE },
+	{ 0x86, 0x6b, 0x01, KEY_1 },
+	{ 0x86, 0x6b, 0x02, KEY_2 },
+	{ 0x86, 0x6b, 0x03, KEY_3 },
+	{ 0x86, 0x6b, 0x04, KEY_4 },
+	{ 0x86, 0x6b, 0x05, KEY_5 },
+	{ 0x86, 0x6b, 0x06, KEY_6 },
+	{ 0x86, 0x6b, 0x07, KEY_7 },
+	{ 0x86, 0x6b, 0x08, KEY_8 },
+	{ 0x86, 0x6b, 0x09, KEY_9 },
+	{ 0x86, 0x6b, 0x0a, KEY_0 },
+	{ 0x86, 0x6b, 0x18, KEY_ZOOM },
+	{ 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
+	{ 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
+	{ 0x86, 0x6b, 0x00, KEY_UNDO },
+	{ 0x86, 0x6b, 0x1d, KEY_RECORD },
+	{ 0x86, 0x6b, 0x0d, KEY_STOP },
+	{ 0x86, 0x6b, 0x0e, KEY_PAUSE },
+	{ 0x86, 0x6b, 0x16, KEY_PLAY },
+	{ 0x86, 0x6b, 0x11, KEY_BACK },
+	{ 0x86, 0x6b, 0x19, KEY_FORWARD },
+	{ 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
+	{ 0x86, 0x6b, 0x15, KEY_ESC },
+	{ 0x86, 0x6b, 0x1a, KEY_UP },
+	{ 0x86, 0x6b, 0x1e, KEY_DOWN },
+	{ 0x86, 0x6b, 0x1f, KEY_LEFT },
+	{ 0x86, 0x6b, 0x1b, KEY_RIGHT },
+};
+
+/*
+ * Read the remote control and feed the appropriate event.
+ * NEC protocol is used for remote controls
+ */
+static int dibusb_read_remote_control(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
+	int ret;
+	int i;
+	if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
+		return ret;
+
+	switch (rb[0]) {
+		case DIBUSB_RC_NEC_KEY_PRESSED:
+			/* rb[1-3] is the actual key, rb[4] is a checksum */
+			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+				rb[1], rb[2], rb[3], rb[4]);
+
+			if ((0xff - rb[3]) != rb[4]) {
+				deb_rc("remote control checksum failed.\n");
+				break;
+			}
+
+			/* See if we can match the raw key code. */
+			for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) {
+				if (rc_keys[i].c0 == rb[1] &&
+					rc_keys[i].c1 == rb[2] &&
+				    rc_keys[i].c2 == rb[3]) {
+					dib->rc_input_event = rc_keys[i].key;
+					deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
+					/* Signal down and up events for this key. */
+					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
+					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
+					input_sync(&dib->rc_input_dev);
+					break;
+				}
+			}
+			break;
+		case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
+			break;
+		case DIBUSB_RC_NEC_KEY_REPEATED:
+			/* rb[1]..rb[4] are always zero.*/
+			/* Repeats often seem to occur so for the moment just ignore this. */
+			deb_rc("Key repeat\n");
+			break;
+		default:
+			break;
+	}
+	return 0;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+   whether the remote control has received anything. */
+static void dibusb_remote_query(void *data)
+{
+	struct usb_dibusb *dib = (struct usb_dibusb *) data;
+	/* TODO: need a lock here.  We can simply skip checking for the remote control
+	   if we're busy. */
+	dibusb_read_remote_control(dib);
+	schedule_delayed_work(&dib->rc_query_work,
+			      msecs_to_jiffies(rc_query_interval));
+}
+
+int dibusb_remote_init(struct usb_dibusb *dib)
+{
+	int i;
+
+	if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
+		return 0;
+	
+	/* Initialise the remote-control structures.*/
+	init_input_dev(&dib->rc_input_dev);
+
+	dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
+	dib->rc_input_dev.keycodesize = sizeof(unsigned char);
+	dib->rc_input_dev.keycodemax = KEY_MAX;
+	dib->rc_input_dev.name = DRIVER_DESC " remote control";
+
+	for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
+		set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
+
+	input_register_device(&dib->rc_input_dev);
+
+	dib->rc_input_event = KEY_MAX;
+
+	INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
+
+	/* Start the remote-control polling. */
+	if (rc_query_interval < 40)
+		rc_query_interval = 100; /* default */
+
+	info("schedule remote query interval to %d msecs.",rc_query_interval);
+	schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(rc_query_interval));
+
+	dib->init_state |= DIBUSB_STATE_REMOTE;
+	
+	return 0;
+}
+
+int dibusb_remote_exit(struct usb_dibusb *dib)
+{
+	if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
+		return 0;
+
+	if (dib->init_state & DIBUSB_STATE_REMOTE) {
+		cancel_delayed_work(&dib->rc_query_work);
+		flush_scheduled_work();
+		input_unregister_device(&dib->rc_input_dev);
+	}
+	dib->init_state &= ~DIBUSB_STATE_REMOTE;
+	return 0;
+}
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-usb.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/dvb-dibusb-usb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/dvb-dibusb-usb.c	2005-01-13 14:24:13.000000000 +0100
@@ -0,0 +1,259 @@
+/*
+ * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices 
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for initializing and handling the 
+ * usb specific stuff.
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/version.h>
+#include <linux/pci.h>
+
+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 ((ret = down_interruptible(&dib->usb_sem)))
+		return ret;
+
+	if (dib->feedcount && 
+		wbuf[0] == DIBUSB_REQ_I2C_WRITE && 
+		dib->dibdev->dev_cl->id == DIBUSB1_1)
+		deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
+				"(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
+			
+	debug_dump(wbuf,wlen);
+
+	ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
+			dib->dibdev->dev_cl->pipe_cmd), 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, and no error before */
+	if (!ret && rbuf && rlen) {
+		ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
+				dib->dibdev->dev_cl->pipe_cmd),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;
+}
+
+/*
+ * Cypress controls
+ */
+
+#if 0
+/* 
+ * #if 0'ing the following functions as they are not in use _now_, 
+ * but probably will be sometime.
+ */
+
+/*
+ * do not use this, just a workaround for a bug, 
+ * which will hopefully never occur :).
+ */
+int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
+{
+	u8 b[1] = { DIBUSB_REQ_INTR_READ };
+	return dibusb_write_usb(dib,b,1);
+}
+
+#endif 
+static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+	return dibusb_readwrite_usb(dib,buf,len,NULL,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;
+	memset(b,0,34);
+	b[0] = DIBUSB_REQ_SET_IOCTL;
+	b[1] = cmd;
+
+	if (size > 0)
+		memcpy(&b[2],param,size);
+
+	return dibusb_write_usb(dib,b,34); //2+size);
+}
+
+/*
+ * ioctl for power control
+ */
+int dibusb_hw_wakeup(struct dvb_frontend *fe)
+{
+	struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
+	u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
+	deb_info("dibusb-device is getting up.\n");
+	dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+	
+	if (dib->fe_init)
+		return dib->fe_init(fe);
+	
+	return 0;
+}
+
+int dibusb_hw_sleep(struct dvb_frontend *fe)
+{
+	struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
+	u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
+	deb_info("dibusb-device is going to bed.\n");
+	dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+
+	if (dib->fe_sleep)
+		return dib->fe_sleep(fe);
+	
+	return 0;
+}
+
+int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
+{
+	u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
+	return dibusb_readwrite_usb(dib,b,2,NULL,0);
+}
+
+int dibusb_streaming(struct usb_dibusb *dib,int onoff)
+{
+	switch (dib->dibdev->dev_cl->id) {
+		case DIBUSB2_0:
+			if (onoff)
+				return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
+			else
+				return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
+			break;
+		case UMT2_0: 
+			return dibusb_set_streaming_mode(dib,onoff);
+			break;
+		default:
+			break;
+	}
+	return 0;
+}
+
+int dibusb_urb_init(struct usb_dibusb *dib)
+{
+	int ret,i,bufsize;
+	
+	/*
+	 * when reloading the driver w/o replugging the device 
+	 * a timeout occures, this helps
+	 */
+	usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
+	usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
+	usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
+
+	/* allocate the array for the data transfer URBs */
+	dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
+	if (dib->urb_list == NULL)
+		return -ENOMEM;
+	memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
+
+	dib->init_state |= DIBUSB_STATE_URB_LIST;
+	
+	bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
+	deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
+	/* allocate the actual buffer for the URBs */
+	if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
+		deb_info("not enough memory.\n");
+		return -ENOMEM;
+	}
+	deb_info("allocation complete\n");
+	memset(dib->buffer,0,bufsize);
+	
+	dib->init_state |= DIBUSB_STATE_URB_BUF;
+
+	/* allocate and submit the URBs */
+	for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+		if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
+			return -ENOMEM;
+		}
+		deb_info("submitting URB no. %d\n",i);
+		
+		usb_fill_bulk_urb( dib->urb_list[i], dib->udev, 
+				usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
+				&dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], 
+				dib->dibdev->dev_cl->urb_buffer_size, 
+				dibusb_urb_complete, dib);
+		
+		dib->urb_list[i]->transfer_flags = 0;
+
+		if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
+			err("could not submit buffer urb no. %d\n",i);
+			return ret;
+		}
+		dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+	}
+
+
+	dib->pid_parse = 1;
+	switch (dib->dibdev->dev_cl->id) {
+		case DIBUSB2_0:
+			if (dib->udev->speed == USB_SPEED_HIGH && !pid_parse) {
+				dib->pid_parse = 0;
+				info("running at HIGH speed, will deliver the complete TS.");
+			} else
+				info("will use pid_parsing.");
+			break;
+		default: 
+			break;
+	}
+	
+	return 0;
+}
+
+int dibusb_urb_exit(struct usb_dibusb *dib)
+{
+	int i;
+	if (dib->init_state & DIBUSB_STATE_URB_LIST) {
+		for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+			if (dib->urb_list[i] != NULL) {
+				deb_info("killing URB no. %d.\n",i);
+
+				/* stop the URBs */
+				usb_kill_urb(dib->urb_list[i]);
+				
+				deb_info("freeing URB no. %d.\n",i);
+				/* free the URBs */
+				usb_free_urb(dib->urb_list[i]);
+			}
+		}
+		/* free the urb array */
+		kfree(dib->urb_list);
+		dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
+		dib->init_state &= ~DIBUSB_STATE_URB_LIST;
+	}
+
+	if (dib->init_state & DIBUSB_STATE_URB_BUF)
+		pci_free_consistent(NULL,
+			dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
+			dib->buffer,dib->dma_handle);
+
+	dib->init_state &= ~DIBUSB_STATE_URB_BUF;
+	return 0;
+}
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/Kconfig linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/Kconfig
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/Kconfig	2005-01-20 19:56:17.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/Kconfig	2005-01-20 19:56:37.000000000 +0100
@@ -1,12 +1,13 @@
 config DVB_DIBUSB
-	tristate "DiBcom USB DVB-T devices (see help for device list)"
+	tristate "DiBcom USB DVB-T devices (see help for a complete device list)"
 	depends on DVB_CORE && USB
 	select FW_LOADER
 	select DVB_DIB3000MB
 	select DVB_DIB3000MC
+	select DVB_MT352
 	help
 	  Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
-	  DiBcom (<http://www.dibcom.fr>).
+	  DiBcom (http://www.dibcom.fr) and C&E.
 
 	  Devices supported by this driver:
 
@@ -14,12 +15,14 @@
 		TwinhanDTV Magic Box (VP7041e)
 	    KWorld V-Stream XPERT DTV - DVB-T USB
 	    Hama DVB-T USB-Box
-	    DiBcom reference device (non-public)
+	    DiBcom reference devices (non-public)
 	    Ultima Electronic/Artec T1 USB TVBOX
 	    Compro Videomate DVB-U2000 - DVB-T USB
 	    Grandtec DVB-T USB
 	    Avermedia AverTV DVBT USB
-	    Yakumo DVB-T mobile USB2.0
+	    Artec T1 USB1.1 and USB2.0 boxes
+	    Yakumo/Typhoon DVB-T USB2.0
+	    Hanftek UMT-010 USB2.0
 
 	  The VP7041 seems to be identical to "CTS Portable" (Chinese
 	  Television System).
@@ -27,7 +30,7 @@
 	  These devices can be understood as budget ones, they "only" deliver
 	  (a part of) the MPEG2 transport stream.
 
-	  A firmware is needed to get the device working. See <file:Documentation/dvb/README.dibusb>
+	  A firmware is needed to get the device working. See Documentation/dvb/README.dibusb
 	  details.
 
 	  Say Y if you own such a device and want to use it. You should build it as
@@ -46,6 +49,7 @@
 	    0x0574:0x2235 (Artec T1 USB1.1, cold)
 	    0x04b4:0x8613 (Artec T1 USB2.0, cold)
 	    0x0574:0x1002 (Artec T1 USB2.0, warm)
+	    0x0574:0x2131 (aged DiBcom USB1.1 test device)
 
 	  Say Y if your device has one of the mentioned IDs.
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dibusb/Makefile linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/Makefile
--- linux-2.6.11-rc2/drivers/media/dvb/dibusb/Makefile	2005-01-20 19:54:06.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dibusb/Makefile	2005-01-20 19:56:37.000000000 +0100
@@ -1,3 +1,11 @@
+dvb-dibusb-objs = dvb-dibusb-core.o \
+	dvb-dibusb-dvb.o \
+	dvb-dibusb-fe-i2c.o \
+	dvb-dibusb-firmware.o \
+	dvb-dibusb-remote.o \
+	dvb-dibusb-usb.o \
+	dvb-dibusb-pid.o
+
 obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/


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

* [PATCH 4/9] support nxt2002 frontend, misc skystar2 fixes
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
                   ` (2 preceding siblings ...)
  2005-01-22 17:34 ` [PATCH 3/9] refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 5/9] add ATSC support, misc fixes Johannes Stezenbach
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] nxt2002: add support for nxt2002 frontend (firmware extraction, Kconfig, driver)
- [DVB] skystar2: misc cleanup, remove unneeded casts, remove unreachable
        code, patches by Francois Romieu
- [DVB] skystar2: fix mt352 clock setting for VHF (6 and 7 MHz bw channels),
        patch by Thomas Martin and Dieter Zander:
- [DVB] b2c2-usb-core: fix file permissions to be octal, ISO C90 compile fix,
        temporally repaired the request_types
- [DVB] remove remains of dibusb driver after splitup

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

diff -uraNwB linux-2.6.11-rc2/Documentation/dvb/get_dvb_firmware linux-2.6.11-rc2-dvb/Documentation/dvb/get_dvb_firmware
--- linux-2.6.11-rc2/Documentation/dvb/get_dvb_firmware	2005-01-20 19:55:06.000000000 +0100
+++ linux-2.6.11-rc2-dvb/Documentation/dvb/get_dvb_firmware	2004-12-17 22:00:17.000000000 +0100
@@ -21,7 +21,8 @@
 use File::Temp qw/ tempdir /;
 use IO::Handle;
 
-@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" );
+@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
+		"dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002" );
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -233,6 +234,23 @@
 	$outfile;
 }
 
+sub nxt2002 {
+    my $sourcefile = "Broadband4PC_4_2_11.zip";
+    my $url = "http://www.bbti.us/download/windows/$sourcefile";
+    my $hash = "c6d2ea47a8f456d887ada0cfb718ff2a";
+    my $outfile = "dvb-fe-nxt2002.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/SkyNETU.sys", $hash);
+    extract("$tmpdir/SkyNETU.sys", 375832, 5908, $outfile);
+
+    $outfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/Makefile linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/Makefile
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/Makefile	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/Makefile	2004-12-17 22:00:17.000000000 +0100
@@ -24,3 +24,5 @@
 obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
+obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
+
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/Kconfig linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/Kconfig
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/Kconfig	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/Kconfig	2005-01-20 19:56:37.000000000 +0100
@@ -46,6 +46,7 @@
 config DVB_SP8870
  	tristate "Spase sp8870 based"
 	depends on DVB_CORE
+	select FW_LOADER
 	help
  	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
@@ -56,6 +57,7 @@
 config DVB_SP887X
  	tristate "Spase sp887x based"
 	depends on DVB_CORE
+	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
@@ -84,6 +86,7 @@
 config DVB_TDA1004X
 	tristate "Philips TDA10045H/TDA10046H based"
 	depends on DVB_CORE
+	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 
@@ -145,4 +148,13 @@
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
+comment "ATSC (North American/Korean Terresterial DTV) frontends"
+	depends on DVB_CORE
+
+config DVB_NXT2002
+	tristate "Nxt2002 based"
+	depends on DVB_CORE
+	help
+	  An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+
 endmenu
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/b2c2/Kconfig linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/Kconfig
--- linux-2.6.11-rc2/drivers/media/dvb/b2c2/Kconfig	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/Kconfig	2004-12-17 22:00:17.000000000 +0100
@@ -4,9 +4,11 @@
 	select DVB_STV0299
 	select DVB_MT352
 	select DVB_MT312
+	select DVB_NXT2002
 	help
 	  Support for the Skystar2 PCI DVB card by Technisat, which
-	  is equipped with the FlexCopII chipset by B2C2.
+	  is equipped with the FlexCopII chipset by B2C2, and
+	  for the B2C2/BBTI Air2PC-ATSC card.
 
 	  Say Y if you own such a device and want to use it.
 
@@ -17,7 +19,7 @@
 	select DVB_MT352
 	help
 	  Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently
-	  this does nothing, but providing basic function for the used usb
+	  the does nothing, but providing basic function for the used usb 
 	  protocol.
 
 	  Say Y if you own such a device and want to use it.
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/b2c2/skystar2.c linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/skystar2.c
--- linux-2.6.11-rc2/drivers/media/dvb/b2c2/skystar2.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/skystar2.c	2005-01-20 19:56:37.000000000 +0100
@@ -53,7 +53,7 @@
 #include "stv0299.h"
 #include "mt352.h"
 #include "mt312.h"
-
+#include "nxt2002.h"
 
 static int debug;
 static int enable_hw_filters = 2;
@@ -1379,10 +1378,7 @@
 		write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc);
 		udelay(1000);
 
-		if (subbuffers == 0)
-			dma_enable_disable_irq(adapter, 0, 1, 0);
-		else
-			dma_enable_disable_irq(adapter, 0, 1, 1);
+		dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0);
 
 		irq_dma_enable_disable_irq(adapter, 1);
 
@@ -1681,84 +1677,80 @@
 	return IRQ_HANDLED;
 }
 
-static void init_dma_queue(struct adapter *adapter)
+static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq,
+			      int size, int dmaq_offset)
 {
+	struct pci_dev *pdev = adapter->pdev;
 	dma_addr_t dma_addr;
 
-	if (adapter->dmaq1.buffer != 0)
-		return;
-
-	adapter->dmaq1.head = 0;
-	adapter->dmaq1.tail = 0;
-	adapter->dmaq1.buffer = NULL;
-
-	adapter->dmaq1.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA1 + 0x80, &dma_addr);
+	dmaq->head = 0;
+	dmaq->tail = 0;
 
-	if (adapter->dmaq1.buffer != 0) {
-		memset(adapter->dmaq1.buffer, 0, SIZE_OF_BUF_DMA1);
-
-		adapter->dmaq1.bus_addr = dma_addr;
-		adapter->dmaq1.buffer_size = SIZE_OF_BUF_DMA1;
-
-		dma_init_dma(adapter, 0);
+	dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr);
+	if (!dmaq->buffer)
+		return -ENOMEM;
 
-		adapter->dma_status = adapter->dma_status | 0x10000000;
+	dmaq->bus_addr = dma_addr;
+	dmaq->buffer_size = size;
 
-		ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", __FUNCTION__, adapter->dmaq1.buffer, SIZE_OF_BUF_DMA1);
+	dma_init_dma(adapter, dmaq_offset);
 
-	} else {
+	ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n",
+		 __FUNCTION__, dmaq->buffer, size);
 
-		adapter->dma_status = adapter->dma_status & ~0x10000000;
+	return 0;
 	}
 
-	if (adapter->dmaq2.buffer != 0)
-		return;
-
-	adapter->dmaq2.head = 0;
-	adapter->dmaq2.tail = 0;
-	adapter->dmaq2.buffer = NULL;
-
-	adapter->dmaq2.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA2 + 0x80, &dma_addr);
-
-	if (adapter->dmaq2.buffer != 0) {
-		memset(adapter->dmaq2.buffer, 0, SIZE_OF_BUF_DMA2);
-
-		adapter->dmaq2.bus_addr = dma_addr;
-		adapter->dmaq2.buffer_size = SIZE_OF_BUF_DMA2;
-
-		dma_init_dma(adapter, 1);
-
-		adapter->dma_status = adapter->dma_status | 0x20000000;
-
-		ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", __FUNCTION__, adapter->dmaq2.buffer, (int) SIZE_OF_BUF_DMA2);
+static int init_dma_queue(struct adapter *adapter)
+{
+	struct {
+		struct dmaq *dmaq;
+		u32 dma_status;
+		int size;
+	} dmaq_desc[] = {
+		{ &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 },
+		{ &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 }
+	}, *p = dmaq_desc;
+	int i;
 
-	} else {
+	for (i = 0; i < 2; i++, p++) {
+		if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0)
+			adapter->dma_status &= ~p->dma_status;
+		else
+			adapter->dma_status |= p->dma_status;
+	}
+	return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM;
+}
 
-		adapter->dma_status = adapter->dma_status & ~0x20000000;
+static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq)
+{
+	if (dmaq->buffer) {
+		pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80,
+				    dmaq->buffer, dmaq->bus_addr);
+		memset(dmaq, 0, sizeof(*dmaq));
 	}
 }
 
 static void free_dma_queue(struct adapter *adapter)
 {
-	if (adapter->dmaq1.buffer != 0) {
-		pci_free_consistent(adapter->pdev, SIZE_OF_BUF_DMA1 + 0x80, adapter->dmaq1.buffer, adapter->dmaq1.bus_addr);
+	struct dmaq *dmaq[] = {
+		&adapter->dmaq1,
+		&adapter->dmaq2,
+		NULL
+	}, **p;
 
-		adapter->dmaq1.bus_addr = 0;
-		adapter->dmaq1.head = 0;
-		adapter->dmaq1.tail = 0;
-		adapter->dmaq1.buffer_size = 0;
-		adapter->dmaq1.buffer = NULL;
+	for (p = dmaq; *p; p++)
+		free_dma_queue_one(adapter, *p);
 	}
 
-	if (adapter->dmaq2.buffer != 0) {
-		pci_free_consistent(adapter->pdev, SIZE_OF_BUF_DMA2 + 0x80, adapter->dmaq2.buffer, adapter->dmaq2.bus_addr);
+static void release_adapter(struct adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
 
-		adapter->dmaq2.bus_addr = 0;
-		adapter->dmaq2.head = 0;
-		adapter->dmaq2.tail = 0;
-		adapter->dmaq2.buffer_size = 0;
-		adapter->dmaq2.buffer = NULL;
-	}
+	iounmap(adapter->io_mem);
+	pci_disable_device(pdev);
+	pci_release_region(pdev, 0);
+	pci_release_region(pdev, 1);
 }
 
 static void free_adapter_object(struct adapter *adapter)
@@ -1766,16 +1758,9 @@
 	dprintk("%s:\n", __FUNCTION__);
 
 	close_stream(adapter, 0);
-
-	if (adapter->irq != 0)
 		free_irq(adapter->irq, adapter);
-
 	free_dma_queue(adapter);
-
-	if (adapter->io_mem)
-		iounmap(adapter->io_mem);
-
-	if (adapter != 0)
+	release_adapter(adapter);
 	kfree(adapter);
 }
 
@@ -1784,21 +1769,24 @@
 static int claim_adapter(struct adapter *adapter)
 {
 	struct pci_dev *pdev = adapter->pdev;
-
 	u16 var;
+	int ret;
 
-	if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), skystar2_pci_driver.name))
-		return -EBUSY;
+	ret = pci_request_region(pdev, 1, skystar2_pci_driver.name);
+	if (ret < 0)
+		goto out;
 
-	if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), skystar2_pci_driver.name))
-		return -EBUSY;
+	ret = pci_request_region(pdev, 0, skystar2_pci_driver.name);
+	if (ret < 0)
+		goto err_pci_release_1;
 
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision);
 
 	dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision);
 
-	if (pci_enable_device(pdev))
-		return -EIO;
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_pci_release_0;
 
 	pci_read_config_word(pdev, 4, &var);
 
@@ -1811,13 +1799,23 @@
 
 	if (!adapter->io_mem) {
 		dprintk("%s: can not map io memory\n", __FUNCTION__);
-
-		return 2;
+		ret = -EIO;
+		goto err_pci_disable;
 	}
 
 	dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem);
 
-	return 1;
+	ret = 1;
+out:
+	return ret;
+
+err_pci_disable:
+	pci_disable_device(pdev);
+err_pci_release_0:
+	pci_release_region(pdev, 0);
+err_pci_release_1:
+	pci_release_region(pdev, 1);
+	goto out;
 }
 
 /*
@@ -1873,11 +1871,12 @@
 {
 	struct adapter *adapter;
 	u32 tmp;
+	int ret = -ENOMEM;
 
-	if (!(adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL))) {
+	adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL);
+	if (!adapter) {
 		dprintk("%s: out of memory!\n", __FUNCTION__);
-
-		return -ENOMEM;
+		goto out;
 	}
 
 	memset(adapter, 0, sizeof(struct adapter));
@@ -1887,20 +1886,16 @@
 	adapter->pdev = pdev;
 	adapter->irq = pdev->irq;
 
-	if ((claim_adapter(adapter)) != 1) {
-		free_adapter_object(adapter);
-
-		return -ENODEV;
-	}
+	ret = claim_adapter(adapter);
+	if (ret < 0)
+		goto err_kfree;
 
 	irq_dma_enable_disable_irq(adapter, 0);
 
-	if (request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter) != 0) {
+	ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter);
+	if (ret < 0) {
 		dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq);
-
-		free_adapter_object(adapter);
-
-		return -ENODEV;
+		goto err_release_adapter;
 	}
 
 	read_reg_dw(adapter, 0x208);
@@ -1908,13 +1903,9 @@
 	write_reg_dw(adapter, 0x210, 0xb2ff);
 	write_reg_dw(adapter, 0x208, 0x40);
 
-	init_dma_queue(adapter);
-
-	if ((adapter->dma_status & 0x30000000) == 0) {
-		free_adapter_object(adapter);
-
-		return -ENODEV;
-	}
+	ret = init_dma_queue(adapter);
+	if (ret < 0)
+		goto err_free_irq;
 
 	adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18);
 
@@ -1931,11 +1922,8 @@
 	default:
 		printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision);
 		printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__);
-		free_adapter_object(adapter);
-		pci_set_drvdata(pdev, NULL);
-		release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
-		release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-			return -ENODEV;
+		ret = -ENODEV;
+		goto err_free_dma_queue;
 		}
 
 	decide_how_many_hw_filters(adapter);
@@ -1979,16 +1967,26 @@
 		ctrl_enable_mac(adapter, 1);
 	}
 
-	spin_lock_init(&adapter->lock);
+	adapter->lock = SPIN_LOCK_UNLOCKED;
 
-	return 0;
+out:
+	return ret;
+
+err_free_dma_queue:
+	free_dma_queue(adapter);
+err_free_irq:
+	free_irq(pdev->irq, adapter);
+err_release_adapter:
+	release_adapter(adapter);
+err_kfree:
+	pci_set_drvdata(pdev, NULL);
+	kfree(adapter);
+	goto out;
 }
 
 static void driver_halt(struct pci_dev *pdev)
 {
-	struct adapter *adapter;
-
-	adapter = pci_get_drvdata(pdev);
+	struct adapter *adapter = pci_get_drvdata(pdev);
 
 	irq_dma_enable_disable_irq(adapter, 0);
 
@@ -1998,9 +1996,9 @@
 
 	pci_set_drvdata(pdev, NULL);
 
-	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
-
-	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+	pci_disable_device(pdev);
+	pci_release_region(pdev, 1);
+	pci_release_region(pdev, 0);
 }
 
 static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
@@ -2325,11 +2323,22 @@
 
 
 
+static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &adapter->pdev->dev);
+}
 
 
+static struct nxt2002_config samsung_tbmv_config = {
+	.demod_address = 0x0A,
+	.request_firmware = nxt2002_request_firmware,
+};
+
 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
 {
-	static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
+	static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
 	static u8 mt352_reset [] = { 0x50, 0x80 };
 	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
 	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
@@ -2407,7 +2416,15 @@
 static void frontend_init(struct adapter *skystar2)
 {
 	switch(skystar2->pdev->device) {
-	case 0x2103: // Technisat Skystar2 OR Technisat Airstar2
+	case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC)
+
+		// Attempt to load the Nextwave nxt2002 for ATSC support 
+		skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap);
+		if (skystar2->fe != NULL) {
+			skystar2->fe_sleep = skystar2->fe->ops->sleep;
+			skystar2->fe->ops->sleep = flexcop_sleep;
+			break;
+		}
 
 		// try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935))
 		skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
@@ -2462,26 +2479,24 @@
 	struct adapter *adapter;
 	struct dvb_adapter *dvb_adapter;
 	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret = -ENODEV;
 
-	int ret;
-
-	if (pdev == NULL)
-		return -ENODEV;
+	if (!pdev)
+		goto out;
 
-	if (driver_initialize(pdev) != 0)
-		return -ENODEV;
-
-	dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, THIS_MODULE);
+	ret = driver_initialize(pdev);
+	if (ret < 0)
+		goto out;
 
-	if (dvb_adapter == NULL) {
+	ret = dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name,
+				   THIS_MODULE);
+	if (ret < 0) {
 		printk("%s: Error registering DVB adapter\n", __FUNCTION__);
-
-		driver_halt(pdev);
-
-		return -ENODEV;
+		goto err_halt;
 	}
 
-	adapter = (struct adapter *) pci_get_drvdata(pdev);
+	adapter = pci_get_drvdata(pdev);
 
 	dvb_adapter->priv = adapter;
 	adapter->dvb_adapter = dvb_adapter;
@@ -2504,14 +2517,13 @@
 	adapter->i2c_adap.algo_data         = NULL;
 	adapter->i2c_adap.id                = I2C_ALGO_BIT;
 
-	if (i2c_add_adapter(&adapter->i2c_adap) < 0) {
-		dvb_unregister_adapter (adapter->dvb_adapter);
-		return -ENOMEM;
-	}
+	ret = i2c_add_adapter(&adapter->i2c_adap);
+	if (ret < 0)
+		goto err_dvb_unregister;
 
 	dvbdemux = &adapter->demux;
 
-	dvbdemux->priv = (void *) adapter;
+	dvbdemux->priv = adapter;
 	dvbdemux->filternum = N_PID_SLOTS;
 	dvbdemux->feednum = N_PID_SLOTS;
 	dvbdemux->start_feed = dvb_start_feed;
@@ -2519,68 +2531,87 @@
 	dvbdemux->write_to_decoder = NULL;
 	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
 
-	dvb_dmx_init(&adapter->demux);
+	ret = dvb_dmx_init(&adapter->demux);
+	if (ret < 0)
+		goto err_i2c_del;
+
+	dmx = &dvbdemux->dmx;
 
 	adapter->hw_frontend.source = DMX_FRONTEND_0;
-
 	adapter->dmxdev.filternum = N_PID_SLOTS;
-	adapter->dmxdev.demux = &dvbdemux->dmx;
+	adapter->dmxdev.demux = dmx;
 	adapter->dmxdev.capabilities = 0;
 
-	dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter);
+	ret = dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter);
+	if (ret < 0)
+		goto err_dmx_release;
 
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+	ret = dmx->add_frontend(dmx, &adapter->hw_frontend);
 	if (ret < 0)
-		return ret;
+		goto err_dmxdev_release;
 
 	adapter->mem_frontend.source = DMX_MEMORY_FE;
 
-	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
+	ret = dmx->add_frontend(dmx, &adapter->mem_frontend);
 	if (ret < 0)
-		return ret;
+		goto err_remove_hw_frontend;
 
-	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+	ret = dmx->connect_frontend(dmx, &adapter->hw_frontend);
 	if (ret < 0)
-		return ret;
+		goto err_remove_mem_frontend;
 
 	dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
 
 	frontend_init(adapter);
+out:
+	return ret;
 
-	return 0;
+err_remove_mem_frontend:
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
+err_remove_hw_frontend:
+	dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
+err_dmxdev_release:
+	dvb_dmxdev_release(&adapter->dmxdev);
+err_dmx_release:
+	dvb_dmx_release(&adapter->demux);
+err_i2c_del:
+	i2c_del_adapter(&adapter->i2c_adap);
+err_dvb_unregister:
+	dvb_unregister_adapter(adapter->dvb_adapter);
+err_halt:
+	driver_halt(pdev);
+	goto out;
 }
 
 static void skystar2_remove(struct pci_dev *pdev)
 {
-	struct adapter *adapter;
+	struct adapter *adapter = pci_get_drvdata(pdev);
 	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
 
-	if (pdev == NULL)
+	if (!adapter)
 		return;
 
-	adapter = pci_get_drvdata(pdev);
-
-	if (adapter != NULL) {
 		dvb_net_release(&adapter->dvbnet);
 		dvbdemux = &adapter->demux;
+	dmx = &dvbdemux->dmx;
 
-		dvbdemux->dmx.close(&dvbdemux->dmx);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
-		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
+	dmx->close(dmx);
+	dmx->remove_frontend(dmx, &adapter->hw_frontend);
+	dmx->remove_frontend(dmx, &adapter->mem_frontend);
 
 		dvb_dmxdev_release(&adapter->dmxdev);
-		dvb_dmx_release(&adapter->demux);
+	dvb_dmx_release(dvbdemux);
+
+	if (adapter->fe != NULL)
+		dvb_unregister_frontend(adapter->fe);
 
-		if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe);
+	dvb_unregister_adapter(adapter->dvb_adapter);
 
-		if (adapter->dvb_adapter != NULL) {
 			i2c_del_adapter(&adapter->i2c_adap);
 
-			dvb_unregister_adapter(adapter->dvb_adapter);
-		}
 		driver_halt(pdev);
 	}
-}
 
 static struct pci_device_id skystar2_pci_tbl[] = {
 	{0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/b2c2/b2c2-usb-core.c linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/b2c2-usb-core.c
--- linux-2.6.11-rc2/drivers/media/dvb/b2c2/b2c2-usb-core.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/b2c2/b2c2-usb-core.c	2005-01-20 19:56:37.000000000 +0100
@@ -33,7 +33,7 @@
 }
 
 static int debug;
-module_param(debug, int, 0x644);
+module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able)).");
 
 #define deb_info(args...) dprintk(0x01,args)
@@ -89,12 +89,22 @@
 
 /* request types */
 typedef enum {
+
+/* something is wrong with this part
 	RTYPE_READ_DW         = (1 << 6),
 	RTYPE_WRITE_DW_1      = (3 << 6),
 	RTYPE_READ_V8_MEMORY  = (6 << 6),
 	RTYPE_WRITE_V8_MEMORY = (7 << 6),
 	RTYPE_WRITE_V8_FLASH  = (8 << 6),
 	RTYPE_GENERIC         = (9 << 6),
+*/
+	RTYPE_READ_DW = (3 << 6),
+	RTYPE_WRITE_DW_1 = (1 << 6),
+	
+	RTYPE_READ_V8_MEMORY  = (6 << 6),
+	RTYPE_WRITE_V8_MEMORY = (7 << 6),
+	RTYPE_WRITE_V8_FLASH  = (8 << 6),
+	RTYPE_GENERIC         = (9 << 6),
 } b2c2_usb_request_type_t;
 
 /* request */
@@ -391,9 +401,9 @@
 		}
 	/* initialising and submitting iso urbs */
 	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
-		deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
 		int frame_offset = 0;
 		struct urb *urb = b2c2->iso_urb[i];
+		deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
 
 		urb->dev = b2c2->udev;
 		urb->context = b2c2;
diff -uraN b/drivers/media/dvb/dibusb/dvb-dibusb.c a/drivers/media/dvb/dibusb/dvb-dibusb.c
--- b/drivers/media/dvb/dibusb/dvb-dibusb.c	2005-01-21 15:27:02.000000000 +0100
+++ a/drivers/media/dvb/dibusb/dvb-dibusb.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1032 +0,0 @@
-/*
- * 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)
- *
- * Remote control code added by David Matthews (dm@prolingua.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, version 2.
- *
- * Acknowledgements
- *
- *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- *  sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
- *
- * 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 <linux/input.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_filter.h"
-#include "dvb_net.h"
-#include "dvb_frontend.h"
-#include "dib3000.h"
-
-#include "dvb-dibusb.h"
-
-
-/* debug */
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(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,8=ts,16=err,32=rc (|-able)).");
-#else
-#define dprintk(args...)
-#define debug_dump(b,l)
-#endif
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_alot(args...) dprintk(0x04,args)
-#define deb_ts(args...)   dprintk(0x08,args)
-#define deb_err(args...)   dprintk(0x10,args)
-#define deb_rc(args...)   dprintk(0x20,args)
-
-static int pid_parse;
-module_param(pid_parse, int, 0x644);
-MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-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 ((ret = down_interruptible(&dib->usb_sem)))
-		return ret;
-
-	if (dib->feedcount &&
-		wbuf[0] == DIBUSB_REQ_I2C_WRITE &&
-		dib->dibdev->parm->type == DIBUSB1_1)
-		deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
-				"(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
-			
-	debug_dump(wbuf,wlen);
-
-	ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
-			dib->dibdev->parm->cmd_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, and no error before */
-	if (!ret && rbuf && rlen) {
-		ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
-				dib->dibdev->parm->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_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 void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
-	struct usb_dibusb *dib = urb->context;
-
-	deb_ts("urb complete feedcount: %d, status: %d\n",dib->feedcount,urb->status);
-
-	if (dib->feedcount > 0 && urb->status == 0) {
-		deb_ts("URB return len: %d\n",urb->actual_length);
-		if (urb->actual_length % 188)
-			deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
-
-		/* Francois recommends to drop not full-filled packets, even if they may 
-		 * contain valid TS packets
-		 */
-		if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready)
-		dvb_dmx_swfilter_packets(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length/188);
-		else
-			deb_ts("URB dropped because of the " 
-					"actual_length or !dvb_is_ready (%d).\n",dib->dvb_is_ready);
-	} else 
-		deb_ts("URB dropped because of feedcount or status.\n");
-
-		usb_submit_urb(urb,GFP_KERNEL);
-}
-
-static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff)
-{
-	if (dib->dibdev->parm->firmware_bug && dib->feedcount) {
-		deb_ts("stop feeding\n");
-		if (dib->xfer_ops.fifo_ctrl != NULL) {
-			if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
-				err("error while inhibiting fifo.");
-				return -ENODEV;
-			}
-		} else {
-			err("fifo_ctrl is not set.");
-			return -ENODEV;
-		}
-	}
-
-	dib->feedcount += onoff ? 1 : -1;
-
-	if (dib->pid_parse) {
-	if (dib->xfer_ops.pid_ctrl != NULL) {
-		if (dib->xfer_ops.pid_ctrl(dib->fe,pid,onoff) < 0) {
-		err("no free pid in list.");
-		return -ENODEV;
-	}
-	} else {
-		err("no pid ctrl callback.");
-		return -ENODEV;
-	}
-	}
-	/*
-	 * start the feed, either if there is the firmware bug or
-	 * if this was the first pid to set.
-	 */
-	if (dib->dibdev->parm->firmware_bug || dib->feedcount == onoff) {
-
-		deb_ts("controlling pid parser\n");
-		if (dib->xfer_ops.pid_parse != NULL) {
-			if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
-				err("could not handle pid_parser");
-			}
-		}
-
-		deb_ts("start feeding\n");
-		if (dib->xfer_ops.fifo_ctrl != NULL) {
-			if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
-				err("error while enabling fifo.");
-				return -ENODEV;
-			}
-		} else {
-			err("fifo_ctrl is not set.");
-			return -ENODEV;
-}
-	}
-	return 0;
-}
-
-static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
-	deb_ts("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
-	dvbdmxfeed->priv = dib;
-	return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,1);
-}
-
-static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-	struct usb_dibusb *dib = (struct usb_dibusb *) dvbdmxfeed->priv;
-	if (dib == NULL) {
-		err("dib in dmxfeed->priv was NULL");
-		return -EINVAL;
-}
-	deb_ts("dvbdmxfeed pid: 0x%04x, feedtype: %d\n",
-			dvbdmxfeed->pid, dvbdmxfeed->type);
-	return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,0);
-}
-
-/* Table to map raw key codes to key events.  This should not be hard-wired
-   into the kernel.  */
-static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
-{
-	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
-	{ 0x00, 0xff, 0x16, KEY_POWER },
-	{ 0x00, 0xff, 0x10, KEY_MUTE },
-	{ 0x00, 0xff, 0x03, KEY_1 },
-	{ 0x00, 0xff, 0x01, KEY_2 },
-	{ 0x00, 0xff, 0x06, KEY_3 },
-	{ 0x00, 0xff, 0x09, KEY_4 },
-	{ 0x00, 0xff, 0x1d, KEY_5 },
-	{ 0x00, 0xff, 0x1f, KEY_6 },
-	{ 0x00, 0xff, 0x0d, KEY_7 },
-	{ 0x00, 0xff, 0x19, KEY_8 },
-	{ 0x00, 0xff, 0x1b, KEY_9 },
-	{ 0x00, 0xff, 0x15, KEY_0 },
-	{ 0x00, 0xff, 0x05, KEY_CHANNELUP },
-	{ 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
-	{ 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
-	{ 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
-	{ 0x00, 0xff, 0x11, KEY_RECORD },
-	{ 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-	{ 0x00, 0xff, 0x14, KEY_PLAY },
-	{ 0x00, 0xff, 0x1a, KEY_STOP },
-	{ 0x00, 0xff, 0x40, KEY_REWIND },
-	{ 0x00, 0xff, 0x12, KEY_FASTFORWARD },
-	{ 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-	{ 0x00, 0xff, 0x4c, KEY_PAUSE },
-	{ 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
-	{ 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
-	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
-	{ 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
-	{ 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
-	{ 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
-	{ 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
-	{ 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
-	{ 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
-	/* Key codes for the KWorld/ADSTech/JetWay remote. */
-	{ 0x86, 0x6b, 0x12, KEY_POWER },
-	{ 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
-	{ 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
-	{ 0x86, 0x6b, 0x0b, KEY_EPG },
-	{ 0x86, 0x6b, 0x10, KEY_MUTE },
-	{ 0x86, 0x6b, 0x01, KEY_1 },
-	{ 0x86, 0x6b, 0x02, KEY_2 },
-	{ 0x86, 0x6b, 0x03, KEY_3 },
-	{ 0x86, 0x6b, 0x04, KEY_4 },
-	{ 0x86, 0x6b, 0x05, KEY_5 },
-	{ 0x86, 0x6b, 0x06, KEY_6 },
-	{ 0x86, 0x6b, 0x07, KEY_7 },
-	{ 0x86, 0x6b, 0x08, KEY_8 },
-	{ 0x86, 0x6b, 0x09, KEY_9 },
-	{ 0x86, 0x6b, 0x0a, KEY_0 },
-	{ 0x86, 0x6b, 0x18, KEY_ZOOM },
-	{ 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
-	{ 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
-	{ 0x86, 0x6b, 0x00, KEY_UNDO },
-	{ 0x86, 0x6b, 0x1d, KEY_RECORD },
-	{ 0x86, 0x6b, 0x0d, KEY_STOP },
-	{ 0x86, 0x6b, 0x0e, KEY_PAUSE },
-	{ 0x86, 0x6b, 0x16, KEY_PLAY },
-	{ 0x86, 0x6b, 0x11, KEY_BACK },
-	{ 0x86, 0x6b, 0x19, KEY_FORWARD },
-	{ 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
-	{ 0x86, 0x6b, 0x15, KEY_ESC },
-	{ 0x86, 0x6b, 0x1a, KEY_UP },
-	{ 0x86, 0x6b, 0x1e, KEY_DOWN },
-	{ 0x86, 0x6b, 0x1f, KEY_LEFT },
-	{ 0x86, 0x6b, 0x1b, KEY_RIGHT },
-};
-
-/*
- * Read the remote control and feed the appropriate event.
- * NEC protocol is used for remote controls
- */
-static int dibusb_read_remote_control(struct usb_dibusb *dib)
-{
-	u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
-	int ret;
-	int i;
-	if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
-		return ret;
-
-	switch (rb[0]) {
-		case DIBUSB_RC_NEC_KEY_PRESSED:
-			/* rb[1-3] is the actual key, rb[4] is a checksum */
-			deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
-				rb[1], rb[2], rb[3], rb[4]);
-
-			if ((0xff - rb[3]) != rb[4]) {
-				deb_rc("remote control checksum failed.\n");
-				break;
-			}
-
-			/* See if we can match the raw key code. */
-			for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) {
-				if (rc_keys[i].c0 == rb[1] &&
-					rc_keys[i].c1 == rb[2] &&
-				    rc_keys[i].c2 == rb[3]) {
-					dib->rc_input_event = rc_keys[i].key;
-					deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
-					/* Signal down and up events for this key. */
-					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
-					input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
-					input_sync(&dib->rc_input_dev);
-					break;
-				}
-			}
-			break;
-		case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
-			break;
-		case DIBUSB_RC_NEC_KEY_REPEATED:
-			/* rb[1]..rb[4] are always zero.*/
-			/* Repeats often seem to occur so for the moment just ignore this. */
-			deb_rc("Key repeat\n");
-			break;
-		default:
-			break;
-	}
-	
-	return 0;
-}
-
-#define RC_QUERY_INTERVAL (100)	/* milliseconds */
-
-/* Remote-control poll function - called every RC_QUERY_INTERVAL ms to see
-   whether the remote control has received anything. */
-static void dibusb_query_rc (void *data)
-{
-	struct usb_dibusb *dib = (struct usb_dibusb *) data;
-	/* TODO: need a lock here.  We can simply skip checking for the remote control
-	   if we're busy. */
-	dibusb_read_remote_control(dib);
-	schedule_delayed_work(&dib->rc_query_work,
-			      msecs_to_jiffies(RC_QUERY_INTERVAL));
-}
-
-/*
- * Cypress controls
- */
-
-#if 0
-/*
- * #if 0'ing the following functions as they are not in use _now_,
- * but probably will be sometime.
- */
-
-/*
- * do not use this, just a workaround for a bug,
- * which will hopefully 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);
-}
-
-/*
- * 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);
-}
-
-#endif
-static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
-	return dibusb_readwrite_usb(dib,buf,len,NULL,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);
-}
-
-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 thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
-		dvb_frontend_parameters* params);
-
-static struct dib3000_config thomson_cable_eu_config = {
-	.demod_address = 0x10,
-	.pll_addr = 194,
-	.pll_set = thomson_cable_eu_pll_set,
-};
-
-static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
-		dvb_frontend_parameters* params)
-{
-	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-	u8 buf[4];
-	struct i2c_msg msg = {
-		.addr = thomson_cable_eu_config.pll_addr,
-		.flags = 0,
-		.buf = buf,
-		.len = sizeof(buf)
-	};
-	u32 tfreq = (params->frequency + 36125000) / 62500;
-	int vu,p0,p1,p2;
-
-	if (params->frequency > 403250000)
-		vu = 1, p2 = 1, p1 = 0, p0 = 1;
-	else if (params->frequency > 115750000)
-		vu = 0, p2 = 1, p1 = 1, p0 = 0;
-	else if (params->frequency > 44250000)
-		vu = 0, p2 = 0, p1 = 1, p0 = 1;
-	else
-		return -EINVAL;
-
-	buf[0] = (tfreq >> 8) & 0x7f;
-	buf[1] = tfreq & 0xff;
-   	buf[2] = 0x8e;
-   	buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
-
-	if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-	return 0;
-}
-
-static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
-		dvb_frontend_parameters *params);
-
-static struct dib3000_config panasonic_cofdm_env57h1xd5 = {
-	.demod_address = 0x18,
-	.pll_addr = 192,
-	.pll_set = panasonic_cofdm_env57h1xd5_pll_set,
-};
-
-static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
-		dvb_frontend_parameters *params)
-{
-	struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
-	u8 buf[4];
-	u32 freq = params->frequency;
-	u32 tfreq = (freq + 36125000) / 1000000 * 6 + 1;
-	u8 TA, T210, R210, ctrl1, cp210, p4321;
-	struct i2c_msg msg = {
-		.addr = panasonic_cofdm_env57h1xd5.pll_addr,
-		.flags = 0,
-		.buf = buf,
-		.len = sizeof(buf)
-	};
-
-	if (freq > 858000000) {
-		err("frequency cannot be larger than 858 MHz.");
-		return -EINVAL;
-	}
-
-	// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
-	TA = 1;
-	T210 = 0;
-	R210 = 0x2;
-	ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
-
-// ********    CHARGE PUMP CONFIG vs RF FREQUENCIES     *****************
-	if (freq < 470000000)
-		cp210 = 2;  // VHF Low and High band ch E12 to E4 to E12
-	else if (freq < 526000000)
-		cp210 = 4;  // UHF band Ch E21 to E27
-	else // if (freq < 862000000)
-		cp210 = 5;  // UHF band ch E28 to E69
-
-//*********************    BW select  *******************************
-	if (freq < 153000000)
-		p4321  = 1; // BW selected for VHF low
-	else if (freq < 470000000)
-		p4321  = 2; // BW selected for VHF high E5 to E12
-	else // if (freq < 862000000)
-		p4321  = 4; // BW selection for UHF E21 to E69
-
-	buf[0] = (tfreq >> 8) & 0xff;
-	buf[1] = (tfreq >> 0) & 0xff;
-	buf[2] = 0xff & ctrl1;
-	buf[3] =  (cp210 << 5) | (p4321);
-
-	if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	msleep(1);
-	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 void frontend_init(struct usb_dibusb* dib)
-{
-	switch (dib->dibdev->parm->type) {
-		case DIBUSB1_1:
-		case DIBUSB1_1_AN2235:
-	dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap,&dib->xfer_ops);
-			break;
-		case DIBUSB2_0:
-			dib->fe = dib3000mc_attach(&panasonic_cofdm_env57h1xd5,&dib->i2c_adap, &dib->xfer_ops);
-			break;
-	}
-
-	if (dib->fe == NULL) {
-		printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n",
-		       le16_to_cpu(dib->udev->descriptor.idVendor),
-		       le16_to_cpu(dib->udev->descriptor.idProduct));
-	} else {
-		if (dvb_register_frontend(dib->adapter, dib->fe)) {
-			printk("dvb-dibusb: Frontend registration failed!\n");
-			if (dib->fe->ops->release)
-				dib->fe->ops->release(dib->fe);
-			dib->fe = NULL;
-		}
-	}
-}
-
-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;
-	}
-	dib->adapter->priv = dib;
-
-	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;
-
-	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;
-	/* get pidcount from demod */
-	dib->demux.feednum = dib->demux.filternum = 16;
-	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);
-
-	frontend_init(dib);
-
-	/* Start the remote-control polling. */
-	schedule_delayed_work(&dib->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL));
-
-	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:
-	dib->dvb_is_ready = 1;
-	return 0;
-}
-
-static int dibusb_dvb_exit(struct usb_dibusb *dib)
-{
-	cancel_delayed_work(&dib->rc_query_work);
-	flush_scheduled_work();
-	input_unregister_device(&dib->rc_input_dev);
-
-	dib->dvb_is_ready = 0;
-	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);
-	if (dib->fe != NULL) dvb_unregister_frontend(dib->fe);
-	i2c_del_adapter(&dib->i2c_adap);
-	dvb_unregister_adapter(dib->adapter);
-
-	return 0;
-}
-
-static int dibusb_exit(struct usb_dibusb *dib)
-{
-	int i;
-	if (dib->urb_list != NULL) {
-		for (i = 0; i < dib->dibdev->parm->num_urbs; i++) {
-			if (dib->urb_list[i] != NULL) {
-			deb_info("killing URB no. %d.\n",i);
-
-				/* stop the URBs */
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
-				usb_unlink_urb(dib->urb_list[i]);
-#else
-				usb_kill_urb(dib->urb_list[i]);
-#endif
-			
-			deb_info("freeing URB no. %d.\n",i);
-				/* free the URBs */
-				usb_free_urb(dib->urb_list[i]);
-			}
-		}
-		/* free the urb array */
-		kfree(dib->urb_list);
-		}
-
-	pci_free_consistent(NULL,
-		dib->dibdev->parm->urb_buf_size*dib->dibdev->parm->num_urbs,dib->buffer,
-		dib->dma_handle);
-	return 0;
-}
-
-static int dibusb_init(struct usb_dibusb *dib)
-{
-	int ret,i,bufsize;
-	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,usb_sndbulkpipe(dib->udev,dib->dibdev->parm->cmd_pipe));
-	usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->result_pipe));
-	usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe));
-
-	/* allocate the array for the data transfer URBs */
-	dib->urb_list = kmalloc(dib->dibdev->parm->num_urbs*sizeof(struct urb *),GFP_KERNEL);
-	if (dib->urb_list == NULL)
-		return -ENOMEM;
-	memset(dib->urb_list,0,dib->dibdev->parm->num_urbs*sizeof(struct urb *));
-
-	bufsize = dib->dibdev->parm->num_urbs*dib->dibdev->parm->urb_buf_size;
-	deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
-	/* allocate the actual buffer for the URBs */
-	if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
-		deb_info("not enough memory.\n");
-		dibusb_exit(dib);
-		return -ENOMEM;
-	}
-	deb_info("allocation complete\n");
-	memset(dib->buffer,0,bufsize);
-
-	/* allocate and submit the URBs */
-	for (i = 0; i < dib->dibdev->parm->num_urbs; i++) {
-		if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_KERNEL))) {
-		dibusb_exit(dib);
-		return -ENOMEM;
-	}
-		deb_info("submitting URB no. %d\n",i);
-
-		usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
-				usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe),
-				&dib->buffer[i*dib->dibdev->parm->urb_buf_size],
-				dib->dibdev->parm->urb_buf_size,
-				dibusb_urb_complete, dib);
-
-		dib->urb_list[i]->transfer_flags = 0;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
-		dib->urb_list[i]->timeout = 0;
-#endif
-
-		if ((ret = usb_submit_urb(dib->urb_list[i],GFP_KERNEL))) {
-			err("could not submit buffer urb no. %d\n",i);
-			dibusb_exit(dib);
-			return ret;
-		}
-	}
-
-	dib->dvb_is_ready = 0;
-
-	/* Initialise the remote-control structures.*/
-	init_input_dev(&dib->rc_input_dev);
-
-	dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
-	dib->rc_input_dev.keycodesize = sizeof(unsigned char);
-	dib->rc_input_dev.keycodemax = KEY_MAX;
-	dib->rc_input_dev.name = DRIVER_DESC " remote control";
-
-	for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
-		set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
-
-	input_register_device(&dib->rc_input_dev);
-
-	dib->rc_input_event = KEY_MAX;
-
-	INIT_WORK(&dib->rc_query_work, dibusb_query_rc, dib);
-
-	dibusb_hw_wakeup(dib);
-
-	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;
-	const char **fws;
-	u16 addr;
-	u8 *b,*p;
-	int ret = 0,i;
-
-	fws = dibdev->parm->fw_filenames;
-
-	for (i = 0; i < sizeof(fws)/sizeof(const char*); i++) {
-		if ((ret = request_firmware(&fw, fws[i], &udev->dev)) == 0) {
-			info("using firmware file (%s).",fws[i]);
-			break;
-		}
-		deb_info("tried to find '%s' firmware - unsuccessful. (%d)\n",
-				fws[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,dibdev->parm->usb_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[0]);
-				ret = -EINVAL;
-				break;
-			}
-			i += 5 + b[0];
-		}
-		/* length in ret */
-		if (ret > 0)
-			ret = 0;
-		/* restart the CPU */
-		reset = 0;
-		if (ret || dibusb_writemem(udev,dibdev->parm->usb_cpu_csreg,&reset,1) != 1) {
-			err("could not restart the USB controller CPU.");
-			ret = -EINVAL;
-		}
-
-		kfree(p);
-	} 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 == le16_to_cpu(udev->descriptor.idProduct) ||
-			dibusb_devices[i].warm_product_id == le16_to_cpu(udev->descriptor.idProduct)) {
-			dibdev = &dibusb_devices[i];
-
-			cold = dibdev->cold_product_id == le16_to_cpu(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",le16_to_cpu(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->pid_parse = 1;
-		switch (udev->speed) {
-			case USB_SPEED_LOW:
-				err("cannot handle USB speed because it is to sLOW.");
-				break;
-			case USB_SPEED_FULL:
-				info("running at FULL speed, will use pid parsing.");
-				break;
-			case USB_SPEED_HIGH:
-				if (!pid_parse) {
-					dib->pid_parse = 0;
-				info("running at HIGH speed, will deliver the complete TS.");
-				} else
-					info("running at HIGH speed, will use pid_parsing anyway.");
-				break;
-			case USB_SPEED_UNKNOWN: /* fall through */
-			default:
-				err("cannot handle USB speed because it is unkown.");
-				break;
-		}
-
-		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");


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

* [PATCH 5/9] add ATSC support, misc fixes
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
                   ` (3 preceding siblings ...)
  2005-01-22 17:34 ` [PATCH 4/9] support nxt2002 frontend, misc skystar2 fixes Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 6/9] refactoring Johannes Stezenbach
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] dvb-core: vfree() checking cleanups, patch by Domen Puncer
- [DVB] dvb-core: fix handling of discontinuity indicator in section filter,
        bug reported by Frank Rosengart
- [DVB] dvb-core: handle PUSI in section filter correctly, patch by Emard,
        bug reported by Patrick Valsecchi
- [DVB] dvb-core: add support for ATSC/VSB frontends, patch by Taylor Jacob
- [DVB] dvb-core: removed semi-colon from a very wrong place; FE_ENABLE_HIGH_LNB_VOLTAGE
        kernel oops; thanks to Christophe Massiot
- [DVB] dvb-core: Fixed slow tuning problems, remove frequeny bending support from
        frontend code, code simplification

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_demux.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_demux.c
--- linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_demux.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_demux.c	2005-01-20 19:56:37.000000000 +0100
@@ -247,7 +249,22 @@
 		}
 
 /* 
-** Losless Section Demux 1.4 by Emard
+** Losless Section Demux 1.4.1 by Emard
+** Valsecchi Patrick:
+**  - middle of section A  (no PUSI)
+**  - end of section A and start of section B 
+**    (with PUSI pointing to the start of the second section)
+**  
+**  In this case, without feed->pusi_seen you'll receive a garbage section
+**  consisting of the end of section A. Basically because tsfeedp
+**  is incemented and the use=0 condition is not raised
+**  when the second packet arrives.
+**
+** Fix:
+** when demux is started, let feed->pusi_seen = 0 to
+** prevent initial feeding of garbage from the end of
+** previous section. When you for the first time see PUSI=1
+** then set feed->pusi_seen = 1
 */
 static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len)
 {
@@ -293,7 +310,12 @@
 		sec->seclen = seclen;
 		sec->crc_val = ~0;
 		/* dump [secbuf .. secbuf+seclen) */
+		if(feed->pusi_seen)
 		dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+		else
+			printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
 		sec->secbufp += seclen; /* secbufp and secbuf moving together is */
 		sec->secbuf += seclen; /* redundand but saves pointer arithmetic */
 		}
@@ -305,7 +327,7 @@
 static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
 {
 	u8 p, count;
-	int ccok;
+	int ccok, dc_i = 0;
 	u8 cc;
 
 	count = payload(buf);
@@ -316,31 +338,41 @@
 	p = 188-count; /* payload start */
 
 	cc = buf[3] & 0x0f;
-	ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
+	ccok = ((feed->cc + 1) & 0x0f) == cc;
 	feed->cc = cc;
-	if(ccok == 0)
-	{
+
+	if (buf[3] & 0x20) {
+		/* adaption field present, check for discontinuity_indicator */
+		if ((buf[4] > 0) && (buf[5] & 0x80))
+			dc_i = 1;
+	}
+
+	if (!ccok || dc_i) {
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
 		printk("dvb_demux.c discontinuity detected %d bytes lost\n", count);
 		/* those bytes under sume circumstances will again be reported
 		** in the following dvb_dmx_swfilter_section_new
 		*/
 #endif
+		/* Discontinuity detected. Reset pusi_seen = 0 to
+		** stop feeding of suspicious data until next PUSI=1 arrives
+		*/
+		feed->pusi_seen = 0;
 		dvb_dmx_swfilter_section_new(feed);
 		return 0;
 	}
 
-	if(buf[1] & 0x40)
-	{
+	if (buf[1] & 0x40) {
 		// PUSI=1 (is set), section boundary is here
-		if(count > 1 && buf[p] < count)
-		{
+		if (count > 1 && buf[p] < count) {
 			const u8 *before = buf+p+1;
 			u8 before_len = buf[p];
 			const u8 *after = before+before_len;
 			u8 after_len = count-1-before_len;
 
 			dvb_dmx_swfilter_section_copy_dump(feed, before, before_len);
+			/* before start of new section, set pusi_seen = 1 */
+			feed->pusi_seen = 1;
 			dvb_dmx_swfilter_section_new(feed);
 			dvb_dmx_swfilter_section_copy_dump(feed, after, after_len);
 		}
@@ -349,9 +381,7 @@
 			if(count > 0)
 				printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
 #endif
-	}
-	else
-	{
+	} else {
 		// PUSI=0 (is not set), no section boundary
 		const u8 *entire = buf+p;
 		u8 entire_len = count;
@@ -784,10 +814,8 @@
 	}
 
 #ifndef NOBUFS
-	if (feed->buffer) { 
 		vfree(feed->buffer);
 		feed->buffer=0;
-	}
 #endif
 
 	feed->state = DMX_STATE_FREE;
@@ -1055,10 +1094,8 @@
 		return -EINVAL;
 	}
 #ifndef NOBUFS
-	if (dvbdmxfeed->buffer) {
 		vfree(dvbdmxfeed->buffer);
 		dvbdmxfeed->buffer=0;
-	}
 #endif
 	dvbdmxfeed->state=DMX_STATE_FREE;
 
@@ -1269,9 +1317,7 @@
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
 	dmx_unregister_demux(dmx);
-	if (dvbdemux->filter)
 		vfree(dvbdemux->filter);
-	if (dvbdemux->feed)
 		vfree(dvbdemux->feed);
 	return 0;
 }
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_demux.h linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_demux.h
--- linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_demux.h	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_demux.h	2005-01-20 19:56:37.000000000 +0100
@@ -93,6 +93,7 @@
         enum dmx_ts_pes pes_type;
 
         int cc;
+        int pusi_seen; /* prevents feeding of garbage from previous section */
 
         u16 peslen;
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_frontend.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_frontend.c
--- linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_frontend.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_frontend.c	2005-01-20 19:56:37.000000000 +0100
@@ -89,9 +89,36 @@
 
 static DECLARE_MUTEX(frontend_mutex);
 
+struct dvb_frontend_private {
+
+	struct dvb_device *dvbdev;
+	struct dvb_frontend_parameters parameters;
+	struct dvb_fe_events events;
+	struct semaphore sem;
+	struct list_head list_head;
+	wait_queue_head_t wait_queue;
+	pid_t thread_pid;
+	unsigned long release_jiffies;
+	int state;
+	int bending;
+	int lnb_drift;
+	int inversion;
+	int auto_step;
+	int auto_sub_step;
+	int started_auto_step;
+	int min_delay;
+	int max_drift;
+	int step_size;
+	int exit;
+	int wakeup;
+	fe_status_t status;
+};
+
+
 static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 {
-	struct dvb_fe_events *events = &fe->events;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_fe_events *events = &fepriv->events;
 	struct dvb_frontend_event *e;
 	int wp;
 
@@ -109,7 +136,7 @@
 
 	e = &events->events[events->eventw];
 
-	memcpy (&e->parameters, &fe->parameters, 
+	memcpy (&e->parameters, &fepriv->parameters,
 		sizeof (struct dvb_frontend_parameters));
 
 	if (status & FE_HAS_LOCK)
@@ -128,7 +155,8 @@
 static int dvb_frontend_get_event(struct dvb_frontend *fe,
 			    struct dvb_frontend_event *event, int flags)
 {
-        struct dvb_fe_events *events = &fe->events;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	struct dvb_fe_events *events = &fepriv->events;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -143,12 +171,12 @@
                 if (flags & O_NONBLOCK)
                         return -EWOULDBLOCK;
 
-		up(&fe->sem);
+		up(&fepriv->sem);
 
                 ret = wait_event_interruptible (events->wait_queue,
                                                 events->eventw != events->eventr);
 
-        	if (down_interruptible (&fe->sem))
+		if (down_interruptible (&fepriv->sem))
 			return -ERESTARTSYS;
 
                 if (ret < 0)
@@ -206,27 +234,28 @@
 {
 	int autoinversion;
 	int ready = 0;
-	int original_inversion = fe->parameters.inversion;
-	u32 original_frequency = fe->parameters.frequency;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	int original_inversion = fepriv->parameters.inversion;
+	u32 original_frequency = fepriv->parameters.frequency;
 
 	/* are we using autoinversion? */
 	autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
-			 (fe->parameters.inversion == INVERSION_AUTO));
+			 (fepriv->parameters.inversion == INVERSION_AUTO));
 
 	/* setup parameters correctly */
 	while(!ready) {
 		/* calculate the lnb_drift */
-		fe->lnb_drift = fe->auto_step * fe->step_size;
+		fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
 
 		/* 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;
+		if (fepriv->lnb_drift > fepriv->max_drift) {
+			fepriv->auto_step = 0;
+			fepriv->auto_sub_step = 0;
+			fepriv->lnb_drift = 0;
 		}
 
 		/* perform inversion and +/- zigzag */
-		switch(fe->auto_sub_step) {
+		switch(fepriv->auto_sub_step) {
 		case 0:
 			/* try with the current inversion and current drift setting */
 			ready = 1;
@@ -235,68 +264,70 @@
 		case 1:
 			if (!autoinversion) break;
 
-			fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
 			ready = 1;
 			break;
 
 		case 2:
-			if (fe->lnb_drift == 0) break;
+			if (fepriv->lnb_drift == 0) break;
 		    
-			fe->lnb_drift = -fe->lnb_drift;
+			fepriv->lnb_drift = -fepriv->lnb_drift;
 			ready = 1;
 			break;
 	    
 		case 3:
-			if (fe->lnb_drift == 0) break;
+			if (fepriv->lnb_drift == 0) break;
 			if (!autoinversion) break;
 		    
-			fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
-			fe->lnb_drift = -fe->lnb_drift;
+			fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+			fepriv->lnb_drift = -fepriv->lnb_drift;
 			ready = 1;
 			break;
 		    
 		default:
-			fe->auto_step++;
-			fe->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
+			fepriv->auto_step++;
+			fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
 			break;
 		}
 	    
-		if (!ready) fe->auto_sub_step++;
+		if (!ready) fepriv->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 ((fepriv->auto_step == fepriv->started_auto_step) &&
+	    (fepriv->auto_sub_step == 0) && check_wrapped) {
 		return 1;
 		}
 
 	dprintk("%s: drift:%i inversion:%i auto_step:%i "
 		"auto_sub_step:%i started_auto_step:%i\n",
-		__FUNCTION__, fe->lnb_drift, fe->inversion,
-		fe->auto_step, fe->auto_sub_step, fe->started_auto_step);
+		__FUNCTION__, fepriv->lnb_drift, fepriv->inversion,
+		fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
     
 	/* set the frontend itself */
-	fe->parameters.frequency += fe->lnb_drift;
+	fepriv->parameters.frequency += fepriv->lnb_drift;
 	if (autoinversion)
-		fe->parameters.inversion = fe->inversion;
+		fepriv->parameters.inversion = fepriv->inversion;
 	if (fe->ops->set_frontend)
-		fe->ops->set_frontend(fe, &fe->parameters);
+		fe->ops->set_frontend(fe, &fepriv->parameters);
 
-	fe->parameters.frequency = original_frequency;
-	fe->parameters.inversion = original_inversion;
+	fepriv->parameters.frequency = original_frequency;
+	fepriv->parameters.inversion = original_inversion;
 
-	fe->auto_sub_step++;
+	fepriv->auto_sub_step++;
 	return 0;
 }
 
 static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
-	if (fe->exit)
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+
+	if (fepriv->exit)
 		return 1;
 
-	if (fe->dvbdev->writers == 1)
-		if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ)
+	if (fepriv->dvbdev->writers == 1)
+		if (jiffies - fepriv->release_jiffies > dvb_shutdown_timeout * HZ)
 			return 1;
 
 	return 0;
@@ -304,8 +335,10 @@
 
 static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
 {
-	if (fe->wakeup) {
-		fe->wakeup = 0;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+
+	if (fepriv->wakeup) {
+		fepriv->wakeup = 0;
 		return 1;
 	}
 	return dvb_frontend_is_exiting(fe);
@@ -313,8 +346,10 @@
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe)
 {
-	fe->wakeup = 1;
-	wake_up_interruptible(&fe->wait_queue);
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+
+	fepriv->wakeup = 1;
+	wake_up_interruptible(&fepriv->wait_queue);
 }
 
 /*
@@ -323,6 +358,7 @@
 static int dvb_frontend_thread (void *data)
 {
 	struct dvb_frontend *fe = (struct dvb_frontend *) data;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 	unsigned long timeout;
 	char name [15];
 	int quality = 0, delay = 3*HZ;
@@ -338,14 +374,14 @@
         sigfillset (&current->blocked);
         unlock_kernel ();
 
-	fe->status = 0;
+	fepriv->status = 0;
 	dvb_frontend_init (fe);
-	fe->wakeup = 0;
+	fepriv->wakeup = 0;
 
 	while (1) {
-		up (&fe->sem);      /* is locked when we enter the thread... */
+		up(&fepriv->sem);	    /* is locked when we enter the thread... */
 
-		timeout = wait_event_interruptible_timeout(fe->wait_queue,
+		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
 							   dvb_frontend_should_wakeup(fe),
 							   delay);
 		if (0 != dvb_frontend_is_exiting (fe)) {
@@ -356,44 +392,43 @@
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_FREEZE);
 
-		if (down_interruptible (&fe->sem))
+		if (down_interruptible(&fepriv->sem))
 			break;
 
 		/* if we've got no parameters, just keep idling */
-		if (fe->state & FESTATE_IDLE) {
+		if (fepriv->state & FESTATE_IDLE) {
 			delay = 3*HZ;
 			quality = 0;
 			continue;
 		}
 
-retune:
 		/* get the frontend status */
-		if (fe->state & FESTATE_RETUNE) {
+		if (fepriv->state & FESTATE_RETUNE) {
 			s = 0;
 		} else {
 			if (fe->ops->read_status)
 				fe->ops->read_status(fe, &s);
-			if (s != fe->status) {
+			if (s != fepriv->status) {
 			dvb_frontend_add_event (fe, s);
-				fe->status = s;
+				fepriv->status = s;
 			}
 		}
 		/* 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 ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
+			fepriv->state = FESTATE_TUNED;
 
 			/* if we're tuned, then we have determined the correct inversion */
 			if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
-			    (fe->parameters.inversion == INVERSION_AUTO)) {
-				fe->parameters.inversion = fe->inversion;
+			    (fepriv->parameters.inversion == INVERSION_AUTO)) {
+				fepriv->parameters.inversion = fepriv->inversion;
 			}
 			continue;
 		}
 
 		/* 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);
+		if (fepriv->state & FESTATE_TUNED) {
+			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
 
 			/* we're tuned, and the lock is still good... */
 			if (s & FE_HAS_LOCK)
@@ -401,49 +436,49 @@
 			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;
+				fepriv->state = FESTATE_ZIGZAG_FAST;
+				fepriv->started_auto_step = fepriv->auto_step;
 				check_wrapped = 0;
 			}
 		}
 
 		/* don't actually do anything if we're in the LOSTLOCK state,
 		 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
-		if ((fe->state & FESTATE_LOSTLOCK) && 
-		    (fe->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
-			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
+		if ((fepriv->state & FESTATE_LOSTLOCK) &&
+		    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
 						continue;
 				}
 	    
 		/* don't do anything if we're in the DISEQC state, since this
 		 * might be someone with a motorized dish controlled by DISEQC.
 		 * If its actually a re-tune, there will be a SET_FRONTEND soon enough.	*/
-		if (fe->state & FESTATE_DISEQC) {
-			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
+		if (fepriv->state & FESTATE_DISEQC) {
+			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
 			continue;
 				}
 
 		/* if we're in the RETUNE state, set everything up for a brand
 		 * new scan, keeping the current inversion setting, as the next
 		 * tune is _very_ likely to require the same */
-		if (fe->state & FESTATE_RETUNE) {
-			fe->lnb_drift = 0;
-			fe->auto_step = 0;
-			fe->auto_sub_step = 0;
-			fe->started_auto_step = 0;
+		if (fepriv->state & FESTATE_RETUNE) {
+			fepriv->lnb_drift = 0;
+			fepriv->auto_step = 0;
+			fepriv->auto_sub_step = 0;
+			fepriv->started_auto_step = 0;
 			check_wrapped = 0;
 		}
 
 		/* fast zigzag. */
-		if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) {
-			delay = fe->min_delay;
+		if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+			delay = fepriv->min_delay;
 
 			/* peform a tune */
 			if (dvb_frontend_autotune(fe, check_wrapped)) {
 				/* OK, if we've run out of trials at the fast speed.
 				 * Drop back to slow for the _next_ attempt */
-				fe->state = FESTATE_SEARCHING_SLOW;
-				fe->started_auto_step = fe->auto_step;
+				fepriv->state = FESTATE_SEARCHING_SLOW;
+				fepriv->started_auto_step = fepriv->auto_step;
 				continue;
 			}
 			check_wrapped = 1;
@@ -452,15 +487,14 @@
 			 * 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;
-				goto retune;
+			if (fepriv->state & FESTATE_RETUNE) {
+				fepriv->state = FESTATE_TUNING_FAST;
 			}
 		}
 
 		/* slow zigzag */
-		if (fe->state & FESTATE_SEARCHING_SLOW) {
-			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
+		if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
 		    
 			/* Note: don't bother checking for wrapping; we stay in this
 			 * state until we get a lock */
@@ -476,7 +510,7 @@
 			fe->ops->sleep(fe);
 	}
 
-	fe->thread_pid = 0;
+	fepriv->thread_pid = 0;
 	mb();
 
 	dvb_frontend_wakeup(fe);
@@ -486,21 +520,22 @@
 static void dvb_frontend_stop(struct dvb_frontend *fe)
 {
 	unsigned long ret;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
-		fe->exit = 1;
+	fepriv->exit = 1;
 	mb();
 
-	if (!fe->thread_pid)
+	if (!fepriv->thread_pid)
 		return;
 
 	/* check if the thread is really alive */
-	if (kill_proc(fe->thread_pid, 0, 1) == -ESRCH) {
+	if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
 		printk("dvb_frontend_stop: thread PID %d already died\n",
-				fe->thread_pid);
+				fepriv->thread_pid);
 		/* make sure the mutex was not held by the thread */
-		init_MUTEX (&fe->sem);
+		init_MUTEX (&fepriv->sem);
 		return;
 	}
 
@@ -508,27 +543,28 @@
 	dvb_frontend_wakeup(fe);
 
 	/* wait until the frontend thread has exited */
-	ret = wait_event_interruptible(fe->wait_queue,0 == fe->thread_pid);
+	ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
 	if (-ERESTARTSYS != ret) {
-		fe->state = FESTATE_IDLE;
+		fepriv->state = FESTATE_IDLE;
 		return;
 	}
-	fe->state = FESTATE_IDLE;
+	fepriv->state = FESTATE_IDLE;
 
 	/* paranoia check in case a signal arrived */
-	if (fe->thread_pid)
+	if (fepriv->thread_pid)
 		printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
-				fe->thread_pid);
+				fepriv->thread_pid);
 }
 
 static int dvb_frontend_start(struct dvb_frontend *fe)
 {
 	int ret;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (fe->thread_pid) {
-		if (!fe->exit)
+	if (fepriv->thread_pid) {
+		if (!fepriv->exit)
 			return 0;
 		else
 		dvb_frontend_stop (fe);
@@ -536,12 +572,12 @@
 
 	if (signal_pending(current))
 		return -EINTR;
-	if (down_interruptible (&fe->sem))
+	if (down_interruptible (&fepriv->sem))
 		return -EINTR;
 
-	fe->state = FESTATE_IDLE;
-	fe->exit = 0;
-	fe->thread_pid = 0;
+	fepriv->state = FESTATE_IDLE;
+	fepriv->exit = 0;
+	fepriv->thread_pid = 0;
 	mb();
 
 	ret = kernel_thread (dvb_frontend_thread, fe, 0);
@@ -545,12 +581,13 @@
 	mb();
 
 	ret = kernel_thread (dvb_frontend_thread, fe, 0);
+
 	if (ret < 0) {
 		printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);
-		up(&fe->sem);
+		up(&fepriv->sem);
 		return ret;
 	}
-	fe->thread_pid = ret;
+	fepriv->thread_pid = ret;
 
 	return 0;
 }
@@ -561,11 +597,12 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 	int err = -EOPNOTSUPP;
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (!fe || fe->exit)
+	if (!fe || fepriv->exit)
 		return -ENODEV;
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -573,7 +610,7 @@
 	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
 		return -EPERM;
 
-	if (down_interruptible (&fe->sem))
+	if (down_interruptible (&fepriv->sem))
 		return -ERESTARTSYS;
 
 	switch (cmd) {
@@ -617,48 +654,48 @@
 	case FE_DISEQC_RESET_OVERLOAD:
 		if (fe->ops->diseqc_reset_overload) {
 			err = fe->ops->diseqc_reset_overload(fe);
-			fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_MASTER_CMD:
 		if (fe->ops->diseqc_send_master_cmd) {
 			err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
-			fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_BURST:
 		if (fe->ops->diseqc_send_burst) {
 			err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
-			fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
 	case FE_SET_TONE:
 		if (fe->ops->set_tone) {
 			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
-			fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
 	case FE_SET_VOLTAGE:
 		if (fe->ops->set_voltage) {
 			err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
-		fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISHNETWORK_SEND_LEGACY_CMD:
 		if (fe->ops->dishnetwork_send_legacy_command) {
 			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
-			fe->state = FESTATE_DISEQC;
-			fe->status = 0;
+			fepriv->state = FESTATE_DISEQC;
+			fepriv->status = 0;
 		}
 		break;
 
@@ -668,14 +705,14 @@
 		break;
 
 	case FE_ENABLE_HIGH_LNB_VOLTAGE:
-		if (fe->ops->enable_high_lnb_voltage);
+		if (fe->ops->enable_high_lnb_voltage)
 			err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
 		break;
 
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
 	    
-		memcpy (&fe->parameters, parg,
+		memcpy (&fepriv->parameters, parg,
 			sizeof (struct dvb_frontend_parameters));
 
 		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
@@ -684,41 +721,41 @@
 		    
 		/* force auto frequency inversion if requested */
 		if (dvb_force_auto_inversion) {
-			fe->parameters.inversion = INVERSION_AUTO;
+			fepriv->parameters.inversion = INVERSION_AUTO;
 			fetunesettings.parameters.inversion = INVERSION_AUTO;
 		}
 		if (fe->ops->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;
+			if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+			    fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+				fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
 		}
 
 		/* get frontend-specific tuning settings */
 		if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
-			fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
-			fe->max_drift = fetunesettings.max_drift;
-			fe->step_size = fetunesettings.step_size;
+			fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+			fepriv->max_drift = fetunesettings.max_drift;
+			fepriv->step_size = fetunesettings.step_size;
 		} else {
 			/* default values */
 			switch(fe->ops->info.type) {
 			case FE_QPSK:
-				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;
+				fepriv->min_delay = HZ/20;
+				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
+				fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
 		break;
 			    
 			case FE_QAM:
-				fe->min_delay = HZ/20;
-				fe->step_size = 0; /* no zigzag */
-				fe->max_drift = 0;
+				fepriv->min_delay = HZ/20;
+				fepriv->step_size = 0; /* no zigzag */
+				fepriv->max_drift = 0;
 				break;
 			    
 			case FE_OFDM:
-				fe->min_delay = HZ/20;
-				fe->step_size = fe->ops->info.frequency_stepsize * 2;
-				fe->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+				fepriv->min_delay = HZ/20;
+				fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
+				fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
 				break;
 			case FE_ATSC:
 				printk("dvb-core: FE_ATSC not handled yet.\n");
@@ -726,12 +763,12 @@
 			}
 		}
 		if (dvb_override_tune_delay > 0)
-		       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+			fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
 
-		fe->state = FESTATE_RETUNE;
+		fepriv->state = FESTATE_RETUNE;
 		dvb_frontend_wakeup(fe);
 		dvb_frontend_add_event (fe, 0);	    
-		fe->status = 0;
+		fepriv->status = 0;
 		err = 0;
 		break;
 	}
@@ -742,13 +779,13 @@
 
 	case FE_GET_FRONTEND:
 		if (fe->ops->get_frontend) {
-			memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters));
+			memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
 			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
 		}
 		break;
 	};
 
-	up (&fe->sem);
+	up (&fepriv->sem);
 	return err;
 }
 
@@ -757,12 +793,13 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	poll_wait (file, &fe->events.wait_queue, wait);
+	poll_wait (file, &fepriv->events.wait_queue, wait);
 
-	if (fe->events.eventw != fe->events.eventr)
+	if (fepriv->events.eventw != fepriv->events.eventr)
 		return (POLLIN | POLLRDNORM | POLLPRI);
 
 	return 0;
@@ -773,6 +809,7 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 	int ret;
 
 	dprintk ("%s\n", __FUNCTION__);
@@ -786,7 +823,7 @@
 			dvb_generic_release (inode, file);
 
 		/*  empty event queue */
-		fe->events.eventr = fe->events.eventw = 0;
+		fepriv->events.eventr = fepriv->events.eventw = 0;
 	}
 	
 	return ret;
@@ -797,11 +833,12 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 
 	dprintk ("%s\n", __FUNCTION__);
 
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
-		fe->release_jiffies = jiffies;
+		fepriv->release_jiffies = jiffies;
 
 	return dvb_generic_release (inode, file);
 }
@@ -818,6 +854,7 @@
 int dvb_register_frontend(struct dvb_adapter* dvb,
 			  struct dvb_frontend* fe)
 {
+	struct dvb_frontend_private *fepriv;
 	static const struct dvb_device dvbdev_template = {
 		.users = ~0,
 		.writers = 1,
@@ -831,20 +868,26 @@
 	if (down_interruptible (&frontend_mutex))
 		return -ERESTARTSYS;
 
-	init_MUTEX (&fe->sem);
-	init_waitqueue_head (&fe->wait_queue);
-	init_waitqueue_head (&fe->events.wait_queue);
-	init_MUTEX (&fe->events.sem);
-	fe->events.eventw = fe->events.eventr = 0;
-	fe->events.overflow = 0;
+	fe->frontend_priv = kmalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
+	if (fe->frontend_priv == NULL) {
+		up(&frontend_mutex);
+		return -ENOMEM;
+	}
+	fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
+	memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private));
+
+	init_MUTEX (&fepriv->sem);
+	init_waitqueue_head (&fepriv->wait_queue);
+	init_waitqueue_head (&fepriv->events.wait_queue);
+	init_MUTEX (&fepriv->events.sem);
 	fe->dvb = dvb;
-	fe->inversion = INVERSION_OFF;
+	fepriv->inversion = INVERSION_OFF;
 
 	printk ("DVB: registering frontend %i (%s)...\n",
 		fe->dvb->num,
 		fe->ops->info.name);
 
-	dvb_register_device (fe->dvb, &fe->dvbdev, &dvbdev_template,
+	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
 
 	up (&frontend_mutex);
@@ -854,15 +897,18 @@
 
 int dvb_unregister_frontend(struct dvb_frontend* fe)
 {
+	struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv;
 	dprintk ("%s\n", __FUNCTION__);
 
 	down (&frontend_mutex);
-			dvb_unregister_device (fe->dvbdev);
+	dvb_unregister_device (fepriv->dvbdev);
 			dvb_frontend_stop (fe);
 	if (fe->ops->release)
 		fe->ops->release(fe);
 	else
 		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+	if (fe->frontend_priv)
+		kfree(fe->frontend_priv);
 	up (&frontend_mutex);
 	return 0;
 }
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_frontend.h linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_frontend.h
--- linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_frontend.h	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_frontend.h	2005-01-20 19:56:37.000000000 +0100
@@ -115,28 +115,7 @@
 	struct dvb_frontend_ops* ops;
 	struct dvb_adapter *dvb;
 	void* demodulator_priv;
-
-	struct dvb_device *dvbdev;
-	struct dvb_frontend_parameters parameters;
-	struct dvb_fe_events events;
-	struct semaphore sem;
-	struct list_head list_head;
-	wait_queue_head_t wait_queue;
-	pid_t thread_pid;
-	unsigned long release_jiffies;
-	int state;
-	int bending;
-	int lnb_drift;
-	int inversion;
-	int auto_step;
-	int auto_sub_step;
-	int started_auto_step;
-	int min_delay;
-	int max_drift;
-	int step_size;
-	int exit;
-	int wakeup;
-	fe_status_t status;
+	void* frontend_priv;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter* dvb,
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_net.c linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_net.c
--- linux-2.6.11-rc2/drivers/media/dvb/dvb-core/dvb_net.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/dvb-core/dvb_net.c	2005-01-20 19:56:37.000000000 +0100
@@ -123,7 +123,6 @@
 struct dvb_net_priv {
 	int in_use;
         struct net_device_stats stats;
-        char name[6];
 	u16 pid;
 	struct dvb_net *host;
         struct dmx_demux *demux;
@@ -1165,12 +1162,17 @@
 	if ((if_num = get_if(dvbnet)) < 0)
 		return -EINVAL;
 
-	net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb",
-			   dvb_net_setup);
+	net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
 	if (!net)
 		return -ENOMEM;
 	
-	sprintf(net->name, "dvb%d_%d", dvbnet->dvbdev->adapter->num, if_num);
+	if (dvbnet->dvbdev->id)
+		snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
+			 dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
+	else
+		/* compatibility fix to keep dvb0_0 format */
+		snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
+			 dvbnet->dvbdev->adapter->num, if_num);
 
 	net->addr_len  		= 6;
 	memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
@@ -1196,6 +1198,7 @@
 		free_netdev(net);
 		return result;
 	}
+	printk("dvb_net: created network interface %s\n", net->name);
 
         return if_num;
 }
@@ -1214,6 +1216,7 @@
 
 	dvb_net_stop(net);
 	flush_scheduled_work();
+	printk("dvb_net: removed network interface %s\n", net->name);
         unregister_netdev(net);
 	dvbnet->state[num]=0;
 	dvbnet->device[num] = NULL;
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttusb-dec/ttusb_dec.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttusb-dec/ttusb_dec.c	2005-01-20 19:56:40.000000000 +0100
@@ -756,7 +755,7 @@
 
 	if (!dec->iso_stream_count) {
 		for (i = 0; i < ISO_BUF_COUNT; i++)
-			usb_unlink_urb(dec->iso_urb[i]);
+			usb_kill_urb(dec->iso_urb[i]);
 	}
 
 	up(&dec->iso_sem);
@@ -821,7 +820,7 @@
 				       "error %d\n", __FUNCTION__, i, result);
 
 				while (i) {
-					usb_unlink_urb(dec->iso_urb[i - 1]);
+					usb_kill_urb(dec->iso_urb[i - 1]);
 					i--;
 				}
 
@@ -1379,7 +1378,7 @@
 	dec->iso_stream_count = 0;
 
 	for (i = 0; i < ISO_BUF_COUNT; i++)
-		usb_unlink_urb(dec->iso_urb[i]);
+		usb_kill_urb(dec->iso_urb[i]);
 
 	ttusb_dec_free_iso_urbs(dec);
 }
diff -uraNwB linux-2.6.11-rc2/include/linux/dvb/frontend.h linux-2.6.11-rc2-dvb/include/linux/dvb/frontend.h
--- linux-2.6.11-rc2/include/linux/dvb/frontend.h	2005-01-20 19:53:19.000000000 +0100
+++ linux-2.6.11-rc2-dvb/include/linux/dvb/frontend.h	2004-12-17 22:00:18.000000000 +0100
@@ -158,10 +158,11 @@
         QAM_64,
         QAM_128,
         QAM_256,
-	QAM_AUTO
+	QAM_AUTO,
+	VSB_8,
+	VSB_16
 } fe_modulation_t;
 
-
 typedef enum fe_transmit_mode {
 	TRANSMISSION_MODE_2K,
 	TRANSMISSION_MODE_8K,
@@ -206,6 +206,9 @@
         fe_modulation_t  modulation;  /* modulation type (see above) */
 };
 
+struct dvb_vsb_parameters {
+	fe_modulation_t	modulation;  /* modulation type (see above) */
+};
 
 struct dvb_ofdm_parameters {
         fe_bandwidth_t      bandwidth;
@@ -219,13 +222,14 @@
 
 
 struct dvb_frontend_parameters {
-        __u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM */
+	__u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM/ATSC */
                                   /* intermediate frequency in kHz for QPSK */
 	fe_spectral_inversion_t inversion;
 	union {
 		struct dvb_qpsk_parameters qpsk;
 		struct dvb_qam_parameters  qam;
 		struct dvb_ofdm_parameters ofdm;
+		struct dvb_vsb_parameters vsb;
 	} u;
 };
 
diff -uraNwB linux-2.6.11-rc2/include/linux/dvb/version.h linux-2.6.11-rc2-dvb/include/linux/dvb/version.h
--- linux-2.6.11-rc2/include/linux/dvb/version.h	2005-01-20 19:53:19.000000000 +0100
+++ linux-2.6.11-rc2-dvb/include/linux/dvb/version.h	2004-12-17 22:00:18.000000000 +0100
@@ -24,6 +24,7 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 3
+#define DVB_API_VERSION_MINOR 1
 
 #endif /*_DVBVERSION_H_*/
 


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

* [PATCH 6/9] refactoring
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
                   ` (4 preceding siblings ...)
  2005-01-22 17:34 ` [PATCH 5/9] add ATSC support, misc fixes Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 7/9] nxt2002: add ATSC support, misc fixes Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 8/9] dvb-ttpci: fix SMP race, budget: fixe init race, " Johannes Stezenbach
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] dib3000: driver refactoring, makes it easier to support device clones

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000-common.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000-common.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000-common.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000-common.c	2005-01-20 19:56:37.000000000 +0100
@@ -2,7 +2,7 @@
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
-module_param(debug, int, 0x644);
+module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
 #endif
 #define deb_info(args...) dprintk(0x01,args)
@@ -42,65 +41,6 @@
 	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
-int dib3000_init_pid_list(struct dib3000_state *state, int num)
-{
-	int i;
-	if (state != NULL) {
-		state->pid_list = kmalloc(sizeof(struct dib3000_pid) * num,GFP_KERNEL);
-		if (state->pid_list == NULL)
-			return -ENOMEM;
-
-		deb_info("initializing %d pids for the pid_list.\n",num);
-		spin_lock_init(&state->pid_list_lock);
-		memset(state->pid_list,0,num*(sizeof(struct dib3000_pid)));
-		for (i=0; i < num; i++) {
-			state->pid_list[i].pid = 0;
-			state->pid_list[i].active = 0;
-		}
-		state->feedcount = 0;
-	} else
-		return -EINVAL;
-
-	return 0;
-}
-
-void dib3000_dealloc_pid_list(struct dib3000_state *state)
-{
-	if (state != NULL && state->pid_list != NULL)
-		kfree(state->pid_list);
-}
-
-/* fetch a pid from pid_list */
-int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids, int pid,
-		spinlock_t *pid_list_lock,int onoff)
-{
-	int i,ret = -1;
-	unsigned long flags;
-
-	spin_lock_irqsave(pid_list_lock,flags);
-	for (i=0; i < num_pids; i++)
-		if (onoff) {
-			if (!pid_list[i].active) {
-				pid_list[i].pid = pid;
-				pid_list[i].active = 1;
-				ret = i;
-				break;
-			}
-		} else {
-			if (pid_list[i].active && pid_list[i].pid == pid) {
-				pid_list[i].pid = 0;
-				pid_list[i].active = 0;
-				ret = i;
-				break;
-			}
-		}
-
-	deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
-
-	spin_unlock_irqrestore(pid_list_lock,flags);
-	return ret;
-}
-
 int dib3000_search_status(u16 irq,u16 lock)
 {
 	if (irq & 0x02) {
@@ -139,7 +79,4 @@
 
 EXPORT_SYMBOL(dib3000_read_reg);
 EXPORT_SYMBOL(dib3000_write_reg);
-EXPORT_SYMBOL(dib3000_init_pid_list);
-EXPORT_SYMBOL(dib3000_dealloc_pid_list);
-EXPORT_SYMBOL(dib3000_get_pid_index);
 EXPORT_SYMBOL(dib3000_search_status);
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000-common.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000-common.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000-common.h	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000-common.h	2005-01-20 19:56:37.000000000 +0100
@@ -4,7 +4,7 @@
  *
  * DiBcom (http://www.dibcom.fr/)
  *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * based on GPL code from DibCom, which has
  *
@@ -29,19 +28,10 @@
 #include "dvb_frontend.h"
 #include "dib3000.h"
 
-/* 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)
-
-/* a PID for the pid_filter list, when in use */
-struct dib3000_pid
-{
-	u16 pid;
-	int active;
-};
+/* info and err, taken from usb.h, if there is anything available like by default. */
+#define err(format, arg...) printk(KERN_ERR "dib3000mX: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "dib3000mX: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000mX: " format "\n" , ## arg)
 
 /* frontend state */
 struct dib3000_state {
@@ -52,25 +42,18 @@
 /* configuration settings */
 	struct dib3000_config config;
 
-	spinlock_t pid_list_lock;
-	struct dib3000_pid *pid_list;
-
-	int feedcount;
-
 	struct dvb_frontend frontend;
 	int timing_offset;
 	int timing_offset_comp_done;
+
+	fe_bandwidth_t last_tuned_bw;
+	u32 last_tuned_freq;
 };
 
 /* commonly used methods by the dib3000mb/mc/p frontend */
 extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
 extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
 
-extern int dib3000_init_pid_list(struct dib3000_state *state, int num);
-extern void dib3000_dealloc_pid_list(struct dib3000_state *state);
-extern int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids,
-	int pid, spinlock_t *pid_list_lock,int onoff);
-
 extern int dib3000_search_status(u16 irq,u16 lock);
 
 /* handy shortcuts */
@@ -81,7 +64,7 @@
 
 #define wr_foreach(a,v) { int i; \
 	if (sizeof(a) != sizeof(v)) \
-		err("sizeof: %zd %zd is different",sizeof(a),sizeof(v));\
+		err("sizeof: %d %d is different",sizeof(a),sizeof(v));\
 	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
 		wr(a[i],v[i]); \
 	}
@@ -136,8 +119,8 @@
 #define DIB3000_DDS_INVERSION_OFF		(     0)
 #define DIB3000_DDS_INVERSION_ON		(     1)
 
-#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 7))
-#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 7) | (1 << 7)))
+#define DIB3000_TUNER_WRITE_ENABLE(a)	(0xffff & (a << 8))
+#define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 8) | (1 << 7)))
 
 /* for auto search */
 extern u16 dib3000_seq[2][2][2];
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000.h	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000.h	2005-01-20 19:56:37.000000000 +0100
@@ -2,7 +2,7 @@
  * public header file of the frontend drivers for mobile DVB-T demodulators
  * DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/)
  *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * based on GPL code from DibCom, which has
  *
@@ -31,25 +31,24 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/* The i2c address of the PLL */
-	u8 pll_addr;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend *fe);
-	int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
+	/* PLL maintenance and the i2c address of the PLL */
+	u8 (*pll_addr)(struct dvb_frontend *fe);
+	int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]);
+	int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]);
 };
 
-struct dib3000_xfer_ops
+struct dib_fe_xfer_ops
 {
 	/* pid and transfer handling is done in the demodulator */
 	int (*pid_parse)(struct dvb_frontend *fe, int onoff);
 	int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff);
-	int (*pid_ctrl)(struct dvb_frontend *fe, int pid, int onoff);
+	int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff);
+	int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
 };
 
 extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
-					     struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
 
 extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
-					     struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
+					     struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
 #endif // DIB3000_H
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mb.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mb.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mb.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mb.c	2005-01-20 19:56:37.000000000 +0100
@@ -2,7 +2,7 @@
  * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
  * DiBcom (http://www.dibcom.fr/)
  *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * based on GPL code from DibCom, which has
  *
@@ -29,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#include "dvb_frontend.h"
 #include "dib3000-common.h"
 #include "dib3000mb_priv.h"
 #include "dib3000.h"
@@ -41,7 +39,7 @@
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
-module_param(debug, int, 0x644);
+module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
 #endif
 #define deb_info(args...) dprintk(0x01,args)
@@ -49,6 +47,8 @@
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
 
+static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
+
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep);
 
@@ -61,11 +61,9 @@
 	int search_state,seq;
 
 	if (tuner) {
-		wr(DIB3000MB_REG_TUNER,
-				DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
-		state->config.pll_set(fe, fep);
-		wr(DIB3000MB_REG_TUNER,
-				DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
+		dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
+		state->config.pll_set(fe, fep, NULL);
+		dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
 
 		deb_setf("bandwidth: ");
 		switch (ofdm->bandwidth) {
@@ -390,11 +388,9 @@
 	wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
 	if (state->config.pll_init) {
-		wr(DIB3000MB_REG_TUNER,
-			DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
-		state->config.pll_init(fe);
-		wr(DIB3000MB_REG_TUNER,
-			DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
+		dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
+		state->config.pll_init(fe,NULL);
+		dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
 	}
 
 	return 0;
@@ -414,6 +410,7 @@
 		return 0;
 
 	dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
+	deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB));
 	if (dds_val < threshold)
 		inv_test1 = 0;
 	else if (dds_val == threshold)
@@ -422,6 +419,7 @@
 		inv_test1 = 2;
 
 	dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
+	deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB));
 	if (dds_val < threshold)
 		inv_test2 = 0;
 	else if (dds_val == threshold)
@@ -714,18 +712,11 @@
 }
 
 /* pid filter and transfer stuff */
-static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff)
+static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
 {
 	struct dib3000_state *state = fe->demodulator_priv;
-	int index = dib3000_get_pid_index(state->pid_list, DIB3000MB_NUM_PIDS, pid, &state->pid_list_lock,onoff);
 	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-
-	if (index >= 0) {
 		wr(index+DIB3000MB_REG_FIRST_PID,pid);
-	} else {
-		err("no more pids for filtering.");
-		return -ENOMEM;
-	}
 	return 0;
 }
 
@@ -749,10 +740,21 @@
 	return 0;
 	}
 
+static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
+{
+	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	if (onoff) {
+		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
+	} else {
+		wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
+	}
+	return 0;
+}
+
 static struct dvb_frontend_ops dib3000mb_ops;
 
 struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
-				      struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
+				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
 {
 	struct dib3000_state* state = NULL;
 
@@ -773,9 +775,6 @@
 	if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
 		goto error;
 
-	if (dib3000_init_pid_list(state,DIB3000MB_NUM_PIDS))
-		goto error;
-
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
@@ -784,6 +783,7 @@
 	xfer_ops->pid_parse = dib3000mb_pid_parse;
 	xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
 	xfer_ops->pid_ctrl = dib3000mb_pid_control;
+	xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl;
 
 	return &state->frontend;
 
@@ -807,6 +807,7 @@
 				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
 				FE_CAN_TRANSMISSION_MODE_AUTO |
 				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
 				FE_CAN_HIERARCHY_AUTO,
 	},
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mc.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mc.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mc.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mc.c	2005-01-20 19:56:38.000000000 +0100
@@ -2,9 +2,9 @@
  * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
  * DiBcom (http://www.dibcom.fr/)
  *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
- * based on GPL code from DibCom, which has
+ * based on GPL code from DiBCom, which has
  *
  * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
  *
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#include "dvb_frontend.h"
 #include "dib3000-common.h"
 #include "dib3000mc_priv.h"
 #include "dib3000.h"
@@ -40,14 +39,16 @@
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
 static int debug;
-module_param(debug, int, 0x644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able)).");
 #endif
 #define deb_info(args...) dprintk(0x01,args)
 #define deb_xfer(args...) dprintk(0x02,args)
 #define deb_setf(args...) dprintk(0x04,args)
 #define deb_getf(args...) dprintk(0x08,args)
+#define deb_stat(args...) dprintk(0x10,args)
 
+static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
 
 static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
 	fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
@@ -185,46 +186,33 @@
 	return 0;
 }
 
-static int dib3000mc_get_frontend(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters *fep);
+static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con)
+{
+	switch (con) {
+		case QAM_64: 
+			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]);
+			break;
+		case QAM_16: 
+			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
+			break;
+		case QPSK: 
+			wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]);
+			break;
+		case QAM_AUTO:
+			break;
+		default:
+			warn("unkown constellation.");
+			break;
+	}
+	return 0;
+}
 
-static int dib3000mc_set_frontend(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters *fep, int tuner)
+static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val)
 {
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	fe_code_rate_t fe_cr = FEC_NONE;
-	int search_state, seq;
-	u16 val;
 	u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
-
-	if (tuner) {
-		wr(DIB3000MC_REG_TUNER,
-				DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
-		state->config.pll_set(fe, fep);
-		wr(DIB3000MC_REG_TUNER,
-				DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
-	}
-
-	dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
-	dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
-
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-
-/* Default cfg isi offset adp */
-	wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
-
-	wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
-	wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
-	wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
-
-	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
-	if (ofdm->bandwidth == BANDWIDTH_8_MHZ) {
-		wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
-	} else {
-		wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
-	}
+	int seq;
 
 	switch (ofdm->transmission_mode) {
 		case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
@@ -282,8 +270,7 @@
 		case INVERSION_OFF:
 			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
 			break;
-		case INVERSION_AUTO:
-			break;
+		case INVERSION_AUTO: /* fall through */
 		case INVERSION_ON:
 			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
 			break;
@@ -298,168 +285,12 @@
 
 	deb_setf("seq? %d\n", seq);
 	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
-
-	dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-
-	val = rd(DIB3000MC_REG_DEMOD_PARM);
-	wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
-	wr(DIB3000MC_REG_DEMOD_PARM,val);
-
-	msleep(70);
-
-	wr_foreach(dib3000mc_reg_agc_bandwidth, dib3000mc_agc_bandwidth);
-
-	/* something has to be auto searched */
-	if (ofdm->constellation == QAM_AUTO ||
+	*auto_val = ofdm->constellation == QAM_AUTO ||
 		ofdm->hierarchy_information == HIERARCHY_AUTO ||
 		ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
 		ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
 		fe_cr == FEC_AUTO ||
-		fep->inversion == INVERSION_AUTO
-		) {
-		int as_count=0;
-
-		deb_setf("autosearch enabled.\n");
-
-		val = rd(DIB3000MC_REG_DEMOD_PARM);
-		wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
-		wr(DIB3000MC_REG_DEMOD_PARM,val);
-
-		while ((search_state = dib3000_search_status(
-					rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
-			msleep(10);
-
-		deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
-
-		if (search_state == 1) {
-			struct dvb_frontend_parameters feps;
-			feps.u.ofdm.bandwidth = ofdm->bandwidth; /* bw is not auto searched */;
-			if (dib3000mc_get_frontend(fe, &feps) == 0) {
-				deb_setf("reading tuning data from frontend succeeded.\n");
-				return dib3000mc_set_frontend(fe, &feps, 0);
-			}
-		}
-	} else {
-		wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
-		wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[qam]);
-		/* set_offset_cfg */
-		wr_foreach(dib3000mc_reg_offset,
-				dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
-
-//		dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth);
-
-//		wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */
-
-/*		set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
-		set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF);
-		wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON);
-		wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/
-	}
-
-	return 0;
-}
-
-
-static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
-{
-	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
-
-	state->timing_offset = 0;
-	state->timing_offset_comp_done = 0;
-
-	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
-	wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
-	wr(DIB3000MC_REG_RST_I2C_ADDR,
-		DIB3000MC_DEMOD_ADDR(state->config.demod_address) |
-		DIB3000MC_DEMOD_ADDR_ON);
-
-	wr(DIB3000MC_REG_RST_I2C_ADDR,
-		DIB3000MC_DEMOD_ADDR(state->config.demod_address));
-
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
-	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-
-	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
-	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
-	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
-	wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
-
-	wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
-	wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
-
-	wr(33,5);
-	wr(36,81);
-	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
-
-	wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
-	wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
-
-	/* mobile mode - portable reception */
-	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
-
-/* TUNER_PANASONIC_ENV57H12D5: */
-	wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
-	wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
-	wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
-
-	wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
-	wr(26,0x6680);
-	wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
-	wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
-	wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
-	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
-
-	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
-	wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
-
-	wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
-
-	wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
-	wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
-
-	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_2K,BANDWIDTH_8_MHZ);
-//	wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
-
-	wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
-	wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
-	wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
-
-	dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
-
-/* output mode control, just the MPEG2_SLAVE */
-	set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
-	wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
-	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
-	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
-
-/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
-	wr(DIB3000MC_REG_OUTMODE,
-		DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
-			rd(DIB3000MC_REG_OUTMODE)));
-
-	wr(DIB3000MC_REG_SMO_MODE,
-			DIB3000MC_SMO_MODE_DEFAULT |
-			DIB3000MC_SMO_MODE_188);
-
-	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
-	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
-*/
-/* diversity */
-	wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
-	wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
-
-	wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
-
-	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
-
-
-/*	if (state->config->pll_init) {
-		wr(DIB3000MC_REG_TUNER,
-			DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
-		state->config->pll_init(fe);
-		wr(DIB3000MC_REG_TUNER,
-			DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
-	}*/
+			fep->inversion == INVERSION_AUTO;
 	return 0;
 }
 
@@ -476,7 +307,8 @@
 	if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
 		return 0;
 
-	dds_val = ((rd(DIB3000MC_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
+	dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
+	deb_getf("DDS_FREQ: %6x\n",dds_val);
 	if (dds_val < threshold)
 		inv_test1 = 0;
 	else if (dds_val == threshold)
@@ -484,7 +316,8 @@
 	else
 		inv_test1 = 2;
 
-	dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
+	dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
+	deb_getf("DDS_SET_FREQ: %6x\n",dds_val);
 	if (dds_val < threshold)
 		inv_test2 = 0;
 	else if (dds_val == threshold)
@@ -499,6 +332,9 @@
 
 	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
 
+	fep->frequency = state->last_tuned_freq;
+	fep->u.ofdm.bandwidth= state->last_tuned_bw;
+	
 	tps_val = rd(DIB3000MC_REG_TUNING_PARM);
 
 	switch (DIB3000MC_TP_QAM(tps_val)) {
@@ -614,9 +450,211 @@
 			err("unexpected transmission mode return by TPS (%d)", tps_val);
 			break;
 	}
+	deb_getf("\n");
+
+	return 0;
+}
+
+static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep, int tuner)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+	int search_state,auto_val;
+	u16 val;
+	
+	if (tuner) { /* initial call from dvb */
+		dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
+		state->config.pll_set(fe,fep,NULL);
+		dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+		
+		state->last_tuned_freq = fep->frequency;
+	//	if (!scanboost) {
+			dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
+			dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
+			state->last_tuned_bw = ofdm->bandwidth;
+
+			wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
+			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
+			wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+			
+			/* Default cfg isi offset adp */
+			wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
+
+			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
+			dib3000mc_set_adp_cfg(state,ofdm->constellation);
+			wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
+
+			wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+			/* power smoothing */
+			if (ofdm->bandwidth != BANDWIDTH_8_MHZ) {
+				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
+			} else {
+				wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
+			}
+			auto_val = 0;
+			dib3000mc_set_general_cfg(state,fep,&auto_val);
+			dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
+		
+			val = rd(DIB3000MC_REG_DEMOD_PARM);
+			wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
+			wr(DIB3000MC_REG_DEMOD_PARM,val);
+	//	}
+		msleep(70);
+
+		/* something has to be auto searched */
+		if (auto_val) {
+			int as_count=0;
+
+			deb_setf("autosearch enabled.\n");
+			
+			val = rd(DIB3000MC_REG_DEMOD_PARM);
+			wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+			wr(DIB3000MC_REG_DEMOD_PARM,val);
+
+			while ((search_state = dib3000_search_status(
+						rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) 
+				msleep(10);
+			
+			deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+			
+			if (search_state == 1) {
+				struct dvb_frontend_parameters feps;
+				if (dib3000mc_get_frontend(fe, &feps) == 0) {
+					deb_setf("reading tuning data from frontend succeeded.\n");
+					return dib3000mc_set_frontend(fe, &feps, 0);
+				}
+			}
+		} else {
+			dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth);
+			wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
+			dib3000mc_set_adp_cfg(state,ofdm->constellation);
+			
+			/* set_offset_cfg */
+			wr_foreach(dib3000mc_reg_offset,
+					dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
+		}
+	} else { /* second call, after autosearch (fka: set_WithKnownParams) */
+//		dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
+		
+		auto_val = 0;
+		dib3000mc_set_general_cfg(state,fep,&auto_val);
+		if (auto_val)
+			deb_info("auto_val is true, even though an auto search was already performed.\n");
+
+		dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
+		
+		val = rd(DIB3000MC_REG_DEMOD_PARM);
+		wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+		wr(DIB3000MC_REG_DEMOD_PARM,val);
+		
+		msleep(30);
+		
+		wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
+			dib3000mc_set_adp_cfg(state,ofdm->constellation);
+		wr_foreach(dib3000mc_reg_offset,
+				dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
+		
+				
+	}
 	return 0;
 }
 
+static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
+{
+	deb_info("init start\n");
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+	state->timing_offset = 0;
+	state->timing_offset_comp_done = 0;
+	
+	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
+	wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
+	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
+	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
+	wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
+	
+	wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
+	wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
+
+	wr(33,5);
+	wr(36,81);
+	wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);				  
+	
+	wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
+	wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
+
+	/* mobile mode - portable reception */
+	wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); 
+
+/* TUNER_PANASONIC_ENV57H12D5: */
+	wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
+	wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
+	wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
+
+	wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
+	wr(26,0x6680);
+	wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
+	wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
+	wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
+	wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
+	
+	wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+	wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+	
+	wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
+
+	wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+	wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
+
+	dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); 
+//	wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
+	
+	wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
+	wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
+	wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
+	
+	wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
+	
+	dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
+
+/* output mode control, just the MPEG2_SLAVE */
+//	set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
+	wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
+	wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
+	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
+	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
+
+/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
+	wr(DIB3000MC_REG_OUTMODE,
+		DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
+			rd(DIB3000MC_REG_OUTMODE)));
+
+	wr(DIB3000MC_REG_SMO_MODE,
+			DIB3000MC_SMO_MODE_DEFAULT | 
+			DIB3000MC_SMO_MODE_188);
+
+	wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
+	wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+*/
+	
+/* diversity */
+	wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
+	wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
+
+	set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
+
+	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
+
+/*	if (state->config->pll_init) {
+		dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
+		state->config->pll_init(fe,NULL);
+		dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+	}*/
+	deb_info("init end\n");
+	return 0;
+}
 static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
 {
 	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
@@ -627,12 +665,12 @@
 		*stat |= FE_HAS_SIGNAL;
 	if (DIB3000MC_CARRIER_LOCK(lock))
 		*stat |= FE_HAS_CARRIER;
-	if (DIB3000MC_TPS_LOCK(lock)) /* VIT_LOCK ? */
+	if (DIB3000MC_TPS_LOCK(lock))
 		*stat |= FE_HAS_VITERBI;
 	if (DIB3000MC_MPEG_SYNC_LOCK(lock))
 		*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
 
-	deb_info("actual status is %2x\n",*stat);
+	deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040));
 
 	return 0;
 }
@@ -659,7 +697,7 @@
 	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
 	*strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
 
-	deb_info("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
+	deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
 	return 0;
 }
 
@@ -667,9 +705,8 @@
 static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
 	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
-
-	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB),
-		val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
+	u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB),
+		val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB);
 	u16 sig,noise;
 
 	sig =   (((val >> 6) & 0xff) << 8) + (val & 0x3f);
@@ -679,9 +716,9 @@
 	else
 		*snr = (u16) sig/noise;
 
-	deb_info("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
-	deb_info("noise:  mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
-	deb_info("snr: %d\n",*snr);
+	deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
+	deb_stat("noise:  mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
+	deb_stat("snr: %d\n",*snr);
 	return 0;
 }
 
@@ -698,7 +735,7 @@
 
 static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-	tune->min_delay_ms = 800;
+	tune->min_delay_ms = 2000;
 	tune->step_size = 166667;
 	tune->max_drift = 166667 * 2;
 
@@ -718,23 +755,15 @@
 static void dib3000mc_release(struct dvb_frontend* fe)
 {
 	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
-	dib3000_dealloc_pid_list(state);
 	kfree(state);
 }
 
 /* pid filter and transfer stuff */
-static int dib3000mc_pid_control(struct dvb_frontend *fe,int pid,int onoff)
+static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
 {
 	struct dib3000_state *state = fe->demodulator_priv;
-	int index = dib3000_get_pid_index(state->pid_list, DIB3000MC_NUM_PIDS, pid, &state->pid_list_lock,onoff);
 	pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
-
-	if (index >= 0) {
 		wr(index+DIB3000MC_REG_FIRST_PID,pid);
-	} else {
-		err("no more pids for filtering.");
-		return -ENOMEM;
-	}
 	return 0;
 }
 
@@ -742,10 +771,14 @@
 {
 	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-	deb_xfer("%s fifo",onoff ? "enabling" : "disabling");
+	
+	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
+	
 	if (onoff) {
+		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
 	} else {
+		deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
 		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
 	}
 	return 0;
@@ -755,19 +788,57 @@
 {
 	struct dib3000_state *state = fe->demodulator_priv;
 	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-	deb_xfer("%s pid parsing",onoff ? "enabling" : "disabling");
+	
+	deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
+	
 	if (onoff) {
+		deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_PID_PARSE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
 		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
 	} else {
+		deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
 		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
 	}
 	return 0;
 }
 
+static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
+{
+	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	if (onoff) {
+		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
+	} else {
+		wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
+	}
+	return 0;
+}
+
+static int dib3000mc_demod_init(struct dib3000_state *state) 
+{
+	u16 default_addr = 0x0a;
+	/* first init */
+	if (state->config.demod_address != default_addr) {
+		deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr);
+		wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+		wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
+		
+		wr(DIB3000MC_REG_RST_I2C_ADDR,
+			DIB3000MC_DEMOD_ADDR(default_addr) |
+			DIB3000MC_DEMOD_ADDR_ON);
+	
+		state->config.demod_address = default_addr;
+		
+		wr(DIB3000MC_REG_RST_I2C_ADDR,
+			DIB3000MC_DEMOD_ADDR(default_addr));
+	} else
+		deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address);
+	return 0;
+}
+
+
 static struct dvb_frontend_ops dib3000mc_ops;
 
 struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
-				      struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
+				      struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
 {
 	struct dib3000_state* state = NULL;
 	u16 devid;
@@ -790,19 +861,15 @@
 	if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
 		goto error;
 
-
 	switch (devid) {
 		case DIB3000MC_DEVICE_ID:
-			info("Found a DiBcom 3000-MC.");
+			info("Found a DiBcom 3000-MC, interesting...");
 			break;
 		case DIB3000P_DEVICE_ID:
 			info("Found a DiBcom 3000-P.");
 			break;
 	}
 
-	if (dib3000_init_pid_list(state,DIB3000MC_NUM_PIDS))
-		goto error;
-
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
@@ -811,6 +878,9 @@
 	xfer_ops->pid_parse = dib3000mc_pid_parse;
 	xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
 	xfer_ops->pid_ctrl = dib3000mc_pid_control;
+	xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl;
+
+	dib3000mc_demod_init(state);
 
 	return &state->frontend;
 
@@ -834,6 +904,7 @@
 				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
 				FE_CAN_TRANSMISSION_MODE_AUTO |
 				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_RECOVER |
 				FE_CAN_HIERARCHY_AUTO,
 	},
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mc_priv.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mc_priv.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/dib3000mc_priv.h	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/dib3000mc_priv.h	2005-01-20 19:56:38.000000000 +0100
@@ -13,31 +13,6 @@
 #ifndef __DIB3000MC_PRIV_H__
 #define __DIB3000MC_PRIV_H__
 
-/* 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)
-
-// defines the phase noise algorithm to be used (O:Inhib, 1:CPE on)
-#define DEF_PHASE_NOISE_MODE                0
-
-// define Mobille algorithms
-#define DEF_MOBILE_MODE      Auto_Reception
-
-// defines the tuner type
-#define DEF_TUNER_TYPE   TUNER_PANASONIC_ENV57H13D5
-
-// defines the impule noise algorithm to be used
-#define DEF_IMPULSE_NOISE_MODE      0
-
-// defines the MPEG2 data output format
-#define DEF_MPEG2_OUTPUT_188       0
-
-// defines the MPEG2 data output format
-#define DEF_OUTPUT_MODE       MPEG2_PARALLEL_CONTINUOUS_CLOCK
-
 /*
  * Demodulator parameters
  * reg: 0  1 1  1 11 11 111
@@ -115,7 +90,7 @@
 	{ 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
 
 static u16 dib3000mc_bandwidth_8mhz[] =
-	{ 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0b0 };
+	{ 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 };
 
 static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
 static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
@@ -173,11 +148,11 @@
 static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
 
 static u16 dib3000mc_imp_noise_ctl[][2] = {
-	{ 0x1294, 0xfff8 }, /* mode 0 */
-	{ 0x1294, 0xfff8 }, /* mode 1 */
-	{ 0x1294, 0xfff8 }, /* mode 2 */
-	{ 0x1294, 0xfff8 }, /* mode 3 */
-	{ 0x1294, 0xfff8 }, /* mode 4 */
+	{ 0x1294, 0x1ff8 }, /* mode 0 */
+	{ 0x1294, 0x1ff8 }, /* mode 1 */
+	{ 0x1294, 0x1ff8 }, /* mode 2 */
+	{ 0x1294, 0x1ff8 }, /* mode 3 */
+	{ 0x1294, 0x1ff8 }, /* mode 4 */
 };
 
 /* AGC registers */
@@ -314,12 +289,26 @@
 #define DIB3000MC_REG_FEC_CFG			(   195)
 #define DIB3000MC_FEC_CFG				(  0x10)
 
+/*
+ * reg 206, output mode
+ *              1111 1111
+ *              |||| ||||
+ *              |||| |||+- unk
+ *              |||| ||+-- unk
+ *              |||| |+--- unk (on by default)
+ *              |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
+ *              |||+------ pid_parse (1 = enabled, 0 = disabled)
+ *              ||+------- outp_188  (1 = TS packet size 188, 0 = packet size 204)
+ *              |+-------- unk 
+ *              +--------- unk
+ */
+
 #define DIB3000MC_REG_SMO_MODE			(   206)
 #define DIB3000MC_SMO_MODE_DEFAULT		(1 << 2)
 #define DIB3000MC_SMO_MODE_FIFO_FLUSH	(1 << 3)
-#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH	~DIB3000MC_SMO_MODE_FIFO_FLUSH
+#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH	(0xfff7)
 #define DIB3000MC_SMO_MODE_PID_PARSE	(1 << 4)
-#define DIB3000MC_SMO_MODE_NO_PID_PARSE	~DIB3000MC_SMO_MODE_PID_PARSE
+#define DIB3000MC_SMO_MODE_NO_PID_PARSE	(0xffef)
 #define DIB3000MC_SMO_MODE_188			(1 << 5)
 #define DIB3000MC_SMO_MODE_SLAVE		(DIB3000MC_SMO_MODE_DEFAULT | \
 			DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
@@ -392,7 +381,7 @@
 
 #define DIB3000MC_REG_RST_I2C_ADDR		(  1024)
 #define DIB3000MC_DEMOD_ADDR_ON			(     1)
-#define DIB3000MC_DEMOD_ADDR(a)			((a << 3) & 0x03F0)
+#define DIB3000MC_DEMOD_ADDR(a)			((a << 4) & 0x03F0)
 
 #define DIB3000MC_REG_RESTART			(  1027)
 #define DIB3000MC_RESTART_OFF			(0x0000)


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

* [PATCH 7/9] nxt2002: add ATSC support, misc fixes
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
                   ` (5 preceding siblings ...)
  2005-01-22 17:34 ` [PATCH 6/9] refactoring Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  2005-01-22 17:34 ` [PATCH 8/9] dvb-ttpci: fix SMP race, budget: fixe init race, " Johannes Stezenbach
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] mt352: exported a mt352_read_reg-function, implemented a single byte
        write_register function (needed for dibusb)
- [DVB] nxt2002: patch by Taylor Jacob to add support for ATSC/VSB frontends
        and the B2C2/BBTI Air2PC-ATSC card
- [DVB] stv0297: fix tuning problems and compile time warnings, patch by Markus Breitenberger
- [DVB] fix spelling errors in various frontend drivers

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/mt352.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/mt352.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/mt352.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/mt352.c	2005-01-20 19:56:38.000000000 +0100
@@ -58,16 +58,26 @@
 		if (debug) printk(KERN_DEBUG "mt352: " args); \
 } while (0)
 
-int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
 {
 	struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+	u8 buf[2] = { reg, val };
 	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0,
-			       .buf = ibuf, .len = ilen };
+			       .buf = buf, .len = 2 };
 	int err = i2c_transfer(state->i2c, &msg, 1);
 	if (err != 1) {
-		dprintk("mt352_write() failed (err = %d)!\n", err);
+		dprintk("mt352_write() to reg %x failed (err = %d)!\n", reg, err);
 		return err;
 }
+	return 0; 
+}
+
+int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+{
+	int err,i;
+	for (i=0; i < ilen-1; i++)
+		if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) 
+			return err;
 
 	return 0;
 }
@@ -92,9 +102,10 @@
 	return b1[0];
 }
 
-
-
-
+u8 mt352_read(struct dvb_frontend *fe, u8 reg)
+{
+	return mt352_read_register(fe->demodulator_priv,reg);
+}
 
 
 
@@ -556,3 +567,4 @@
 
 EXPORT_SYMBOL(mt352_attach);
 EXPORT_SYMBOL(mt352_write);
+EXPORT_SYMBOL(mt352_read);
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/mt352.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/mt352.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/mt352.h	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/mt352.h	2005-01-20 19:56:38.000000000 +0100
@@ -54,5 +54,6 @@
 					 struct i2c_adapter* i2c);
 
 extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
+extern u8 mt352_read(struct dvb_frontend *fe, u8 reg);
 
 #endif // MT352_H
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/nxt2002.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/nxt2002.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/nxt2002.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/nxt2002.c	2004-12-16 16:45:54.000000000 +0100
@@ -0,0 +1,670 @@
+/*
+    Support for B2C2/BBTI Technisat Air2PC - ATSC  
+
+    Copyright (C) 2004 Taylor Jacob <rtjacob@earthlink.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.
+
+*/
+
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ */
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "nxt2002.h"
+
+struct nxt2002_state {
+
+	struct i2c_adapter* i2c;
+	struct dvb_frontend_ops ops;
+	const struct nxt2002_config* config;
+	struct dvb_frontend frontend;
+
+	/* demodulator private data */
+	u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) printk(KERN_DEBUG "nxt2002: " args); \
+	} while (0)
+
+static int i2c_writebytes (struct nxt2002_state* state, u8 reg, u8 *buf, u8 len)
+{
+	/* probbably a much better way or doing this */
+	u8 buf2 [256],x;
+	int err;
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+       
+	buf2[0] = reg;
+	for (x = 0 ; x < len ; x++)
+		buf2[x+1] = buf[x];
+
+	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+		printk ("%s: i2c write error (addr %02x, err == %i)\n",
+			__FUNCTION__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static u8 i2c_readbytes (struct nxt2002_state* state, u8 reg, u8* buf, u8 len)
+{
+	u8 reg2 [] = { reg };
+
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+			{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+	int err;
+
+	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+		printk ("%s: i2c read error (addr %02x, err == %i)\n",
+			__FUNCTION__, state->config->demod_address, err);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static u16 nxt2002_crc(u16 crc, u8 c) 
+{
+
+	u8 i;
+	u16 input = (u16) c & 0xFF;
+  
+	input<<=8;
+	for(i=0 ;i<8 ;i++) {
+		if((crc ^ input) & 0x8000)
+			crc=(crc<<1)^CRC_CCIT_MASK;
+		else
+			crc<<=1;
+	input<<=1;
+	}
+	return crc;
+}
+
+static int nxt2002_writereg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len)
+{
+	u8 buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	/* set multi register length */
+	i2c_writebytes(state,0x34,&len,1);
+
+	/* set mutli register register */
+	i2c_writebytes(state,0x35,&reg,1);
+
+	/* send the actual data */
+	i2c_writebytes(state,0x36,data,len);
+
+	/* toggle the multireg write bit*/
+	buf = 0x02;
+	i2c_writebytes(state,0x21,&buf,1);
+
+	i2c_readbytes(state,0x21,&buf,1);
+
+	if ((buf & 0x02) == 0)
+		return 0;
+ 
+	dprintk("Error writing multireg register %02X\n",reg);
+
+	return 0;
+}
+
+static int nxt2002_readreg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len)
+{
+	u8 len2;
+	dprintk("%s\n", __FUNCTION__);
+
+	/* set multi register length */
+	len2 = len & 0x80;
+	i2c_writebytes(state,0x34,&len2,1);
+
+	/* set mutli register register */
+	i2c_writebytes(state,0x35,&reg,1);
+
+	/* send the actual data */
+	i2c_readbytes(state,reg,data,len);
+
+	return 0;
+}
+
+static void nxt2002_microcontroller_stop (struct nxt2002_state* state)
+{
+	u8 buf[2],counter = 0;
+	dprintk("%s\n", __FUNCTION__);
+
+	buf[0] = 0x80;
+	i2c_writebytes(state,0x22,buf,1);
+
+	while (counter < 20) { 
+		i2c_readbytes(state,0x31,buf,1);
+		if (buf[0] & 0x40) 
+			return;
+		msleep(10);
+		counter++;
+	}
+
+	dprintk("Timeout waiting for micro to stop.. This is ok after firmware upload\n");
+	return; 
+}
+
+static void nxt2002_microcontroller_start (struct nxt2002_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	buf = 0x00;
+	i2c_writebytes(state,0x22,&buf,1);
+}
+
+static int nxt2002_writetuner (struct nxt2002_state* state, u8* data)
+{
+	u8 buf,count = 0;
+
+	dprintk("Tuner Bytes: %02X %02X %02X %02X\n",data[0],data[1],data[2],data[3]);
+
+	dprintk("%s\n", __FUNCTION__);
+	/* stop the micro first */
+	nxt2002_microcontroller_stop(state);
+
+	/* set the i2c transfer speed to the tuner */
+	buf = 0x03;
+	i2c_writebytes(state,0x20,&buf,1);
+
+	/* setup to transfer 4 bytes via i2c */
+	buf = 0x04;
+	i2c_writebytes(state,0x34,&buf,1);
+
+	/* write actual tuner bytes */
+	i2c_writebytes(state,0x36,data,4);
+
+	/* set tuner i2c address */
+	buf = 0xC2;
+	i2c_writebytes(state,0x35,&buf,1);
+
+	/* write UC Opmode to begin transfer */
+	buf = 0x80;
+	i2c_writebytes(state,0x21,&buf,1);
+ 
+	while (count < 20) {
+		i2c_readbytes(state,0x21,&buf,1);
+		if ((buf & 0x80)== 0x00)
+			return 0;
+		msleep(100);
+		count++;
+	}
+
+	printk("nxt2002: timeout error writing tuner\n");
+	return 0;
+}
+
+static void nxt2002_agc_reset(struct nxt2002_state* state)
+{
+	u8 buf;
+	dprintk("%s\n", __FUNCTION__);
+
+	buf = 0x08;
+	i2c_writebytes(state,0x08,&buf,1);
+
+	buf = 0x00;
+	i2c_writebytes(state,0x08,&buf,1);
+
+	return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 buf[256],written = 0,chunkpos = 0;
+	u16 rambase,position,crc = 0;  
+
+	dprintk("%s\n", __FUNCTION__);
+	dprintk("Firmware is %d bytes\n",fw->size);
+
+	/* Get the RAM base for this nxt2002 */
+	i2c_readbytes(state,0x10,buf,1);
+
+	
+	if (buf[0] & 0x10)
+		rambase = 0x1000;
+	else
+		rambase = 0x0000;
+
+	dprintk("rambase on this nxt2002 is %04X\n",rambase);
+
+	/* Hold the micro in reset while loading firmware */
+	buf[0] = 0x80;
+	i2c_writebytes(state,0x2B,buf,1);
+
+        
+	for (position = 0; position < fw->size ; position++) {
+		if (written == 0) {
+			crc = 0;
+			chunkpos = 0x28;
+			buf[0] = ((rambase + position) >> 8);
+			buf[1] = (rambase + position) & 0xFF;
+			buf[2] = 0x81;
+			/* write starting address */
+			i2c_writebytes(state,0x29,buf,3);
+		}
+		written++;          
+		chunkpos++;
+
+		if ((written % 4) == 0)
+			i2c_writebytes(state,chunkpos,&fw->data[position-3],4);
+
+		crc = nxt2002_crc(crc,fw->data[position]);
+
+            
+		if ((written == 255) || (position+1 == fw->size)) {
+			/* write remaining bytes of firmware */
+			i2c_writebytes(state, chunkpos+4-(written %4),
+				&fw->data[position-(written %4) + 1],
+				written %4);
+			buf[0] = crc << 8;
+			buf[1] = crc & 0xFF;
+               
+			/* write crc */
+			i2c_writebytes(state,0x2C,buf,2);
+
+			/* do a read to stop things */
+			i2c_readbytes(state,0x2A,buf,1);
+
+			/* set transfer mode to complete */
+			buf[0] = 0x80;
+			i2c_writebytes(state,0x2B,buf,1);
+
+			written = 0;
+		}
+	}
+
+	printk ("done.\n");
+	return 0;
+};
+
+
+static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe,
+					     struct dvb_frontend_parameters *p)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u32 freq = 0;
+	u16 tunerfreq = 0; 
+	u8 buf[4];
+
+	freq = 44000 + ( p->frequency / 1000 ); 
+
+	dprintk("freq = %d      p->frequency = %d\n",freq,p->frequency);
+
+	tunerfreq = freq * 24/4000;
+ 
+	buf[0] = (tunerfreq >> 8) & 0x7F;
+	buf[1] = (tunerfreq & 0xFF);
+        
+	if (p->frequency <= 214000000) {
+		buf[2] = 0x84 + (0x06 << 3);
+		buf[3] = (p->frequency <= 172000000) ? 0x01 : 0x02;
+	} else if (p->frequency <= 721000000) {
+		buf[2] = 0x84 + (0x07 << 3);
+		buf[3] = (p->frequency <= 467000000) ? 0x02 : 0x08;
+	} else if (p->frequency <= 841000000) {
+		buf[2] = 0x84 + (0x0E << 3);
+		buf[3] = 0x08;
+	} else {
+		buf[2] = 0x84 + (0x0F << 3);         
+		buf[3] = 0x02;
+	}
+
+	/* write frequency information */
+	nxt2002_writetuner(state,buf);
+
+	/* reset the agc now that tuning has been completed */
+	nxt2002_agc_reset(state);
+
+	/* set target power level */
+	buf[0] = 0x70;
+	i2c_writebytes(state,0x42,buf,1);
+
+	/* configure sdm */
+	buf[0] = 0x87;
+	i2c_writebytes(state,0x57,buf,1);
+
+	/* write sdm1 input */
+	buf[0] = 0x10;
+	buf[1] = 0x00;
+	nxt2002_writereg_multibyte(state,0x58,buf,2);
+
+	/* write sdmx input */
+	buf[0] = 0x60;
+	buf[1] = 0x00;
+	nxt2002_writereg_multibyte(state,0x5C,buf,2);
+
+	/* write adc power lpf fc */
+	buf[0] = 0x05;
+	i2c_writebytes(state,0x43,buf,1);
+
+	/* write adc power lpf fc */
+	buf[0] = 0x05;
+	i2c_writebytes(state,0x43,buf,1);
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	nxt2002_writereg_multibyte(state,0x4B,buf,2);
+
+	/* write kg1 */
+	buf[0] = 0x00;
+	i2c_writebytes(state,0x4D,buf,1);
+
+	/* write sdm12 lpf fc */
+	buf[0] = 0x44;
+	i2c_writebytes(state,0x55,buf,1);
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	i2c_writebytes(state,0x41,buf,1);
+
+	/* write agc ucgp0 */
+	buf[0] = 0x00;
+	i2c_writebytes(state,0x30,buf,1);
+
+	/* write agc control reg */
+	buf[0] = 0x00;
+	i2c_writebytes(state,0x41,buf,1);
+
+	/* write accumulator2 input */
+	buf[0] = 0x80;
+	buf[1] = 0x00;
+	nxt2002_writereg_multibyte(state,0x49,buf,2);
+	nxt2002_writereg_multibyte(state,0x4B,buf,2);
+
+	/* write agc control reg */
+	buf[0] = 0x04;
+	i2c_writebytes(state,0x41,buf,1);
+
+	nxt2002_microcontroller_start(state);
+
+	/* adjacent channel detection should be done here, but I don't 
+	have any stations with this need so I cannot test it */
+
+	return 0;
+}
+
+static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 lock;
+	i2c_readbytes(state,0x31,&lock,1);
+
+	*status = 0;
+	if (lock & 0x20) {
+		*status |= FE_HAS_SIGNAL;
+		*status |= FE_HAS_CARRIER;
+		*status |= FE_HAS_VITERBI;
+		*status |= FE_HAS_SYNC;                
+		*status |= FE_HAS_LOCK;
+	}
+	return 0;
+}
+
+static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 b[3];
+
+	nxt2002_readreg_multibyte(state,0xE6,b,3);        
+
+	*ber = ((b[0] << 8) + b[1]) * 8;
+ 
+	return 0;
+}
+
+static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	i2c_writebytes(state,0xA1,b,1);
+
+	/* get multreg val */
+	nxt2002_readreg_multibyte(state,0xA6,b,2);        
+
+	temp = (b[0] << 8) | b[1];
+	*strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+	return 0;
+}
+
+static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 b[2];
+	u16 temp = 0, temp2;
+	u32 snrdb = 0;
+
+	/* setup to read cluster variance */
+	b[0] = 0x00;
+	i2c_writebytes(state,0xA1,b,1);
+
+	/* get multreg val from 0xA6 */
+	nxt2002_readreg_multibyte(state,0xA6,b,2);        
+
+	temp = (b[0] << 8) | b[1];
+	temp2 = 0x7FFF - temp;
+
+	/* snr will be in db */
+	if (temp2 > 0x7F00)
+		snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+	else if (temp2 > 0x7EC0)
+		snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+	else if (temp2 > 0x7C00)
+		snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+	else
+		snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+        /* the value reported back from the frontend will be FFFF=32db 0000=0db */
+
+	*snr = snrdb * (0xFFFF/32000);
+
+	return 0;
+}
+
+static int nxt2002_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	u8 b[3];
+ 
+	nxt2002_readreg_multibyte(state,0xE6,b,3);
+
+	*ucblocks = b[2];
+
+	return 0;
+}
+
+static int nxt2002_sleep(struct dvb_frontend* fe)
+{
+	return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	const struct firmware *fw;
+	int ret;
+	u8 buf[2];
+
+	if (!state->initialised) {
+		/* request the firmware, this will block until someone uploads it */
+		printk("nxt2002: Waiting for firmware upload...\n");
+		ret = state->config->request_firmware(fe, &fw, NXT2002_DEFAULT_FIRMWARE);
+		printk("nxt2002: Waiting for firmware upload(2)...\n");
+		if (ret) {
+			printk("nxt2002: no firmware upload (timeout or file not found?)\n");
+			return ret;
+		}
+
+		ret = nxt2002_load_firmware(fe, fw);
+		if (ret) {
+			printk("nxt2002: writing firmware to device failed\n");
+			release_firmware(fw);
+			return ret;
+		}
+
+		/* Put the micro into reset */
+		nxt2002_microcontroller_stop(state);
+ 
+		/* ensure transfer is complete */
+		buf[0]=0;
+		i2c_writebytes(state,0x2B,buf,1);
+
+		/* Put the micro into reset for real this time */
+		nxt2002_microcontroller_stop(state);
+
+		/* soft reset everything (agc,frontend,eq,fec)*/
+		buf[0] = 0x0F;
+		i2c_writebytes(state,0x08,buf,1);
+		buf[0] = 0x00;
+		i2c_writebytes(state,0x08,buf,1);
+
+		/* write agc sdm configure */
+		buf[0] = 0xF1;		
+		i2c_writebytes(state,0x57,buf,1);
+
+		/* write mod output format */
+		buf[0] = 0x20;		
+		i2c_writebytes(state,0x09,buf,1);
+
+		/* write fec mpeg mode */
+		buf[0] = 0x7E;
+		buf[1] = 0x00;
+		i2c_writebytes(state,0xE9,buf,2);
+
+		/* write mux selection */
+		buf[0] = 0x00;
+		i2c_writebytes(state,0xCC,buf,1);
+
+		state->initialised = 1;
+	}
+
+	return 0;
+}
+
+static int nxt2002_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+	fesettings->min_delay_ms = 500;
+	fesettings->step_size = 0;
+	fesettings->max_drift = 0;
+	return 0;
+}
+
+static void nxt2002_release(struct dvb_frontend* fe)
+{
+	struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops nxt2002_ops;
+
+struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config,
+				   struct i2c_adapter* i2c)
+{
+	struct nxt2002_state* state = NULL;
+	u8 buf [] = {0,0,0,0,0};
+
+	/* allocate memory for the internal state */
+	state = (struct nxt2002_state*) kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->ops, &nxt2002_ops, sizeof(struct dvb_frontend_ops));
+	state->initialised = 0;
+
+        /* Check the first 5 registers to ensure this a revision we can handle */
+
+	i2c_readbytes(state, 0x00, buf, 5);
+	if (buf[0] != 0x04) goto error; 		/* device id */
+	if (buf[1] != 0x02) goto error; 		/* fab id */
+	if (buf[2] != 0x11) goto error; 		/* month */
+	if (buf[3] != 0x20) goto error; 		/* year msb */
+	if (buf[4] != 0x00) goto error; 		/* year lsb */
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state) kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops nxt2002_ops = {
+
+	.info = {
+		.name = "Nextwave nxt2002 VSB/QAM frontend",
+		.type = FE_ATSC,
+		.frequency_min =  54000000,
+		.frequency_max = 803000000,
+                /* stepsize is just a guess */
+		.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_8VSB 
+	},
+
+	.release = nxt2002_release,
+
+	.init = nxt2002_init,
+	.sleep = nxt2002_sleep,
+
+	.set_frontend = nxt2002_setup_frontend_parameters,
+	.get_tune_settings = nxt2002_get_tune_settings,
+
+	.read_status = nxt2002_read_status,
+	.read_ber = nxt2002_read_ber,
+	.read_signal_strength = nxt2002_read_signal_strength,
+	.read_snr = nxt2002_read_snr,
+	.read_ucblocks = nxt2002_read_ucblocks,
+
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT2002 ATSC (8VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
+MODULE_AUTHOR("Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt2002_attach);
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/nxt2002.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/nxt2002.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/nxt2002.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/nxt2002.h	2004-12-16 16:45:54.000000000 +0100
@@ -0,0 +1,23 @@
+/*
+   Driver for the Nxt2002 demodulator
+*/
+
+#ifndef NXT2002_H
+#define NXT2002_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct nxt2002_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* request firmware for device */
+	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config,
+					  struct i2c_adapter* i2c);
+
+#endif // NXT2002_H
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/stv0297.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/stv0297.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/stv0297.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/stv0297.c	2005-01-20 19:56:38.000000000 +0100
@@ -38,10 +38,7 @@
 
         struct dvb_frontend frontend;
 
-        int freq_off;
-
 	unsigned long base_freq;
-
 	u8 pwm;
 };
 
@@ -162,8 +159,10 @@
         int ret;
         u8 b0[] = { reg };
         u8 b1[] = { 0 };
-        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-                                  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
+				  1},
+	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+	};
 
         // this device needs a STOP between the register and data
         if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
@@ -193,8 +192,10 @@
 static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len)
 {
         int ret;
-        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
-                                  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf =
+				  &reg1,.len = 1},
+	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len}
+	};
 
         // this device needs a STOP between the register and data
         if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
@@ -209,6 +210,21 @@
         return 0;
 }
 
+static u32 stv0297_get_symbolrate(struct stv0297_state *state)
+{
+	u64 tmp;
+
+	tmp = stv0297_readreg(state, 0x55);
+	tmp |= stv0297_readreg(state, 0x56) << 8;
+	tmp |= stv0297_readreg(state, 0x57) << 16;
+	tmp |= stv0297_readreg(state, 0x58) << 24;
+
+	tmp *= STV0297_CLOCK_KHZ;
+	tmp >>= 32;
+
+	return (u32) tmp;
+}
+
 static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate)
 {
 	long tmp;
@@ -259,39 +275,40 @@
 	stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f);
 }
 
+/*
 static long stv0297_get_carrieroffset(struct stv0297_state* state)
 {
-        s32 raw;
-	long tmp;
+	s64 tmp;
 
         stv0297_writereg(state,0x6B, 0x00);
 
-        raw =   stv0297_readreg(state,0x66);
-        raw |= (stv0297_readreg(state,0x67) << 8);
-        raw |= (stv0297_readreg(state,0x68) << 16);
-        raw |= (stv0297_readreg(state,0x69) & 0x0F) << 24;
+	tmp = stv0297_readreg(state, 0x66);
+	tmp |= (stv0297_readreg(state, 0x67) << 8);
+	tmp |= (stv0297_readreg(state, 0x68) << 16);
+	tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24;
 
-        tmp = raw;
-	tmp /= 26844L;
+	tmp *= stv0297_get_symbolrate(state);
+	tmp >>= 28;
 
-	return tmp;
+	return (s32) tmp;
 }
+*/
 
 static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq)
 {
-/*
-        s64 tmp;
+	s32 tmp;
 
-        if (freq > 10000) freq -= STV0297_CLOCK_KHZ;
+	if (freq > 10000)
+		freq -= STV0297_CLOCK_KHZ;
 
-        tmp = freq << 16;
-        do_div(tmp, STV0297_CLOCK_KHZ);
-        if (tmp > 0xffff) tmp = 0xffff; // check this calculation
+	tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16);
+	tmp = (freq * 1000) / tmp;
+	if (tmp > 0xffff)
+		tmp = 0xffff;
 
         stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
         stv0297_writereg(state, 0x21, tmp >> 8);
         stv0297_writereg(state, 0x20, tmp);
-*/
 }
 
 static int stv0297_set_qam(struct stv0297_state* state, fe_modulation_t modulation)
@@ -413,6 +430,15 @@
         return 0;
 }
 
+static int stv0297_sleep(struct dvb_frontend *fe)
+{
+	struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv;
+
+	stv0297_writereg_mask(state, 0x80, 1, 1);
+
+	return 0;
+}
+
 static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
         struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
@@ -484,6 +510,7 @@
         int carrieroffset;
         unsigned long starttime;
         unsigned long timeout;
+	fe_spectral_inversion_t inversion;
 
         switch(p->u.qam.modulation) {
         case QAM_16:
@@ -508,8 +535,11 @@
         }
 
         // determine inversion dependant parameters
+	inversion = p->inversion;
+	if (state->config->invert)
+		inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
         carrieroffset = -330;
-        switch(p->inversion) {
+	switch (inversion) {
         case INVERSION_OFF:
           break;
 
@@ -522,13 +552,14 @@
           return -EINVAL;
         }
 
+	stv0297_init(fe);
         state->config->pll_set(fe, p);
 
 	/* clear software interrupts */
 	stv0297_writereg(state, 0x82, 0x0);
 
 	/* set initial demodulation frequency */
-        stv0297_set_initialdemodfreq(state, state->freq_off + 7250);
+	stv0297_set_initialdemodfreq(state, 7250);
 
 	/* setup AGC */
         stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
@@ -588,7 +619,7 @@
         stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000);
 	stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000);
         stv0297_set_carrieroffset(state, carrieroffset);
-        stv0297_set_inversion(state, p->inversion);
+	stv0297_set_inversion(state, inversion);
 
 	/* kick off lock */
         stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
@@ -664,7 +695,6 @@
 
 	/* success!! */
         stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
-        state->freq_off = stv0297_get_carrieroffset(state);
         state->base_freq = p->frequency;
         return 0;
 
@@ -681,10 +711,12 @@
         reg_00 = stv0297_readreg(state, 0x00);
         reg_83 = stv0297_readreg(state, 0x83);
 
-        p->frequency = state->base_freq + state->freq_off;
+	p->frequency = state->base_freq;
         p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
-	p->u.qam.symbol_rate = 0;
-        p->u.qam.fec_inner = 0;
+	if (state->config->invert)
+		p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
+	p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000;
+	p->u.qam.fec_inner = FEC_NONE;
 
         switch((reg_00 >> 4) & 0x7) {
 	case 0:
@@ -729,7 +761,6 @@
         state->config = config;
         state->i2c = i2c;
         memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
-        state->freq_off = 0;
         state->base_freq = 0;
         state->pwm = pwm;
 
@@ -764,6 +795,7 @@
         .release = stv0297_release,
 
         .init = stv0297_init,
+	.sleep = stv0297_sleep,
 
         .set_frontend = stv0297_set_frontend,
         .get_frontend = stv0297_get_frontend,
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/stv0297.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/stv0297.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/stv0297.h	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/stv0297.h	2004-12-17 22:00:18.000000000 +0100
@@ -29,6 +29,9 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
+	/* does the "inversion" need inverted? */
+	u8 invert:1;
+
 	/* PLL maintenance */
 	int (*pll_init)(struct dvb_frontend* fe);
 	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/tda10021.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda10021.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/tda10021.c	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda10021.c	2005-01-20 19:56:38.000000000 +0100
@@ -4,7 +4,7 @@
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
     Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-                   Suppport for TDA10021
+                   Support for TDA10021
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/tda10021.h linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda10021.h
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/tda10021.h	2005-01-20 19:54:04.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda10021.h	2005-01-20 19:56:38.000000000 +0100
@@ -4,7 +4,7 @@
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
     Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-                   Suppport for TDA10021
+                   Support for TDA10021
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/frontends/tda80xx.c linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda80xx.c
--- linux-2.6.11-rc2/drivers/media/dvb/frontends/tda80xx.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/frontends/tda80xx.c	2004-11-18 15:58:34.000000000 +0100
@@ -27,10 +27,10 @@
 #include <linux/spinlock.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <asm/irq.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"


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

* [PATCH 8/9] dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes
  2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
                   ` (6 preceding siblings ...)
  2005-01-22 17:34 ` [PATCH 7/9] nxt2002: add ATSC support, misc fixes Johannes Stezenbach
@ 2005-01-22 17:34 ` Johannes Stezenbach
  7 siblings, 0 replies; 9+ messages in thread
From: Johannes Stezenbach @ 2005-01-22 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, js

- [DVB] dvb-ttpci: re-added support for Fujitsu-Siemens DVB-S rev 1.6 0x13c2:0x0006
- [DVB] dvb-ttpci: finally clean up debi irq/tasklet handling to make it work on SMP
- [DVB] dvb-ttpci: misc. changes to av7110_send_fw_cmd() error handling done along the way
- [DVB] dvb-ttpci: budgetpatch integrated into dvb-ttpci: enables full ts option running
        in parallel with all previous functions of dvb-ttpci
- [DVB] dvb-ttpci: fix Oops provoked by insmod/rmmod test loop, patch by Emard
- [DVB] budget: Fixed start_ts_capture(): saa7146 will not issue a VPE interrupt
        if VPE bit is set in PSR and VPE interrupts are enabled afterwards.
- [DVB] budget: enable satelco support. code was commented out, but actually it works, patch by Emard
- [DVB] budget: Budget patch improved driver, fixed slight packet loss by using different trigger mode

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

diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110.c	2005-01-20 19:56:38.000000000 +0100
@@ -67,6 +67,12 @@
 #include "av7110_ca.h"
 #include "av7110_ipack.h"
 
+#define TS_WIDTH  376
+#define TS_HEIGHT 512
+#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
+#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
+
+
 int av7110_debug;
 
 static int vidmode=CVBS_RGB_OUT;
@@ -75,6 +81,7 @@
 static int hw_sections;
 static int rgb_on;
 static int volume = 255;
+static int budgetpatch = 0;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -91,6 +98,8 @@
 		" 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)");
+module_param(budgetpatch, int, 0444);
+MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
 
 static void restart_feeds(struct av7110 *av7110);
 
@@ -349,27 +358,42 @@
 #endif
 }
 
+#define DEBI_READ 0
+#define DEBI_WRITE 1
+static inline void start_debi_dma(struct av7110 *av7110, int dir,
+				  unsigned long addr, unsigned int len)
+{
+	dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);
+	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);
+		return;
+	}
+
+	SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */
+	SAA7146_IER_ENABLE(av7110->dev, MASK_19);
+	if (len < 5)
+		len = 5; /* we want a real DEBI DMA */
+	if (dir == DEBI_WRITE)
+		iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3);
+	else
+		irdebi(av7110, DEBISWAB, addr, 0, len);
+}
+
 static void debiirq (unsigned long data)
 {
 	struct av7110 *av7110 = (struct av7110*) data;
         int type=av7110->debitype;
         int handle=(type>>8)&0x1f;
-	
-//	dprintk(4, "%p\n",av7110);
+	unsigned int xfer = 0;
 
         print_time("debi");
-	SAA7146_IER_DISABLE(av7110->dev, MASK_19);
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
+	dprintk(4, "type 0x%04x\n", type);
 
         if (type==-1) {
 		printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
 		       jiffies, saa7146_read(av7110->dev, PSR),
 		       saa7146_read(av7110->dev, SSR));
-		spin_lock(&av7110->debilock);
-                ARM_ClearMailBox(av7110);
-                ARM_ClearIrq(av7110);
-		spin_unlock(&av7110->debilock);
-                return;
+		goto debi_done;
         }
         av7110->debitype=-1;
 
@@ -379,22 +403,16 @@
                 dvb_dmx_swfilter_packets(&av7110->demux, 
                                       (const u8 *)av7110->debi_virt, 
                                       av7110->debilen/188);
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
 
         case DATA_PES_RECORD:
                 if (av7110->demux.recording) 
 			av7110_record_cb(&av7110->p2t[handle],
                                   (u8 *)av7110->debi_virt,
                                   av7110->debilen);
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
 
         case DATA_IPMPE:
         case DATA_FSECTION:
@@ -404,11 +422,8 @@
                                              av7110->debilen, NULL, 0, 
                                              av7110->handle2filter[handle], 
                                              DMX_OK, av7110); 
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
 
         case DATA_CI_GET:
         {
@@ -425,11 +440,8 @@
                         ci_get_data(&av7110->ci_rbuffer, 
                                     av7110->debi_virt, 
                                     av7110->debilen);
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
         }
 
         case DATA_COMMON_INTERFACE:
@@ -449,37 +461,35 @@
                 printk("\n");
         }
 #endif
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
 
         case DATA_DEBUG_MESSAGE:
                 ((s8*)av7110->debi_virt)[Reserved_SIZE-1]=0;
                 printk("%s\n", (s8 *)av7110->debi_virt);
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		xfer = RX_BUFF;
+		break;
 
         case DATA_CI_PUT:
+		dprintk(4, "debi DATA_CI_PUT\n");
         case DATA_MPEG_PLAY:
+		dprintk(4, "debi DATA_MPEG_PLAY\n");
         case DATA_BMP_LOAD:
-                spin_lock(&av7110->debilock);
-                iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
-                ARM_ClearMailBox(av7110);
-                spin_unlock(&av7110->debilock);
-                return;
+		dprintk(4, "debi DATA_BMP_LOAD\n");
+		xfer = TX_BUFF;
+		break;
         default:
                 break;
         }
+debi_done:
         spin_lock(&av7110->debilock);
+	if (xfer)
+		iwdebi(av7110, DEBINOSWAP, xfer, 0, 2);
         ARM_ClearMailBox(av7110);
         spin_unlock(&av7110->debilock);
 }
 
+/* irq from av7110 firmware writing the mailbox register in the DPRAM */
 static void gpioirq (unsigned long data)
 {
 	struct av7110 *av7110 = (struct av7110*) data;
@@ -487,27 +497,29 @@
         int len;
         
         if (av7110->debitype !=-1)
+		/* we shouldn't get any irq while a debi xfer is running */
 		printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
 		       jiffies, saa7146_read(av7110->dev, PSR),
 		       saa7146_read(av7110->dev, SSR));
        
-        spin_lock(&av7110->debilock);
+	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
+		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);
+		BUG(); /* maybe we should try resetting the debi? */
+	}
 
+	spin_lock(&av7110->debilock);
 	ARM_ClearIrq(av7110);
 
-	SAA7146_IER_DISABLE(av7110->dev, MASK_19);
-	SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
-
+	/* see what the av7110 wants */
         av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);
         av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
         rxbuf=irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
         txbuf=irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
 	len = (av7110->debilen + 3) & ~3;
 
-//	dprintk(8, "GPIO0 irq %d %d\n", av7110->debitype, av7110->debilen);
         print_time("gpio");
+	dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen);
 
-//	dprintk(8, "GPIO0 irq %02x\n", av7110->debitype&0xff);
         switch (av7110->debitype&0xff) {
 
         case DATA_TS_PLAY:
@@ -579,16 +591,12 @@
 
                 dvb_ringbuffer_read(cibuf,av7110->debi_virt,len,0);
 
-                wake_up(&cibuf->queue);
                 iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
                 iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		saa7146_wait_for_debi_done(av7110->dev, 0);
-                saa7146_write(av7110->dev, IER, 
-                              saa7146_read(av7110->dev, IER) | MASK_19 );
-		if (len < 5)
-			len = 5; /* we want a real DEBI DMA */
-                iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3);
+		dprintk(8, "DMA: CI\n");
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
                 spin_unlock(&av7110->debilock);
+		wake_up(&cibuf->queue);
                 return;
         }
 
@@ -620,22 +628,21 @@
 		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
                 iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
                 iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		saa7146_wait_for_debi_done(av7110->dev, 0);
-                saa7146_write(av7110->dev, IER, 
-                              saa7146_read(av7110->dev, IER) | MASK_19 );
-
-                iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3);
+		dprintk(8, "DMA: MPEG_PLAY\n");
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
                 spin_unlock(&av7110->debilock);
                 return;
 
         case DATA_BMP_LOAD:
                 len=av7110->debilen;
+		dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len);
                 if (!len) {
                         av7110->bmp_state=BMP_LOADED;
                         iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);
                         iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);
                         iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);
                         wake_up(&av7110->bmpq);
+			dprintk(8, "gpio DATA_BMP_LOAD done\n");
                         break;
                 }
                 if (len>av7110->bmplen)
@@ -647,12 +654,8 @@
                 memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
                 av7110->bmpp+=len;
                 av7110->bmplen-=len;
-		saa7146_wait_for_debi_done(av7110->dev, 0);
-                saa7146_write(av7110->dev, IER, 
-                              saa7146_read(av7110->dev, IER) | MASK_19 );
-		if (len < 5)
-			len = 5; /* we want a real DEBI DMA */
-                iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3);
+		dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
+		start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len);
                 spin_unlock(&av7110->debilock);
                 return;
 
@@ -669,22 +672,17 @@
 
         case DATA_TS_RECORD:
         case DATA_PES_RECORD:
-		saa7146_wait_for_debi_done(av7110->dev, 0);
-                saa7146_write(av7110->dev, IER, 
-                              saa7146_read(av7110->dev, IER) | MASK_19);
-                irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len);
+		dprintk(8, "DMA: TS_REC etc.\n");
+		start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len);
                 spin_unlock(&av7110->debilock);
                 return;
 
         case DATA_DEBUG_MESSAGE:
-		saa7146_wait_for_debi_done(av7110->dev, 0);
                 if (!len || len>0xff) {
                         iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
                         break;
                 }
-                saa7146_write(av7110->dev, IER, 
-                              saa7146_read(av7110->dev, IER) | MASK_19);
-                irdebi(av7110, DEBISWAB, Reserved, 0, len);
+		start_debi_dma(av7110, DEBI_READ, Reserved, len);
                 spin_unlock(&av7110->debilock);
                 return;
 
@@ -699,8 +697,8 @@
                        av7110->debitype, av7110->debilen);
                 break;
         }      
-        ARM_ClearMailBox(av7110);
         av7110->debitype=-1;
+	ARM_ClearMailBox(av7110);
         spin_unlock(&av7110->debilock);
 }
 
@@ -1145,11 +1144,107 @@
 	return 0;
 }
 
+/* simplified code from budget-core.c */
+static int stop_ts_capture(struct av7110 *budget)
+{
+	dprintk(2, "budget: %p\n", budget);
+
+	if (--budget->feeding1)
+		return budget->feeding1;
+	saa7146_write(budget->dev, MC1, MASK_20);	/* DMA3 off */
+	SAA7146_IER_DISABLE(budget->dev, MASK_10);
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);
+	return 0;
+}
+
+static int start_ts_capture(struct av7110 *budget)
+{
+	dprintk(2, "budget: %p\n", budget);
+
+	if (budget->feeding1)
+		return ++budget->feeding1;
+	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
+	budget->tsf = 0xff;
+	budget->ttbp = 0;
+	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
+	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
+	return ++budget->feeding1;
+}
+
+static int budget_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *budget = (struct av7110 *) demux->priv;
+	int status;
+
+	dprintk(2, "av7110: %p\n", budget);
+
+	spin_lock(&budget->feedlock1);
+	feed->pusi_seen = 0; /* have a clean section start */
+	status = start_ts_capture(budget);
+	spin_unlock(&budget->feedlock1);
+	return status;
+}
+
+static int budget_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct av7110 *budget = (struct av7110 *) demux->priv;
+	int status;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	spin_lock(&budget->feedlock1);
+	status = stop_ts_capture(budget);
+	spin_unlock(&budget->feedlock1);
+	return status;
+}
+
+static void vpeirq(unsigned long data)
+{
+	struct av7110 *budget = (struct av7110 *) data;
+	u8 *mem = (u8 *) (budget->grabbing);
+	u32 olddma = budget->ttbp;
+	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+
+	if (!budgetpatch) {
+		printk("av7110.c: vpeirq() called while budgetpatch disabled!"
+		       " check saa7146 IER register\n");
+		BUG();
+	}
+	/* nearest lower position divisible by 188 */
+	newdma -= newdma % 188;
+
+	if (newdma >= TS_BUFLEN)
+		return;
+
+	budget->ttbp = newdma;
+
+	if (!budget->feeding1 || (newdma == olddma))
+		return;
+
+#if 0
+	/* track rps1 activity */
+	printk("vpeirq: %02x Event Counter 1 0x%04x\n",
+	       mem[olddma],
+	       saa7146_read(budget->dev, EC1R) & 0x3fff);
+#endif
+
+	if (newdma > olddma)
+		/* no wraparound, dump olddma..newdma */
+		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
+	else {
+		/* wraparound, dump olddma..buflen and 0..newdma */
+		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
+		dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
+	}
+}
 
 static int av7110_register(struct av7110 *av7110)
 {
         int ret, i;
         struct dvb_demux *dvbdemux=&av7110->demux;
+	struct dvb_demux *dvbdemux1 = &av7110->demux1;
 
 	dprintk(4, "%p\n", av7110);
 
@@ -1209,6 +1304,32 @@
         
         dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx);
 
+	if (budgetpatch) {
+		/* initialize software demux1 without its own frontend
+		 * demux1 hardware is connected to frontend0 of demux0
+		 */
+		dvbdemux1->priv = (void *) av7110;
+
+		dvbdemux1->filternum = 256;
+		dvbdemux1->feednum = 256;
+		dvbdemux1->start_feed = budget_start_feed;
+		dvbdemux1->stop_feed = budget_stop_feed;
+		dvbdemux1->write_to_decoder = NULL;
+
+		dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+					       DMX_MEMORY_BASED_FILTERING);
+
+		dvb_dmx_init(&av7110->demux1);
+
+		av7110->dmxdev1.filternum = 256;
+		av7110->dmxdev1.demux = &dvbdemux1->dmx;
+		av7110->dmxdev1.capabilities = 0;
+
+		dvb_dmxdev_init(&av7110->dmxdev1, av7110->dvb_adapter);
+
+		dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
+		printk("dvb-ttpci: additional demux1 for budget-patch registered\n");
+	}
 	return 0;
 }
 
@@ -1216,12 +1337,20 @@
 static void dvb_unregister(struct av7110 *av7110)
 {
         struct dvb_demux *dvbdemux=&av7110->demux;
+	struct dvb_demux *dvbdemux1 = &av7110->demux1;
 
 	dprintk(4, "%p\n", av7110);
 
         if (!av7110->registered)
                 return;
 
+	if (budgetpatch) {
+		dvb_net_release(&av7110->dvb_net1);
+		dvbdemux->dmx.close(&dvbdemux1->dmx);
+		dvb_dmxdev_release(&av7110->dmxdev1);
+		dvb_dmx_release(&av7110->demux1);
+	}
+
 	dvb_net_release(&av7110->dvb_net);
 
 	dvbdemux->dmx.close(&dvbdemux->dmx);
@@ -1700,6 +1829,7 @@
 static struct stv0297_config nexusca_stv0297_config = {
 
 	.demod_address = 0x1C,
+	.invert = 1,
 	.pll_set = nexusca_stv0297_pll_set,
 };
 
@@ -1899,12 +2029,22 @@
                         av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
 			break;
 
+		case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
+			/* Grundig 29504-451 */
+			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops->set_tone = av7110_set_tone;
+			}
+			break;
+
 		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
 
 			av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b);
 			if (av7110->fe) {
 				/* set TDA9819 into DVB mode */
-				saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+				saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
 				saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
 
 				/* tuner on this needs a slower i2c bus speed */
@@ -1940,13 +2080,169 @@
 	}
 }
 
+/* Budgetpatch note:
+ * Original hardware design by Roberto Deza:
+ * There is a DVB_Wiki at
+ * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page
+ * where is described this 'DVB TT Budget Patch', on Card Modding:
+ * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch
+ * On the short description there is also a link to a external file,
+ * with more details:
+ * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip
+ *
+ * New software triggering design by Emard that works on
+ * original Roberto Deza's hardware:
+ *
+ * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin.
+ * GPIO3 is in budget-patch hardware connectd to port B VSYNC
+ * HS is an internal event of 7146, accessible with RPS
+ * and temporarily raised high every n lines
+ * (n in defined in the RPS_THRESH1 counter threshold)
+ * I think HS is raised high on the beginning of the n-th line
+ * and remains high until this n-th line that triggered
+ * it is completely received. When the receiption of n-th line
+ * ends, HS is lowered.
+ *
+ * To transmit data over DMA, 7146 needs changing state at
+ * port B VSYNC pin. Any changing of port B VSYNC will
+ * cause some DMA data transfer, with more or less packets loss.
+ * It depends on the phase and frequency of VSYNC and
+ * the way of 7146 is instructed to trigger on port B (defined
+ * in DD1_INIT register, 3rd nibble from the right valid
+ * numbers are 0-7, see datasheet)
+ *
+ * The correct triggering can minimize packet loss,
+ * dvbtraffic should give this stable bandwidths:
+ *   22k transponder = 33814 kbit/s
+ * 27.5k transponder = 38045 kbit/s
+ * by experiment it is found that the best results
+ * (stable bandwidths and almost no packet loss)
+ * are obtained using DD1_INIT triggering number 2
+ * (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
+ * and a VSYNC phase that occurs in the middle of DMA transfer
+ * (about byte 188*512=96256 in the DMA window).
+ *
+ * Phase of HS is still not clear to me how to control,
+ * It just happens to be so. It can be seen if one enables
+ * RPS_IRQ and print Event Counter 1 in vpeirq(). Every
+ * time RPS_INTERRUPT is called, the Event Counter 1 will
+ * increment. That's how the 7146 is programmed to do event
+ * counting in this budget-patch.c
+ * I *think* HPS setting has something to do with the phase
+ * of HS but I cant be 100% sure in that.
+ *
+ * hardware debug note: a working budget card (including budget patch)
+ * with vpeirq() interrupt setup in mode "0x90" (every 64K) will
+ * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
+ * and that means 3*25=75 Hz of interrupt freqency, as seen by
+ * watch cat /proc/interrupts
+ *
+ * If this frequency is 3x lower (and data received in the DMA
+ * buffer don't start with 0x47, but in the middle of packets,
+ * whose lengths appear to be like 188 292 188 104 etc.
+ * this means VSYNC line is not connected in the hardware.
+ * (check soldering pcb and pins)
+ * The same behaviour of missing VSYNC can be duplicated on budget
+ * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
+ */
 static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
 {
 	struct av7110 *av7110 = NULL;
+	int length = TS_WIDTH * TS_HEIGHT;
 	int ret = 0;
+	int count = 0;
 
 	dprintk(4, "dev: %p\n", dev);
 
+        /* Set RPS_IRQ to 1 to track rps1 activity.
+         * Enabling this won't send any interrupt to PC CPU.
+         */
+#define RPS_IRQ 0
+
+	if (budgetpatch == 1) {
+		budgetpatch = 0;
+		/* autodetect the presence of budget patch
+		 * this only works if saa7146 has been recently
+		 * reset with with MASK_31 to MC1
+		 *
+		 * will wait for VBI_B event (vertical blank at port B)
+		 * and will reset GPIO3 after VBI_B is detected.
+		 * (GPIO3 should be raised high by CPU to
+		 * test if GPIO3 will generate vertical blank signal
+		 * in budget patch GPIO3 is connected to VSYNC_B
+		 */
+
+		/* RESET SAA7146 */
+		saa7146_write(dev, MC1, MASK_31);
+		/* autodetection success seems to be time-dependend after reset */
+
+		/* Fix VSYNC level */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		/* set vsync_b triggering */
+		saa7146_write(dev, DD1_STREAM_B, 0);
+		/* port B VSYNC at rising edge */
+		saa7146_write(dev, DD1_INIT, 0x00000200);
+		saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
+		saa7146_write(dev, MC2,
+			      1 * (MASK_08 | MASK_24)  |   // BRS control
+			      0 * (MASK_09 | MASK_25)  |   // a
+			      1 * (MASK_10 | MASK_26)  |   // b
+			      0 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
+			      0 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
+			      0 * (MASK_01 | MASK_15)      // DEBI
+		);
+
+		/* start writing RPS1 code from beginning */
+		count = 0;
+		/* Disable RPS1 */
+		saa7146_write(dev, MC1, MASK_29);
+		/* RPS1 timeout disable */
+		saa7146_write(dev, RPS_TOV1, 0);
+		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
+		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+#if RPS_IRQ
+		/* issue RPS1 interrupt to increment counter */
+		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+		WRITE_RPS1(cpu_to_le32(CMD_STOP));
+		/* Jump to begin of RPS program as safety measure               (p37) */
+		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
+		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+
+#if RPS_IRQ
+		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+		 */
+		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+		/* set event counter 1 treshold to maximum allowed value        (rEC p55) */
+		saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
+		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+		/* Enable RPS1,                                                 (rFC p33) */
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
+
+		mdelay(10);
+		/* now send VSYNC_B to rps1 by rising GPIO3 */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+		mdelay(10);
+		/* if rps1 responded by lowering the GPIO3,
+		 * then we have budgetpatch hardware
+		 */
+		if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) {
+			budgetpatch = 1;
+			printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n");
+		}
+		/* Disable RPS1 */
+		saa7146_write(dev, MC1, ( MASK_29 ));
+#if RPS_IRQ
+		printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
+#endif
+	}
+
 	/* prepare the av7110 device struct */
 	if (!(av7110 = kmalloc (sizeof (struct av7110), GFP_KERNEL))) {
 		dprintk(1, "out of memory\n");
@@ -1980,6 +2276,7 @@
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
 
 	if (i2c_add_adapter(&av7110->i2c_adap) < 0) {
+err_no_mem:
 		dvb_unregister_adapter (av7110->dvb_adapter);
 		kfree(av7110);
 		return -ENOMEM;
@@ -1987,6 +2284,86 @@
 
 	ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac);
 
+	if (budgetpatch) {
+		spin_lock_init(&av7110->feedlock1);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(
+					 dev->pci, length, &av7110->pt);
+		if (!av7110->grabbing)
+			goto err_no_mem;
+		saa7146_write(dev, PCI_BT_V1, 0x1c1f101f);
+		saa7146_write(dev, BCS_CTRL, 0x80400040);
+		/* set dd1 stream a & b */
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, DD1_INIT, 0x03000200);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		saa7146_write(dev, BASE_ODD3, 0);
+		saa7146_write(dev, BASE_EVEN3, 0);
+		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+
+		saa7146_write(dev, PITCH3, TS_WIDTH);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+
+		/* upload all */
+		saa7146_write(dev, MC2, 0x077c077c);
+		saa7146_write(dev, GPIO_CTRL, 0x000000);
+#if RPS_IRQ
+		/* set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+		 * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+		 * use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+		 */
+		saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+		/* set event counter 1 treshold to maximum allowed value        (rEC p55) */
+		saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+		/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
+		count = 0;
+
+		/* Wait Source Line Counter Threshold                           (p36) */
+		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+		/* Set GPIO3=1                                                  (p42) */
+		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+#if RPS_IRQ
+		/* issue RPS1 interrupt */
+		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+		/* Wait reset Source Line Counter Threshold                     (p36) */
+		WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+		/* Set GPIO3=0                                                  (p42) */
+		WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+		WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+		WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+#if RPS_IRQ
+		/* issue RPS1 interrupt */
+		WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+		/* Jump to begin of RPS program                                 (p37) */
+		WRITE_RPS1(cpu_to_le32(CMD_JUMP));
+		WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+
+		/* Fix VSYNC level */
+		saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		/* Set RPS1 Address register to point to RPS code               (r108 p42) */
+		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+		/* Set Source Line Counter Threshold, using BRS                 (rCC p43)
+		 * It generates HS event every TS_HEIGHT lines
+		 * this is related to TS_WIDTH set in register
+		 * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits
+		 * are set to TS_WIDTH bytes (TS_WIDTH=2*188),
+		 * then RPS_THRESH1 should be set to trigger
+		 * every TS_HEIGHT (512) lines.
+		 */
+		saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
+
+		/* Enable RPS1                                                  (rFC p33) */
+		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
+
+		/* end of budgetpatch register initialization */
+		tasklet_init (&av7110->vpe_tasklet,  vpeirq,  (unsigned long) av7110);
+	} else {
 	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
 	saa7146_write(dev, BCS_CTRL, 0x80400040);
 
@@ -1998,6 +2375,7 @@
 	/* upload all */
 	saa7146_write(dev, MC2, 0x077c077c);
         saa7146_write(dev, GPIO_CTRL, 0x000000);
+	}
 
 	tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
 	tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
@@ -2109,10 +2487,21 @@
 	struct av7110 *av7110 = (struct av7110*)saa->ext_priv;
 	dprintk(4, "%p\n", av7110);
 	
-	if( 0 == av7110->device_initialized ) {
+	if (!av7110->device_initialized )
 		return 0;
-	}
 
+	if (budgetpatch) {
+		/* Disable RPS1 */
+		saa7146_write(saa, MC1, MASK_29);
+		/* VSYNC LOW (inactive) */
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+		saa7146_write(saa, MC1, MASK_20);	/* DMA3 off */
+		SAA7146_IER_DISABLE(saa, MASK_10);
+		SAA7146_ISR_CLEAR(saa, MASK_10);
+		msleep(50);
+		tasklet_kill(&av7110->vpe_tasklet);
+		saa7146_pgtable_free(saa->pci, &av7110->pt);
+	}
 	av7110_exit_v4l(av7110);
 
 	av7110->arm_rmmod=1;
@@ -2121,6 +2510,9 @@
 	while (av7110->arm_thread)
 		msleep(1);
 
+	tasklet_kill(&av7110->debi_tasklet);
+	tasklet_kill(&av7110->gpio_tasklet);
+
 	dvb_unregister(av7110);
 	
 	SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03);
@@ -2153,13 +2545,43 @@
 {
 	struct av7110 *av7110 = dev->ext_priv;
 
-	if (*isr & MASK_19)
+	//print_time("av7110_irq");
+
+	/* Note: Don't try to handle the DEBI error irq (MASK_18), in
+	 * intel mode the timeout is asserted all the time...
+	 */
+
+	if (*isr & MASK_19) {
+		//printk("av7110_irq: DEBI\n");
+		/* Note 1: The DEBI irq is level triggered: We must enable it
+		 * only after we started a DMA xfer, and disable it here
+		 * immediately, or it will be signalled all the time while
+		 * DEBI is idle.
+		 * Note 2: You would think that an irq which is masked is
+		 * not signalled by the hardware. Not so for the SAA7146:
+		 * An irq is signalled as long as the corresponding bit
+		 * in the ISR is set, and disabling irqs just prevents the
+		 * hardware from setting the ISR bit. This means a) that we
+		 * must clear the ISR *after* disabling the irq (which is why
+		 * we must do it here even though saa7146_core did it already),
+		 * and b) that if we were to disable an edge triggered irq
+		 * (like the gpio irqs sadly are) temporarily we would likely
+		 * loose some. This sucks :-(
+		 */
+		SAA7146_IER_DISABLE(av7110->dev, MASK_19);
+		SAA7146_ISR_CLEAR(av7110->dev, MASK_19);
 		tasklet_schedule (&av7110->debi_tasklet);
+	}
 	
-	if (*isr & MASK_03)
+	if (*isr & MASK_03) {
+		//printk("av7110_irq: GPIO\n");
 		tasklet_schedule (&av7110->gpio_tasklet);
 }
 
+	if ((*isr & MASK_10) && budgetpatch)
+		tasklet_schedule(&av7110->vpe_tasklet);
+}
+
 
 static struct saa7146_extension av7110_extension;
 
@@ -2173,8 +2595,9 @@
 MAKE_AV7110_INFO(ttc_1_X,    "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
 MAKE_AV7110_INFO(ttc_2_X,    "Technotrend/Hauppauge WinTV DVB-C rev2.X");
 MAKE_AV7110_INFO(tts_2_X,    "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
-MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV Nexus-S rev1.3");
+MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE");
 MAKE_AV7110_INFO(fsc,        "Fujitsu Siemens DVB-C");
+MAKE_AV7110_INFO(fss,        "Fujitsu Siemens DVB-S rev1.6");
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(tts_1_X,   0x13c2, 0x0000),
@@ -2184,10 +2607,10 @@
 	MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
 	MAKE_EXTENSION_PCI(fsc,       0x110a, 0x0000),
 	MAKE_EXTENSION_PCI(ttc_1_X,   0x13c2, 0x000a),
+	MAKE_EXTENSION_PCI(fss,       0x13c2, 0x0006),
 
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
-/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v????
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
 /*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
 
@@ -2208,7 +2631,7 @@
 	.attach		= av7110_attach,
 	.detach		= av7110_detach,
 
-	.irq_mask	= MASK_19|MASK_03,
+	.irq_mask	= MASK_19 | MASK_03 | MASK_10,
 	.irq_func	= av7110_irq,
 };	
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110.h linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110.h
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110.h	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110.h	2005-01-20 19:56:38.000000000 +0100
@@ -115,7 +115,7 @@
 
         int                     bmpp;
         int                     bmplen;
-        int                     bmp_state;
+	volatile int		bmp_state;
 #define BMP_NONE     0
 #define BMP_LOADING  1
 #define BMP_LOADINGS 2
@@ -158,6 +158,18 @@
         struct dmx_frontend	hw_frontend;
         struct dmx_frontend	mem_frontend;
 
+	/* for budget mode demux1 */
+	struct dmxdev		dmxdev1;
+	struct dvb_demux	demux1;
+	struct dvb_net		dvb_net1;
+	spinlock_t		feedlock1;
+	int			feeding1;
+	u8			tsf;
+	u32			ttbp;
+	unsigned char           *grabbing;
+	struct saa7146_pgtable  pt;
+	struct tasklet_struct   vpe_tasklet;
+
         int                     fe_synced; 
         struct semaphore        pid_mutex;
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110_hw.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110_hw.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110_hw.c	2005-01-20 19:55:47.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110_hw.c	2005-01-20 19:56:39.000000000 +0100
@@ -153,8 +153,10 @@
 	base = DRAM_START_CODE;
 
 	for (i = 0; i < blocks; i++) {
-		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
+		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
 			return -1;
+		}
 		dprintk(4, "writing DRAM block %d\n", i);
 		mwdebi(av7110, DEBISWAB, bootblock,
 		       ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
@@ -166,8 +168,10 @@
 	}
 
 	if (rest > 0) {
-		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
+		if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+			printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
 			return -1;
+		}
 		if (rest > 4)
 			mwdebi(av7110, DEBISWAB, bootblock,
 			       ((char*)data) + i * BOOT_MAX_SIZE, rest);
@@ -179,12 +183,16 @@
 		iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2);
 		iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 	}
-	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
+	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+		printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
 		return -1;
+	}
 	iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
 	iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0)
+	if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
+		printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
 		return -1;
+	}
 	return 0;
 }
 
@@ -261,8 +269,11 @@
 	mdelay(1);
 
 	dprintk(1, "load dram code\n");
-	if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0)
+	if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
+		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
+		       "load_dram() failed\n");
 		return -1;
+	}
 
 	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 	mdelay(1);
@@ -336,7 +347,7 @@
 
 	if (!av7110->arm_ready) {
 		dprintk(1, "arm not ready.\n");
-		return -1;
+		return -ENXIO;
 	}
 
 	start = jiffies;
@@ -344,7 +355,7 @@
 		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
-			return -1;
+			return -ETIMEDOUT;
 		}
 	}
 
@@ -356,7 +367,7 @@
 		msleep(1);
 		if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-			return -1;
+			return -ETIMEDOUT;
 		}
 	}
 #endif
@@ -375,6 +386,13 @@
 		flags[0] = OSDQOver;
 		flags[1] = OSDQFull;
 		break;
+	case COMTYPE_MISC:
+		if (FW_VERSION(av7110->arm_app) >= 0x261d) {
+			type = "MSG";
+			flags[0] = GPMQOver;
+			flags[1] = GPMQBusy;
+		}
+		break;
 	default:
 		break;
 	}
@@ -419,18 +437,18 @@
 		if (time_after(jiffies, start + ARM_WAIT_FREE)) {
 			printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
 			       __FUNCTION__);
-			return -1;
+			return -ETIMEDOUT;
 		}
 	}
 
 	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 	if (stat & GPMQOver) {
 		printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
-		return -1;
+		return -ENOSPC;
 	}
 	else if (stat & OSDQOver) {
 		printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
-		return -1;
+		return -ENOSPC;
 	}
 #endif
 
@@ -453,7 +471,8 @@
 	ret = __av7110_send_fw_cmd(av7110, buf, length);
 	up(&av7110->dcomlock);
 	if (ret)
-		printk("dvb-ttpci: %s(): av7110_send_fw_cmd error\n", __FUNCTION__);
+		printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
+		       __FUNCTION__, ret);
 	return ret;
 }
 
@@ -477,7 +496,7 @@
 
 	ret = av7110_send_fw_cmd(av7110, buf, num + 2);
 	if (ret)
-		printk("dvb-ttpci: av7110_fw_cmd error\n");
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
 	return ret;
 }
 
@@ -499,7 +518,7 @@
 
 	ret = av7110_send_fw_cmd(av7110, cmd, 18);
 	if (ret)
-		printk("dvb-ttpci: av7110_send_ci_cmd error\n");
+		printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
 	return ret;
 }
 
@@ -525,7 +544,7 @@
 
 	if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
 		up(&av7110->dcomlock);
-		printk("dvb-ttpci: av7110_fw_request error\n");
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
 		return err;
 	}
 
@@ -579,7 +598,7 @@
 	int ret;
 	ret = av7110_fw_request(av7110, &tag, 0, buf, length);
 	if (ret)
-		printk("dvb-ttpci: av7110_fw_query error\n");
+		printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
 	return ret;
 }
 
@@ -626,7 +645,7 @@
 
 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
 {
-	int i;
+	int i, ret;
 	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
 			16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
@@ -646,8 +665,8 @@
 	for (i = 0; i < len; i++)
 		buf[i + 4] = msg[i];
 
-	if (av7110_send_fw_cmd(av7110, buf, 18))
-		printk("dvb-ttpci: av7110_diseqc_send error\n");
+	if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
+		printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
 
 	return 0;
 }
@@ -741,7 +775,7 @@
 	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
 	up(&av7110->dcomlock);
 	if (ret)
-		printk("dvb-ttpci: WriteText error\n");
+		printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
 	return ret;
 }
 
@@ -808,7 +842,8 @@
 
 	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__);
+		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+		       ret, av7110->bmp_state);
 		av7110->bmp_state = BMP_NONE;
 		return -1;
 	}
@@ -850,6 +885,7 @@
 		}
 	}
 	av7110->bmplen += 1024;
+	dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
 	return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
 }
 
@@ -861,11 +897,13 @@
 
 	BUG_ON (av7110->bmp_state == BMP_NONE);
 
-	ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
+	ret = wait_event_interruptible_timeout(av7110->bmpq,
+				av7110->bmp_state != BMP_LOADING, 10*HZ);
 	if (ret == -ERESTARTSYS || ret == 0) {
-		printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__);
+		printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
+		       ret, av7110->bmp_state);
 		av7110->bmp_state = BMP_NONE;
-		return -1;
+		return (ret == 0) ? -ETIMEDOUT : ret;
 		}
 
 	BUG_ON (av7110->bmp_state != BMP_LOADED);
@@ -943,6 +981,7 @@
 {
 	uint w, h, bpp, bpl, size, lpb, bnum, brest;
 	int i;
+	int rc;
 
 	w = x1 - x0 + 1;
 	h = y1 - y0 + 1;
@@ -958,15 +997,23 @@
 	brest = size - bnum * lpb * bpl;
 
 	for (i = 0; i < bnum; i++) {
-		LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
+		rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
 			   w, lpb, inc, data);
-		BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+		if (rc)
+			return rc;
+		rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+		if (rc)
+			return rc;
 		data += lpb * inc;
 	}
 	if (brest) {
-		LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
+		rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
 			   w, brest / bpl, inc, data);
-		BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
+		if (rc)
+			return rc;
+		rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
+		if (rc)
+			return rc;
 	}
 	ReleaseBitmap(av7110);
 	return 0;
@@ -1019,7 +1066,7 @@
 			goto out;
 		} else {
 			int i, len = dc->x0-dc->color+1;
-			u8 __user *colors = (u8 __user *)dc->data;
+			u8 __user *colors = (u8 *)dc->data;
 			u8 r, g, b, blend;
 
 			for (i = 0; i<len; i++) {
@@ -1048,7 +1095,7 @@
 		dc->y1 = dc->y0;
 		/* fall through */
 	case OSD_SetBlock:
-		OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
+		ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
 		goto out;
 	case OSD_FillRow:
 		DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110_v4l.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110_v4l.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/av7110_v4l.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/av7110_v4l.c	2005-01-20 19:56:39.000000000 +0100
@@ -250,7 +248,7 @@
 			if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
 				dprintk(1, "setting band in demodulator failed.\n");
 		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
 		}
 	}
@@ -591,7 +589,7 @@
 			if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
 				dprintk(1, "setting band in demodulator failed.\n");
 		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
-			saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
+			saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
 			saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
 		}
 
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget.c	2005-01-20 19:56:39.000000000 +0100
@@ -414,7 +412,7 @@
 {
 	switch(budget->dev->pci->subsystem_device) {
 	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
-
+	case 0x1013:
 		// try the ALPS BSRV2 first of all
 		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
@@ -522,14 +517,14 @@
 MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
-/* MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
+MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
-/*	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
+	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
 	MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
 	{
 		.vendor    = 0,
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget-core.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget-core.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget-core.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget-core.c	2005-01-20 19:56:39.000000000 +0100
@@ -89,11 +87,18 @@
 	 *	Pitch: 188, NumBytes3: 188, NumLines3: 1024
 	 */
 
-	if (budget->card->type == BUDGET_FS_ACTIVY) {
+        switch(budget->card->type) {
+	case BUDGET_FS_ACTIVY:
 		saa7146_write(dev, DD1_INIT, 0x04000000);
 		saa7146_write(dev, MC2, (MASK_09 | MASK_25));
 		saa7146_write(dev, BRS_CTRL, 0x00000000);
-	} else {
+		break;
+	case BUDGET_PATCH:
+		saa7146_write(dev, DD1_INIT, 0x00000200);
+		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		break;
+	default:
 		if (budget->video_port == BUDGET_VIDEO_PORTA) {
 			saa7146_write(dev, DD1_INIT, 0x06000200);
 			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
@@ -122,9 +127,10 @@
 	}
 
       	saa7146_write(dev, MC2, (MASK_04 | MASK_20));
-     	saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on
 
-	SAA7146_IER_ENABLE(budget->dev, MASK_10);	// VPE
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
+	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
+	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
 
         return ++budget->feeding;
 }
@@ -249,6 +254,7 @@
                 return -EINVAL;
 
    	spin_lock(&budget->feedlock);   
+	feed->pusi_seen = 0; /* have a clean section start */
 	status = start_ts_capture (budget);
    	spin_unlock(&budget->feedlock);
 	return status;
diff -uraNwB linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget-patch.c linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget-patch.c
--- linux-2.6.11-rc2/drivers/media/dvb/ttpci/budget-patch.c	2005-01-20 19:54:05.000000000 +0100
+++ linux-2.6.11-rc2-dvb/drivers/media/dvb/ttpci/budget-patch.c	2005-01-20 19:56:39.000000000 +0100
@@ -41,34 +41,127 @@
 
 static struct saa7146_extension budget_extension;
 
-MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);
+MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
+//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
 
 static struct pci_device_id pci_tbl[] = {
-        MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),
+        MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
+//        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
         {
                 .vendor    = 0,
         }
 };
 
-static int budget_wdebi(struct budget_patch *budget, u32 config, int addr, u32 val, int count)
+/* those lines are for budget-patch to be tried
+** on a true budget card and observe the
+** behaviour of VSYNC generated by rps1.
+** this code was shamelessly copy/pasted from budget.c 
+*/
+static void gpio_Set22K (struct budget *budget, int state)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
+}
+
+/* Diseqc functions only for TT Budget card */
+/* taken from the Skyvision DVB driver by
+   Ralph Metzler <rjkm@metzlerbros.de> */
+
+static void DiseqcSendBit (struct budget *budget, int data)
+{
+	struct saa7146_dev *dev=budget->dev;
+	dprintk(2, "budget: %p\n", budget);
+
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+	udelay(data ? 500 : 1000);
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	udelay(data ? 1000 : 500);
+}
+
+static void DiseqcSendByte (struct budget *budget, int data)
+{
+	int i, par=1, d;
+
+	dprintk(2, "budget: %p\n", budget);
+
+	for (i=7; i>=0; i--) {
+		d = (data>>i)&1;
+		par ^= d;
+		DiseqcSendBit(budget, d);
+	}
+
+	DiseqcSendBit(budget, par);
+}
+
+static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
 {
         struct saa7146_dev *dev=budget->dev;
+	int i;
 
         dprintk(2, "budget: %p\n", budget);
 
-        if (count <= 0 || count > 4)
-                return -1;
+	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+	mdelay(16);
+
+	for (i=0; i<len; i++)
+		DiseqcSendByte(budget, msg[i]);
+
+	mdelay(16);
+
+	if (burst!=-1) {
+		if (burst)
+			DiseqcSendByte(budget, 0xff);
+		else {
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+			udelay(12500);
+			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+/* shamelessly copy/pasted from budget.c 
+*/
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		gpio_Set22K (budget, 1);
+		break;
+
+	case SEC_TONE_OFF:
+		gpio_Set22K (budget, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
-        saa7146_write(dev, DEBI_CONFIG, config);
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
 
-        saa7146_write(dev, DEBI_AD, val );
-        saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
-        saa7146_write(dev, MC2, (2 << 16) | 2);
-        mdelay(5);
+	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
 
         return 0;
 }
 
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+	return 0;
+}
 
 static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
 {
@@ -77,14 +170,17 @@
         dprintk(2, "budget: %p\n", budget);
 
         for (i = 2; i < length; i++)
-                budget_wdebi(budget, DEBINOSWAP, COMMAND + 2*i, (u32) buf[i], 2);
-
+        {
+                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
+                  msleep(5);
+        }                  
         if (length)
-                budget_wdebi(budget, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
+                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
         else
-                budget_wdebi(budget, DEBINOSWAP, COMMAND + 2, 0, 2);
-
-        budget_wdebi(budget, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
+                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
+        msleep(5);     
+        ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
+        msleep(5);
         return 0;
 }
 
@@ -319,6 +415,7 @@
 {
 	switch(budget->dev->pci->subsystem_device) {
 	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+        case 0x1013: // SATELCO Multimedia PCI
 
 		// try the ALPS BSRV2 first of all
 		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
@@ -332,18 +429,18 @@
 		// try the ALPS BSRU6 now
 		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_set_tone;
 			break;
 		}
 
 		// Try the grundig 29504-451
 		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_set_tone;
 			break;
 		}
 		break;
@@ -365,23 +462,120 @@
 	}
 }
 
+/* written by Emard */
 static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
         struct budget_patch *budget;
         int err;
 	int count = 0;
+	int detected = 0;
 
-        if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
-                return -ENOMEM;
+#define PATCH_RESET 0
+#define RPS_IRQ 0
+#define HPS_SETUP 0
+#if PATCH_RESET
+        saa7146_write(dev, MC1, MASK_31);
+        msleep(40);
+#endif
+#if HPS_SETUP
+        // initialize registers. Better to have it like this
+        // than leaving something unconfigured
+	saa7146_write(dev, DD1_STREAM_B, 0);
+	// port B VSYNC at rising edge
+	saa7146_write(dev, DD1_INIT, 0x00000200);  // have this in budget-core too!
+	saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
+
+	// debi config
+	// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
+
+        // zero all HPS registers
+        saa7146_write(dev, HPS_H_PRESCALE, 0);                  // r68
+        saa7146_write(dev, HPS_H_SCALE, 0);                     // r6c
+        saa7146_write(dev, BCS_CTRL, 0);                        // r70
+        saa7146_write(dev, HPS_V_SCALE, 0);                     // r60
+        saa7146_write(dev, HPS_V_GAIN, 0);                      // r64
+        saa7146_write(dev, CHROMA_KEY_RANGE, 0);                // r74
+        saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
+        // Set HPS prescaler for port B input
+        saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
+        saa7146_write(dev, MC2, 
+          0 * (MASK_08 | MASK_24)  |   // BRS control
+          0 * (MASK_09 | MASK_25)  |   // a
+          0 * (MASK_10 | MASK_26)  |   // b
+          1 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
+          1 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
+          0 * (MASK_01 | MASK_15)      // DEBI
+           );
+#endif
+	// Disable RPS1 and RPS0
+        saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
+        // RPS1 timeout disable
+        saa7146_write(dev, RPS_TOV1, 0);
+
+	// code for autodetection 
+	// will wait for VBI_B event (vertical blank at port B)
+	// and will reset GPIO3 after VBI_B is detected.
+	// (GPIO3 should be raised high by CPU to
+	// test if GPIO3 will generate vertical blank signal 
+	// in budget patch GPIO3 is connected to VSYNC_B
+	count = 0;
+#if 0
+	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD | 
+	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
+#endif
+        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
+        WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
+        WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
+        WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+#if RPS_IRQ
+        // issue RPS1 interrupt to increment counter
+        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+        // at least a NOP is neede between two interrupts
+        WRITE_RPS1(cpu_to_le32(CMD_NOP));
+        // interrupt again
+        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
+        WRITE_RPS1(cpu_to_le32(CMD_STOP));
+
+#if RPS_IRQ
+        // set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
+        // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
+        // use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
+        saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+        // set event counter 1 treshold to maximum allowed value        (rEC p55)
+        saa7146_write(dev, ECT1R,  0x3fff );
+#endif
+        // Fix VSYNC level
+        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
+        // Set RPS1 Address register to point to RPS code               (r108 p42)
+        saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
+        // Enable RPS1,                                                 (rFC p33)
+        saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
 
-        dprintk(2, "budget: %p\n", budget);
 
-        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
-                kfree (budget);
-                return err;
-        }
+        mdelay(50);
+        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
+	mdelay(150);
+
+	
+	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
+		detected = 1;
+
+#if RPS_IRQ
+        printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
+#endif
+	// Disable RPS1
+        saa7146_write(dev, MC1, ( MASK_29 ));
+
+	if(detected == 0)
+                printk("budget-patch not detected or saa7146 in non-default state.\n"
+                       "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
+                
+	else
+                printk("BUDGET-PATCH DETECTED.\n");
 
-/*
+
+/*      OLD (Original design by Roberto Deza):
 **      This code will setup the SAA7146_RPS1 to generate a square 
 **      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of 
 **      TS_WIDTH packets) has been acquired on SAA7146_D1B video port; 
@@ -393,24 +587,85 @@
 **      which seems that can be done perfectly without this :-)).
 */                                                      
 
+/*      New design (By Emard)
+**      this rps1 code will copy internal HS event to GPIO3 pin.
+**      GPIO3 is in budget-patch hardware connectd to port B VSYNC
+
+**      HS is an internal event of 7146, accessible with RPS
+**      and temporarily raised high every n lines 
+**      (n in defined in the RPS_THRESH1 counter threshold)
+**      I think HS is raised high on the beginning of the n-th line
+**      and remains high until this n-th line that triggered
+**      it is completely received. When the receiption of n-th line
+**      ends, HS is lowered.
+
+**      To transmit data over DMA, 7146 needs changing state at 
+**      port B VSYNC pin. Any changing of port B VSYNC will 
+**      cause some DMA data transfer, with more or less packets loss.
+**      It depends on the phase and frequency of VSYNC and 
+**      the way of 7146 is instructed to trigger on port B (defined
+**      in DD1_INIT register, 3rd nibble from the right valid
+**      numbers are 0-7, see datasheet)
+**
+**      The correct triggering can minimize packet loss, 
+**      dvbtraffic should give this stable bandwidths:
+**        22k transponder = 33814 kbit/s
+**      27.5k transponder = 38045 kbit/s
+**      by experiment it is found that the best results 
+**      (stable bandwidths and almost no packet loss) 
+**      are obtained using DD1_INIT triggering number 2 
+**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle) 
+**      and a VSYNC phase that occurs in the middle of DMA transfer
+**      (about byte 188*512=96256 in the DMA window).
+**
+**      Phase of HS is still not clear to me how to control,
+**      It just happens to be so. It can be seen if one enables
+**      RPS_IRQ and print Event Counter 1 in vpeirq(). Every
+**      time RPS_INTERRUPT is called, the Event Counter 1 will
+**      increment. That's how the 7146 is programmed to do event
+**      counting in this budget-patch.c
+**      I *think* HPS setting has something to do with the phase
+**      of HS but I cant be 100% sure in that. 
+
+**      hardware debug note: a working budget card (including budget patch)
+**      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
+**      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
+**      and that means 3*25=75 Hz of interrupt freqency, as seen by
+**      watch cat /proc/interrupts 
+**
+**      If this frequency is 3x lower (and data received in the DMA
+**      buffer don't start with 0x47, but in the middle of packets,
+**      whose lengths appear to be like 188 292 188 104 etc.
+**      this means VSYNC line is not connected in the hardware. 
+**      (check soldering pcb and pins)
+**      The same behaviour of missing VSYNC can be duplicated on budget 
+**      cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
+*/
+
 	// Setup RPS1 "program" (p35)
+        count = 0;
+
 
-        // Wait reset Source Line Counter Threshold                     (p36)
-        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
         // Wait Source Line Counter Threshold                           (p36)
         WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
         // Set GPIO3=1                                                  (p42)
         WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
         WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
         WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+#if RPS_IRQ
+        // issue RPS1 interrupt
+        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
         // Wait reset Source Line Counter Threshold                     (p36)
         WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
-        // Wait Source Line Counter Threshold
-        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
         // Set GPIO3=0                                                  (p42)
         WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
         WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
         WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+#if RPS_IRQ
+        // issue RPS1 interrupt
+        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+#endif
         // Jump to begin of RPS program                                 (p37)
         WRITE_RPS1(cpu_to_le32(CMD_JUMP));
         WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
@@ -420,10 +675,31 @@
         // Set RPS1 Address register to point to RPS code               (r108 p42)
         saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
         // Set Source Line Counter Threshold, using BRS                 (rCC p43)
-        saa7146_write(dev, RPS_THRESH1, ((TS_HEIGHT/2) | MASK_12));
+        // It generates HS event every TS_HEIGHT lines
+        // this is related to TS_WIDTH set in register
+        // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
+        // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
+        //,then RPS_THRESH1
+        // should be set to trigger every TS_HEIGHT (512) lines.
+        // 
+        saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
+        
+        // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
         // Enable RPS1                                                  (rFC p33)
         saa7146_write(dev, MC1, (MASK_13 | MASK_29));
 
+	
+        if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
+                return -ENOMEM;
+
+        dprintk(2, "budget: %p\n", budget);
+
+        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
+                kfree (budget);
+                return err;
+        }
+
+
         dev->ext_priv = budget;
 
 	budget->dvb_adapter->priv = budget;


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

end of thread, other threads:[~2005-01-22 18:08 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-22 17:34 [PATCH 0/9] 2.6.11-rc2 DVB update Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 1/9] fix RPS init race Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 2/9] support pinnacle pctv-sat, clean-ups Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 3/9] refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 4/9] support nxt2002 frontend, misc skystar2 fixes Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 5/9] add ATSC support, misc fixes Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 6/9] refactoring Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 7/9] nxt2002: add ATSC support, misc fixes Johannes Stezenbach
2005-01-22 17:34 ` [PATCH 8/9] dvb-ttpci: fix SMP race, budget: fixe init race, " Johannes Stezenbach

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