summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c')
-rw-r--r--linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c
new file mode 100644
index 000000000..9cbfede7d
--- /dev/null
+++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c
@@ -0,0 +1,462 @@
+/*
+ * Driver for mobile USB Budget DVB-T devices based on reference
+ * design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * dvb-dibusb-core.c
+ *
+ * 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
+ * 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 dib3000mb/mc/p frontends) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/moduleparam.h>
+
+/* debug */
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able)).");
+#endif
+
+int pid_parse;
+module_param(pid_parse, int, 0x644);
+MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
+
+int rc_query_interval;
+module_param(rc_query_interval, int, 0x644);
+MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+static const char * dibusb_fw_filenames1_1[] = {
+ "dvb-dibusb-5.0.0.11.fw"
+};
+
+static const char * dibusb_fw_filenames1_1_an2235[] = {
+ "dvb-dibusb-an2235-1.fw"
+};
+
+static const char * dibusb_fw_filenames2_0[] = {
+ "dvb-dibusb-6.0.0.5.fw"
+};
+
+int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
+ dvb_frontend_parameters *params);
+
+int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
+ dvb_frontend_parameters* params);
+
+static struct dibusb_device_parameter dibusb_dev_parm[3] = {
+ { .type = DIBUSB1_1,
+ .fw_filenames = dibusb_fw_filenames1_1,
+ .usb_controller = "Cypress AN2135",
+ .usb_cpu_csreg = 0x7f92,
+
+ .num_urbs = 3,
+ .urb_buf_size = 4096,
+ .default_size = 188*21,
+ .firmware_bug = 1,
+
+ .cmd_pipe = 0x01,
+ .result_pipe = 0x01,
+ .data_pipe = 0x02,
+
+ .pll_set = thomson_cable_eu_pll_set,
+ .pll_addr = 194,
+ .demod_i2c_addrs = { 0x10, 0, 0, 0 },
+ },
+ { .type = DIBUSB2_0,
+ .fw_filenames = dibusb_fw_filenames2_0,
+ .usb_controller = "Cypress FX2",
+ .usb_cpu_csreg = 0xe600,
+
+ .num_urbs = 3,
+ .urb_buf_size = 40960,
+ .default_size = 188*210,
+ .firmware_bug = 0,
+
+ .cmd_pipe = 0x01,
+ .result_pipe = 0x01,
+ .data_pipe = 0x06,
+
+ .pll_set = panasonic_cofdm_env57h1xd5_pll_set,
+ .pll_addr = 192,
+ .demod_i2c_addrs = { 0x12, 0x14, 0x16, 0x18 },
+ },
+ { .type = DIBUSB1_1_AN2235,
+ .fw_filenames = dibusb_fw_filenames1_1_an2235,
+ .usb_controller = "Cypress CY7C64613 (AN2235)",
+ .usb_cpu_csreg = 0x7f92,
+
+ .num_urbs = 3,
+ .urb_buf_size = 4096,
+ .default_size = 188*21,
+ .firmware_bug = 1,
+
+ .cmd_pipe = 0x01,
+ .result_pipe = 0x01,
+ .data_pipe = 0x02,
+
+ .pll_set = thomson_cable_eu_pll_set,
+ .pll_addr = 194,
+ .demod_i2c_addrs = { 0x10, 0, 0, 0 },
+ }
+};
+
+/* Vendor IDs */
+#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
+#define USB_VID_HYPER_PALTEK 0x1025
+#define USB_VID_IMC_NETWORKS 0x13d3
+#define USB_VID_TWINHAN 0x1822
+#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+
+/* Product IDs */
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
+#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
+#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
+#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+#define USB_PID_TWINHAN_VP7041_COLD 0x3201
+#define USB_PID_TWINHAN_VP7041_WARM 0x3202
+#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
+#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 16
+
+/* USB Driver stuff */
+static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
+ { .name = "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
+ .cold_product_id = USB_PID_TWINHAN_VP7041_COLD,
+ .warm_product_id = USB_PID_TWINHAN_VP7041_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+ .cold_product_id = USB_PID_KWORLD_VSTREAM_COLD,
+ .warm_product_id = USB_PID_KWORLD_VSTREAM_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "Grandtec USB1.1 DVB-T/DiBcom USB1.1 DVB-T reference design (MOD3000)",
+ .cold_product_id = USB_PID_DIBCOM_MOD3000_COLD,
+ .warm_product_id = USB_PID_DIBCOM_MOD3000_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
+ .cold_product_id = USB_PID_DIBCOM_ANCHOR_2135_COLD,
+ .warm_product_id = 0, /* undefined, let's see what comes out */
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "Artec T1 USB1.1 TVBOX with AN2135",
+ .cold_product_id = USB_PID_ULTIMA_TVBOX_COLD,
+ .warm_product_id = USB_PID_ULTIMA_TVBOX_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "Artec T1 USB1.1 TVBOX with AN2235",
+ .cold_product_id = USB_PID_ULTIMA_TVBOX_AN2235_COLD,
+ .warm_product_id = USB_PID_ULTIMA_TVBOX_AN2235_WARM,
+ .parm = &dibusb_dev_parm[2],
+ },
+ { .name = "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
+ .cold_product_id = USB_PID_ULTIMA_TVBOX_ANCHOR_COLD,
+ .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,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+ .cold_product_id = USB_PID_DIBCOM_MOD3001_COLD,
+ .warm_product_id = USB_PID_DIBCOM_MOD3001_WARM,
+ .parm = &dibusb_dev_parm[1],
+ },
+ { .name = "Grandtec DVB-T USB1.1",
+ .cold_product_id = USB_PID_GRANDTEC_DVBT_USB_COLD,
+ .warm_product_id = USB_PID_GRANDTEC_DVBT_USB_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "Avermedia AverTV DVBT USB1.1",
+ .cold_product_id = USB_PID_AVERMEDIA_DVBT_USB_COLD,
+ .warm_product_id = USB_PID_AVERMEDIA_DVBT_USB_WARM,
+ .parm = &dibusb_dev_parm[0],
+ },
+ { .name = "Yakumo/Typhoon DVB-T mobile USB2.0",
+ .cold_product_id = USB_PID_YAKUMO_DTT200U_COLD,
+ .warm_product_id = USB_PID_YAKUMO_DTT200U_WARM,
+ .parm = &dibusb_dev_parm[1],
+ }
+};
+
+/* USB Driver stuff */
+/* table of devices that this driver is working with */
+static struct usb_device_id dibusb_table [] = {
+ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
+ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
+ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
+ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
+ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
+ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
+ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
+ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
+ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
+ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_COLD) },
+ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_WARM) },
+ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
+ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
+ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+ { 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 one of the devices and want to
+ * build it from build-2.6 in dvb-kernel
+ */
+// #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) },
+ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) },
+#endif
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dibusb_table);
+
+static int dibusb_exit(struct usb_dibusb *dib)
+{
+ dibusb_remote_exit(dib);
+ dibusb_fe_exit(dib);
+ dibusb_i2c_exit(dib);
+ dibusb_dvb_exit(dib);
+ dibusb_usb_exit(dib);
+ kfree(dib);
+ return 0;
+}
+
+static int dibusb_init(struct usb_dibusb *dib)
+{
+ int ret = 0;
+ sema_init(&dib->usb_sem, 1);
+ sema_init(&dib->i2c_sem, 1);
+
+ if ((ret = dibusb_usb_init(dib)) ||
+ (ret = dibusb_dvb_init(dib)) ||
+ (ret = dibusb_i2c_init(dib))) {
+ dibusb_exit(dib);
+ return ret;
+ }
+
+ dibusb_hw_wakeup(dib);
+ dibusb_set_streaming_mode(dib,0);
+ dibusb_streaming(dib,1);
+
+ if ((ret = dibusb_fe_init(dib)))
+ err("could not initialize a frontend.");
+
+ if ((ret = dibusb_remote_init(dib)))
+ err("could not initialize remote control.");
+
+ return 0;
+}
+
+/*
+ * USB
+ */
+static int dibusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_dibusb *dib = NULL;
+ struct dibusb_device *dibdev = NULL;
+
+ int ret = -ENOMEM,i,cold=0;
+
+ for (i = 0; i < DIBUSB_SUPPORTED_DEVICES; i++)
+ if (dibusb_devices[i].cold_product_id == udev->descriptor.idProduct ||
+ dibusb_devices[i].warm_product_id == udev->descriptor.idProduct) {
+ dibdev = &dibusb_devices[i];
+
+ cold = dibdev->cold_product_id == udev->descriptor.idProduct;
+
+ if (cold)
+ info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
+ else
+ info("found a '%s' in warm state.",dibdev->name);
+ }
+
+ if (dibdev == NULL) {
+ err("something went very wrong, "
+ "unknown product ID: %.4x",udev->descriptor.idProduct);
+ return -ENODEV;
+ }
+
+ 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 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->udev = udev;
+ dib->dibdev = dibdev;
+
+ usb_set_intfdata(intf, dib);
+
+ ret = dibusb_init(dib);
+ }
+
+ if (ret == 0)
+ info("%s successfully initialized and connected.",dibdev->name);
+ else
+ info("%s error while loading driver (%d)",dibdev->name,ret);
+ return ret;
+}
+
+static void dibusb_disconnect(struct usb_interface *intf)
+{
+ struct usb_dibusb *dib = usb_get_intfdata(intf);
+ const char *name = DRIVER_DESC;
+
+ usb_set_intfdata(intf,NULL);
+ if (dib != NULL && dib->dibdev != NULL) {
+ name = dib->dibdev->name;
+ dibusb_exit(dib);
+ }
+ info("%s successfully deinitialized and disconnected.",name);
+
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dibusb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_dibusb",
+ .probe = dibusb_probe,
+ .disconnect = dibusb_disconnect,
+ .id_table = dibusb_table,
+};
+
+/* module stuff */
+static int __init usb_dibusb_init(void)
+{
+ int result;
+ if ((result = usb_register(&dibusb_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit usb_dibusb_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dibusb_driver);
+}
+
+module_init (usb_dibusb_init);
+module_exit (usb_dibusb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");