Commit 65f4cda1 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] DVB: revamp dibusb driver

- [DVB] dibusb: update documentation for the dibusb DVB driver
- [DVB] dibusb: major overhaul of the driver, including adding new vendor and product ids from clones
Signed-off-by: default avatarMichael Hunold <hunold@linuxtv.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5c9de4d6
Documentation for dib3000mb frontend driver and dibusb device driver
The drivers should work with
- Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device (VP7041)
http://www.twinhan.com/visiontv-2_4.htm
http://www.twinhan.com/
- CTS Portable (Chinese Television System)
http://www.2cts.tv/ctsportable/
......@@ -19,6 +21,10 @@ The drivers should work with
- Ultima Electronic/Artec T1 USB TVBOX
http://www.arteceuro.com/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB
http://www.comprousa.com/products/vmu2000.htm
- Unknown USB DVB-T device with vendor ID Hyper-Paltek
Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de),
......@@ -32,6 +38,11 @@ published by the Free Software Foundation, version 2.
NEWS:
2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
to Amaury Demol for reporting
- changed usb TS transfer method (several urbs, stopping transfer
before setting a new pid)
2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
to Christian Motschke for reporting
2004-09-05 - released the dibusb device and dib3000mb-frontend driver
......@@ -85,8 +96,13 @@ in the device).
If you want to enable debug output, you have to load the driver manually.
modprobe dvb-dibusb debug=1
modprobe dib3000mb debug=1
first have a look, which debug level are available:
modinfo dvb-dibusb
modinfo dib3000mb
modprobe dvb-dibusb debug=<level>
modprobe dib3000mb debug=<level>
should do the trick.
......@@ -102,11 +118,13 @@ as a slave device in vdr, was not working for me. Some work has to be done
2. Known problems and bugs
TODO:
- add some additional URBs for USB data transfer
- due a firmware problem i2c writes during mpeg transfers destroy the stream
no i2c writes during streaming, interrupt streaming, when adding another pid
- remote control tasklet
- signal-quality and strength calculations
- debug messages restructure
- i2c address probing
-
2.1. Adding new devices
2.1. Adding support for devices
It is not possible to determine the range of devices based on the DiBcom
reference design. This is because the reference design of DiBcom can be sold
......@@ -122,7 +140,7 @@ of the device. I will add it to this list in order to make this clear to
others.
If you are familar with C you can also add the VID and PID of the device to
the dvb-dibusb.[hc]-files and create a patch and send it over to me or to
the 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.
......
config DVB_DIBUSB
tristate "Twinhan/KWorld/Hama/Artec USB DVB-T devices"
tristate "DiBcom/Twinhan/KWorld/Hama/Artec/Compro USB DVB-T devices"
depends on DVB_CORE && USB
select FW_LOADER
help
......@@ -8,11 +8,13 @@ config DVB_DIBUSB
Devices supported by this driver:
Twinhan VisionPlus VisionDTV USB-Ter (VP7041)
TwinhanDTV USB-Ter (VP7041)
TwinhanDTV Magic Box (VP7041e)
KWorld V-Stream XPERT DTV - DVB-T USB
Hama DVB-T USB-Box
DiBcom reference device (non-public)
Ultima Electronic/Artec T1 USB TVBOX
Compro Videomate DVB-U2000 - DVB-T USB
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
......@@ -20,7 +22,7 @@ config DVB_DIBUSB
These devices can be understood as budget ones, they "only" deliver
the MPEG data.
Currently all known copies of the DiBcom reference design have the DiBcom 3000MB
Currently all known copies of the DiBcom reference design have the DiBcom 3000-MB
frontend onboard. Please enable and load this one manually in order to use this
device.
......
......@@ -20,9 +20,7 @@
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dib3000mb frontend) are based.
*
* TODO
* - probing for i2c addresses, it is possible, that they have been changed
* by the vendor
*
*
* see Documentation/dvb/README.dibusb for more information
*/
......@@ -57,7 +55,7 @@
static int debug;
module_param(debug, int, 0x644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore (|-able)).");
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err (|-able)).");
#else
#define dprintk_new(args...)
#define debug_dump(b,l)
......@@ -66,31 +64,14 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore (|-able))
#define deb_info(args...) dprintk_new(0x01,args)
#define deb_xfer(args...) dprintk_new(0x02,args)
#define deb_alot(args...) dprintk_new(0x04,args)
#define deb_ts(args...) dprintk_new(0x08,args)
#define deb_err(args...) dprintk_new(0x10,args)
/* Version information */
#define DRIVER_VERSION "0.0"
#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
/* USB Driver stuff */
/* table of devices that work with this driver */
static struct usb_device_id dibusb_table [] = {
{ USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_PREFW_ID) },
{ USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_ID) },
{ USB_DEVICE(USB_IMC_NETWORKS_VENDOR_ID, USB_VP7041_PRODUCT_PREFW_ID) },
{ USB_DEVICE(USB_IMC_NETWORKS_VENDOR_ID, USB_VP7041_PRODUCT_ID) },
{ USB_DEVICE(USB_KWORLD_VENDOR_ID, USB_VSTREAM_PRODUCT_PREFW_ID) },
{ USB_DEVICE(USB_KWORLD_VENDOR_ID, USB_VSTREAM_PRODUCT_ID) },
{ USB_DEVICE(USB_DIBCOM_VENDOR_ID, USB_DIBCOM_PRODUCT_PREFW_ID) },
{ USB_DEVICE(USB_DIBCOM_VENDOR_ID, USB_DIBCOM_PRODUCT_ID) },
{ USB_DEVICE(USB_ULTIMA_ELECTRONIC_ID, USB_ULTIMA_ELEC_PROD_PREFW_ID) },
{ USB_DEVICE(USB_ULTIMA_ELECTRONIC_ID, USB_ULTIMA_ELEC_PROD_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_table);
static int dibusb_readwrite_usb(struct usb_dibusb *dib,
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
......@@ -99,12 +80,14 @@ static int dibusb_readwrite_usb(struct usb_dibusb *dib,
if (wbuf == NULL || wlen == 0)
return -EINVAL;
/* if (dib->disconnecting)
return -EINVAL;*/
if ((ret = down_interruptible(&dib->usb_sem)))
return ret;
if (dib->streaming && wbuf[0] == DIBUSB_REQ_I2C_WRITE)
deb_err("BUG: writing to i2c, while TS-streaming destroys the stream. What"
" did you do ? Please enable debugging and send the syslog to the author. (%x reg: %x %x)",
wbuf[0],wbuf[2],wbuf[3]);
debug_dump(wbuf,wlen);
ret = usb_bulk_msg(dib->udev,COMMAND_PIPE,
......@@ -189,6 +172,8 @@ static int dibusb_start_xfer(struct usb_dibusb *dib)
(DIB3000MB_FIFO_ACTIVATE >> 8) & 0xff,
(DIB3000MB_FIFO_ACTIVATE) & 0xff
};
dib->streaming = 1;
deb_ts("start streaming\n");
return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
}
......@@ -200,11 +185,14 @@ static int dibusb_stop_xfer(struct usb_dibusb *dib)
(DIB3000MB_FIFO_INHIBIT >> 8) & 0xff,
(DIB3000MB_FIFO_INHIBIT) & 0xff
};
dib->streaming = 0;
deb_ts("stop streaming\n");
return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
}
static int dibusb_set_pid(struct dibusb_pid *dpid)
{
struct usb_dibusb *dib = dpid->dib;
u16 pid = dpid->pid | (dpid->active ? DIB3000MB_ACTIVATE_FILTERING : 0);
u8 b[4] = {
(dpid->reg >> 8) & 0xff,
......@@ -212,25 +200,50 @@ static int dibusb_set_pid(struct dibusb_pid *dpid)
(pid >> 8) & 0xff,
(pid) & 0xff
};
int ret;
/* firmware bug, i2c write during mpeg transfer */
if (dib->feedcount) {
deb_info("stop streaming\n");
ret = dibusb_stop_xfer(dib);
}
if (dpid->active)
dib->feedcount++;
else
dib->feedcount--;
return dibusb_i2c_msg(dpid->dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
ret = dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0);
if (ret == 0 && dib->feedcount) {
deb_info("start streaming\n");
ret = dibusb_start_xfer(dib);
}
return ret;
}
static void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
{
struct usb_dibusb *dib = urb->context;
if (!dib->streaming)
return;
deb_xfer("urb complete feedcount: %d, status: %d\n",dib->feedcount,urb->status);
if (urb->status == 0) {
deb_info("URB return len: %d\n",urb->actual_length);
if (dib->feedcount > 0 && urb->status == 0) {
deb_xfer("URB return len: %d\n",urb->actual_length);
if (urb->actual_length % 188)
deb_info("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
deb_xfer("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
/* Francois recommends to drop not full-filled packets, even if they may
* contain valid TS packets
*/
if (urb->actual_length == DIBUSB_TS_DEFAULT_SIZE && dib->dvb_is_ready)
dvb_dmx_swfilter_packets(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length/188);
}
else
deb_ts("URB dropped because of the "
"actual_length or !dvb_is_ready (%d).\n",dib->dvb_is_ready);
} else
deb_ts("URB dropped because of feedcount or status.\n");
if (dib->streaming)
usb_submit_urb(urb,GFP_KERNEL);
}
......@@ -240,9 +253,8 @@ static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
// struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
struct dibusb_pid *dpid;
int ret = 0;
deb_info("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
deb_ts("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
if ((dpid = dibusb_get_free_pid(dib)) == NULL) {
err("no free pid in list.");
......@@ -253,32 +265,14 @@ static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
dibusb_set_pid(dpid);
if (0 == dib->feed_count++) {
usb_fill_bulk_urb( dib->buf_urb, dib->udev, DATA_PIPE,
dib->buffer, 8192, dibusb_urb_complete, dib);
dib->buf_urb->transfer_flags = 0;
if ((ret = usb_submit_urb(dib->buf_urb,GFP_KERNEL))) {
dibusb_stop_xfer(dib);
err("could not submit buffer urb.");
return ret;
}
if ((ret = dibusb_start_xfer(dib)))
return ret;
dib->streaming = 1;
}
return 0;
}
static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
struct dibusb_pid *dpid = (struct dibusb_pid *) dvbdmxfeed->priv;
deb_info("stopfeed pid: 0x%04x, feedtype: %d",dvbdmxfeed->pid, dvbdmxfeed->type);
deb_ts("stopfeed pid: 0x%04x, feedtype: %d\n",dvbdmxfeed->pid, dvbdmxfeed->type);
if (dpid == NULL)
err("channel in dmxfeed->priv was NULL");
......@@ -288,11 +282,6 @@ static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
dibusb_set_pid(dpid);
}
if (--dib->feed_count == 0) {
dib->streaming = 0;
usb_unlink_urb(dib->buf_urb);
dibusb_stop_xfer(dib);
}
return 0;
}
......@@ -302,7 +291,7 @@ static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
/*
* do not use this, just a workaround for a bug,
* which will never occur :).
* which will hopefully never occur :).
*/
static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
{
......@@ -312,7 +301,8 @@ static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
/*
* TODO: a tasklet should run with a delay of 1/10 second
* and fill an appropriate event device ?
* and feed an appropriate event device ?
* NEC protocol is used for remote controlls
*/
static int dibusb_read_remote_control(struct usb_dibusb *dib)
{
......@@ -321,6 +311,18 @@ static int dibusb_read_remote_control(struct usb_dibusb *dib)
if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
return ret;
switch (rb[0]) {
case DIBUSB_RC_NEC_KEY_PRESSED:
break;
case DIBUSB_RC_NEC_EMPTY:
case DIBUSB_RC_NEC_KEY_REPEATED:
default:
break;
}
return 0;
}
......@@ -474,11 +476,13 @@ static int dibusb_dvb_init(struct usb_dibusb *dib)
err:
return ret;
success:
dib->dvb_is_ready = 1;
return 0;
}
static int dibusb_dvb_exit(struct usb_dibusb *dib)
{
dib->dvb_is_ready = 0;
deb_info("unregistering DVB part\n");
dvb_net_release(&dib->dvb_net);
dib->demux.dmx.close(&dib->demux.dmx);
......@@ -492,8 +496,16 @@ static int dibusb_dvb_exit(struct usb_dibusb *dib)
static int dibusb_exit(struct usb_dibusb *dib)
{
usb_free_urb(dib->buf_urb);
pci_free_consistent(NULL,8192,dib->buffer,dib->dma_handle);
int i;
for (i = 0; i < DIBUSB_TS_NUM_URBS; i++)
if (dib->buf_urb[i] != NULL) {
deb_info("killing URB no. %d.\n",i);
usb_kill_urb(dib->buf_urb[i]); // TODO kernel version ifdef for unlink_urb
deb_info("freeing URB no. %d.\n",i);
usb_free_urb(dib->buf_urb[i]);
}
pci_free_consistent(NULL,DIBUSB_TS_BUFFER_SIZE,dib->buffer,dib->dma_handle);
return 0;
}
......@@ -513,12 +525,28 @@ static int dibusb_init(struct usb_dibusb *dib)
/* dibusb_reset_cpu(dib); */
dib->buffer = pci_alloc_consistent(NULL,8192, &dib->dma_handle);
memset(dib->buffer,0,8192);
if (!(dib->buf_urb = usb_alloc_urb(0,GFP_KERNEL))) {
if ((dib->buffer = pci_alloc_consistent(NULL,DIBUSB_TS_BUFFER_SIZE, &dib->dma_handle)) == NULL) {
return -ENOMEM;
}
memset(dib->buffer,0,DIBUSB_TS_BUFFER_SIZE);
for (i = 0; i < DIBUSB_TS_NUM_URBS; i++) {
if (!(dib->buf_urb[i] = usb_alloc_urb(0,GFP_KERNEL))) {
dibusb_exit(dib);
return -ENOMEM;
}
deb_info("submitting URB no. %d\n",i);
usb_fill_bulk_urb( dib->buf_urb[i], dib->udev, DATA_PIPE,
&dib->buffer[i*DIBUSB_TS_URB_BUFFER_SIZE], DIBUSB_TS_URB_BUFFER_SIZE,
dibusb_urb_complete, dib);
dib->buf_urb[i]->transfer_flags = 0;
if ((ret = usb_submit_urb(dib->buf_urb[i],GFP_KERNEL))) {
err("could not submit buffer urb no. %d\n",i);
dibusb_exit(dib);
return ret;
}
}
for (i=0; i < DIBUSB_MAX_PIDS; i++) {
dib->pid_list[i].reg = i+DIB3000MB_REG_FIRST_PID;
......@@ -527,8 +555,9 @@ static int dibusb_init(struct usb_dibusb *dib)
dib->pid_list[i].dib = dib;
}
dib->feedcount = 0;
dib->streaming = 0;
dib->feed_count = 0;
dib->dvb_is_ready = 0;
if ((ret = dibusb_dvb_init(dib))) {
dibusb_exit(dib);
......@@ -591,19 +620,23 @@ static int dibusb_loadfirmware(struct usb_device *udev,
if (ret != b[0]) {
err("error while transferring firmware "
"(transferred size: %d, block size: %d)",
ret,b[1]);
ret,b[0]);
ret = -EINVAL;
break;
}
i += 5 + b[0];
}
/* length in ret */
if (ret > 0)
ret = 0;
/* restart the CPU */
reset = 0;
if ((ret = dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1)) != 1)
if (ret || dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1) != 1) {
err("could not restart the USB controller CPU.");
ret = -EINVAL;
}
kfree(p);
ret = 0;
} else {
ret = -ENOMEM;
}
......
......@@ -7,6 +7,7 @@
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*
*
* for more information see dvb-dibusb.c .
*/
......@@ -14,24 +15,102 @@
#ifndef __DVB_DIBUSB_H__
#define __DVB_DIBUSB_H__
#define DIBUSB_DEMOD_I2C_ADDR_DEFAULT 0x10
/* Vendor IDs */
#define USB_TWINHAN_VENDOR_ID 0x1822
#define USB_IMC_NETWORKS_VENDOR_ID 0x13d3
#define USB_KWORLD_VENDOR_ID 0xeb1a
#define USB_DIBCOM_VENDOR_ID 0x10b8
#define USB_ULTIMA_ELECTRONIC_ID 0x05d8
#define USB_VID_TWINHAN_ID 0x1822
#define USB_VID_IMC_NETWORKS_ID 0x13d3
#define USB_VID_EMPIA_ID 0xeb1a
#define USB_VID_DIBCOM_ID 0x10b8
#define USB_VID_ULTIMA_ELECTRONIC_ID 0x05d8
#define USB_VID_COMPRO_ID 0x185b
#define USB_VID_HYPER_PALTEK 0x1025
/* Product IDs before loading the firmware */
#define USB_VP7041_PRODUCT_PREFW_ID 0x3201
#define USB_VSTREAM_PRODUCT_PREFW_ID 0x17de
#define USB_DIBCOM_PRODUCT_PREFW_ID 0x0bb8
#define USB_ULTIMA_ELEC_PROD_PREFW_ID 0x8105
#define USB_PID_TWINHAN_VP7041_COLD_ID 0x3201
#define USB_PID_KWORLD_VSTREAM_COLD_ID 0x17de
#define USB_PID_DIBCOM_MOD3000_COLD_ID 0x0bb8
#define USB_PID_ULTIMA_TVBOX_COLD_ID 0x8105
#define USB_PID_COMPRO_DVBU2000_COLD_ID 0xd000
#define USB_PID_UNK_HYPER_PALTEK_COLD_ID 0x005e
/* product ID afterwards */
#define USB_VP7041_PRODUCT_ID 0x3202
#define USB_VSTREAM_PRODUCT_ID 0x17df
#define USB_DIBCOM_PRODUCT_ID 0x0bb9
#define USB_ULTIMA_ELEC_PROD_ID 0x8106
#define USB_PID_TWINHAN_VP7041_WARM_ID 0x3202
#define USB_PID_KWORLD_VSTREAM_WARM_ID 0x17df
#define USB_PID_DIBCOM_MOD3000_WARM_ID 0x0bb9
#define USB_PID_ULTIMA_TVBOX_WARM_ID 0x8106
#define USB_PID_COMPRO_DVBU2000_WARM_ID 0xd001
#define USB_PID_UNK_HYPER_PALTEK_WARM_ID 0x005f
/* static array of valid firmware names, the best one first */
static const char * valid_firmware_filenames[] = {
"dvb-dibusb-5.0.0.11.fw",
};
struct dibusb_device {
u16 cold_product_id;
u16 warm_product_id;
u8 demod_addr;
const char *name;
};
#define DIBUSB_SUPPORTED_DEVICES 6
/* USB Driver stuff */
static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
{ .cold_product_id = USB_PID_TWINHAN_VP7041_COLD_ID,
.warm_product_id = USB_PID_TWINHAN_VP7041_WARM_ID,
.name = "TwinhanDTV USB-Ter/Magic Box / HAMA USB DVB-T device",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_PID_KWORLD_VSTREAM_COLD_ID,
.warm_product_id = USB_PID_KWORLD_VSTREAM_WARM_ID,
.name = "KWorld V-Stream XPERT DTV - DVB-T USB",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_PID_DIBCOM_MOD3000_COLD_ID,
.warm_product_id = USB_PID_DIBCOM_MOD3000_WARM_ID,
.name = "DiBcom USB DVB-T reference design (MOD300)",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_PID_ULTIMA_TVBOX_COLD_ID,
.warm_product_id = USB_PID_ULTIMA_TVBOX_WARM_ID,
.name = "Ultima Electronic/Artec T1 USB TVBOX",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_PID_COMPRO_DVBU2000_COLD_ID,
.warm_product_id = USB_PID_COMPRO_DVBU2000_WARM_ID,
.name = "Compro Videomate DVB-U2000 - DVB-T USB",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD_ID,
.warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM_ID,
.name = "Unkown USB DVB-T device ???? please report the name to linux-dvb or to the author",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
}
};
/* USB Driver stuff */
/* table of devices that work with this driver */
static struct usb_device_id dibusb_table [] = {
{ USB_DEVICE(USB_VID_TWINHAN_ID, USB_PID_TWINHAN_VP7041_COLD_ID) },
{ USB_DEVICE(USB_VID_TWINHAN_ID, USB_PID_TWINHAN_VP7041_WARM_ID) },
{ USB_DEVICE(USB_VID_IMC_NETWORKS_ID,USB_PID_TWINHAN_VP7041_COLD_ID) },
{ USB_DEVICE(USB_VID_IMC_NETWORKS_ID,USB_PID_TWINHAN_VP7041_WARM_ID) },
{ USB_DEVICE(USB_VID_EMPIA_ID, USB_PID_KWORLD_VSTREAM_COLD_ID) },
{ USB_DEVICE(USB_VID_EMPIA_ID, USB_PID_KWORLD_VSTREAM_WARM_ID) },
{ USB_DEVICE(USB_VID_DIBCOM_ID, USB_PID_DIBCOM_MOD3000_COLD_ID) },
{ USB_DEVICE(USB_VID_DIBCOM_ID, USB_PID_DIBCOM_MOD3000_WARM_ID) },
{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC_ID, USB_PID_ULTIMA_TVBOX_COLD_ID) },
{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC_ID, USB_PID_ULTIMA_TVBOX_WARM_ID) },
{ USB_DEVICE(USB_VID_COMPRO_ID, USB_PID_COMPRO_DVBU2000_COLD_ID) },
{ USB_DEVICE(USB_VID_COMPRO_ID, USB_PID_COMPRO_DVBU2000_WARM_ID) },
{ USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD_ID) },
{ USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_table);
/* CS register start/stop the usb controller cpu */
#define DIBUSB_CPU_CSREG 0x7F92
......@@ -53,15 +132,20 @@ struct dibusb_pid {
struct usb_dibusb *dib;
};
#define DIBUSB_TS_NUM_URBS 3
#define DIBUSB_TS_URB_BUFFER_SIZE 4096
#define DIBUSB_TS_BUFFER_SIZE (DIBUSB_TS_NUM_URBS * DIBUSB_TS_URB_BUFFER_SIZE)
#define DIBUSB_TS_DEFAULT_SIZE (188*21)
struct usb_dibusb {
/* usb */
struct usb_device * udev;
struct dibusb_device * dibdev;
int feedcount;
int streaming;
int feed_count;
struct urb *buf_urb;
struct urb * buf_urb[DIBUSB_TS_NUM_URBS];
u8 *buffer;
dma_addr_t dma_handle;
......@@ -77,52 +161,13 @@ struct usb_dibusb {
struct semaphore i2c_sem;
/* dvb */
int dvb_is_ready;
struct dvb_adapter *adapter;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
};
struct dibusb_device {
u16 cold_product_id;
u16 warm_product_id;
u8 demod_addr;
const char *name;
};
/* static array of valid firmware names, the best one first */
static const char * valid_firmware_filenames[] = {
"dvb-dibusb-5.0.0.11.fw",
};
#define DIBUSB_SUPPORTED_DEVICES 4
/* USB Driver stuff */
static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
{ .cold_product_id = USB_VP7041_PRODUCT_PREFW_ID,
.warm_product_id = USB_VP7041_PRODUCT_ID,
.name = "Twinhan VisionDTV USB-Ter/HAMA USB DVB-T device",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_VSTREAM_PRODUCT_PREFW_ID,
.warm_product_id = USB_VSTREAM_PRODUCT_ID,
.name = "KWorld V-Stream XPERT DTV - DVB-T USB",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{ .cold_product_id = USB_DIBCOM_PRODUCT_PREFW_ID,
.warm_product_id = USB_DIBCOM_PRODUCT_ID,
.name = "DiBcom USB reference design",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
{
.cold_product_id = USB_ULTIMA_ELEC_PROD_PREFW_ID,
.warm_product_id = USB_ULTIMA_ELEC_PROD_ID,
.name = "Ultima Electronic/Artec T1 USB TVBOX",
.demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT,
},
};
#define COMMAND_PIPE usb_sndbulkpipe(dib->udev, 0x01)
#define RESULT_PIPE usb_rcvbulkpipe(dib->udev, 0x81)
#define DATA_PIPE usb_rcvbulkpipe(dib->udev, 0x82)
......@@ -142,6 +187,10 @@ static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
/* prefix for reading the current RC key */
#define DIBUSB_REQ_POLL_REMOTE 0x04
#define DIBUSB_RC_NEC_EMPTY 0x00
#define DIBUSB_RC_NEC_KEY_PRESSED 0x01
#define DIBUSB_RC_NEC_KEY_REPEATED 0x02
/* 0x05 0xXX */
#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
......
......@@ -17,6 +17,8 @@
* 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
*
*/
......@@ -36,19 +38,21 @@
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk_new(level,args...) \
#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 (|-able)).");
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=setfe,16=getfe (|-able)).");
#else
#define dprintk_new(args...)
#define dprintk(args...) do { } while (0);
#endif
#define deb_info(args...) dprintk_new(0x01,args)
#define deb_xfer(args...) dprintk_new(0x02,args)
#define deb_alot(args...) dprintk_new(0x04,args)
#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"
......@@ -63,7 +67,7 @@ struct dib3000mb_state {
};
static struct dvb_frontend_info dib3000mb_info = {
.name = "DiBcom 3000-MB DVB-T frontend",
.name = "DiBcom 3000-MB DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
......@@ -72,8 +76,8 @@ static struct dvb_frontend_info dib3000mb_info = {
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_TRANSMISSION_MODE_AUTO |
FE_CAN_HIERARCHY_AUTO,
};
......@@ -149,7 +153,7 @@ static int dib3000mb_get_frontend(struct dib3000mb_state *state,
u32 dds_val, threshold = 0x800000;
if (!rd(DIB3000MB_REG_TPS_LOCK))
return -EINVAL;
return 0;
dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
if (dds_val & threshold)
......@@ -172,56 +176,56 @@ static int dib3000mb_get_frontend(struct dib3000mb_state *state,
||
((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
deb_info("inversion %d %d, %d\n",inv_test2,inv_test1, fep->inversion);
deb_getf("inversion %d %d, %d\n",inv_test2,inv_test1, fep->inversion);
switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
case DIB3000MB_QAM_QPSK:
deb_info("QPSK ");
deb_getf("QPSK ");
ofdm->constellation = QPSK;
break;
case DIB3000MB_QAM_QAM16:
deb_info("QAM16 ");
deb_getf("QAM16 ");
ofdm->constellation = QAM_16;
break;
case DIB3000MB_QAM_QAM64:
deb_info("QAM64 ");
deb_getf("QAM64 ");
ofdm->constellation = QAM_64;
break;
default:
err("Unexpected constellation returned by TPS (%d)",tps_val);
break;
}
deb_info("TPS: %d\n",tps_val);
deb_getf("TPS: %d\n",tps_val);
if (rd(DIB3000MB_REG_TPS_HRCH)) {
deb_info("HRCH ON\n");
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 DIB3000MB_VIT_ALPHA_OFF:
deb_info("HIERARCHY_NONE ");
deb_getf("HIERARCHY_NONE ");
ofdm->hierarchy_information = HIERARCHY_NONE;
break;
case DIB3000MB_VIT_ALPHA_1:
deb_info("HIERARCHY_1 ");
deb_getf("HIERARCHY_1 ");
ofdm->hierarchy_information = HIERARCHY_1;
break;
case DIB3000MB_VIT_ALPHA_2:
deb_info("HIERARCHY_2 ");
deb_getf("HIERARCHY_2 ");
ofdm->hierarchy_information = HIERARCHY_2;
break;
case DIB3000MB_VIT_ALPHA_4:
deb_info("HIERARCHY_4 ");
deb_getf("HIERARCHY_4 ");
ofdm->hierarchy_information = HIERARCHY_4;
break;
default:
err("Unexpected ALPHA value returned by TPS (%d)",tps_val);
}
deb_info("TPS: %d\n",tps_val);
deb_getf("TPS: %d\n",tps_val);
} else {
deb_info("HRCH OFF\n");
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;
......@@ -230,67 +234,67 @@ static int dib3000mb_get_frontend(struct dib3000mb_state *state,
switch (tps_val) {
case DIB3000MB_FEC_1_2:
deb_info("FEC_1_2 ");
deb_getf("FEC_1_2 ");
*cr = FEC_1_2;
break;
case DIB3000MB_FEC_2_3:
deb_info("FEC_2_3 ");
deb_getf("FEC_2_3 ");
*cr = FEC_2_3;
break;
case DIB3000MB_FEC_3_4:
deb_info("FEC_3_4 ");
deb_getf("FEC_3_4 ");
*cr = FEC_3_4;
break;
case DIB3000MB_FEC_5_6:
deb_info("FEC_5_6 ");
deb_getf("FEC_5_6 ");
*cr = FEC_4_5;
break;
case DIB3000MB_FEC_7_8:
deb_info("FEC_7_8 ");
deb_getf("FEC_7_8 ");
*cr = FEC_7_8;
break;
default:
err("Unexpected FEC returned by TPS (%d)",tps_val);
break;
}
deb_info("TPS: %d\n",tps_val);
deb_getf("TPS: %d\n",tps_val);
switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
case DIB3000MB_GUARD_TIME_1_32:
deb_info("GUARD_INTERVAL_1_32 ");
deb_getf("GUARD_INTERVAL_1_32 ");
ofdm->guard_interval = GUARD_INTERVAL_1_32;
break;
case DIB3000MB_GUARD_TIME_1_16:
deb_info("GUARD_INTERVAL_1_16 ");
deb_getf("GUARD_INTERVAL_1_16 ");
ofdm->guard_interval = GUARD_INTERVAL_1_16;
break;
case DIB3000MB_GUARD_TIME_1_8:
deb_info("GUARD_INTERVAL_1_8 ");
deb_getf("GUARD_INTERVAL_1_8 ");
ofdm->guard_interval = GUARD_INTERVAL_1_8;
break;
case DIB3000MB_GUARD_TIME_1_4:
deb_info("GUARD_INTERVAL_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;
}
deb_info("TPS: %d\n",tps_val);
deb_getf("TPS: %d\n",tps_val);
switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
case DIB3000MB_FFT_2K:
deb_info("TRANSMISSION_MODE_2K ");
deb_getf("TRANSMISSION_MODE_2K ");
ofdm->transmission_mode = TRANSMISSION_MODE_2K;
break;
case DIB3000MB_FFT_8K:
deb_info("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);
}
deb_info("TPS: %d\n",tps_val);
deb_getf("TPS: %d\n",tps_val);
return 0;
}
......@@ -307,18 +311,18 @@ static int dib3000mb_fe_read_search_status(struct dib3000mb_state *state)
if (irq & 0x02) {
if (rd(DIB3000MB_REG_LOCK2_VALUE) & 0x01) {
if (dib3000mb_get_frontend(state,&fep) == 0) {
deb_info("reading tuning data from frontend succeeded.\n");
deb_setf("reading tuning data from frontend succeeded.\n");
return dib3000mb_set_frontend(state,&fep,0) == 0;
} else {
deb_info("reading tuning data failed -> tuning failed.\n");
deb_setf("reading tuning data failed -> tuning failed.\n");
return 0;
}
} else {
deb_info("AS IRQ was pending, but LOCK2 was not & 0x01.\n");
deb_setf("AS IRQ was pending, but LOCK2 was not & 0x01.\n");
return 0;
}
} else if (irq & 0x01) {
deb_info("Autosearch failed.\n");
deb_setf("Autosearch failed.\n");
return 0;
}
......@@ -329,7 +333,7 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
struct dvb_frontend_parameters *fep, int tuner)
{
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t fe_cr;
fe_code_rate_t fe_cr = FEC_NONE;
int search_state,seq;
if (tuner) {
......@@ -342,82 +346,105 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
wr(DIB3000MB_REG_TUNER,
DIB3000MB_DEACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) );
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
case BANDWIDTH_8_MHZ:
case BANDWIDTH_AUTO:
deb_setf("8 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
break;
case BANDWIDTH_7_MHZ:
deb_setf("7 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[1]);
wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_7mhz);
break;
case BANDWIDTH_6_MHZ:
deb_setf("6 MHz\n");
wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[0]);
wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_6mhz);
break;
case BANDWIDTH_AUTO:
return -EOPNOTSUPP;
default:
err("unkown bandwidth value.");
return -EINVAL;
break;
}
}
wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
deb_setf("transmission mode: ");
switch (ofdm->transmission_mode) {
case TRANSMISSION_MODE_2K:
deb_setf("2k\n");
wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_2K);
break;
case TRANSMISSION_MODE_8K:
deb_setf("8k\n");
wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_8K);
break;
case TRANSMISSION_MODE_AUTO:
deb_setf("auto\n");
wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_AUTO);
break;
default:
return -EINVAL;
}
deb_setf("guard: ");
switch (ofdm->guard_interval) {
case GUARD_INTERVAL_1_32:
deb_setf("1_32\n");
wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_32);
break;
case GUARD_INTERVAL_1_16:
deb_setf("1_16\n");
wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_16);
break;
case GUARD_INTERVAL_1_8:
deb_setf("1_8\n");
wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_8);
break;
case GUARD_INTERVAL_1_4:
deb_setf("1_4\n");
wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_4);
break;
case GUARD_INTERVAL_AUTO:
deb_setf("auto\n");
wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_AUTO);
break;
default:
return -EINVAL;
}
deb_setf("invsersion: ");
switch (fep->inversion) {
case INVERSION_AUTO:
deb_setf("auto\n");
break;
case INVERSION_OFF:
deb_setf("on\n");
wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_OFF);
break;
case INVERSION_AUTO:
case INVERSION_ON:
deb_setf("on\n");
wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_ON);
break;
default:
return -EINVAL;
}
deb_setf("constellation: ");
switch (ofdm->constellation) {
case QPSK:
deb_setf("qpsk\n");
wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QPSK);
break;
case QAM_16:
deb_setf("qam16\n");
wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM16);
break;
case QAM_64:
deb_setf("qam64\n");
wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM64);
break;
case QAM_AUTO:
......@@ -425,53 +452,69 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
default:
return -EINVAL;
}
deb_setf("hierachy: ");
switch (ofdm->hierarchy_information) {
case HIERARCHY_NONE:
deb_setf("none ");
/* fall through alpha is 1, even when HIERARCHY is NONE */
case HIERARCHY_1:
deb_setf("alpha=1\n");
wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_1);
break;
case HIERARCHY_2:
deb_setf("alpha=2\n");
wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_2);
break;
case HIERARCHY_4:
deb_setf("alpha=4\n");
wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_4);
break;
case HIERARCHY_AUTO:
deb_setf("alpha=auto\n");
wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO);
break;
default:
return -EINVAL;
}
deb_setf("hierarchy: ");
if (ofdm->hierarchy_information == HIERARCHY_NONE) {
deb_setf("none\n");
wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_OFF);
wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP);
fe_cr = ofdm->code_rate_HP;
} else {
} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
deb_setf("on\n");
wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_ON);
wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_LP);
fe_cr = ofdm->code_rate_LP;
}
deb_setf("fec: ");
switch (fe_cr) {
case FEC_1_2:
deb_setf("1_2\n");
wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2);
break;
case FEC_2_3:
deb_setf("2_3\n");
wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_2_3);
break;
case FEC_3_4:
deb_setf("3_4\n");
wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_3_4);
break;
case FEC_5_6:
deb_setf("5_6\n");
wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_5_6);
break;
case FEC_7_8:
deb_setf("7_8\n");
wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_7_8);
break;
case FEC_NONE:
deb_setf("none ");
case FEC_AUTO:
deb_setf("auto\n");
break;
default:
return -EINVAL;
......@@ -482,7 +525,7 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
[fep->inversion == INVERSION_AUTO];
deb_info("seq? %d\n",seq);
deb_setf("seq? %d\n",seq);
wr(DIB3000MB_REG_SEQ,seq);
......@@ -522,7 +565,7 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
fe_cr == FEC_AUTO ||
fep->inversion == INVERSION_AUTO) {
deb_info("autosearch enabled.\n");
deb_setf("autosearch enabled.\n");
wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
......@@ -530,7 +573,7 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
while ((search_state = dib3000mb_fe_read_search_status(state)) < 0);
deb_info("search_state after autosearch %d\n",search_state);
return search_state ? 0 : -EINVAL;
} else {
wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
......@@ -622,14 +665,25 @@ static int dib3000mb_fe_init(struct dib3000mb_state *state,int mobile_mode)
static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat)
{
*stat = 0;
*stat |= rd(DIB3000MB_REG_AGC_LOCK) ? FE_HAS_SIGNAL : 0;
*stat |= rd(DIB3000MB_REG_CARRIER_LOCK) ? FE_HAS_CARRIER : 0;
*stat |= rd(DIB3000MB_REG_VIT_LCK) ? FE_HAS_VITERBI : 0;
*stat |= rd(DIB3000MB_REG_TS_SYNC_LOCK) ? FE_HAS_SYNC : 0;
*stat |= *stat ? FE_HAS_LOCK : 0;
if (rd(DIB3000MB_REG_AGC_LOCK))
*stat |= FE_HAS_SIGNAL;
if (rd(DIB3000MB_REG_CARRIER_LOCK))
*stat |= FE_HAS_CARRIER;
if (rd(DIB3000MB_REG_VIT_LCK))
*stat |= FE_HAS_VITERBI;
if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
deb_info("actual status is %2x\n",*stat);
deb_getf("tps %x %x %x %x %x\n",
rd(DIB3000MB_REG_TPS_1),
rd(DIB3000MB_REG_TPS_2),
rd(DIB3000MB_REG_TPS_3),
rd(DIB3000MB_REG_TPS_4),
rd(DIB3000MB_REG_TPS_5));
deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
rd(DIB3000MB_REG_TPS_LOCK),
rd(DIB3000MB_REG_TPS_QAM),
......@@ -647,15 +701,75 @@ static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat
static int dib3000mb_read_ber(struct dib3000mb_state *state,u32 *ber)
{
*ber =
(((rd(DIB3000MB_REG_BER_MSB) << 16) & 0x1f) | rd(DIB3000MB_REG_BER_LSB) ) /
100000000;
*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
return 0;
}
/*
* Amaury:
* signal strength is measured with dBm (power compared to mW)
* the standard range is -90dBm(low power) to -10 dBm (strong power),
* but the calibration is done for -100 dBm to 0dBm
*/
#define DIB3000MB_AGC_REF_dBm -14
#define DIB3000MB_GAIN_SLOPE_dBm 100
#define DIB3000MB_GAIN_DELTA_dBm -2
static int dib3000mb_read_signal_strength(struct dib3000mb_state *state, u16 *strength)
{
/* TODO log10
u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER),
n_agc_power = rd(DIB3000MB_REG_AGC_POWER),
rf_power = rd(DIB3000MB_REG_RF_POWER);
double rf_power_dBm, ad_power_dBm, minar_power_dBm;
if (n_agc_power == 0 )
n_agc_power = 1 ;
ad_power_dBm = 10 * log10 ( (float)n_agc_power / (float)(1<<16) );
minor_power_dBm = ad_power_dBm - DIB3000MB_AGC_REF_dBm;
rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) +
DIB3000MB_GAIN_DELTA_dBm) + minor_power_dBm;
// relative rf_power
*strength = (u16) ((rf_power_dBm + 100) / 100 * 0xffff);
*/
*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
return 0;
}
static int dib3000mb_signal_strength(struct dib3000mb_state *state, u16 *strength)
/*
* Amaury:
* snr is the signal quality measured in dB.
* snr = 10*log10(signal power / noise power)
* the best quality is near 35dB (cable transmission & good modulator)
* the minimum without errors depend of transmission parameters
* some indicative values are given in en300744 Annex A
* ex : 16QAM 2/3 (Gaussian) = 11.1 dB
*
* If SNR is above 20dB, BER should be always 0.
* choose 0dB as the minimum
*/
static int dib3000mb_read_snr(struct dib3000mb_state *state,u16 *snr)
{
short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
rd(DIB3000MB_REG_NOISE_POWER_LSB);
/*
float snr_dBm=0;
if (sigpow > 0 && icipow > 0)
snr_dBm = 10.0 * log10( (float) (sigpow<<8) / (float)icipow ) ;
else if (sigpow > 0)
snr_dBm = 35;
*snr = (u16) ((snr_dBm / 35) * 0xffff);
*/
*snr = (sigpow<<8) / (icipow > 0 ? icipow : 1);
return 0;
}
static int dib3000mb_read_unc_blocks(struct dib3000mb_state *state,u32 *unc)
{
// *stength = DIB3000MB_REG_SIGNAL_POWER
*unc = rd(DIB3000MB_REG_UNC);
return 0;
}
......@@ -665,63 +779,81 @@ static int dib3000mb_sleep(struct dib3000mb_state *state)
return 0;
}
static int dib3000mb_fe_get_tune_settings(struct dib3000mb_state *state,
struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 800;
tune->step_size = 166667;
tune->max_drift = 166667*2;
return 0;
}
static int dib3000mb_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
struct dib3000mb_state *state = fe->data;
int ret = 0;
switch (cmd) {
case FE_GET_INFO:
deb_info("FE_GET_INFO\n");
memcpy(arg, &dib3000mb_info, sizeof(struct dvb_frontend_info));
return 0;
break;
case FE_READ_STATUS:
deb_info("FE_READ_STATUS\n");
ret = dib3000mb_read_status(state,(fe_status_t *)arg);
return dib3000mb_read_status(state,(fe_status_t *)arg);
break;
case FE_READ_BER:
deb_info("FE_READ_BER\n");
ret = dib3000mb_read_ber(state,(u32 *)arg);
return dib3000mb_read_ber(state,(u32 *)arg);
break;
case FE_READ_SIGNAL_STRENGTH:
deb_info("FE_READ_SIG_STRENGTH\n");
ret = dib3000mb_signal_strength(state,(u16 *) arg);
return dib3000mb_read_signal_strength(state,(u16 *) arg);
break;
case FE_READ_SNR:
deb_info("FE_READ_SNR\n");
return dib3000mb_read_snr(state,(u16 *) arg);
break;
case FE_READ_UNCORRECTED_BLOCKS:
deb_info("FE_READ_UNCORRECTED_BLOCKS\n");
return dib3000mb_read_unc_blocks(state,(u32 *) arg);
break;
case FE_SET_FRONTEND:
deb_info("FE_SET_FRONTEND\n");
ret = dib3000mb_set_frontend(state,(struct dvb_frontend_parameters *) arg,1);
return dib3000mb_set_frontend(state,(struct dvb_frontend_parameters *) arg,1);
break;
case FE_GET_FRONTEND:
deb_info("FE_GET_FRONTEND\n");
ret = dib3000mb_get_frontend(state,(struct dvb_frontend_parameters *) arg);
return dib3000mb_get_frontend(state,(struct dvb_frontend_parameters *) arg);
break;
case FE_SLEEP:
deb_info("FE_SLEEP\n");
ret = dib3000mb_sleep(state);
return dib3000mb_sleep(state);
break;
case FE_INIT:
deb_info("FE_INIT\n");
ret = dib3000mb_fe_init(state,0);
return dib3000mb_fe_init(state,0);
break;
case FE_GET_TUNE_SETTINGS:
deb_info("GET_TUNE_SETTINGS");
return dib3000mb_fe_get_tune_settings(state, (struct
dvb_frontend_tune_settings *) arg);
break;
case FE_SET_TONE:
case FE_SET_VOLTAGE:
default:
ret = -EOPNOTSUPP;
return -EOPNOTSUPP;
break;
}
return 0;
......@@ -753,16 +885,20 @@ static int dib3000mb_attach_adapter(struct i2c_adapter *adapter)
i2c_set_clientdata(client,state);
state->manufactor_id = dib3000mb_read_reg(client, DIB3000MB_REG_MANUFACTOR_ID);
if (state->manufactor_id != 0x01b3) {
ret = -ENODEV;
goto probe_err;
}
state->device_id = dib3000mb_read_reg(client,DIB3000MB_REG_DEVICE_ID);
if (state->manufactor_id == 0x01b3 && state->device_id == 0x3000)
info("found a DiBCom (0x%04x) 3000-MB DVB-T frontend (ver: %x).",
state->manufactor_id, state->device_id);
else {
err("did not found a DiBCom 3000-MB.");
if (state->device_id != 0x3000) {
ret = -ENODEV;
goto probe_err;
}
info("found a DiBCom (0x%04x) 3000-MB DVB-T frontend (ver: %x).",
state->manufactor_id, state->device_id);
if ((ret = i2c_attach_client(client)))
goto i2c_attach_err;
......
......@@ -7,6 +7,7 @@
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*
*
* for more information see dib3000mb.c .
*/
......@@ -320,7 +321,7 @@ static u16 dib3000mb_bandwidth_8mhz[] =
#define DIB3000MB_REG_UNK_108 ( 108)
#define DIB3000MB_UNK_108 (0x0080)
/* fft ??? */
/* fft */
#define DIB3000MB_REG_UNK_121 ( 121)
#define DIB3000MB_UNK_121_2K ( 7)
#define DIB3000MB_UNK_121_DEFAULT ( 5)
......@@ -351,12 +352,11 @@ static u16 dib3000mb_bandwidth_8mhz[] =
#define DIB3000MB_REG_VIT_CODE_RATE ( 129)
/* forward error correction code rates */
#define DIB3000MB_FEC_1_2 ( 0)
#define DIB3000MB_FEC_2_3 ( 1)
#define DIB3000MB_FEC_3_4 ( 2)
#define DIB3000MB_FEC_4_5 ( 3)
#define DIB3000MB_FEC_5_6 ( 4)
#define DIB3000MB_FEC_7_8 ( 5)
#define DIB3000MB_FEC_1_2 ( 1)
#define DIB3000MB_FEC_2_3 ( 2)
#define DIB3000MB_FEC_3_4 ( 3)
#define DIB3000MB_FEC_5_6 ( 5)
#define DIB3000MB_FEC_7_8 ( 7)
/* vit select hp */
#define DIB3000MB_REG_VIT_HP ( 130)
......@@ -627,8 +627,8 @@ static u16 dib3000mb_filter_coeffs[] = {
/* packet error rate (uncorrected TS packets) (16) */
#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417)
/* packet error count (16) */
#define DIB3000MB_REG_PACKET_ERROR_COUNT ( 420)
/* uncorrected packet count (16) */
#define DIB3000MB_REG_UNC ( 420)
/* viterbi locked (1) */
#define DIB3000MB_REG_VIT_LCK ( 421)
......
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