diff options
Diffstat (limited to 'linux/drivers/media/dvb/dvb-usb/digitv.c')
-rw-r--r-- | linux/drivers/media/dvb/dvb-usb/digitv.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/dvb-usb/digitv.c b/linux/drivers/media/dvb/dvb-usb/digitv.c new file mode 100644 index 000000000..1375446d5 --- /dev/null +++ b/linux/drivers/media/dvb/dvb-usb/digitv.c @@ -0,0 +1,238 @@ +/* DVB USB compliant linux driver for Nebula Electronics µDigiTV DVB-T USB2.0 + * receiver + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and + * Allan Third (allan.third@cs.man.ac.uk) + * + * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?) + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dvb-usb.h" + +#include "mt352.h" + +/* protocol: this is what I read of the USB log: + * + * Always 7 bytes control message(s), + * + * First byte at describes the command. Reads are 2 consecutive transfer (as always). + * + * I2C address is stored somewhere inside the device. + * + * 0x02 i2c reading (2 messages) + * 1st msg <reg> <len> + * 2nd msg <reg> <len> <value> + * + * 0x05 i2c writing + * <reg> <len> <value> + * len = 1 for the mt352 + * + * Others: + * + * 0x03 remote control query (read 4 bytes) + * 1st msg: 0x00 0x04 + * 2nd msg: 0x00 0x04 4 bytes key (probably NEC protocol) + * + * 0x08 stream control ? + * 0x00 0x04 0x01 + * + * 0x07 unkown (maybe pid filter?) + */ + + +/* I2C */ +static int digitv_i2c_msg(struct dvb_usb_device *d,u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 sndbuf[7],rcvbuf[7]; /* <cmd> <reg> <len> <val[4]> */ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + + memset(sndbuf,0,7); memset(rcvbuf,0,7); + + sndbuf[0] = wo ? 0x05 : 0x03; + sndbuf[1] = wbuf[0]; /* register */ + sndbuf[2] = wo ? wlen-1 : rlen; + + if (wo) + memcpy(&sndbuf[3],&wbuf[1],wlen-1); + + dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7); + + if (!wo) + memcpy(rbuf,&rcvbuf[3],rlen); + + return 0; +} + +static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (down_interruptible(&d->i2c_sem) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (digitv_i2c_msg(d, msg[i].buf, msg[i].len, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else + if (digitv_i2c_msg(d, msg[i].buf,msg[i].len,NULL,0) < 0) + break; + } + + up(&d->i2c_sem); + return i; +} + +static u32 digitv_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm digitv_i2c_algo = { + .name = "Nebula DigiTV USB I2C algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = digitv_i2c_xfer, + .functionality = digitv_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int probe_count; +static int digitv_identify_state (struct usb_device *udev, struct + dvb_usb_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + + /* here we have to determine if the device is in cold state (pre firmware + * load) or in warm state therefore compare the 'lsusb -v' of each state. + * Most likely the number of endpoints or interfaces can be used to figure + * the real state out. + * For now we assume each odd call of this function (when the device is + * plugged in or virtually plugged in after the firmware load) is warm + * state and each even call is cold probe_count is set to 0 at module load. + */ + + *cold = (probe_count % 2) == 0; + probe_count++; + return 0; +} + +static int digitv_frontend_attach(struct dvb_usb_device *d) +{ + struct mt352_config digitv_config; + + memset(&digitv_config,0,sizeof(struct mt352_config)); + digitv_config.demod_init = NULL; /* TODO maybe */ + digitv_config.demod_address = 0x0; /* ignore by the digitv anyway */ + digitv_config.pll_set = NULL; /* TODO */ + + d->fe = mt352_attach(&digitv_config, &d->i2c_adap); + return 0; +} + + +/* DVB USB Driver stuff */ +static struct dvb_usb_properties digitv_properties; + +static int digitv_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE); +} + +static struct usb_device_id digitv_table [] = { + { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, digitv_table); + +static struct dvb_usb_properties digitv_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-digitv-01.fw", + + .size_of_priv = 0, + + .streaming_ctrl = NULL, // digitv_streaming_ctrl, + .pid_filter = NULL, + .pid_filter_ctrl = NULL, + .power_ctrl = NULL, // digitv_power_ctrl, + .frontend_attach = digitv_frontend_attach, + .tuner_attach = NULL, // digitv_tuner_attach, + .read_mac_address = NULL, + + .rc_interval = 0, // 150, + .init_rc = NULL, // digitv_rc_init, + .query_rc = NULL, // digitv_rc_query, + + .identify_state = digitv_identify_state, + + .i2c_algo = &digitv_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 2, + .devices = { + { "Nebula Electronics µDigiTV DVB-T USB2.0)", + { &digitv_table[0], NULL }, + { NULL }, + }, + } +}; + +static struct usb_driver digitv_driver = { + .owner = THIS_MODULE, + .name = "Nebula Electronics µDigiTV DVB-T USB2.0 device", + .probe = digitv_probe, + .disconnect = dvb_usb_device_exit, + .id_table = digitv_table, +}; + +/* module stuff */ +static int __init digitv_module_init(void) +{ + int result; + if ((result = usb_register(&digitv_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit digitv_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&digitv_driver); +} + +module_init (digitv_module_init); +module_exit (digitv_module_exit); + +MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); +MODULE_DESCRIPTION("Driver for Nebula Electronics µDigiTV DVB-T USB2.0"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); |