diff options
Diffstat (limited to 'linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c')
-rw-r--r-- | linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c | 462 |
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"); |