summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/dvb-usb/digitv.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb/dvb-usb/digitv.c')
-rw-r--r--linux/drivers/media/dvb/dvb-usb/digitv.c238
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");