1/* 2 tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices 3 4 Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation version 2 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20#include <linux/init.h> 21#include <linux/module.h> 22#include <linux/pci.h> 23#include <linux/delay.h> 24#include <linux/i2c.h> 25#include <linux/usb.h> 26#include <linux/version.h> 27#include <linux/slab.h> 28#include <media/v4l2-common.h> 29#include <media/tuner.h> 30#include <media/tvaudio.h> 31#include <media/i2c-addr.h> 32#include <media/rc-map.h> 33 34#include "tm6000.h" 35#include "tm6000-regs.h" 36#include "tuner-xc2028.h" 37#include "xc5000.h" 38 39#define TM6000_BOARD_UNKNOWN 0 40#define TM5600_BOARD_GENERIC 1 41#define TM6000_BOARD_GENERIC 2 42#define TM6010_BOARD_GENERIC 3 43#define TM5600_BOARD_10MOONS_UT821 4 44#define TM5600_BOARD_10MOONS_UT330 5 45#define TM6000_BOARD_ADSTECH_DUAL_TV 6 46#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 47#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 48#define TM6010_BOARD_HAUPPAUGE_900H 9 49#define TM6010_BOARD_BEHOLD_WANDER 10 50#define TM6010_BOARD_BEHOLD_VOYAGER 11 51#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 52#define TM6010_BOARD_TWINHAN_TU501 13 53 54#define TM6000_MAXBOARDS 16 55static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; 56 57module_param_array(card, int, NULL, 0444); 58 59static unsigned long tm6000_devused; 60 61 62struct tm6000_board { 63 char *name; 64 65 struct tm6000_capabilities caps; 66 67 enum tm6000_devtype type; /* variant of the chipset */ 68 int tuner_type; /* type of the tuner */ 69 int tuner_addr; /* tuner address */ 70 int demod_addr; /* demodulator address */ 71 72 struct tm6000_gpio gpio; 73 74 char *ir_codes; 75}; 76 77struct tm6000_board tm6000_boards[] = { 78 [TM6000_BOARD_UNKNOWN] = { 79 .name = "Unknown tm6000 video grabber", 80 .caps = { 81 .has_tuner = 1, 82 }, 83 .gpio = { 84 .tuner_reset = TM6000_GPIO_1, 85 }, 86 }, 87 [TM5600_BOARD_GENERIC] = { 88 .name = "Generic tm5600 board", 89 .type = TM5600, 90 .tuner_type = TUNER_XC2028, 91 .tuner_addr = 0xc2 >> 1, 92 .caps = { 93 .has_tuner = 1, 94 }, 95 .gpio = { 96 .tuner_reset = TM6000_GPIO_1, 97 }, 98 }, 99 [TM6000_BOARD_GENERIC] = { 100 .name = "Generic tm6000 board", 101 .tuner_type = TUNER_XC2028, 102 .tuner_addr = 0xc2 >> 1, 103 .caps = { 104 .has_tuner = 1, 105 .has_dvb = 1, 106 }, 107 .gpio = { 108 .tuner_reset = TM6000_GPIO_1, 109 }, 110 }, 111 [TM6010_BOARD_GENERIC] = { 112 .name = "Generic tm6010 board", 113 .type = TM6010, 114 .tuner_type = TUNER_XC2028, 115 .tuner_addr = 0xc2 >> 1, 116 .demod_addr = 0x1e >> 1, 117 .caps = { 118 .has_tuner = 1, 119 .has_dvb = 1, 120 .has_zl10353 = 1, 121 .has_eeprom = 1, 122 .has_remote = 1, 123 }, 124 .gpio = { 125 .tuner_reset = TM6010_GPIO_2, 126 .tuner_on = TM6010_GPIO_3, 127 .demod_reset = TM6010_GPIO_1, 128 .demod_on = TM6010_GPIO_4, 129 .power_led = TM6010_GPIO_7, 130 .dvb_led = TM6010_GPIO_5, 131 .ir = TM6010_GPIO_0, 132 }, 133 }, 134 [TM5600_BOARD_10MOONS_UT821] = { 135 .name = "10Moons UT 821", 136 .tuner_type = TUNER_XC2028, 137 .type = TM5600, 138 .tuner_addr = 0xc2 >> 1, 139 .caps = { 140 .has_tuner = 1, 141 .has_eeprom = 1, 142 }, 143 .gpio = { 144 .tuner_reset = TM6000_GPIO_1, 145 }, 146 }, 147 [TM5600_BOARD_10MOONS_UT330] = { 148 .name = "10Moons UT 330", 149 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, 150 .tuner_addr = 0xc8 >> 1, 151 .caps = { 152 .has_tuner = 1, 153 .has_dvb = 0, 154 .has_zl10353 = 0, 155 .has_eeprom = 1, 156 }, 157 }, 158 [TM6000_BOARD_ADSTECH_DUAL_TV] = { 159 .name = "ADSTECH Dual TV USB", 160 .tuner_type = TUNER_XC2028, 161 .tuner_addr = 0xc8 >> 1, 162 .caps = { 163 .has_tuner = 1, 164 .has_tda9874 = 1, 165 .has_dvb = 1, 166 .has_zl10353 = 1, 167 .has_eeprom = 1, 168 }, 169 }, 170 [TM6000_BOARD_FREECOM_AND_SIMILAR] = { 171 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", 172 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 173 .tuner_addr = 0xc2 >> 1, 174 .demod_addr = 0x1e >> 1, 175 .caps = { 176 .has_tuner = 1, 177 .has_dvb = 1, 178 .has_zl10353 = 1, 179 .has_eeprom = 0, 180 .has_remote = 1, 181 }, 182 .gpio = { 183 .tuner_reset = TM6000_GPIO_4, 184 }, 185 }, 186 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { 187 .name = "ADSTECH Mini Dual TV USB", 188 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 189 .tuner_addr = 0xc8 >> 1, 190 .demod_addr = 0x1e >> 1, 191 .caps = { 192 .has_tuner = 1, 193 .has_dvb = 1, 194 .has_zl10353 = 1, 195 .has_eeprom = 0, 196 }, 197 .gpio = { 198 .tuner_reset = TM6000_GPIO_4, 199 }, 200 }, 201 [TM6010_BOARD_HAUPPAUGE_900H] = { 202 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", 203 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 204 .tuner_addr = 0xc2 >> 1, 205 .demod_addr = 0x1e >> 1, 206 .type = TM6010, 207 .caps = { 208 .has_tuner = 1, 209 .has_dvb = 1, 210 .has_zl10353 = 1, 211 .has_eeprom = 1, 212 .has_remote = 1, 213 }, 214 .gpio = { 215 .tuner_reset = TM6010_GPIO_2, 216 .tuner_on = TM6010_GPIO_3, 217 .demod_reset = TM6010_GPIO_1, 218 .demod_on = TM6010_GPIO_4, 219 .power_led = TM6010_GPIO_7, 220 .dvb_led = TM6010_GPIO_5, 221 .ir = TM6010_GPIO_0, 222 }, 223 }, 224 [TM6010_BOARD_BEHOLD_WANDER] = { 225 .name = "Beholder Wander DVB-T/TV/FM USB2.0", 226 .tuner_type = TUNER_XC5000, 227 .tuner_addr = 0xc2 >> 1, 228 .demod_addr = 0x1e >> 1, 229 .type = TM6010, 230 .caps = { 231 .has_tuner = 1, 232 .has_dvb = 1, 233 .has_zl10353 = 1, 234 .has_eeprom = 1, 235 .has_remote = 1, 236 }, 237 .gpio = { 238 .tuner_reset = TM6010_GPIO_0, 239 .demod_reset = TM6010_GPIO_1, 240 .power_led = TM6010_GPIO_6, 241 }, 242 }, 243 [TM6010_BOARD_BEHOLD_VOYAGER] = { 244 .name = "Beholder Voyager TV/FM USB2.0", 245 .tuner_type = TUNER_XC5000, 246 .tuner_addr = 0xc2 >> 1, 247 .type = TM6010, 248 .caps = { 249 .has_tuner = 1, 250 .has_dvb = 0, 251 .has_zl10353 = 0, 252 .has_eeprom = 1, 253 .has_remote = 1, 254 }, 255 .gpio = { 256 .tuner_reset = TM6010_GPIO_0, 257 .power_led = TM6010_GPIO_6, 258 }, 259 }, 260 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { 261 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", 262 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 263 .tuner_addr = 0xc2 >> 1, 264 .demod_addr = 0x1e >> 1, 265 .type = TM6010, 266 .caps = { 267 .has_tuner = 1, 268 .has_dvb = 1, 269 .has_zl10353 = 1, 270 .has_eeprom = 1, 271 .has_remote = 1, 272 }, 273 .gpio = { 274 .tuner_reset = TM6010_GPIO_2, 275 .tuner_on = TM6010_GPIO_3, 276 .demod_reset = TM6010_GPIO_1, 277 .demod_on = TM6010_GPIO_4, 278 .power_led = TM6010_GPIO_7, 279 .dvb_led = TM6010_GPIO_5, 280 .ir = TM6010_GPIO_0, 281 }, 282 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, 283 }, 284 [TM6010_BOARD_TWINHAN_TU501] = { 285 .name = "Twinhan TU501(704D1)", 286 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 287 .tuner_addr = 0xc2 >> 1, 288 .demod_addr = 0x1e >> 1, 289 .type = TM6010, 290 .caps = { 291 .has_tuner = 1, 292 .has_dvb = 1, 293 .has_zl10353 = 1, 294 .has_eeprom = 1, 295 .has_remote = 1, 296 }, 297 .gpio = { 298 .tuner_reset = TM6010_GPIO_2, 299 .tuner_on = TM6010_GPIO_3, 300 .demod_reset = TM6010_GPIO_1, 301 .demod_on = TM6010_GPIO_4, 302 .power_led = TM6010_GPIO_7, 303 .dvb_led = TM6010_GPIO_5, 304 .ir = TM6010_GPIO_0, 305 }, 306 } 307}; 308 309/* table of devices that work with this driver */ 310struct usb_device_id tm6000_id_table[] = { 311 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 }, 312 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, 313 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, 314 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, 315 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, 316 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 317 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 318 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 319 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 320 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, 321 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, 322 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 323 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 324 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 325 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 326 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 327 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 328 { }, 329}; 330 331/* Tuner callback to provide the proper gpio changes needed for xc5000 */ 332int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) 333{ 334 int rc = 0; 335 struct tm6000_core *dev = ptr; 336 337 if (dev->tuner_type != TUNER_XC5000) 338 return 0; 339 340 switch (command) { 341 case XC5000_TUNER_RESET: 342 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 343 dev->gpio.tuner_reset, 0x01); 344 msleep(15); 345 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 346 dev->gpio.tuner_reset, 0x00); 347 msleep(15); 348 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 349 dev->gpio.tuner_reset, 0x01); 350 break; 351 } 352 return (rc); 353} 354EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); 355 356/* Tuner callback to provide the proper gpio changes needed for xc2028 */ 357 358int tm6000_tuner_callback(void *ptr, int component, int command, int arg) 359{ 360 int rc = 0; 361 struct tm6000_core *dev = ptr; 362 363 if (dev->tuner_type != TUNER_XC2028) 364 return 0; 365 366 switch (command) { 367 case XC2028_RESET_CLK: 368 tm6000_ir_wait(dev, 0); 369 370 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 371 0x02, arg); 372 msleep(10); 373 rc = tm6000_i2c_reset(dev, 10); 374 break; 375 case XC2028_TUNER_RESET: 376 /* Reset codes during load firmware */ 377 switch (arg) { 378 case 0: 379 /* newer tuner can faster reset */ 380 switch (dev->model) { 381 case TM5600_BOARD_10MOONS_UT821: 382 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 383 dev->gpio.tuner_reset, 0x01); 384 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 385 0x300, 0x01); 386 msleep(10); 387 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 388 dev->gpio.tuner_reset, 0x00); 389 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 390 0x300, 0x00); 391 msleep(10); 392 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 393 dev->gpio.tuner_reset, 0x01); 394 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 395 0x300, 0x01); 396 break; 397 case TM6010_BOARD_HAUPPAUGE_900H: 398 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 399 case TM6010_BOARD_TWINHAN_TU501: 400 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 401 dev->gpio.tuner_reset, 0x01); 402 msleep(60); 403 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 404 dev->gpio.tuner_reset, 0x00); 405 msleep(75); 406 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 407 dev->gpio.tuner_reset, 0x01); 408 msleep(60); 409 break; 410 default: 411 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 412 dev->gpio.tuner_reset, 0x00); 413 msleep(130); 414 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 415 dev->gpio.tuner_reset, 0x01); 416 msleep(130); 417 break; 418 } 419 420 tm6000_ir_wait(dev, 1); 421 break; 422 case 1: 423 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 424 0x02, 0x01); 425 msleep(10); 426 break; 427 case 2: 428 rc = tm6000_i2c_reset(dev, 100); 429 break; 430 } 431 } 432 return rc; 433} 434EXPORT_SYMBOL_GPL(tm6000_tuner_callback); 435 436int tm6000_cards_setup(struct tm6000_core *dev) 437{ 438 int i, rc; 439 440 /* 441 * Board-specific initialization sequence. Handles all GPIO 442 * initialization sequences that are board-specific. 443 * Up to now, all found devices use GPIO1 and GPIO4 at the same way. 444 * Probably, they're all based on some reference device. Due to that, 445 * there's a common routine at the end to handle those GPIO's. Devices 446 * that use different pinups or init sequences can just return at 447 * the board-specific session. 448 */ 449 switch (dev->model) { 450 case TM6010_BOARD_HAUPPAUGE_900H: 451 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 452 case TM6010_BOARD_TWINHAN_TU501: 453 case TM6010_BOARD_GENERIC: 454 /* Turn xceive 3028 on */ 455 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); 456 msleep(15); 457 /* Turn zarlink zl10353 on */ 458 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 459 msleep(15); 460 /* Reset zarlink zl10353 */ 461 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 462 msleep(50); 463 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 464 msleep(15); 465 /* Turn zarlink zl10353 off */ 466 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); 467 msleep(15); 468 /* ir ? */ 469 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); 470 msleep(15); 471 /* Power led on (blue) */ 472 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); 473 msleep(15); 474 /* DVB led off (orange) */ 475 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); 476 msleep(15); 477 /* Turn zarlink zl10353 on */ 478 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 479 msleep(15); 480 break; 481 case TM6010_BOARD_BEHOLD_WANDER: 482 /* Power led on (blue) */ 483 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 484 msleep(15); 485 /* Reset zarlink zl10353 */ 486 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 487 msleep(50); 488 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 489 msleep(15); 490 break; 491 case TM6010_BOARD_BEHOLD_VOYAGER: 492 /* Power led on (blue) */ 493 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 494 msleep(15); 495 break; 496 default: 497 break; 498 } 499 500 /* 501 * Default initialization. Most of the devices seem to use GPIO1 502 * and GPIO4.on the same way, so, this handles the common sequence 503 * used by most devices. 504 * If a device uses a different sequence or different GPIO pins for 505 * reset, just add the code at the board-specific part 506 */ 507 508 if (dev->gpio.tuner_reset) { 509 for (i = 0; i < 2; i++) { 510 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 511 dev->gpio.tuner_reset, 0x00); 512 if (rc < 0) { 513 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 514 return rc; 515 } 516 517 msleep(10); /* Just to be conservative */ 518 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 519 dev->gpio.tuner_reset, 0x01); 520 if (rc < 0) { 521 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 522 return rc; 523 } 524 msleep(10); 525 526 if (!i) { 527 rc = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); 528 if (rc >= 0) 529 printk(KERN_DEBUG "board=0x%08x\n", rc); 530 } 531 } 532 } else { 533 printk(KERN_ERR "Tuner reset is not configured\n"); 534 return -1; 535 } 536 537 msleep(50); 538 539 return 0; 540}; 541 542static void tm6000_config_tuner(struct tm6000_core *dev) 543{ 544 struct tuner_setup tun_setup; 545 546 /* Load tuner module */ 547 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 548 "tuner", "tuner", dev->tuner_addr, NULL); 549 550 memset(&tun_setup, 0, sizeof(tun_setup)); 551 tun_setup.type = dev->tuner_type; 552 tun_setup.addr = dev->tuner_addr; 553 554 tun_setup.mode_mask = 0; 555 if (dev->caps.has_tuner) 556 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); 557 if (dev->caps.has_dvb) 558 tun_setup.mode_mask |= T_DIGITAL_TV; 559 560 switch (dev->tuner_type) { 561 case TUNER_XC2028: 562 tun_setup.tuner_callback = tm6000_tuner_callback; 563 break; 564 case TUNER_XC5000: 565 tun_setup.tuner_callback = tm6000_xc5000_callback; 566 break; 567 } 568 569 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); 570 571 switch (dev->tuner_type) { 572 case TUNER_XC2028: { 573 struct v4l2_priv_tun_config xc2028_cfg; 574 struct xc2028_ctrl ctl; 575 576 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); 577 memset(&ctl, 0, sizeof(ctl)); 578 579 ctl.input1 = 1; 580 ctl.read_not_reliable = 0; 581 ctl.msleep = 10; 582 ctl.demod = XC3028_FE_ZARLINK456; 583 ctl.vhfbw7 = 1; 584 ctl.uhfbw8 = 1; 585 xc2028_cfg.tuner = TUNER_XC2028; 586 xc2028_cfg.priv = &ctl; 587 588 switch (dev->model) { 589 case TM6010_BOARD_HAUPPAUGE_900H: 590 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 591 case TM6010_BOARD_TWINHAN_TU501: 592 ctl.fname = "xc3028L-v36.fw"; 593 break; 594 default: 595 if (dev->dev_type == TM6010) 596 ctl.fname = "xc3028-v27.fw"; 597 else 598 ctl.fname = "xc3028-v24.fw"; 599 } 600 601 printk(KERN_INFO "Setting firmware parameters for xc2028\n"); 602 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 603 &xc2028_cfg); 604 605 } 606 break; 607 case TUNER_XC5000: 608 { 609 struct v4l2_priv_tun_config xc5000_cfg; 610 struct xc5000_config ctl = { 611 .i2c_address = dev->tuner_addr, 612 .if_khz = 4570, 613 .radio_input = XC5000_RADIO_FM1, 614 }; 615 616 xc5000_cfg.tuner = TUNER_XC5000; 617 xc5000_cfg.priv = &ctl; 618 619 620 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 621 &xc5000_cfg); 622 } 623 break; 624 default: 625 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); 626 break; 627 } 628} 629 630static int tm6000_init_dev(struct tm6000_core *dev) 631{ 632 struct v4l2_frequency f; 633 int rc = 0; 634 635 mutex_init(&dev->lock); 636 637 mutex_lock(&dev->lock); 638 639 /* Initializa board-specific data */ 640 dev->dev_type = tm6000_boards[dev->model].type; 641 dev->tuner_type = tm6000_boards[dev->model].tuner_type; 642 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; 643 644 dev->gpio = tm6000_boards[dev->model].gpio; 645 646 dev->ir_codes = tm6000_boards[dev->model].ir_codes; 647 648 dev->demod_addr = tm6000_boards[dev->model].demod_addr; 649 650 dev->caps = tm6000_boards[dev->model].caps; 651 652 /* initialize hardware */ 653 rc = tm6000_init(dev); 654 if (rc < 0) 655 goto err; 656 657 rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); 658 if (rc < 0) 659 goto err; 660 661 /* register i2c bus */ 662 rc = tm6000_i2c_register(dev); 663 if (rc < 0) 664 goto err; 665 666 /* Default values for STD and resolutions */ 667 dev->width = 720; 668 dev->height = 480; 669 dev->norm = V4L2_STD_PAL_M; 670 671 /* Configure tuner */ 672 tm6000_config_tuner(dev); 673 674 /* Set video standard */ 675 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); 676 677 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ 678 f.tuner = 0; 679 f.type = V4L2_TUNER_ANALOG_TV; 680 f.frequency = 3092; /* 193.25 MHz */ 681 dev->freq = f.frequency; 682 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); 683 684 if (dev->caps.has_tda9874) 685 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 686 "tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL); 687 688 /* register and initialize V4L2 */ 689 rc = tm6000_v4l2_register(dev); 690 if (rc < 0) 691 goto err; 692 693 tm6000_add_into_devlist(dev); 694 tm6000_init_extension(dev); 695 696 tm6000_ir_init(dev); 697 698 mutex_unlock(&dev->lock); 699 return 0; 700 701err: 702 mutex_unlock(&dev->lock); 703 return rc; 704} 705 706/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ 707#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) 708 709static void get_max_endpoint(struct usb_device *udev, 710 struct usb_host_interface *alt, 711 char *msgtype, 712 struct usb_host_endpoint *curr_e, 713 struct tm6000_endpoint *tm_ep) 714{ 715 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); 716 unsigned int size = tmp & 0x7ff; 717 718 if (udev->speed == USB_SPEED_HIGH) 719 size = size * hb_mult(tmp); 720 721 if (size > tm_ep->maxsize) { 722 tm_ep->endp = curr_e; 723 tm_ep->maxsize = size; 724 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; 725 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; 726 727 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", 728 msgtype, curr_e->desc.bEndpointAddress, 729 size); 730 } 731} 732 733/* 734 * tm6000_usb_probe() 735 * checks for supported devices 736 */ 737static int tm6000_usb_probe(struct usb_interface *interface, 738 const struct usb_device_id *id) 739{ 740 struct usb_device *usbdev; 741 struct tm6000_core *dev = NULL; 742 int i, rc = 0; 743 int nr = 0; 744 char *speed; 745 746 usbdev = usb_get_dev(interface_to_usbdev(interface)); 747 748 /* Selects the proper interface */ 749 rc = usb_set_interface(usbdev, 0, 1); 750 if (rc < 0) 751 goto err; 752 753 /* Check to see next free device and mark as used */ 754 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); 755 if (nr >= TM6000_MAXBOARDS) { 756 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); 757 usb_put_dev(usbdev); 758 return -ENOMEM; 759 } 760 761 /* Create and initialize dev struct */ 762 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 763 if (dev == NULL) { 764 printk(KERN_ERR "tm6000" ": out of memory!\n"); 765 usb_put_dev(usbdev); 766 return -ENOMEM; 767 } 768 spin_lock_init(&dev->slock); 769 770 /* Increment usage count */ 771 tm6000_devused |= 1<<nr; 772 snprintf(dev->name, 29, "tm6000 #%d", nr); 773 774 dev->model = id->driver_info; 775 if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards))) 776 dev->model = card[nr]; 777 778 dev->udev = usbdev; 779 dev->devno = nr; 780 781 switch (usbdev->speed) { 782 case USB_SPEED_LOW: 783 speed = "1.5"; 784 break; 785 case USB_SPEED_UNKNOWN: 786 case USB_SPEED_FULL: 787 speed = "12"; 788 break; 789 case USB_SPEED_HIGH: 790 speed = "480"; 791 break; 792 default: 793 speed = "unknown"; 794 } 795 796 797 798 /* Get endpoints */ 799 for (i = 0; i < interface->num_altsetting; i++) { 800 int ep; 801 802 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { 803 struct usb_host_endpoint *e; 804 int dir_out; 805 806 e = &interface->altsetting[i].endpoint[ep]; 807 808 dir_out = ((e->desc.bEndpointAddress & 809 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); 810 811 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", 812 i, 813 interface->altsetting[i].desc.bInterfaceNumber, 814 interface->altsetting[i].desc.bInterfaceClass); 815 816 switch (e->desc.bmAttributes) { 817 case USB_ENDPOINT_XFER_BULK: 818 if (!dir_out) { 819 get_max_endpoint(usbdev, 820 &interface->altsetting[i], 821 "Bulk IN", e, 822 &dev->bulk_in); 823 } else { 824 get_max_endpoint(usbdev, 825 &interface->altsetting[i], 826 "Bulk OUT", e, 827 &dev->bulk_out); 828 } 829 break; 830 case USB_ENDPOINT_XFER_ISOC: 831 if (!dir_out) { 832 get_max_endpoint(usbdev, 833 &interface->altsetting[i], 834 "ISOC IN", e, 835 &dev->isoc_in); 836 } else { 837 get_max_endpoint(usbdev, 838 &interface->altsetting[i], 839 "ISOC OUT", e, 840 &dev->isoc_out); 841 } 842 break; 843 case USB_ENDPOINT_XFER_INT: 844 if (!dir_out) { 845 get_max_endpoint(usbdev, 846 &interface->altsetting[i], 847 "INT IN", e, 848 &dev->int_in); 849 } else { 850 get_max_endpoint(usbdev, 851 &interface->altsetting[i], 852 "INT OUT", e, 853 &dev->int_out); 854 } 855 break; 856 } 857 } 858 } 859 860 861 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", 862 speed, 863 le16_to_cpu(dev->udev->descriptor.idVendor), 864 le16_to_cpu(dev->udev->descriptor.idProduct), 865 interface->altsetting->desc.bInterfaceNumber); 866 867/* check if the the device has the iso in endpoint at the correct place */ 868 if (!dev->isoc_in.endp) { 869 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); 870 rc = -ENODEV; 871 872 goto err; 873 } 874 875 /* save our data pointer in this interface device */ 876 usb_set_intfdata(interface, dev); 877 878 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); 879 880 rc = tm6000_init_dev(dev); 881 882 if (rc < 0) 883 goto err; 884 885 return 0; 886 887err: 888 printk(KERN_ERR "tm6000: Error %d while registering\n", rc); 889 890 tm6000_devused &= ~(1<<nr); 891 usb_put_dev(usbdev); 892 893 kfree(dev); 894 return rc; 895} 896 897/* 898 * tm6000_usb_disconnect() 899 * called when the device gets diconencted 900 * video device will be unregistered on v4l2_close in case it is still open 901 */ 902static void tm6000_usb_disconnect(struct usb_interface *interface) 903{ 904 struct tm6000_core *dev = usb_get_intfdata(interface); 905 usb_set_intfdata(interface, NULL); 906 907 if (!dev) 908 return; 909 910 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); 911 912 mutex_lock(&dev->lock); 913 914 tm6000_ir_fini(dev); 915 916 if (dev->gpio.power_led) { 917 switch (dev->model) { 918 case TM6010_BOARD_HAUPPAUGE_900H: 919 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 920 case TM6010_BOARD_TWINHAN_TU501: 921 /* Power led off */ 922 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 923 dev->gpio.power_led, 0x01); 924 msleep(15); 925 break; 926 case TM6010_BOARD_BEHOLD_WANDER: 927 case TM6010_BOARD_BEHOLD_VOYAGER: 928 /* Power led off */ 929 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 930 dev->gpio.power_led, 0x00); 931 msleep(15); 932 break; 933 } 934 } 935 tm6000_v4l2_unregister(dev); 936 937 tm6000_i2c_unregister(dev); 938 939 v4l2_device_unregister(&dev->v4l2_dev); 940 941 dev->state |= DEV_DISCONNECTED; 942 943 usb_put_dev(dev->udev); 944 945 tm6000_close_extension(dev); 946 tm6000_remove_from_devlist(dev); 947 948 mutex_unlock(&dev->lock); 949 kfree(dev); 950} 951 952static struct usb_driver tm6000_usb_driver = { 953 .name = "tm6000", 954 .probe = tm6000_usb_probe, 955 .disconnect = tm6000_usb_disconnect, 956 .id_table = tm6000_id_table, 957}; 958 959static int __init tm6000_module_init(void) 960{ 961 int result; 962 963 printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n", 964 (TM6000_VERSION >> 16) & 0xff, 965 (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff); 966 967 /* register this driver with the USB subsystem */ 968 result = usb_register(&tm6000_usb_driver); 969 if (result) 970 printk(KERN_ERR "tm6000" 971 " usb_register failed. Error number %d.\n", result); 972 973 return result; 974} 975 976static void __exit tm6000_module_exit(void) 977{ 978 /* deregister at USB subsystem */ 979 usb_deregister(&tm6000_usb_driver); 980} 981 982module_init(tm6000_module_init); 983module_exit(tm6000_module_exit); 984 985MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); 986MODULE_AUTHOR("Mauro Carvalho Chehab"); 987MODULE_LICENSE("GPL"); 988