/* * 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 /* 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");