Commit 5355c9c6 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] dvb: update dib-usb driver

- 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: default avatarMichael Hunold <hunold@linuxtv.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 92aeca38
......@@ -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 working for me. Some work has to be done
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 and send it over to me or to
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
......
......@@ -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.
Say Y if your Artec device has 0x0574 as Vendor ID and 0x2235 as Product ID.
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 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.
......@@ -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 level (1=info,2=xfer,4=alotmore,8=ts,16=e
#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 usb_dibusb *dib,
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_dibusb *dib, int pid, int onoff)
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_dibusb *dib, int pid, int onoff)
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; uint32_t key; } rc_keys [] =
{ 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 :).
......@@ -395,6 +407,21 @@ static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
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
*/
......@@ -409,23 +436,12 @@ static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
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_adapter *adapter)
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_cable_eu_config = {
.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(struct dvb_frontend* fe, struct dvb_frontend
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 *dib)
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 *dib)
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_interface *intf,
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;
......
......@@ -67,7 +67,7 @@ static struct dibusb_device_parameter dibusb_dev_parm[3] = {
.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_devices[DIBUSB_SUPPORTED_DEVICES] = {
.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;
......
......@@ -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
......
......@@ -11,7 +11,8 @@ obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o
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
......
#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);
......@@ -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)
......
......@@ -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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment