
From: Michael Hunold <hunold@linuxtv.org>

- added new usb ids for some more clones
- added option to deliver the complete TS with USB2.0 devices
- added support for the dib3000mc/p frontend driver

Signed-off-by: Michael Hunold <hunold@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/Documentation/dvb/README.dibusb              |   37 
 25-akpm/drivers/media/dvb/dibusb/Kconfig             |   21 
 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.c        |  162 ++-
 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.h        |   39 
 25-akpm/drivers/media/dvb/frontends/Kconfig          |    7 
 25-akpm/drivers/media/dvb/frontends/Makefile         |    3 
 25-akpm/drivers/media/dvb/frontends/dib3000-common.c |  145 +++
 25-akpm/drivers/media/dvb/frontends/dib3000-common.h |   71 +
 25-akpm/drivers/media/dvb/frontends/dib3000.h        |    4 
 25-akpm/drivers/media/dvb/frontends/dib3000mb.c      |  234 +----
 25-akpm/drivers/media/dvb/frontends/dib3000mc.c      |  860 +++++++++++++++++++
 25-akpm/drivers/media/dvb/frontends/dib3000mc_priv.h |  439 +++++++++
 12 files changed, 1784 insertions(+), 238 deletions(-)

diff -puN Documentation/dvb/README.dibusb~dvb-update-dib-usb-driver Documentation/dvb/README.dibusb
--- 25/Documentation/dvb/README.dibusb~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/Documentation/dvb/README.dibusb	Fri Dec 10 15:14:14 2004
@@ -47,7 +47,7 @@ Produced and reselled by KWorld:
 Others:
 -------
 - Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235)
-	http://www.arteceuro.com/products-tvbox.html
+	http://82.161.246.249/products-tvbox.html
 
 - Compro Videomate DVB-U2000 - DVB-T USB
 	http://www.comprousa.com/products/vmu2000.htm
@@ -63,14 +63,23 @@ Others:
 
 Supported devices USB2.0
 ========================
+- Twinhan MagicBox II
+	http://www.twinhan.com/product_terrestrial_7.asp
+
 - Yakumo DVB-T mobile
 	http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
 
 - DiBcom USB2.0 DVB-T reference device (non-public)
 
 
-
 0. NEWS:
+  2004-12-06 - possibility for demod i2c-address probing
+             - new usb IDs (Compro,Artec)
+  2004-11-23 - merged changes from DiB3000MC_ver2.1
+             - revised the debugging
+             - possibility to deliver the complete TS for USB2.0
+  2004-11-21 - first working version of the dib3000mc/p frontend driver.
+  2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
   2004-11-07 - added remote control support. Thanks to David Matthews.
   2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
              - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
@@ -165,9 +174,7 @@ as a slave device in vdr, was not workin
 2. Known problems and bugs
 
 TODO:
-- remote control
 - signal-quality and strength calculations
-- i2c address probing
 
 2.1. Adding support for devices 
 
@@ -189,7 +196,29 @@ the dvb-dibusb.h-file and create a patch
 the linux-dvb mailing list, _after_ you have tried compiling and modprobing
 it.
 
-2.2. Comments
+2.2. USB1.1 Bandwidth limitation
+
+Most of the current supported devices are USB1.1 and thus they have a
+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.
+
+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
+enabled. When you set another pid while receiving MPEG2-TS it happens, that
+the stream is disturbed and probably data is lost (results in distortions of
+the video or strange beeps within the audio stream). DiBcom is preparing a
+firmware especially for Linux which perhaps solves the problem.
+
+Especially VDR users are victoms of this bug. VDR frequently requests new PIDs
+due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
+these features is maybe a solution. Additionally this behaviour of VDR exceeds
+the USB1.1 bandwidth.
+
+2.3. Comments
 
 Patches, comments and suggestions are very very welcome
 
diff -puN drivers/media/dvb/dibusb/dvb-dibusb.c~dvb-update-dib-usb-driver drivers/media/dvb/dibusb/dvb-dibusb.c
--- 25/drivers/media/dvb/dibusb/dvb-dibusb.c~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.c	Fri Dec 10 15:14:14 2004
@@ -7,10 +7,8 @@
  * 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
