1/* DVB USB compliant linux driver for mobile DVB-T USB devices based on 2 * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) 3 * 4 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) 5 * 6 * based on GPL code from DiBcom, which has 7 * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation, version 2. 12 * 13 * see Documentation/dvb/README.dvb-usb for more information 14 */ 15#include "dibusb.h" 16 17DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 18 19static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 20{ 21 struct dvb_usb_adapter *adap = fe->dvb->priv; 22 struct dibusb_state *st = adap->priv; 23 24 return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); 25} 26 27static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) 28{ 29 struct dib3000_config demod_cfg; 30 struct dibusb_state *st = adap->priv; 31 32 demod_cfg.demod_address = 0x8; 33 34 adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, 35 &adap->dev->i2c_adap, &st->ops); 36 if ((adap->fe_adap[0].fe) == NULL) 37 return -ENODEV; 38 39 adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; 40 41 return 0; 42} 43 44static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) 45{ 46 struct dibusb_state *st = adap->priv; 47 48 st->tuner_addr = 0x61; 49 50 dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, 51 DVB_PLL_TUA6010XS); 52 return 0; 53} 54 55static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) 56{ 57 struct dibusb_state *st = adap->priv; 58 59 st->tuner_addr = 0x60; 60 61 dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 62 DVB_PLL_TDA665X); 63 return 0; 64} 65 66/* Some of the Artec 1.1 device aren't equipped with the default tuner 67 * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures 68 * this out. */ 69static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) 70{ 71 u8 b[2] = { 0,0 }, b2[1]; 72 int ret = 0; 73 struct i2c_msg msg[2] = { 74 { .flags = 0, .buf = b, .len = 2 }, 75 { .flags = I2C_M_RD, .buf = b2, .len = 1 }, 76 }; 77 struct dibusb_state *st = adap->priv; 78 79 /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ 80 msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; 81 82 if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) 83 adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); 84 85 if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { 86 err("tuner i2c write failed."); 87 ret = -EREMOTEIO; 88 } 89 90 if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) 91 adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); 92 93 if (b2[0] == 0xfe) { 94 info("This device has the Thomson Cable onboard. Which is default."); 95 ret = dibusb_thomson_tuner_attach(adap); 96 } else { 97 info("This device has the Panasonic ENV77H11D5 onboard."); 98 ret = dibusb_panasonic_tuner_attach(adap); 99 } 100 101 return ret; 102} 103 104/* USB Driver stuff */ 105static struct dvb_usb_device_properties dibusb1_1_properties; 106static struct dvb_usb_device_properties dibusb1_1_an2235_properties; 107static struct dvb_usb_device_properties dibusb2_0b_properties; 108static struct dvb_usb_device_properties artec_t1_usb2_properties; 109 110static int dibusb_probe(struct usb_interface *intf, 111 const struct usb_device_id *id) 112{ 113 if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties, 114 THIS_MODULE, NULL, adapter_nr) || 115 0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties, 116 THIS_MODULE, NULL, adapter_nr) || 117 0 == dvb_usb_device_init(intf, &dibusb2_0b_properties, 118 THIS_MODULE, NULL, adapter_nr) || 119 0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties, 120 THIS_MODULE, NULL, adapter_nr)) 121 return 0; 122 123 return -EINVAL; 124} 125 126/* do not change the order of the ID table */ 127static struct usb_device_id dibusb_dib3000mb_table [] = { 128/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, 129/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, 130/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, 131/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, 132/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, 133/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, 134/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, 135/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, 136/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, 137/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, 138/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, 139/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, 140/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, 141/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, 142/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, 143/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, 144/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, 145/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, 146/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, 147/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, 148/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, 149/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, 150/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, 151/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, 152 153/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ 154/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, 155/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, 156/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, 157 158/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, 159 160/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, 161/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, 162 163/* 164 * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices 165 * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that 166 * have been left on the device. If you don't have such a device but an Artec 167 * device that's supposed to work with this driver but is not detected by it, 168 * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. 169 */ 170 171#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY 172/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, 173#endif 174 175 { } /* Terminating entry */ 176}; 177MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); 178 179static struct dvb_usb_device_properties dibusb1_1_properties = { 180 .caps = DVB_USB_IS_AN_I2C_ADAPTER, 181 182 .usb_ctrl = CYPRESS_AN2135, 183 184 .firmware = "dvb-usb-dibusb-5.0.0.11.fw", 185 186 .num_adapters = 1, 187 .adapter = { 188 { 189 .num_frontends = 1, 190 .fe = {{ 191 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 192 .pid_filter_count = 16, 193 194 .streaming_ctrl = dibusb_streaming_ctrl, 195 .pid_filter = dibusb_pid_filter, 196 .pid_filter_ctrl = dibusb_pid_filter_ctrl, 197 .frontend_attach = dibusb_dib3000mb_frontend_attach, 198 .tuner_attach = dibusb_tuner_probe_and_attach, 199 200 /* parameter for the MPEG2-data transfer */ 201 .stream = { 202 .type = USB_BULK, 203 .count = 7, 204 .endpoint = 0x02, 205 .u = { 206 .bulk = { 207 .buffersize = 4096, 208 } 209 } 210 }, 211 }}, 212 .size_of_priv = sizeof(struct dibusb_state), 213 } 214 }, 215 216 .power_ctrl = dibusb_power_ctrl, 217 218 .rc.legacy = { 219 .rc_interval = DEFAULT_RC_INTERVAL, 220 .rc_map_table = rc_map_dibusb_table, 221 .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ 222 .rc_query = dibusb_rc_query, 223 }, 224 225 .i2c_algo = &dibusb_i2c_algo, 226 227 .generic_bulk_ctrl_endpoint = 0x01, 228 229 .num_device_descs = 9, 230 .devices = { 231 { "AVerMedia AverTV DVBT USB1.1", 232 { &dibusb_dib3000mb_table[0], NULL }, 233 { &dibusb_dib3000mb_table[1], NULL }, 234 }, 235 { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", 236 { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, 237 { &dibusb_dib3000mb_table[3], NULL }, 238 }, 239 { "DiBcom USB1.1 DVB-T reference design (MOD3000)", 240 { &dibusb_dib3000mb_table[5], NULL }, 241 { &dibusb_dib3000mb_table[6], NULL }, 242 }, 243 { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", 244 { &dibusb_dib3000mb_table[7], NULL }, 245 { &dibusb_dib3000mb_table[8], NULL }, 246 }, 247 { "Grandtec USB1.1 DVB-T", 248 { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, 249 { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, 250 }, 251 { "Unknown USB1.1 DVB-T device ???? please report the name to the author", 252 { &dibusb_dib3000mb_table[13], NULL }, 253 { &dibusb_dib3000mb_table[14], NULL }, 254 }, 255 { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", 256 { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, 257 { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, 258 }, 259 { "Artec T1 USB1.1 TVBOX with AN2135", 260 { &dibusb_dib3000mb_table[19], NULL }, 261 { &dibusb_dib3000mb_table[20], NULL }, 262 }, 263 { "VideoWalker DVB-T USB", 264 { &dibusb_dib3000mb_table[25], NULL }, 265 { &dibusb_dib3000mb_table[26], NULL }, 266 }, 267 } 268}; 269 270static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { 271 .caps = DVB_USB_IS_AN_I2C_ADAPTER, 272 .usb_ctrl = CYPRESS_AN2235, 273 274 .firmware = "dvb-usb-dibusb-an2235-01.fw", 275 276 .num_adapters = 1, 277 .adapter = { 278 { 279 .num_frontends = 1, 280 .fe = {{ 281 .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, 282 .pid_filter_count = 16, 283 284 .streaming_ctrl = dibusb_streaming_ctrl, 285 .pid_filter = dibusb_pid_filter, 286 .pid_filter_ctrl = dibusb_pid_filter_ctrl, 287 .frontend_attach = dibusb_dib3000mb_frontend_attach, 288 .tuner_attach = dibusb_tuner_probe_and_attach, 289 290 /* parameter for the MPEG2-data transfer */ 291 .stream = { 292 .type = USB_BULK, 293 .count = 7, 294 .endpoint = 0x02, 295 .u = { 296 .bulk = { 297 .buffersize = 4096, 298 } 299 } 300 }, 301 }}, 302 .size_of_priv = sizeof(struct dibusb_state), 303 }, 304 }, 305 .power_ctrl = dibusb_power_ctrl, 306 307 .rc.legacy = { 308 .rc_interval = DEFAULT_RC_INTERVAL, 309 .rc_map_table = rc_map_dibusb_table, 310 .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ 311 .rc_query = dibusb_rc_query, 312 }, 313 314 .i2c_algo = &dibusb_i2c_algo, 315 316 .generic_bulk_ctrl_endpoint = 0x01, 317 318#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY 319 .num_device_descs = 2, 320#else 321 .num_device_descs = 1, 322#endif 323 .devices = { 324 { "Artec T1 USB1.1 TVBOX with AN2235", 325 { &dibusb_dib3000mb_table[21], NULL }, 326 { &dibusb_dib3000mb_table[22], NULL }, 327 }, 328#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY 329 { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", 330 { &dibusb_dib3000mb_table[30], NULL }, 331 { NULL }, 332 }, 333 { NULL }, 334#endif 335 } 336}; 337 338static struct dvb_usb_device_properties dibusb2_0b_properties = { 339 .caps = DVB_USB_IS_AN_I2C_ADAPTER, 340 341 .usb_ctrl = CYPRESS_FX2, 342 343 .firmware = "dvb-usb-adstech-usb2-02.fw", 344 345 .num_adapters = 1, 346 .adapter = { 347 { 348 .num_frontends = 1, 349 .fe = {{ 350 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 351 .pid_filter_count = 16, 352 353 .streaming_ctrl = dibusb2_0_streaming_ctrl, 354 .pid_filter = dibusb_pid_filter, 355 .pid_filter_ctrl = dibusb_pid_filter_ctrl, 356 .frontend_attach = dibusb_dib3000mb_frontend_attach, 357 .tuner_attach = dibusb_thomson_tuner_attach, 358 359 /* parameter for the MPEG2-data transfer */ 360 .stream = { 361 .type = USB_BULK, 362 .count = 7, 363 .endpoint = 0x06, 364 .u = { 365 .bulk = { 366 .buffersize = 4096, 367 } 368 } 369 }, 370 }}, 371 .size_of_priv = sizeof(struct dibusb_state), 372 } 373 }, 374 .power_ctrl = dibusb2_0_power_ctrl, 375 376 .rc.legacy = { 377 .rc_interval = DEFAULT_RC_INTERVAL, 378 .rc_map_table = rc_map_dibusb_table, 379 .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ 380 .rc_query = dibusb_rc_query, 381 }, 382 383 .i2c_algo = &dibusb_i2c_algo, 384 385 .generic_bulk_ctrl_endpoint = 0x01, 386 387 .num_device_descs = 2, 388 .devices = { 389 { "KWorld/ADSTech Instant DVB-T USB2.0", 390 { &dibusb_dib3000mb_table[23], NULL }, 391 { &dibusb_dib3000mb_table[24], NULL }, 392 }, 393 { "KWorld Xpert DVB-T USB2.0", 394 { &dibusb_dib3000mb_table[27], NULL }, 395 { NULL } 396 }, 397 { NULL }, 398 } 399}; 400 401static struct dvb_usb_device_properties artec_t1_usb2_properties = { 402 .caps = DVB_USB_IS_AN_I2C_ADAPTER, 403 404 .usb_ctrl = CYPRESS_FX2, 405 406 .firmware = "dvb-usb-dibusb-6.0.0.8.fw", 407 408 .num_adapters = 1, 409 .adapter = { 410 { 411 .num_frontends = 1, 412 .fe = {{ 413 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 414 .pid_filter_count = 16, 415 416 .streaming_ctrl = dibusb2_0_streaming_ctrl, 417 .pid_filter = dibusb_pid_filter, 418 .pid_filter_ctrl = dibusb_pid_filter_ctrl, 419 .frontend_attach = dibusb_dib3000mb_frontend_attach, 420 .tuner_attach = dibusb_tuner_probe_and_attach, 421 /* parameter for the MPEG2-data transfer */ 422 .stream = { 423 .type = USB_BULK, 424 .count = 7, 425 .endpoint = 0x06, 426 .u = { 427 .bulk = { 428 .buffersize = 4096, 429 } 430 } 431 }, 432 }}, 433 .size_of_priv = sizeof(struct dibusb_state), 434 } 435 }, 436 .power_ctrl = dibusb2_0_power_ctrl, 437 438 .rc.legacy = { 439 .rc_interval = DEFAULT_RC_INTERVAL, 440 .rc_map_table = rc_map_dibusb_table, 441 .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ 442 .rc_query = dibusb_rc_query, 443 }, 444 445 .i2c_algo = &dibusb_i2c_algo, 446 447 .generic_bulk_ctrl_endpoint = 0x01, 448 449 .num_device_descs = 1, 450 .devices = { 451 { "Artec T1 USB2.0", 452 { &dibusb_dib3000mb_table[28], NULL }, 453 { &dibusb_dib3000mb_table[29], NULL }, 454 }, 455 { NULL }, 456 } 457}; 458 459static struct usb_driver dibusb_driver = { 460 .name = "dvb_usb_dibusb_mb", 461 .probe = dibusb_probe, 462 .disconnect = dvb_usb_device_exit, 463 .id_table = dibusb_dib3000mb_table, 464}; 465 466module_usb_driver(dibusb_driver); 467 468MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); 469MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); 470MODULE_VERSION("1.0"); 471MODULE_LICENSE("GPL"); 472