@@ -70,6 +68,9 @@ MODULE_PARM_DESC(debug, "set debugging l
 #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"
@@ -91,7 +92,7 @@ static int dibusb_readwrite_usb(struct u
 		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)", wbuf[0],wbuf[2],wbuf[3]);
+				"(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
 			
 	debug_dump(wbuf,wlen);
 
@@ -190,6 +191,7 @@ static int dibusb_ctrl_feed(struct usb_d
 
 	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.");
@@ -199,11 +201,20 @@ static int dibusb_ctrl_feed(struct usb_d
 		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)) {
@@ -269,6 +280,13 @@ static const struct { u8 c0, c1, c2; uin
 	{ 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 */
@@ -374,17 +392,11 @@ static void dibusb_query_rc (void *data)
  */
 
 #if 0
-
 /*
- * #if 0'ing the following 5 functions as they are not in use _now_,
+ * #if 0'ing the following functions as they are not in use _now_,
  * but probably will be sometime.
  */
 
-static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
-	return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
-
 /*
  * do not use this, just a workaround for a bug,
  * which will hopefully never occur :).
@@ -396,6 +408,21 @@ static int dibusb_interrupt_read_loop(st
 }
 
 /*
+ * 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)
@@ -409,23 +436,12 @@ static int dibusb_ioctl_cmd(struct usb_d
 	return dibusb_write_usb(dib,b,2+size);
 }
 
-/*
- * ioctl for power control
- */
-static int dibusb_hw_sleep(struct usb_dibusb *dib)
-{
-	u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
-	return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-}
-
 static int dibusb_hw_wakeup(struct usb_dibusb *dib)
 {
 	u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
 	return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
 }
 
-#endif
-
 /*
  * I2C
  */
@@ -458,7 +474,8 @@ static u32 dibusb_i2c_func(struct i2c_ad
 	return I2C_FUNC_I2C;
 }
 
-static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+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,
@@ -466,7 +483,8 @@ static struct dib3000_config thomson_cab
 	.pll_set = thomson_cable_eu_pll_set,
 };
 
-static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+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];
@@ -493,7 +511,71 @@ static int thomson_cable_eu_pll_set(stru
    	buf[2] = 0x8e;
    	buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
 
-	if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) return -EIO;
+	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;
@@ -508,7 +590,15 @@ static struct i2c_algorithm dibusb_algo 
 
 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",
@@ -671,9 +761,11 @@ static int dibusb_init(struct usb_dibusb
 	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 */
@@ -721,6 +813,8 @@ static int dibusb_init(struct usb_dibusb
 
 	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;
@@ -844,27 +938,33 @@ static int dibusb_probe(struct usb_inter
 	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 filter.");
+				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 = 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;
diff -puN drivers/media/dvb/dibusb/dvb-dibusb.h~dvb-update-dib-usb-driver drivers/media/dvb/dibusb/dvb-dibusb.h
--- 25/drivers/media/dvb/dibusb/dvb-dibusb.h~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/dibusb/dvb-dibusb.h	Fri Dec 10 15:14:14 2004
@@ -67,7 +67,7 @@ static struct dibusb_device_parameter di
 		.data_pipe = 0x82,
 	},
 	{	.type = DIBUSB2_0,
-		.demod_addr = 0x10,
+		.demod_addr = 0x18,
 		.fw_filenames = dibusb_fw_filenames2_0,
 		.usb_controller = "Cypress FX2",
 		.usb_cpu_csreg = 0xe600,
@@ -109,6 +109,8 @@ struct dibusb_device {
 #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
@@ -122,6 +124,8 @@ struct dibusb_device {
 #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
@@ -137,12 +141,15 @@ struct dibusb_device {
 #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	12
+#define DIBUSB_SUPPORTED_DEVICES	15
 
 /* USB Driver stuff */
 static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
@@ -176,11 +183,26 @@ static struct dibusb_device dibusb_devic
 		.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,
@@ -237,14 +259,18 @@ static struct usb_device_id dibusb_table
 	{ 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) },
 
 /*
- * activate the following define when you have the device and want to compile
- * build from build-2.6 in dvb-kernel
+ * 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_AN2235
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235
+// #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 */
 };
@@ -260,6 +286,7 @@ struct usb_dibusb {
 	struct dibusb_device * dibdev;
 
 	int feedcount;
+	int pid_parse;
 	struct dib3000_xfer_ops xfer_ops;
 
 	struct urb **urb_list;
diff -puN drivers/media/dvb/dibusb/Kconfig~dvb-update-dib-usb-driver drivers/media/dvb/dibusb/Kconfig
--- 25/drivers/media/dvb/dibusb/Kconfig~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/dibusb/Kconfig	Fri Dec 10 15:14:14 2004
@@ -3,6 +3,7 @@ config DVB_DIBUSB
 	depends on DVB_CORE && USB
 	select FW_LOADER
 	select DVB_DIB3000MB
+	select DVB_DIB3000MC
 	help
 	  Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
 	  DiBcom (http://www.dibcom.fr).
@@ -32,19 +33,25 @@ config DVB_DIBUSB
 	  Say Y if you own such a device and want to use it. You should build it as
 	  a module.
 
-config DVB_DIBUSB_MISDESIGNED_AN2235
-	bool "Enable support for some Artec T1 device, which identifies as AN2235"
+config DVB_DIBUSB_MISDESIGNED_DEVICES
+	bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
 	depends on DVB_DIBUSB
 	help
-	  Somehow Artec forgot to program the eeprom for some of their T1 devices. So
-	  comes that they identify with the default Vendor and Product ID of the Cypress
-	  CY7C64613 (AN2235).
+	  Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
+	  USB1.1/USB2.0 devices.
+	  So comes that they identify with the default Vendor and Product ID of the Cypress
+	  CY7C64613 (AN2235) or Cypress FX2.
+
+	  Affected device IDs:
+	    0x0574:0x2235 (Artec T1 USB1.1, cold)
+	    0x04b4:0x8613 (Artec T1 USB2.0, cold)
+	    0x0574:0x1002 (Artec T1 USB2.0, warm)
 
-	  Say Y if your Artec device has 0x0574 as Vendor ID and 0x2235 as Product ID.
+	  Say Y if your device one of the mentioned IDs.
 
 config DVB_DIBCOM_DEBUG
 	bool "Enable extended debug support for DiBcom USB device"
 	depends on DVB_DIBUSB
 	help
 	  Say Y if you want to enable debuging. See modinfo dvb-dibusb for
-	  debug level.
+	  debug levels.
diff -puN /dev/null drivers/media/dvb/frontends/dib3000-common.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/frontends/dib3000-common.c	Fri Dec 10 15:14:14 2004
@@ -0,0 +1,145 @@
+#include "dib3000-common.h"
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
+#endif
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...) dprintk(0x02,args)
+#define deb_srch(args...) dprintk(0x04,args)
+
+
+int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+{
+	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+	u8 rb[2];
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
+		{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+	};
+
+	if (i2c_transfer(state->i2c, msg, 2) != 2)
+		deb_i2c("i2c read error\n");
+
+	deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+			(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+
+	return (rb[0] << 8) | rb[1];
+}
+
+int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+{
+	u8 b[] = {
+		(reg >> 8) & 0xff, reg & 0xff,
+		(val >> 8) & 0xff, val & 0xff,
+	};
+	struct i2c_msg msg[] = {
+		{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+	};
+	deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+
+	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+int dib3000_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);
+		state->pid_list_lock = SPIN_LOCK_UNLOCKED;
+		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) {
+		if (lock & 0x01) {
+			deb_srch("auto search succeeded\n");
+			return 1; // auto search succeeded
+		} else {
+			deb_srch("auto search not successful\n");
+			return 0; // auto search failed
+		}
+	} else if (irq & 0x01)  {
+		deb_srch("auto search failed\n");
+		return 0; // auto search failed
+	}
+	return -1; // try again
+}
+
+/* for auto search */
+u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
+	{ /* fft */
+		{ /* gua */
+			{ 0, 1 },                   /*  0   0   { 0,1 } */
+			{ 3, 9 },                   /*  0   1   { 0,1 } */
+		},
+		{
+			{ 2, 5 },                   /*  1   0   { 0,1 } */
+			{ 6, 11 },                  /*  1   1   { 0,1 } */
+		}
+	};
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000_seq);
+
+EXPORT_SYMBOL(dib3000_read_reg);
+EXPORT_SYMBOL(dib3000_write_reg);
+EXPORT_SYMBOL(dib3000_init_pid_list);
+EXPORT_SYMBOL(dib3000_dealloc_pid_list);
+EXPORT_SYMBOL(dib3000_get_pid_index);
+EXPORT_SYMBOL(dib3000_search_status);
diff -puN drivers/media/dvb/frontends/dib3000-common.h~dvb-update-dib-usb-driver drivers/media/dvb/frontends/dib3000-common.h
--- 25/drivers/media/dvb/frontends/dib3000-common.h~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/frontends/dib3000-common.h	Fri Dec 10 15:14:14 2004
@@ -26,6 +26,8 @@
 #ifndef DIB3000_COMMON_H
 #define DIB3000_COMMON_H
 
+#include "dvb_frontend.h"
+#include "dib3000.h"
 
 /* info and err, taken from usb.h, if there is anything available like by default,
  * please change !
@@ -41,6 +43,63 @@ struct dib3000_pid
 	int active;
 };
 
+/* frontend state */
+struct dib3000_state {
+	struct i2c_adapter* i2c;
+
+	struct dvb_frontend_ops ops;
+
+/* 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;
+};
+
+/* 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 */
+#define rd(reg) dib3000_read_reg(state,reg)
+
+#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+
+#define wr_foreach(a,v) { int i; \
+	if (sizeof(a) != sizeof(v)) \
+		err("sizeof: %d %d is different",sizeof(a),sizeof(v));\
+	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+		wr(a[i],v[i]); \
+	}
+
+#define set_or(reg,val) wr(reg,rd(reg) | val)
+
+#define set_and(reg,val) wr(reg,rd(reg) & val)
+
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(level,args...) \
+    do { if ((debug & level)) { printk(args); } } while (0)
+#else
+#define dprintk(args...) do { } while (0)
+#endif
+
 /* mask for enabling a specific pid for the pid_filter */
 #define DIB3000_ACTIVATE_PID_FILTERING	(0x2000)
 
@@ -81,17 +140,7 @@ struct dib3000_pid
 #define DIB3000_TUNER_WRITE_DISABLE(a)	(0xffff & ((a << 7) | (1 << 7)))
 
 /* for auto search */
-static u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
-	{ /* fft */
-		{ /* gua */
-			{ 0, 1 },                   /*  0   0   { 0,1 } */
-			{ 3, 9 },                   /*  0   1   { 0,1 } */
-		},
-		{
-			{ 2, 5 },                   /*  1   0   { 0,1 } */
-			{ 6, 11 },                  /*  1   1   { 0,1 } */
-		}
-	};
+extern u16 dib3000_seq[2][2][2];
 
 #define DIB3000_REG_MANUFACTOR_ID		(  1025)
 #define DIB3000_I2C_ID_DIBCOM			(0x01b3)
diff -puN drivers/media/dvb/frontends/dib3000.h~dvb-update-dib-usb-driver drivers/media/dvb/frontends/dib3000.h
--- 25/drivers/media/dvb/frontends/dib3000.h~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/frontends/dib3000.h	Fri Dec 10 15:14:14 2004
@@ -42,7 +42,7 @@ struct dib3000_config
 struct dib3000_xfer_ops
 {
 	/* pid and transfer handling is done in the demodulator */
-	int (*pid_filter)(struct dvb_frontend *fe, int onoff);
+	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);
 };
@@ -50,4 +50,6 @@ struct dib3000_xfer_ops
 extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 					     struct i2c_adapter* i2c, struct dib3000_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);
 #endif // DIB3000_H
diff -puN drivers/media/dvb/frontends/dib3000mb.c~dvb-update-dib-usb-driver drivers/media/dvb/frontends/dib3000mb.c
--- 25/drivers/media/dvb/frontends/dib3000mb.c~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/frontends/dib3000mb.c	Fri Dec 10 15:14:14 2004
@@ -34,135 +34,38 @@
 #include "dib3000mb_priv.h"
 #include "dib3000.h"
 
-struct dib3000mb_state {
-
-	struct i2c_adapter* i2c;
-
-	struct dvb_frontend_ops ops;
-
-	/* configuration settings */
-	const struct dib3000_config* config;
-
-	spinlock_t pid_list_lock;
-	struct dib3000_pid pid_list[DIB3000MB_NUM_PIDS];
-	int feedcount;
-
-	struct dvb_frontend frontend;
-};
-
-
-/* debug */
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
 
 #ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(level,args...) \
-	do { if ((debug & level)) { printk(args); } } while (0)
-
 static int debug;
 module_param(debug, int, 0x644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=setfe,16=getfe (|-able)).");
-#else
-#define dprintk(args...) do { } while (0);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
 #endif
-
 #define deb_info(args...) dprintk(0x01,args)
 #define deb_xfer(args...) dprintk(0x02,args)
-#define deb_alot(args...) dprintk(0x04,args)
-#define deb_setf(args...) dprintk(0x08,args)
-#define deb_getf(args...) dprintk(0x10,args)
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-
-/* handy shortcuts */
-#define rd(reg) dib3000mb_read_reg(state,reg)
-#define wr(reg,val) if (dib3000mb_write_reg(state,reg,val)) \
-	{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
-#define wr_foreach(a,v) { int i; \
-	deb_alot("sizeof: %d %d\n",sizeof(a),sizeof(v));\
-	for (i=0; i < sizeof(a)/sizeof(u16); i++) \
-		wr(a[i],v[i]); \
-}
-
-static int dib3000mb_read_reg(struct dib3000mb_state *state, u16 reg)
-{
-	u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
-	u8 rb[2];
-	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address, .flags = 0,        .buf = wb, .len = 2 },
-		{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
-	};
-	deb_alot("reading from i2c bus (reg: %d)\n",reg);
-
-	if (i2c_transfer(state->i2c, msg, 2) != 2)
-		deb_alot("i2c read error\n");
-
-	return (rb[0] << 8) | rb[1];
-}
-
-static int dib3000mb_write_reg(struct dib3000mb_state *state, u16 reg, u16 val)
-{
-	u8 b[] = {
-		(reg >> 8) & 0xff, reg & 0xff,
-		(val >> 8) & 0xff, val & 0xff,
-	};
-	struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 4 } };
-	deb_alot("writing to i2c bus (reg: %d, val: %d)\n",reg,val);
-
-	return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-static int dib3000mb_set_frontend(struct dvb_frontend* fe,
-		struct dvb_frontend_parameters *fep, int tuner);
+#define deb_setf(args...) dprintk(0x04,args)
+#define deb_getf(args...) dprintk(0x08,args)
 
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep);
 
-static int dib3000mb_fe_read_search_status(struct dvb_frontend* fe)
-{
-	u16 irq;
-	struct dvb_frontend_parameters fep;
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
-
-	irq = rd(DIB3000MB_REG_AS_IRQ_PENDING);
-
-	if (irq & 0x02) {
-		if (rd(DIB3000MB_REG_LOCK2_VALUE) & 0x01) {
-			if (dib3000mb_get_frontend(fe, &fep) == 0) {
-				deb_setf("reading tuning data from frontend succeeded.\n");
-				return dib3000mb_set_frontend(fe, &fep, 0) == 0;
-			} else {
-				deb_setf("reading tuning data failed -> tuning failed.\n");
-				return 0;
-			}
-		} else {
-			deb_setf("AS IRQ was pending, but LOCK2 was not & 0x01.\n");
-			return 0;
-		}
-	} else if (irq & 0x01) {
-		deb_setf("Autosearch failed.\n");
-		return 0;
-	}
-
-	return -1;
-}
-
 static int dib3000mb_set_frontend(struct dvb_frontend* fe,
 		struct dvb_frontend_parameters *fep, int tuner)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	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;
 
 	if (tuner) {
 		wr(DIB3000MB_REG_TUNER,
-				DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
-		state->config->pll_set(fe, fep);
+				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));
+				DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
 
 		deb_setf("bandwidth: ");
 		switch (ofdm->bandwidth) {
@@ -389,10 +292,22 @@ static int dib3000mb_set_frontend(struct
 		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH);
 		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
 
-		while ((search_state = dib3000mb_fe_read_search_status(fe)) < 0 && as_count++ < 100)
+		while ((search_state =
+				dib3000_search_status(
+					rd(DIB3000MB_REG_AS_IRQ_PENDING),
+					rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
 			msleep(1);
 
 		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 (dib3000mb_get_frontend(fe, &feps) == 0) {
+				deb_setf("reading tuning data from frontend succeeded.\n");
+				return dib3000mb_set_frontend(fe, &feps, 0);
+			}
+		}
+
 	} else {
 		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
 		wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
@@ -403,7 +318,7 @@ static int dib3000mb_set_frontend(struct
 
 static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
 
@@ -474,12 +389,12 @@ static int dib3000mb_fe_init(struct dvb_
 
 	wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
-	if (state->config->pll_init) {
+	if (state->config.pll_init) {
 		wr(DIB3000MB_REG_TUNER,
-			DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
-		state->config->pll_init(fe);
+			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));
+			DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
 	}
 
 	return 0;
@@ -488,7 +403,7 @@ static int dib3000mb_fe_init(struct dvb_
 static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *fep)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
 	fe_code_rate_t *cr;
 	u16 tps_val;
@@ -499,7 +414,7 @@ static int dib3000mb_get_frontend(struct
 		return 0;
 
 	dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
-	if (dds_val & threshold)
+	if (dds_val < threshold)
 		inv_test1 = 0;
 	else if (dds_val == threshold)
 		inv_test1 = 1;
@@ -507,7 +422,7 @@ static int dib3000mb_get_frontend(struct
 		inv_test1 = 2;
 
 	dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
-	if (dds_val & threshold)
+	if (dds_val < threshold)
 		inv_test2 = 0;
 	else if (dds_val == threshold)
 		inv_test2 = 1;
@@ -516,7 +431,8 @@ static int dib3000mb_get_frontend(struct
 
 	fep->inversion =
 		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
-		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
+		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+		INVERSION_ON : INVERSION_OFF;
 
 	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
 
@@ -541,10 +457,8 @@ static int dib3000mb_get_frontend(struct
 
 	if (rd(DIB3000MB_REG_TPS_HRCH)) {
 		deb_getf("HRCH ON\n");
-		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
 		cr = &ofdm->code_rate_LP;
 		ofdm->code_rate_HP = FEC_NONE;
-
 		switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
 			case DIB3000_ALPHA_0:
 				deb_getf("HIERARCHY_NONE ");
@@ -567,12 +481,15 @@ static int dib3000mb_get_frontend(struct
 				break;
 		}
 		deb_getf("TPS: %d\n", tps_val);
+
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
 	} else {
 		deb_getf("HRCH OFF\n");
-		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
 		cr = &ofdm->code_rate_HP;
 		ofdm->code_rate_LP = FEC_NONE;
 		ofdm->hierarchy_information = HIERARCHY_NONE;
+
+		tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
 	}
 
 	switch (tps_val) {
@@ -645,7 +562,7 @@ static int dib3000mb_get_frontend(struct
 
 static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 	*stat = 0;
 
@@ -684,7 +601,7 @@ static int dib3000mb_read_status(struct 
 
 static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 	*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
 	return 0;
@@ -701,7 +618,7 @@ static int dib3000mb_read_ber(struct dvb
 #define DIB3000MB_GAIN_DELTA_dBm	-2
 static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 /* TODO log10 
 	u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER), 
@@ -737,7 +654,7 @@ static int dib3000mb_read_signal_strengt
  */
 static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 	short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
 	int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
 		rd(DIB3000MB_REG_NOISE_POWER_LSB);
@@ -757,7 +674,7 @@ static int dib3000mb_read_snr(struct dvb
 
 static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 	*unc = rd(DIB3000MB_REG_UNC);
 	return 0;
@@ -765,7 +682,7 @@ static int dib3000mb_read_unc_blocks(str
 
 static int dib3000mb_sleep(struct dvb_frontend* fe)
 {
-	struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
 
 	wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
 	return 0;
@@ -792,49 +709,17 @@ static int dib3000mb_set_frontend_and_tu
 
 static void dib3000mb_release(struct dvb_frontend* fe)
 {
-	struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
 	kfree(state);
 }
 
 /* pid filter and transfer stuff */
-
-/* fetch a pid from pid_list */
-static 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;
-	}
-}
-
-	spin_unlock_irqrestore(pid_list_lock,flags);
-	return ret;
-}
-
 static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff)
 {
-	struct dib3000mb_state *state = fe->demodulator_priv;
+	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);
 
-	deb_info("setting pid 0x%x on index %d\n",pid,index);
-
 	if (index >= 0) {
 		wr(index+DIB3000MB_REG_FIRST_PID,pid);
 	} else {
@@ -846,8 +731,9 @@ static int dib3000mb_pid_control(struct 
 
 static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
 {
-	struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv;
+	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
 
+	deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
 	if (onoff) {
 		wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE);
 	} else {
@@ -856,9 +742,9 @@ static int dib3000mb_fifo_control(struct
 	return 0;
 	}
 
-static int dib3000mb_pid_filter(struct dvb_frontend *fe, int onoff)
+static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
 {
-	//struct dib3000mb_state *state = fe->demodulator_priv;
+	//struct dib3000_state *state = fe->demodulator_priv;
 	/* switch it off and on */
 	return 0;
 	}
@@ -868,17 +754,16 @@ static struct dvb_frontend_ops dib3000mb
 struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 				      struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
 {
-	struct dib3000mb_state* state = NULL;
-	int i;
+	struct dib3000_state* state = NULL;
 
 	/* allocate memory for the internal state */
-	state = (struct dib3000mb_state*) kmalloc(sizeof(struct dib3000mb_state), GFP_KERNEL);
+	state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
 	if (state == NULL)
 		goto error;
 
 	/* setup the state */
-	state->config = config;
 	state->i2c = i2c;
+	memcpy(&state->config,config,sizeof(struct dib3000_config));
 	memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check for the correct demod */
@@ -888,22 +773,15 @@ struct dvb_frontend* dib3000mb_attach(co
 	if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
 		goto error;
 
-	/* initialize the id_list */
-	deb_info("initializing %d pids for the pid_list.\n",DIB3000MB_NUM_PIDS);
-	state->pid_list_lock = SPIN_LOCK_UNLOCKED;
-	memset(state->pid_list,0,DIB3000MB_NUM_PIDS*(sizeof(struct dib3000_pid)));
-	for (i=0; i < DIB3000MB_NUM_PIDS; i++) {
-		state->pid_list[i].pid = 0;
-		state->pid_list[i].active = 0;
-}
-	state->feedcount = 0;
+	if (dib3000_init_pid_list(state,DIB3000MB_NUM_PIDS))
+		goto error;
 
 	/* create dvb_frontend */
 	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 
 	/* set the xfer operations */
-	xfer_ops->pid_filter = dib3000mb_pid_filter;
+	xfer_ops->pid_parse = dib3000mb_pid_parse;
 	xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
 	xfer_ops->pid_ctrl = dib3000mb_pid_control;
 
diff -puN /dev/null drivers/media/dvb/frontends/dib3000mc.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/frontends/dib3000mc.c	Fri Dec 10 15:14:14 2004
@@ -0,0 +1,860 @@
+/*
+ * 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)
+ *
+ * based on GPL code from DibCom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "dib3000-common.h"
+#include "dib3000mc_priv.h"
+#include "dib3000.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+#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)).");
+#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)
+
+
+static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
+	fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
+{
+	switch (transmission_mode) {
+		case TRANSMISSION_MODE_2K:
+			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
+			break;
+		case TRANSMISSION_MODE_8K:
+			wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
+			break;
+		default:
+			break;
+	}
+
+	switch (bandwidth) {
+/*		case BANDWIDTH_5_MHZ:
+			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
+			break; */
+		case BANDWIDTH_6_MHZ:
+			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
+			break;
+		case BANDWIDTH_7_MHZ:
+			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
+			break;
+		case BANDWIDTH_8_MHZ:
+			wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
+			break;
+		default:
+			break;
+	}
+
+	switch (mode) {
+		case 0: /* no impulse */ /* fall through */
+			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
+			break;
+		case 1: /* new algo */
+			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
+			set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
+			break;
+		default: /* old algo */
+			wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
+			break;
+	}
+	return 0;
+}
+
+static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
+		fe_transmit_mode_t fft, fe_bandwidth_t bw)
+{
+	u16 timf_msb,timf_lsb;
+	s32 tim_offset,tim_sgn;
+	u64 comp1,comp2,comp=0;
+
+	switch (bw) {
+		case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
+		case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
+		case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
+		default: err("unknown bandwidth (%d)",bw); break;
+	}
+	timf_msb = (comp >> 16) & 0xff;
+	timf_lsb = (comp & 0xffff);
+
+	// Update the timing offset ;
+	if (upd_offset > 0) {
+		if (!state->timing_offset_comp_done) {
+			msleep(200);
+			state->timing_offset_comp_done = 1;
+		}
+		tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
+		if ((tim_offset & 0x2000) == 0x2000)
+			tim_offset |= 0xC000;
+		if (fft == TRANSMISSION_MODE_2K)
+			tim_offset <<= 2;
+		state->timing_offset += tim_offset;
+	}
+
+	tim_offset = state->timing_offset;
+	if (tim_offset < 0) {
+		tim_sgn = 1;
+		tim_offset = -tim_offset;
+	} else
+		tim_sgn = 0;
+
+	comp1 =  (u32)tim_offset * (u32)timf_lsb ;
+	comp2 =  (u32)tim_offset * (u32)timf_msb ;
+	comp  = ((comp1 >> 16) + comp2) >> 7;
+
+	if (tim_sgn == 0)
+		comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
+	else
+		comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
+
+	timf_msb = (comp >> 16) & 0xff;
+	timf_lsb = comp & 0xffff;
+
+	wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
+	wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
+	return 0;
+}
+
+static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
+{
+	if (boost) {
+		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
+	} else {
+		wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
+	}
+	switch (bw) {
+		case BANDWIDTH_8_MHZ:
+			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+			break;
+		case BANDWIDTH_7_MHZ:
+			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
+			break;
+		case BANDWIDTH_6_MHZ:
+			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
+			break;
+/*		case BANDWIDTH_5_MHZ:
+			wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
+			break;*/
+		case BANDWIDTH_AUTO:
+			return -EOPNOTSUPP;
+		default:
+			err("unknown bandwidth value (%d).",bw);
+			return -EINVAL;
+	}
+	if (boost) {
+		u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
+			rd(DIB3000MC_REG_BW_TIMOUT_LSB);
+		timeout *= 85; timeout >>= 7;
+		wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
+		wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
+	}
+	return 0;
+}
+
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep);
+
+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;
+	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]);
+	}
+
+	switch (ofdm->transmission_mode) {
+		case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
+		case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
+		case TRANSMISSION_MODE_AUTO: break;
+		default: return -EINVAL;
+	}
+	switch (ofdm->guard_interval) {
+		case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
+		case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
+		case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
+		case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
+		case GUARD_INTERVAL_AUTO: break;
+		default: return -EINVAL;
+	}
+	switch (ofdm->constellation) {
+		case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
+		case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
+		case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
+		case QAM_AUTO: break;
+		default: return -EINVAL;
+	}
+	switch (ofdm->hierarchy_information) {
+		case HIERARCHY_NONE: /* fall through */
+		case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
+		case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
+		case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
+		case HIERARCHY_AUTO: break;
+		default: return -EINVAL;
+	}
+	if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+		hrch = DIB3000_HRCH_OFF;
+		sel_hp = DIB3000_SELECT_HP;
+		fe_cr = ofdm->code_rate_HP;
+	} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+		hrch = DIB3000_HRCH_ON;
+		sel_hp = DIB3000_SELECT_LP;
+		fe_cr = ofdm->code_rate_LP;
+	}
+	switch (fe_cr) {
+		case FEC_1_2: cr = DIB3000_FEC_1_2; break;
+		case FEC_2_3: cr = DIB3000_FEC_2_3; break;
+		case FEC_3_4: cr = DIB3000_FEC_3_4; break;
+		case FEC_5_6: cr = DIB3000_FEC_5_6; break;
+		case FEC_7_8: cr = DIB3000_FEC_7_8; break;
+		case FEC_NONE: break;
+		case FEC_AUTO: break;
+		default: return -EINVAL;
+	}
+
+	wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
+	wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
+
+	switch (fep->inversion) {
+		case INVERSION_OFF:
+			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+			break;
+		case INVERSION_AUTO:
+			break;
+		case INVERSION_ON:
+			wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	seq = dib3000_seq
+		[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
+		[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
+		[fep->inversion == INVERSION_AUTO];
+
+	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 ||
+		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));
+	}*/
+	return 0;
+}
+
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+	fe_code_rate_t *cr;
+	u16 tps_val,cr_val;
+	int inv_test1,inv_test2;
+	u32 dds_val, threshold = 0x1000000;
+
+	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);
+	if (dds_val < threshold)
+		inv_test1 = 0;
+	else if (dds_val == threshold)
+		inv_test1 = 1;
+	else
+		inv_test1 = 2;
+
+	dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
+	if (dds_val < threshold)
+		inv_test2 = 0;
+	else if (dds_val == threshold)
+		inv_test2 = 1;
+	else
+		inv_test2 = 2;
+
+	fep->inversion =
+		((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+		((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+		INVERSION_ON : INVERSION_OFF;
+
+	deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+
+	tps_val = rd(DIB3000MC_REG_TUNING_PARM);
+
+	switch (DIB3000MC_TP_QAM(tps_val)) {
+		case DIB3000_CONSTELLATION_QPSK:
+			deb_getf("QPSK ");
+			ofdm->constellation = QPSK;
+			break;
+		case DIB3000_CONSTELLATION_16QAM:
+			deb_getf("QAM16 ");
+			ofdm->constellation = QAM_16;
+			break;
+		case DIB3000_CONSTELLATION_64QAM:
+			deb_getf("QAM64 ");
+			ofdm->constellation = QAM_64;
+			break;
+		default:
+			err("Unexpected constellation returned by TPS (%d)", tps_val);
+			break;
+ 	}
+
+	if (DIB3000MC_TP_HRCH(tps_val)) {
+		deb_getf("HRCH ON ");
+		cr = &ofdm->code_rate_LP;
+		ofdm->code_rate_HP = FEC_NONE;
+		switch (DIB3000MC_TP_ALPHA(tps_val)) {
+			case DIB3000_ALPHA_0:
+				deb_getf("HIERARCHY_NONE ");
+				ofdm->hierarchy_information = HIERARCHY_NONE;
+				break;
+			case DIB3000_ALPHA_1:
+				deb_getf("HIERARCHY_1 ");
+				ofdm->hierarchy_information = HIERARCHY_1;
+				break;
+			case DIB3000_ALPHA_2:
+				deb_getf("HIERARCHY_2 ");
+				ofdm->hierarchy_information = HIERARCHY_2;
+				break;
+			case DIB3000_ALPHA_4:
+				deb_getf("HIERARCHY_4 ");
+				ofdm->hierarchy_information = HIERARCHY_4;
+				break;
+			default:
+				err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+				break;
+		}
+		cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
+	} else {
+		deb_getf("HRCH OFF ");
+		cr = &ofdm->code_rate_HP;
+		ofdm->code_rate_LP = FEC_NONE;
+		ofdm->hierarchy_information = HIERARCHY_NONE;
+		cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
+	}
+
+	switch (cr_val) {
+		case DIB3000_FEC_1_2:
+			deb_getf("FEC_1_2 ");
+			*cr = FEC_1_2;
+			break;
+		case DIB3000_FEC_2_3:
+			deb_getf("FEC_2_3 ");
+			*cr = FEC_2_3;
+			break;
+		case DIB3000_FEC_3_4:
+			deb_getf("FEC_3_4 ");
+			*cr = FEC_3_4;
+			break;
+		case DIB3000_FEC_5_6:
+			deb_getf("FEC_5_6 ");
+			*cr = FEC_4_5;
+			break;
+		case DIB3000_FEC_7_8:
+			deb_getf("FEC_7_8 ");
+			*cr = FEC_7_8;
+			break;
+		default:
+			err("Unexpected FEC returned by TPS (%d)", tps_val);
+			break;
+	}
+
+	switch (DIB3000MC_TP_GUARD(tps_val)) {
+		case DIB3000_GUARD_TIME_1_32:
+			deb_getf("GUARD_INTERVAL_1_32 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case DIB3000_GUARD_TIME_1_16:
+			deb_getf("GUARD_INTERVAL_1_16 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case DIB3000_GUARD_TIME_1_8:
+			deb_getf("GUARD_INTERVAL_1_8 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case DIB3000_GUARD_TIME_1_4:
+			deb_getf("GUARD_INTERVAL_1_4 ");
+			ofdm->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+			break;
+	}
+
+	switch (DIB3000MC_TP_FFT(tps_val)) {
+		case DIB3000_TRANSMISSION_MODE_2K:
+			deb_getf("TRANSMISSION_MODE_2K ");
+			ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case DIB3000_TRANSMISSION_MODE_8K:
+			deb_getf("TRANSMISSION_MODE_8K ");
+			ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			err("unexpected transmission mode return by TPS (%d)", tps_val);
+			break;
+	}
+	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;
+	u16 lock = rd(DIB3000MC_REG_LOCKING);
+
+	*stat = 0;
+	if (DIB3000MC_AGC_LOCK(lock))
+		*stat |= FE_HAS_SIGNAL;
+	if (DIB3000MC_CARRIER_LOCK(lock))
+		*stat |= FE_HAS_CARRIER;
+	if (DIB3000MC_TPS_LOCK(lock)) /* VIT_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);
+
+	return 0;
+}
+
+static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	*ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
+	return 0;
+}
+
+static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+	*unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
+	return 0;
+}
+
+/* see dib3000mb.c for calculation comments */
+static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+	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);
+	return 0;
+}
+
+/* see dib3000mb.c for calculation comments */
+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 sig,noise;
+
+	sig =   (((val >> 6) & 0xff) << 8) + (val & 0x3f);
+	noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
+	if (noise == 0)
+		*snr = 0xffff;
+	else
+		*snr = (u16) sig/noise;
+
+	deb_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);
+	return 0;
+}
+
+static int dib3000mc_sleep(struct dvb_frontend* fe)
+{
+	struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
+	wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
+	wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
+	wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
+	return 0;
+}
+
+static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	tune->step_size = 166667;
+	tune->max_drift = 166667 * 2;
+
+	return 0;
+}
+
+static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
+{
+	return dib3000mc_fe_init(fe, 0);
+}
+
+static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+{
+	return dib3000mc_set_frontend(fe, fep, 1);
+}
+
+static void dib3000mc_release(struct dvb_frontend* fe)
+{
+	struct dib3000_state *state = (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)
+{
+	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;
+}
+
+static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+	struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+	deb_xfer("%s fifo",onoff ? "enabling" : "disabling");
+	if (onoff) {
+		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
+	} else {
+		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
+	}
+	return 0;
+}
+
+static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+{
+	struct dib3000_state *state = fe->demodulator_priv;
+	u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+	deb_xfer("%s pid parsing",onoff ? "enabling" : "disabling");
+	if (onoff) {
+		wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
+	} else {
+		wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
+	}
+	return 0;
+}
+
+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 dib3000_state* state = NULL;
+	u16 devid;
+
+	/* allocate memory for the internal state */
+	state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->i2c = i2c;
+	memcpy(&state->config,config,sizeof(struct dib3000_config));
+	memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+
+	/* check for the correct demod */
+	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
+		goto error;
+
+	devid = rd(DIB3000_REG_DEVICE_ID);
+	if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
+		goto error;
+
+
+	switch (devid) {
+		case DIB3000MC_DEVICE_ID:
+			info("Found a DiBcom 3000-MC.");
+			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;
+
+	/* set the xfer operations */
+	xfer_ops->pid_parse = dib3000mc_pid_parse;
+	xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
+	xfer_ops->pid_ctrl = dib3000mc_pid_control;
+
+	return &state->frontend;
+
+error:
+	if (state)
+		kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dib3000mc_ops = {
+
+	.info = {
+		.name			= "DiBcom 3000-MC/P DVB-T",
+		.type 			= FE_OFDM,
+		.frequency_min 		= 44250000,
+		.frequency_max 		= 867250000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = dib3000mc_release,
+
+	.init = dib3000mc_fe_init_nonmobile,
+	.sleep = dib3000mc_sleep,
+
+	.set_frontend = dib3000mc_set_frontend_and_tuner,
+	.get_frontend = dib3000mc_get_frontend,
+	.get_tune_settings = dib3000mc_fe_get_tune_settings,
+
+	.read_status = dib3000mc_read_status,
+	.read_ber = dib3000mc_read_ber,
+	.read_signal_strength = dib3000mc_read_signal_strength,
+	.read_snr = dib3000mc_read_snr,
+	.read_ucblocks = dib3000mc_read_unc_blocks,
+};
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000mc_attach);
diff -puN /dev/null drivers/media/dvb/frontends/dib3000mc_priv.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/frontends/dib3000mc_priv.h	Fri Dec 10 15:14:14 2004
@@ -0,0 +1,439 @@
+/*
+ * dib3000mc_priv.h
+ *
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * for more information see dib3000mc.c .
+ */
+
+#ifndef __DIB3000MC_PRIV_H__
+#define __DIB3000MC_PRIV_H__
+
+/* 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
+ *         | |  |  |  |  |
+ *         | |  |  |  |  +-- alpha (000=0, 001=1, 010=2, 100=4)
+ *         | |  |  |  +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
+ *         | |  |  +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
+ *         | |  +----------- transmission mode (0=2k, 1=8k)
+ *         | |
+ *         | +-------------- restart autosearch for parameters
+ *         +---------------- restart the demodulator
+ * reg: 181      1 111 1
+ *               |  |  |
+ *               |  |  +- FEC applies for HP or LP (0=LP, 1=HP)
+ *               |  +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
+ *               +------- hierarchy on (0=no, 1=yes)
+ */
+
+/* demodulator tuning parameter and restart options */
+#define DIB3000MC_REG_DEMOD_PARM		(     0)
+#define DIB3000MC_DEMOD_PARM(a,c,g,t)	( \
+		 (0x7 & a) | \
+		((0x3 & c) << 3) | \
+		((0x3 & g) << 5) | \
+		((0x1 & t) << 7) )
+#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON	(1 << 8)
+#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF	(0 << 8)
+#define DIB3000MC_DEMOD_RST_DEMOD_ON		(1 << 9)
+#define DIB3000MC_DEMOD_RST_DEMOD_OFF		(0 << 9)
+
+/* register for hierarchy parameters */
+#define DIB3000MC_REG_HRCH_PARM			(   181)
+#define DIB3000MC_HRCH_PARM(s,f,h)		( \
+		 (0x1 & s) | \
+		((0x7 & f) << 1) | \
+		((0x1 & h) << 4) )
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_1				(     1)
+#define DIB3000MC_UNK_1					(  0x04)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_2				(     2)
+#define DIB3000MC_UNK_2					(  0x04)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_3				(     3)
+#define DIB3000MC_UNK_3					(0x1000)
+
+#define DIB3000MC_REG_UNK_4				(     4)
+#define DIB3000MC_UNK_4					(0x0814)
+
+/* timeout ??? */
+#define DIB3000MC_REG_SEQ_TPS			(     5)
+#define DIB3000MC_SEQ_TPS_DEFAULT		(     1)
+#define DIB3000MC_SEQ_TPS(s,t)			( \
+		((s & 0x0f) << 4) | \
+		((t & 0x01) << 8) )
+#define DIB3000MC_IS_TPS(v)				((v << 8) & 0x1)
+#define DIB3000MC_IS_AS(v)				((v >> 4) & 0xf)
+
+/* parameters for the bandwidth */
+#define DIB3000MC_REG_BW_TIMOUT_MSB		(     6)
+#define DIB3000MC_REG_BW_TIMOUT_LSB		(     7)
+
+static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
+
+/*static u16 dib3000mc_bandwidth_5mhz[] =
+	{ 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
+
+static u16 dib3000mc_bandwidth_6mhz[] =
+	{ 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
+
+static u16 dib3000mc_bandwidth_7mhz[] =
+	{ 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
+
+static u16 dib3000mc_bandwidth_8mhz[] =
+	{ 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0b0 };
+
+static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
+static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
+
+/* lock mask */
+#define DIB3000MC_REG_LOCK_MASK			(    15)
+#define DIB3000MC_ACTIVATE_LOCK_MASK	(0x0800)
+
+/* reset the uncorrected packet count (??? do it 5 times) */
+#define DIB3000MC_REG_RST_UNC			(    18)
+#define DIB3000MC_RST_UNC_ON			(     1)
+#define DIB3000MC_RST_UNC_OFF			(     0)
+
+#define DIB3000MC_REG_UNK_19			(    19)
+#define DIB3000MC_UNK_19				(     0)
+
+/* DDS frequency value (IF position) and inversion bit */
+#define DIB3000MC_REG_INVERSION			(    21)
+#define DIB3000MC_REG_SET_DDS_FREQ_MSB	(    21)
+#define DIB3000MC_DDS_FREQ_MSB_INV_OFF	(0x0164)
+#define DIB3000MC_DDS_FREQ_MSB_INV_ON	(0x0364)
+
+#define DIB3000MC_REG_SET_DDS_FREQ_LSB	(    22)
+#define DIB3000MC_DDS_FREQ_LSB			(0x463d)
+
+/* timing frequencies setting */
+#define DIB3000MC_REG_TIMING_FREQ_MSB	(    23)
+#define DIB3000MC_REG_TIMING_FREQ_LSB	(    24)
+#define DIB3000MC_CLOCK_REF				(0x151fd1)
+
+//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
+
+//static u16 dib3000mc_timing_freq[][2] = {
+//	{ 0x69, 0x9f18 }, /* 5 MHz */
+//	{ 0x7e ,0xbee9 }, /* 6 MHz */
+//	{ 0x93 ,0xdebb }, /* 7 MHz */
+//	{ 0xa8 ,0xfe8c }, /* 8 MHz */
+//};
+
+/* timeout ??? */
+static u16 dib3000mc_reg_offset[] = { 26,33 };
+
+static u16 dib3000mc_offset[][2] = {
+	{ 26240, 5 }, /* default */
+	{ 30336, 6 }, /* 8K */
+	{ 38528, 8 }, /* 2K */
+};
+
+#define DIB3000MC_REG_ISI				(    29)
+#define DIB3000MC_ISI_DEFAULT			(0x1073)
+#define DIB3000MC_ISI_ACTIVATE			(0x0000)
+#define DIB3000MC_ISI_INHIBIT			(0x0200)
+
+/* impulse noise control */
+static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
+
+static u16 dib3000mc_imp_noise_ctl[][2] = {
+	{ 0x1294, 0xfff8 }, /* mode 0 */
+	{ 0x1294, 0xfff8 }, /* mode 1 */
+	{ 0x1294, 0xfff8 }, /* mode 2 */
+	{ 0x1294, 0xfff8 }, /* mode 3 */
+	{ 0x1294, 0xfff8 }, /* mode 4 */
+};
+
+/* AGC registers */
+static u16 dib3000mc_reg_agc[] = {
+	36,37,38,39,42,43,44,45,46,47,48,49
+};
+
+static u16 dib3000mc_agc_tuner[][12] = {
+	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
+		0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
+	}, /* TUNER_PANASONIC_ENV77H04D5, */
+
+	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
+		0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
+	}, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
+
+	{	0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
+		0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
+	}, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
+
+	{	0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
+		0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
+	}, /* TUNER_PROVIDER_X */
+	/* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
+};
+
+/* AGC loop bandwidth */
+static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
+static u16 dib3000mc_agc_bandwidth[]  = { 0x119,0x330 };
+
+static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
+static u16 dib3000mc_agc_bandwidth_general[] =
+	{ 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
+
+#define DIB3000MC_REG_IMP_NOISE_55 		(    55)
+#define DIB3000MC_IMP_NEW_ALGO(w)		(w | (1<<10))
+
+/* Impulse noise params */
+static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
+static u16 dib3000mc_impluse_noise[][3] = {
+	{ 0x489, 0x89, 0x72 }, /* 5 MHz */
+	{ 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
+	{ 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
+	{ 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
+};
+
+static u16 dib3000mc_reg_fft[] = {
+	58,59,60,61,62,63,64,65,66,67,68,69,
+	70,71,72,73,74,75,76,77,78,79,80,81,
+	82,83,84,85,86
+};
+
+static u16 dib3000mc_fft_modes[][29] = {
+	{	0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+	  	0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+	  	0x3ffe, 0x5b3, 0x3feb, 0x76,   0x0, 0xd
+	}, /* fft mode 0 */
+	{	0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+		0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+		0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+	  	0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+	  	0x3ffe, 0x5b3, 0x3feb, 0x0,  0x8200, 0xd
+	}, /* fft mode 1 */
+};
+
+#define DIB3000MC_REG_UNK_88			(    88)
+#define DIB3000MC_UNK_88				(0x0410)
+
+static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
+static u16 dib3000mc_bw[][6] = {
+	{ 0,0,0,0,0,0 }, /* 5 MHz */
+	{ 0,0,0,0,0,0 }, /* 6 MHz */
+	{ 0,0,0,0,0,0 }, /* 7 MHz */
+	{ 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
+};
+
+
+/* phase noise control */
+#define DIB3000MC_REG_UNK_99			(    99)
+#define DIB3000MC_UNK_99				(0x0220)
+
+#define DIB3000MC_REG_SCAN_BOOST		(   100)
+#define DIB3000MC_SCAN_BOOST_ON			((11 << 6) + 6)
+#define DIB3000MC_SCAN_BOOST_OFF		((16 << 6) + 9)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_110			(   110)
+#define DIB3000MC_UNK_110				(  3277)
+
+#define DIB3000MC_REG_UNK_111			(   111)
+#define DIB3000MC_UNK_111_PH_N_MODE_0	(     0)
+#define DIB3000MC_UNK_111_PH_N_MODE_1	(1 << 1)
+
+/* superious rm config */
+#define DIB3000MC_REG_UNK_120			(   120)
+#define DIB3000MC_UNK_120				(  8207)
+
+#define DIB3000MC_REG_UNK_133			(   133)
+#define DIB3000MC_UNK_133				( 15564)
+
+#define DIB3000MC_REG_UNK_134			(   134)
+#define DIB3000MC_UNK_134				(     0)
+
+/* adapter config for constellation */
+static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
+
+static u16 dib3000mc_adp_cfg[][4] = {
+	{ 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK  */
+	{ 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
+	{ 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
+};
+
+static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
+
+static u16 dib3000mc_mobile_mode[][5] = {
+	{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
+	{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
+	{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
+	{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
+};
+
+#define DIB3000MC_REG_DIVERSITY1		(   177)
+#define DIB3000MC_DIVERSITY1_DEFAULT	(     1)
+
+#define DIB3000MC_REG_DIVERSITY2		(   178)
+#define DIB3000MC_DIVERSITY2_DEFAULT	(     1)
+
+#define DIB3000MC_REG_DIVERSITY3		(   180)
+#define DIB3000MC_DIVERSITY3_IN_OFF		(0xfff0)
+#define DIB3000MC_DIVERSITY3_IN_ON		(0xfff6)
+
+#define DIB3000MC_REG_FEC_CFG			(   195)
+#define DIB3000MC_FEC_CFG				(  0x10)
+
+#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_PID_PARSE	(1 << 4)
+#define DIB3000MC_SMO_MODE_NO_PID_PARSE	~DIB3000MC_SMO_MODE_PID_PARSE
+#define DIB3000MC_SMO_MODE_188			(1 << 5)
+#define DIB3000MC_SMO_MODE_SLAVE		(DIB3000MC_SMO_MODE_DEFAULT | \
+			DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
+
+#define DIB3000MC_REG_FIFO_THRESHOLD	(   207)
+#define DIB3000MC_FIFO_THRESHOLD_DEFAULT	(  1792)
+#define DIB3000MC_FIFO_THRESHOLD_SLAVE	(   512)
+/*
+ * pidfilter
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. When connected to USB1.1 bandwidth this is important.
+ * DiB3000-MC/P can filter up to 32 PIDs
+ */
+#define DIB3000MC_REG_FIRST_PID			(   212)
+#define DIB3000MC_NUM_PIDS				(    32)
+
+#define DIB3000MC_REG_OUTMODE			(   244)
+#define DIB3000MC_OM_PARALLEL_GATED_CLK	(     0)
+#define DIB3000MC_OM_PAR_CONT_CLK		(1 << 11)
+#define DIB3000MC_OM_SERIAL				(2 << 11)
+#define DIB3000MC_OM_DIVOUT_ON			(4 << 11)
+#define DIB3000MC_OM_SLAVE				(DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
+
+#define DIB3000MC_REG_RF_POWER			(   392)
+
+#define DIB3000MC_REG_FFT_POSITION		(   407)
+
+#define DIB3000MC_REG_DDS_FREQ_MSB		(   414)
+#define DIB3000MC_REG_DDS_FREQ_LSB		(   415)
+
+#define DIB3000MC_REG_TIMING_OFFS_MSB	(   416)
+#define DIB3000MC_REG_TIMING_OFFS_LSB	(   417)
+
+#define DIB3000MC_REG_TUNING_PARM		(   458)
+#define DIB3000MC_TP_QAM(v)				((v >> 13) & 0x03)
+#define DIB3000MC_TP_HRCH(v)			((v >> 12) & 0x01)
+#define DIB3000MC_TP_ALPHA(v)			((v >> 9) & 0x07)
+#define DIB3000MC_TP_FFT(v)				((v >> 8) & 0x01)
+#define DIB3000MC_TP_FEC_CR_HP(v)		((v >> 5) & 0x07)
+#define DIB3000MC_TP_FEC_CR_LP(v)		((v >> 2) & 0x07)
+#define DIB3000MC_TP_GUARD(v)			(v & 0x03)
+
+#define DIB3000MC_REG_SIGNAL_NOISE_MSB	(   483)
+#define DIB3000MC_REG_SIGNAL_NOISE_LSB	(   484)
+
+#define DIB3000MC_REG_MER				(   485)
+
+#define DIB3000MC_REG_BER_MSB			(   500)
+#define DIB3000MC_REG_BER_LSB			(   501)
+
+#define DIB3000MC_REG_PACKET_ERRORS		(   503)
+
+#define DIB3000MC_REG_PACKET_ERROR_COUNT	(   506)
+
+#define DIB3000MC_REG_LOCK_507			(   507)
+#define DIB3000MC_LOCK_507				(0x0002) // ? name correct ?
+
+#define DIB3000MC_REG_LOCKING			(   509)
+#define DIB3000MC_AGC_LOCK(v)			(v & 0x8000)
+#define DIB3000MC_CARRIER_LOCK(v)		(v & 0x2000)
+#define DIB3000MC_MPEG_SYNC_LOCK(v)		(v & 0x0080)
+#define DIB3000MC_MPEG_DATA_LOCK(v)		(v & 0x0040)
+#define DIB3000MC_TPS_LOCK(v)			(v & 0x0004)
+
+#define DIB3000MC_REG_AS_IRQ			(   511)
+#define DIB3000MC_AS_IRQ_SUCCESS		(1 << 1)
+#define DIB3000MC_AS_IRQ_FAIL			(     1)
+
+#define DIB3000MC_REG_TUNER				(   769)
+
+#define DIB3000MC_REG_RST_I2C_ADDR		(  1024)
+#define DIB3000MC_DEMOD_ADDR_ON			(     1)
+#define DIB3000MC_DEMOD_ADDR(a)			((a << 3) & 0x03F0)
+
+#define DIB3000MC_REG_RESTART			(  1027)
+#define DIB3000MC_RESTART_OFF			(0x0000)
+#define DIB3000MC_RESTART_AGC			(0x0800)
+#define DIB3000MC_RESTART_CONFIG		(0x8000)
+
+#define DIB3000MC_REG_RESTART_VIT		(  1028)
+#define DIB3000MC_RESTART_VIT_OFF		(     0)
+#define DIB3000MC_RESTART_VIT_ON		(     1)
+
+#define DIB3000MC_REG_CLK_CFG_1			(  1031)
+#define DIB3000MC_CLK_CFG_1_POWER_UP	(     0)
+#define DIB3000MC_CLK_CFG_1_POWER_DOWN	(0xffff)
+
+#define DIB3000MC_REG_CLK_CFG_2			(  1032)
+#define DIB3000MC_CLK_CFG_2_PUP_FIXED	(0x012c)
+#define DIB3000MC_CLK_CFG_2_PUP_PORT	(0x0104)
+#define DIB3000MC_CLK_CFG_2_PUP_MOBILE  (0x0000)
+#define DIB3000MC_CLK_CFG_2_POWER_DOWN	(0xffff)
+
+#define DIB3000MC_REG_CLK_CFG_3			(  1033)
+#define DIB3000MC_CLK_CFG_3_POWER_UP	(     0)
+#define DIB3000MC_CLK_CFG_3_POWER_DOWN	(0xfff5)
+
+#define DIB3000MC_REG_CLK_CFG_7			(  1037)
+#define DIB3000MC_CLK_CFG_7_INIT		( 12592)
+#define DIB3000MC_CLK_CFG_7_POWER_UP	(~0x0003)
+#define DIB3000MC_CLK_CFG_7_PWR_DOWN	(0x0003)
+#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF	(1 << 8)
+
+/* was commented out ??? */
+#define DIB3000MC_REG_CLK_CFG_8			(  1038)
+#define DIB3000MC_CLK_CFG_8_POWER_UP	(0x160c)
+
+#define DIB3000MC_REG_CLK_CFG_9			(  1039)
+#define DIB3000MC_CLK_CFG_9_POWER_UP	(     0)
+
+/* also clock ??? */
+#define DIB3000MC_REG_ELEC_OUT			(  1040)
+#define DIB3000MC_ELEC_OUT_HIGH_Z		(     0)
+#define DIB3000MC_ELEC_OUT_DIV_OUT_ON	(     1)
+#define DIB3000MC_ELEC_OUT_SLAVE		(     3)
+
+#endif
diff -puN drivers/media/dvb/frontends/Kconfig~dvb-update-dib-usb-driver drivers/media/dvb/frontends/Kconfig
--- 25/drivers/media/dvb/frontends/Kconfig~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/frontends/Kconfig	Fri Dec 10 15:14:14 2004
@@ -111,6 +111,13 @@ config DVB_DIB3000MB
 	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
 	  to support this frontend.
 
+config DVB_DIB3000MC
+	tristate "DiBcom 3000-MC/P"
+	depends on DVB_CORE
+	help
+	  A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+	  to support this frontend.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
diff -puN drivers/media/dvb/frontends/Makefile~dvb-update-dib-usb-driver drivers/media/dvb/frontends/Makefile
--- 25/drivers/media/dvb/frontends/Makefile~dvb-update-dib-usb-driver	Fri Dec 10 15:14:14 2004
+++ 25-akpm/drivers/media/dvb/frontends/Makefile	Fri Dec 10 15:14:14 2004
@@ -11,7 +11,8 @@ obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
 obj-$(CONFIG_DVB_TDA8083) += tda8083.o
 obj-$(CONFIG_DVB_L64781) += l64781.o
-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
_
