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/slab.h> 27#include <media/v4l2-common.h> 28#include <media/tuner.h> 29#include <media/tvaudio.h> 30#include <media/i2c-addr.h> 31#include <media/rc-map.h> 32 33#include "tm6000.h" 34#include "tm6000-regs.h" 35#include "tuner-xc2028.h" 36#include "xc5000.h" 37 38#define TM6000_BOARD_UNKNOWN 0 39#define TM5600_BOARD_GENERIC 1 40#define TM6000_BOARD_GENERIC 2 41#define TM6010_BOARD_GENERIC 3 42#define TM5600_BOARD_10MOONS_UT821 4 43#define TM5600_BOARD_10MOONS_UT330 5 44#define TM6000_BOARD_ADSTECH_DUAL_TV 6 45#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 46#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 47#define TM6010_BOARD_HAUPPAUGE_900H 9 48#define TM6010_BOARD_BEHOLD_WANDER 10 49#define TM6010_BOARD_BEHOLD_VOYAGER 11 50#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 51#define TM6010_BOARD_TWINHAN_TU501 13 52#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 53#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 54#define TM5600_BOARD_TERRATEC_GRABSTER 16 55 56#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \ 57 (model == TM5600_BOARD_GENERIC) || \ 58 (model == TM6000_BOARD_GENERIC) || \ 59 (model == TM6010_BOARD_GENERIC)) 60 61#define TM6000_MAXBOARDS 16 62static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; 63 64module_param_array(card, int, NULL, 0444); 65 66static unsigned long tm6000_devused; 67 68 69struct tm6000_board { 70 char *name; 71 char eename[16]; /* EEPROM name */ 72 unsigned eename_size; /* size of EEPROM name */ 73 unsigned eename_pos; /* Position where it appears at ROM */ 74 75 struct tm6000_capabilities caps; 76 77 enum tm6000_devtype type; /* variant of the chipset */ 78 int tuner_type; /* type of the tuner */ 79 int tuner_addr; /* tuner address */ 80 int demod_addr; /* demodulator address */ 81 82 struct tm6000_gpio gpio; 83 84 struct tm6000_input vinput[3]; 85 struct tm6000_input rinput; 86 87 char *ir_codes; 88}; 89 90static struct tm6000_board tm6000_boards[] = { 91 [TM6000_BOARD_UNKNOWN] = { 92 .name = "Unknown tm6000 video grabber", 93 .caps = { 94 .has_tuner = 1, 95 .has_eeprom = 1, 96 }, 97 .gpio = { 98 .tuner_reset = TM6000_GPIO_1, 99 }, 100 .vinput = { { 101 .type = TM6000_INPUT_TV, 102 .vmux = TM6000_VMUX_VIDEO_B, 103 .amux = TM6000_AMUX_ADC1, 104 }, { 105 .type = TM6000_INPUT_COMPOSITE1, 106 .vmux = TM6000_VMUX_VIDEO_A, 107 .amux = TM6000_AMUX_ADC2, 108 }, { 109 .type = TM6000_INPUT_SVIDEO, 110 .vmux = TM6000_VMUX_VIDEO_AB, 111 .amux = TM6000_AMUX_ADC2, 112 }, 113 }, 114 }, 115 [TM5600_BOARD_GENERIC] = { 116 .name = "Generic tm5600 board", 117 .type = TM5600, 118 .tuner_type = TUNER_XC2028, 119 .tuner_addr = 0xc2 >> 1, 120 .caps = { 121 .has_tuner = 1, 122 .has_eeprom = 1, 123 }, 124 .gpio = { 125 .tuner_reset = TM6000_GPIO_1, 126 }, 127 .vinput = { { 128 .type = TM6000_INPUT_TV, 129 .vmux = TM6000_VMUX_VIDEO_B, 130 .amux = TM6000_AMUX_ADC1, 131 }, { 132 .type = TM6000_INPUT_COMPOSITE1, 133 .vmux = TM6000_VMUX_VIDEO_A, 134 .amux = TM6000_AMUX_ADC2, 135 }, { 136 .type = TM6000_INPUT_SVIDEO, 137 .vmux = TM6000_VMUX_VIDEO_AB, 138 .amux = TM6000_AMUX_ADC2, 139 }, 140 }, 141 }, 142 [TM6000_BOARD_GENERIC] = { 143 .name = "Generic tm6000 board", 144 .tuner_type = TUNER_XC2028, 145 .tuner_addr = 0xc2 >> 1, 146 .caps = { 147 .has_tuner = 1, 148 .has_eeprom = 1, 149 }, 150 .gpio = { 151 .tuner_reset = TM6000_GPIO_1, 152 }, 153 .vinput = { { 154 .type = TM6000_INPUT_TV, 155 .vmux = TM6000_VMUX_VIDEO_B, 156 .amux = TM6000_AMUX_ADC1, 157 }, { 158 .type = TM6000_INPUT_COMPOSITE1, 159 .vmux = TM6000_VMUX_VIDEO_A, 160 .amux = TM6000_AMUX_ADC2, 161 }, { 162 .type = TM6000_INPUT_SVIDEO, 163 .vmux = TM6000_VMUX_VIDEO_AB, 164 .amux = TM6000_AMUX_ADC2, 165 }, 166 }, 167 }, 168 [TM6010_BOARD_GENERIC] = { 169 .name = "Generic tm6010 board", 170 .type = TM6010, 171 .tuner_type = TUNER_XC2028, 172 .tuner_addr = 0xc2 >> 1, 173 .demod_addr = 0x1e >> 1, 174 .caps = { 175 .has_tuner = 1, 176 .has_dvb = 1, 177 .has_zl10353 = 1, 178 .has_eeprom = 1, 179 .has_remote = 1, 180 }, 181 .gpio = { 182 .tuner_reset = TM6010_GPIO_2, 183 .tuner_on = TM6010_GPIO_3, 184 .demod_reset = TM6010_GPIO_1, 185 .demod_on = TM6010_GPIO_4, 186 .power_led = TM6010_GPIO_7, 187 .dvb_led = TM6010_GPIO_5, 188 .ir = TM6010_GPIO_0, 189 }, 190 .vinput = { { 191 .type = TM6000_INPUT_TV, 192 .vmux = TM6000_VMUX_VIDEO_B, 193 .amux = TM6000_AMUX_SIF1, 194 }, { 195 .type = TM6000_INPUT_COMPOSITE1, 196 .vmux = TM6000_VMUX_VIDEO_A, 197 .amux = TM6000_AMUX_ADC2, 198 }, { 199 .type = TM6000_INPUT_SVIDEO, 200 .vmux = TM6000_VMUX_VIDEO_AB, 201 .amux = TM6000_AMUX_ADC2, 202 }, 203 }, 204 }, 205 [TM5600_BOARD_10MOONS_UT821] = { 206 .name = "10Moons UT 821", 207 .tuner_type = TUNER_XC2028, 208 .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b}, 209 .eename_size = 14, 210 .eename_pos = 0x14, 211 .type = TM5600, 212 .tuner_addr = 0xc2 >> 1, 213 .caps = { 214 .has_tuner = 1, 215 .has_eeprom = 1, 216 }, 217 .gpio = { 218 .tuner_reset = TM6000_GPIO_1, 219 }, 220 .vinput = { { 221 .type = TM6000_INPUT_TV, 222 .vmux = TM6000_VMUX_VIDEO_B, 223 .amux = TM6000_AMUX_ADC1, 224 }, { 225 .type = TM6000_INPUT_COMPOSITE1, 226 .vmux = TM6000_VMUX_VIDEO_A, 227 .amux = TM6000_AMUX_ADC2, 228 }, { 229 .type = TM6000_INPUT_SVIDEO, 230 .vmux = TM6000_VMUX_VIDEO_AB, 231 .amux = TM6000_AMUX_ADC2, 232 }, 233 }, 234 }, 235 [TM5600_BOARD_10MOONS_UT330] = { 236 .name = "10Moons UT 330", 237 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, 238 .tuner_addr = 0xc8 >> 1, 239 .caps = { 240 .has_tuner = 1, 241 .has_dvb = 0, 242 .has_zl10353 = 0, 243 .has_eeprom = 1, 244 }, 245 .vinput = { { 246 .type = TM6000_INPUT_TV, 247 .vmux = TM6000_VMUX_VIDEO_B, 248 .amux = TM6000_AMUX_ADC1, 249 }, { 250 .type = TM6000_INPUT_COMPOSITE1, 251 .vmux = TM6000_VMUX_VIDEO_A, 252 .amux = TM6000_AMUX_ADC2, 253 }, { 254 .type = TM6000_INPUT_SVIDEO, 255 .vmux = TM6000_VMUX_VIDEO_AB, 256 .amux = TM6000_AMUX_ADC2, 257 }, 258 }, 259 }, 260 [TM6000_BOARD_ADSTECH_DUAL_TV] = { 261 .name = "ADSTECH Dual TV USB", 262 .tuner_type = TUNER_XC2028, 263 .tuner_addr = 0xc8 >> 1, 264 .caps = { 265 .has_tuner = 1, 266 .has_tda9874 = 1, 267 .has_dvb = 1, 268 .has_zl10353 = 1, 269 .has_eeprom = 1, 270 }, 271 .vinput = { { 272 .type = TM6000_INPUT_TV, 273 .vmux = TM6000_VMUX_VIDEO_B, 274 .amux = TM6000_AMUX_ADC1, 275 }, { 276 .type = TM6000_INPUT_COMPOSITE1, 277 .vmux = TM6000_VMUX_VIDEO_A, 278 .amux = TM6000_AMUX_ADC2, 279 }, { 280 .type = TM6000_INPUT_SVIDEO, 281 .vmux = TM6000_VMUX_VIDEO_AB, 282 .amux = TM6000_AMUX_ADC2, 283 }, 284 }, 285 }, 286 [TM6000_BOARD_FREECOM_AND_SIMILAR] = { 287 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", 288 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 289 .tuner_addr = 0xc2 >> 1, 290 .demod_addr = 0x1e >> 1, 291 .caps = { 292 .has_tuner = 1, 293 .has_dvb = 1, 294 .has_zl10353 = 1, 295 .has_eeprom = 0, 296 .has_remote = 1, 297 }, 298 .gpio = { 299 .tuner_reset = TM6000_GPIO_4, 300 }, 301 .vinput = { { 302 .type = TM6000_INPUT_TV, 303 .vmux = TM6000_VMUX_VIDEO_B, 304 .amux = TM6000_AMUX_ADC1, 305 }, { 306 .type = TM6000_INPUT_COMPOSITE1, 307 .vmux = TM6000_VMUX_VIDEO_A, 308 .amux = TM6000_AMUX_ADC2, 309 }, { 310 .type = TM6000_INPUT_SVIDEO, 311 .vmux = TM6000_VMUX_VIDEO_AB, 312 .amux = TM6000_AMUX_ADC2, 313 }, 314 }, 315 }, 316 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { 317 .name = "ADSTECH Mini Dual TV USB", 318 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 319 .tuner_addr = 0xc8 >> 1, 320 .demod_addr = 0x1e >> 1, 321 .caps = { 322 .has_tuner = 1, 323 .has_dvb = 1, 324 .has_zl10353 = 1, 325 .has_eeprom = 0, 326 }, 327 .gpio = { 328 .tuner_reset = TM6000_GPIO_4, 329 }, 330 .vinput = { { 331 .type = TM6000_INPUT_TV, 332 .vmux = TM6000_VMUX_VIDEO_B, 333 .amux = TM6000_AMUX_ADC1, 334 }, { 335 .type = TM6000_INPUT_COMPOSITE1, 336 .vmux = TM6000_VMUX_VIDEO_A, 337 .amux = TM6000_AMUX_ADC2, 338 }, { 339 .type = TM6000_INPUT_SVIDEO, 340 .vmux = TM6000_VMUX_VIDEO_AB, 341 .amux = TM6000_AMUX_ADC2, 342 }, 343 }, 344 }, 345 [TM6010_BOARD_HAUPPAUGE_900H] = { 346 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", 347 .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 }, 348 .eename_size = 14, 349 .eename_pos = 0x42, 350 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 351 .tuner_addr = 0xc2 >> 1, 352 .demod_addr = 0x1e >> 1, 353 .type = TM6010, 354 .ir_codes = RC_MAP_HAUPPAUGE, 355 .caps = { 356 .has_tuner = 1, 357 .has_dvb = 1, 358 .has_zl10353 = 1, 359 .has_eeprom = 1, 360 .has_remote = 1, 361 }, 362 .gpio = { 363 .tuner_reset = TM6010_GPIO_2, 364 .tuner_on = TM6010_GPIO_3, 365 .demod_reset = TM6010_GPIO_1, 366 .demod_on = TM6010_GPIO_4, 367 .power_led = TM6010_GPIO_7, 368 .dvb_led = TM6010_GPIO_5, 369 .ir = TM6010_GPIO_0, 370 }, 371 .vinput = { { 372 .type = TM6000_INPUT_TV, 373 .vmux = TM6000_VMUX_VIDEO_B, 374 .amux = TM6000_AMUX_SIF1, 375 }, { 376 .type = TM6000_INPUT_COMPOSITE1, 377 .vmux = TM6000_VMUX_VIDEO_A, 378 .amux = TM6000_AMUX_ADC2, 379 }, { 380 .type = TM6000_INPUT_SVIDEO, 381 .vmux = TM6000_VMUX_VIDEO_AB, 382 .amux = TM6000_AMUX_ADC2, 383 }, 384 }, 385 }, 386 [TM6010_BOARD_BEHOLD_WANDER] = { 387 .name = "Beholder Wander DVB-T/TV/FM USB2.0", 388 .tuner_type = TUNER_XC5000, 389 .tuner_addr = 0xc2 >> 1, 390 .demod_addr = 0x1e >> 1, 391 .type = TM6010, 392 .caps = { 393 .has_tuner = 1, 394 .has_dvb = 1, 395 .has_zl10353 = 1, 396 .has_eeprom = 1, 397 .has_remote = 1, 398 .has_radio = 1, 399 }, 400 .gpio = { 401 .tuner_reset = TM6010_GPIO_0, 402 .demod_reset = TM6010_GPIO_1, 403 .power_led = TM6010_GPIO_6, 404 }, 405 .vinput = { { 406 .type = TM6000_INPUT_TV, 407 .vmux = TM6000_VMUX_VIDEO_B, 408 .amux = TM6000_AMUX_SIF1, 409 }, { 410 .type = TM6000_INPUT_COMPOSITE1, 411 .vmux = TM6000_VMUX_VIDEO_A, 412 .amux = TM6000_AMUX_ADC2, 413 }, { 414 .type = TM6000_INPUT_SVIDEO, 415 .vmux = TM6000_VMUX_VIDEO_AB, 416 .amux = TM6000_AMUX_ADC2, 417 }, 418 }, 419 .rinput = { 420 .type = TM6000_INPUT_RADIO, 421 .amux = TM6000_AMUX_ADC1, 422 }, 423 }, 424 [TM6010_BOARD_BEHOLD_VOYAGER] = { 425 .name = "Beholder Voyager TV/FM USB2.0", 426 .tuner_type = TUNER_XC5000, 427 .tuner_addr = 0xc2 >> 1, 428 .type = TM6010, 429 .caps = { 430 .has_tuner = 1, 431 .has_dvb = 0, 432 .has_zl10353 = 0, 433 .has_eeprom = 1, 434 .has_remote = 1, 435 .has_radio = 1, 436 }, 437 .gpio = { 438 .tuner_reset = TM6010_GPIO_0, 439 .power_led = TM6010_GPIO_6, 440 }, 441 .vinput = { { 442 .type = TM6000_INPUT_TV, 443 .vmux = TM6000_VMUX_VIDEO_B, 444 .amux = TM6000_AMUX_SIF1, 445 }, { 446 .type = TM6000_INPUT_COMPOSITE1, 447 .vmux = TM6000_VMUX_VIDEO_A, 448 .amux = TM6000_AMUX_ADC2, 449 }, { 450 .type = TM6000_INPUT_SVIDEO, 451 .vmux = TM6000_VMUX_VIDEO_AB, 452 .amux = TM6000_AMUX_ADC2, 453 }, 454 }, 455 .rinput = { 456 .type = TM6000_INPUT_RADIO, 457 .amux = TM6000_AMUX_ADC1, 458 }, 459 }, 460 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { 461 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", 462 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 463 .tuner_addr = 0xc2 >> 1, 464 .demod_addr = 0x1e >> 1, 465 .type = TM6010, 466 .caps = { 467 .has_tuner = 1, 468 .has_dvb = 1, 469 .has_zl10353 = 1, 470 .has_eeprom = 1, 471 .has_remote = 1, 472 .has_radio = 1, 473 }, 474 .gpio = { 475 .tuner_reset = TM6010_GPIO_2, 476 .tuner_on = TM6010_GPIO_3, 477 .demod_reset = TM6010_GPIO_1, 478 .demod_on = TM6010_GPIO_4, 479 .power_led = TM6010_GPIO_7, 480 .dvb_led = TM6010_GPIO_5, 481 .ir = TM6010_GPIO_0, 482 }, 483 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, 484 .vinput = { { 485 .type = TM6000_INPUT_TV, 486 .vmux = TM6000_VMUX_VIDEO_B, 487 .amux = TM6000_AMUX_SIF1, 488 }, { 489 .type = TM6000_INPUT_COMPOSITE1, 490 .vmux = TM6000_VMUX_VIDEO_A, 491 .amux = TM6000_AMUX_ADC2, 492 }, { 493 .type = TM6000_INPUT_SVIDEO, 494 .vmux = TM6000_VMUX_VIDEO_AB, 495 .amux = TM6000_AMUX_ADC2, 496 }, 497 }, 498 .rinput = { 499 .type = TM6000_INPUT_RADIO, 500 .amux = TM6000_AMUX_SIF1, 501 }, 502 }, 503 [TM5600_BOARD_TERRATEC_GRABSTER] = { 504 .name = "Terratec Grabster AV 150/250 MX", 505 .type = TM5600, 506 .tuner_type = TUNER_ABSENT, 507 .vinput = { { 508 .type = TM6000_INPUT_TV, 509 .vmux = TM6000_VMUX_VIDEO_B, 510 .amux = TM6000_AMUX_ADC1, 511 }, { 512 .type = TM6000_INPUT_COMPOSITE1, 513 .vmux = TM6000_VMUX_VIDEO_A, 514 .amux = TM6000_AMUX_ADC2, 515 }, { 516 .type = TM6000_INPUT_SVIDEO, 517 .vmux = TM6000_VMUX_VIDEO_AB, 518 .amux = TM6000_AMUX_ADC2, 519 }, 520 }, 521 }, 522 [TM6010_BOARD_TWINHAN_TU501] = { 523 .name = "Twinhan TU501(704D1)", 524 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 525 .tuner_addr = 0xc2 >> 1, 526 .demod_addr = 0x1e >> 1, 527 .type = TM6010, 528 .caps = { 529 .has_tuner = 1, 530 .has_dvb = 1, 531 .has_zl10353 = 1, 532 .has_eeprom = 1, 533 .has_remote = 1, 534 }, 535 .gpio = { 536 .tuner_reset = TM6010_GPIO_2, 537 .tuner_on = TM6010_GPIO_3, 538 .demod_reset = TM6010_GPIO_1, 539 .demod_on = TM6010_GPIO_4, 540 .power_led = TM6010_GPIO_7, 541 .dvb_led = TM6010_GPIO_5, 542 .ir = TM6010_GPIO_0, 543 }, 544 .vinput = { { 545 .type = TM6000_INPUT_TV, 546 .vmux = TM6000_VMUX_VIDEO_B, 547 .amux = TM6000_AMUX_SIF1, 548 }, { 549 .type = TM6000_INPUT_COMPOSITE1, 550 .vmux = TM6000_VMUX_VIDEO_A, 551 .amux = TM6000_AMUX_ADC2, 552 }, { 553 .type = TM6000_INPUT_SVIDEO, 554 .vmux = TM6000_VMUX_VIDEO_AB, 555 .amux = TM6000_AMUX_ADC2, 556 }, 557 }, 558 }, 559 [TM6010_BOARD_BEHOLD_WANDER_LITE] = { 560 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", 561 .tuner_type = TUNER_XC5000, 562 .tuner_addr = 0xc2 >> 1, 563 .demod_addr = 0x1e >> 1, 564 .type = TM6010, 565 .caps = { 566 .has_tuner = 1, 567 .has_dvb = 1, 568 .has_zl10353 = 1, 569 .has_eeprom = 1, 570 .has_remote = 0, 571 .has_radio = 1, 572 }, 573 .gpio = { 574 .tuner_reset = TM6010_GPIO_0, 575 .demod_reset = TM6010_GPIO_1, 576 .power_led = TM6010_GPIO_6, 577 }, 578 .vinput = { { 579 .type = TM6000_INPUT_TV, 580 .vmux = TM6000_VMUX_VIDEO_B, 581 .amux = TM6000_AMUX_SIF1, 582 }, 583 }, 584 .rinput = { 585 .type = TM6000_INPUT_RADIO, 586 .amux = TM6000_AMUX_ADC1, 587 }, 588 }, 589 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { 590 .name = "Beholder Voyager Lite TV/FM USB2.0", 591 .tuner_type = TUNER_XC5000, 592 .tuner_addr = 0xc2 >> 1, 593 .type = TM6010, 594 .caps = { 595 .has_tuner = 1, 596 .has_dvb = 0, 597 .has_zl10353 = 0, 598 .has_eeprom = 1, 599 .has_remote = 0, 600 .has_radio = 1, 601 }, 602 .gpio = { 603 .tuner_reset = TM6010_GPIO_0, 604 .power_led = TM6010_GPIO_6, 605 }, 606 .vinput = { { 607 .type = TM6000_INPUT_TV, 608 .vmux = TM6000_VMUX_VIDEO_B, 609 .amux = TM6000_AMUX_SIF1, 610 }, 611 }, 612 .rinput = { 613 .type = TM6000_INPUT_RADIO, 614 .amux = TM6000_AMUX_ADC1, 615 }, 616 }, 617}; 618 619/* table of devices that work with this driver */ 620static struct usb_device_id tm6000_id_table[] = { 621 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, 622 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, 623 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, 624 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, 625 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, 626 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 627 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 628 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 629 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 630 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, 631 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, 632 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 633 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 634 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, 635 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 636 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 637 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 638 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 639 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, 640 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, 641 { } 642}; 643MODULE_DEVICE_TABLE(usb, tm6000_id_table); 644 645/* Control power led for show some activity */ 646void tm6000_flash_led(struct tm6000_core *dev, u8 state) 647{ 648 /* Power LED unconfigured */ 649 if (!dev->gpio.power_led) 650 return; 651 652 /* ON Power LED */ 653 if (state) { 654 switch (dev->model) { 655 case TM6010_BOARD_HAUPPAUGE_900H: 656 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 657 case TM6010_BOARD_TWINHAN_TU501: 658 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 659 dev->gpio.power_led, 0x00); 660 break; 661 case TM6010_BOARD_BEHOLD_WANDER: 662 case TM6010_BOARD_BEHOLD_VOYAGER: 663 case TM6010_BOARD_BEHOLD_WANDER_LITE: 664 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 665 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 666 dev->gpio.power_led, 0x01); 667 break; 668 } 669 } 670 /* OFF Power LED */ 671 else { 672 switch (dev->model) { 673 case TM6010_BOARD_HAUPPAUGE_900H: 674 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 675 case TM6010_BOARD_TWINHAN_TU501: 676 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 677 dev->gpio.power_led, 0x01); 678 break; 679 case TM6010_BOARD_BEHOLD_WANDER: 680 case TM6010_BOARD_BEHOLD_VOYAGER: 681 case TM6010_BOARD_BEHOLD_WANDER_LITE: 682 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 683 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 684 dev->gpio.power_led, 0x00); 685 break; 686 } 687 } 688} 689 690/* Tuner callback to provide the proper gpio changes needed for xc5000 */ 691int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) 692{ 693 int rc = 0; 694 struct tm6000_core *dev = ptr; 695 696 if (dev->tuner_type != TUNER_XC5000) 697 return 0; 698 699 switch (command) { 700 case XC5000_TUNER_RESET: 701 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 702 dev->gpio.tuner_reset, 0x01); 703 msleep(15); 704 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 705 dev->gpio.tuner_reset, 0x00); 706 msleep(15); 707 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 708 dev->gpio.tuner_reset, 0x01); 709 break; 710 } 711 return rc; 712} 713EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); 714 715/* Tuner callback to provide the proper gpio changes needed for xc2028 */ 716 717int tm6000_tuner_callback(void *ptr, int component, int command, int arg) 718{ 719 int rc = 0; 720 struct tm6000_core *dev = ptr; 721 722 if (dev->tuner_type != TUNER_XC2028) 723 return 0; 724 725 switch (command) { 726 case XC2028_RESET_CLK: 727 tm6000_ir_wait(dev, 0); 728 729 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 730 0x02, arg); 731 msleep(10); 732 rc = tm6000_i2c_reset(dev, 10); 733 break; 734 case XC2028_TUNER_RESET: 735 /* Reset codes during load firmware */ 736 switch (arg) { 737 case 0: 738 /* newer tuner can faster reset */ 739 switch (dev->model) { 740 case TM5600_BOARD_10MOONS_UT821: 741 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 742 dev->gpio.tuner_reset, 0x01); 743 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 744 0x300, 0x01); 745 msleep(10); 746 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 747 dev->gpio.tuner_reset, 0x00); 748 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 749 0x300, 0x00); 750 msleep(10); 751 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 752 dev->gpio.tuner_reset, 0x01); 753 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 754 0x300, 0x01); 755 break; 756 case TM6010_BOARD_HAUPPAUGE_900H: 757 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 758 case TM6010_BOARD_TWINHAN_TU501: 759 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 760 dev->gpio.tuner_reset, 0x01); 761 msleep(60); 762 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 763 dev->gpio.tuner_reset, 0x00); 764 msleep(75); 765 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 766 dev->gpio.tuner_reset, 0x01); 767 msleep(60); 768 break; 769 default: 770 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 771 dev->gpio.tuner_reset, 0x00); 772 msleep(130); 773 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 774 dev->gpio.tuner_reset, 0x01); 775 msleep(130); 776 break; 777 } 778 779 tm6000_ir_wait(dev, 1); 780 break; 781 case 1: 782 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 783 0x02, 0x01); 784 msleep(10); 785 break; 786 case 2: 787 rc = tm6000_i2c_reset(dev, 100); 788 break; 789 } 790 break; 791 case XC2028_I2C_FLUSH: 792 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); 793 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); 794 break; 795 } 796 return rc; 797} 798EXPORT_SYMBOL_GPL(tm6000_tuner_callback); 799 800int tm6000_cards_setup(struct tm6000_core *dev) 801{ 802 /* 803 * Board-specific initialization sequence. Handles all GPIO 804 * initialization sequences that are board-specific. 805 * Up to now, all found devices use GPIO1 and GPIO4 at the same way. 806 * Probably, they're all based on some reference device. Due to that, 807 * there's a common routine at the end to handle those GPIO's. Devices 808 * that use different pinups or init sequences can just return at 809 * the board-specific session. 810 */ 811 switch (dev->model) { 812 case TM6010_BOARD_HAUPPAUGE_900H: 813 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 814 case TM6010_BOARD_TWINHAN_TU501: 815 case TM6010_BOARD_GENERIC: 816 /* Turn xceive 3028 on */ 817 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); 818 msleep(15); 819 /* Turn zarlink zl10353 on */ 820 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 821 msleep(15); 822 /* Reset zarlink zl10353 */ 823 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 824 msleep(50); 825 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 826 msleep(15); 827 /* Turn zarlink zl10353 off */ 828 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); 829 msleep(15); 830 /* ir ? */ 831 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); 832 msleep(15); 833 /* Power led on (blue) */ 834 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); 835 msleep(15); 836 /* DVB led off (orange) */ 837 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); 838 msleep(15); 839 /* Turn zarlink zl10353 on */ 840 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 841 msleep(15); 842 break; 843 case TM6010_BOARD_BEHOLD_WANDER: 844 case TM6010_BOARD_BEHOLD_WANDER_LITE: 845 /* Power led on (blue) */ 846 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 847 msleep(15); 848 /* Reset zarlink zl10353 */ 849 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 850 msleep(50); 851 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 852 msleep(15); 853 break; 854 case TM6010_BOARD_BEHOLD_VOYAGER: 855 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 856 /* Power led on (blue) */ 857 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 858 msleep(15); 859 break; 860 default: 861 break; 862 } 863 864 /* 865 * Default initialization. Most of the devices seem to use GPIO1 866 * and GPIO4.on the same way, so, this handles the common sequence 867 * used by most devices. 868 * If a device uses a different sequence or different GPIO pins for 869 * reset, just add the code at the board-specific part 870 */ 871 872 if (dev->gpio.tuner_reset) { 873 int rc; 874 int i; 875 876 for (i = 0; i < 2; i++) { 877 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 878 dev->gpio.tuner_reset, 0x00); 879 if (rc < 0) { 880 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 881 return rc; 882 } 883 884 msleep(10); /* Just to be conservative */ 885 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 886 dev->gpio.tuner_reset, 0x01); 887 if (rc < 0) { 888 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 889 return rc; 890 } 891 } 892 } else { 893 printk(KERN_ERR "Tuner reset is not configured\n"); 894 return -1; 895 } 896 897 msleep(50); 898 899 return 0; 900}; 901 902static void tm6000_config_tuner(struct tm6000_core *dev) 903{ 904 struct tuner_setup tun_setup; 905 906 /* Load tuner module */ 907 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 908 "tuner", dev->tuner_addr, NULL); 909 910 memset(&tun_setup, 0, sizeof(tun_setup)); 911 tun_setup.type = dev->tuner_type; 912 tun_setup.addr = dev->tuner_addr; 913 914 tun_setup.mode_mask = 0; 915 if (dev->caps.has_tuner) 916 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); 917 918 switch (dev->tuner_type) { 919 case TUNER_XC2028: 920 tun_setup.tuner_callback = tm6000_tuner_callback; 921 break; 922 case TUNER_XC5000: 923 tun_setup.tuner_callback = tm6000_xc5000_callback; 924 break; 925 } 926 927 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); 928 929 switch (dev->tuner_type) { 930 case TUNER_XC2028: { 931 struct v4l2_priv_tun_config xc2028_cfg; 932 struct xc2028_ctrl ctl; 933 934 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); 935 memset(&ctl, 0, sizeof(ctl)); 936 937 ctl.demod = XC3028_FE_ZARLINK456; 938 939 xc2028_cfg.tuner = TUNER_XC2028; 940 xc2028_cfg.priv = &ctl; 941 942 switch (dev->model) { 943 case TM6010_BOARD_HAUPPAUGE_900H: 944 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 945 case TM6010_BOARD_TWINHAN_TU501: 946 ctl.max_len = 80; 947 ctl.fname = "xc3028L-v36.fw"; 948 break; 949 default: 950 if (dev->dev_type == TM6010) 951 ctl.fname = "xc3028-v27.fw"; 952 else 953 ctl.fname = "xc3028-v24.fw"; 954 } 955 956 printk(KERN_INFO "Setting firmware parameters for xc2028\n"); 957 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 958 &xc2028_cfg); 959 960 } 961 break; 962 case TUNER_XC5000: 963 { 964 struct v4l2_priv_tun_config xc5000_cfg; 965 struct xc5000_config ctl = { 966 .i2c_address = dev->tuner_addr, 967 .if_khz = 4570, 968 .radio_input = XC5000_RADIO_FM1_MONO, 969 }; 970 971 xc5000_cfg.tuner = TUNER_XC5000; 972 xc5000_cfg.priv = &ctl; 973 974 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 975 &xc5000_cfg); 976 } 977 break; 978 default: 979 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); 980 break; 981 } 982} 983 984static int fill_board_specific_data(struct tm6000_core *dev) 985{ 986 int rc; 987 988 dev->dev_type = tm6000_boards[dev->model].type; 989 dev->tuner_type = tm6000_boards[dev->model].tuner_type; 990 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; 991 992 dev->gpio = tm6000_boards[dev->model].gpio; 993 994 dev->ir_codes = tm6000_boards[dev->model].ir_codes; 995 996 dev->demod_addr = tm6000_boards[dev->model].demod_addr; 997 998 dev->caps = tm6000_boards[dev->model].caps; 999 1000 dev->vinput[0] = tm6000_boards[dev->model].vinput[0]; 1001 dev->vinput[1] = tm6000_boards[dev->model].vinput[1]; 1002 dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; 1003 dev->rinput = tm6000_boards[dev->model].rinput; 1004 1005 /* setup per-model quirks */ 1006 switch (dev->model) { 1007 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 1008 case TM6010_BOARD_HAUPPAUGE_900H: 1009 dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; 1010 break; 1011 1012 default: 1013 break; 1014 } 1015 1016 /* initialize hardware */ 1017 rc = tm6000_init(dev); 1018 if (rc < 0) 1019 return rc; 1020 1021 return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); 1022} 1023 1024 1025static void use_alternative_detection_method(struct tm6000_core *dev) 1026{ 1027 int i, model = -1; 1028 1029 if (!dev->eedata_size) 1030 return; 1031 1032 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) { 1033 if (!tm6000_boards[i].eename_size) 1034 continue; 1035 if (dev->eedata_size < tm6000_boards[i].eename_pos + 1036 tm6000_boards[i].eename_size) 1037 continue; 1038 1039 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos], 1040 tm6000_boards[i].eename, 1041 tm6000_boards[i].eename_size)) { 1042 model = i; 1043 break; 1044 } 1045 } 1046 if (model < 0) { 1047 printk(KERN_INFO "Device has eeprom but is currently unknown\n"); 1048 return; 1049 } 1050 1051 dev->model = model; 1052 1053 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n", 1054 tm6000_boards[model].name, model); 1055} 1056 1057#if defined(CONFIG_MODULES) && defined(MODULE) 1058static void request_module_async(struct work_struct *work) 1059{ 1060 struct tm6000_core *dev = container_of(work, struct tm6000_core, 1061 request_module_wk); 1062 1063 request_module("tm6000-alsa"); 1064 1065 if (dev->caps.has_dvb) 1066 request_module("tm6000-dvb"); 1067} 1068 1069static void request_modules(struct tm6000_core *dev) 1070{ 1071 INIT_WORK(&dev->request_module_wk, request_module_async); 1072 schedule_work(&dev->request_module_wk); 1073} 1074 1075static void flush_request_modules(struct tm6000_core *dev) 1076{ 1077 flush_work(&dev->request_module_wk); 1078} 1079#else 1080#define request_modules(dev) 1081#define flush_request_modules(dev) 1082#endif /* CONFIG_MODULES */ 1083 1084static int tm6000_init_dev(struct tm6000_core *dev) 1085{ 1086 struct v4l2_frequency f; 1087 int rc = 0; 1088 1089 mutex_init(&dev->lock); 1090 mutex_lock(&dev->lock); 1091 1092 if (!is_generic(dev->model)) { 1093 rc = fill_board_specific_data(dev); 1094 if (rc < 0) 1095 goto err; 1096 1097 /* register i2c bus */ 1098 rc = tm6000_i2c_register(dev); 1099 if (rc < 0) 1100 goto err; 1101 } else { 1102 /* register i2c bus */ 1103 rc = tm6000_i2c_register(dev); 1104 if (rc < 0) 1105 goto err; 1106 1107 use_alternative_detection_method(dev); 1108 1109 rc = fill_board_specific_data(dev); 1110 if (rc < 0) 1111 goto err; 1112 } 1113 1114 /* Default values for STD and resolutions */ 1115 dev->width = 720; 1116 dev->height = 480; 1117 dev->norm = V4L2_STD_NTSC_M; 1118 1119 /* Configure tuner */ 1120 tm6000_config_tuner(dev); 1121 1122 /* Set video standard */ 1123 v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); 1124 1125 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ 1126 f.tuner = 0; 1127 f.type = V4L2_TUNER_ANALOG_TV; 1128 f.frequency = 3092; /* 193.25 MHz */ 1129 dev->freq = f.frequency; 1130 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); 1131 1132 if (dev->caps.has_tda9874) 1133 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 1134 "tvaudio", I2C_ADDR_TDA9874, NULL); 1135 1136 /* register and initialize V4L2 */ 1137 rc = tm6000_v4l2_register(dev); 1138 if (rc < 0) 1139 goto err; 1140 1141 tm6000_add_into_devlist(dev); 1142 tm6000_init_extension(dev); 1143 1144 tm6000_ir_init(dev); 1145 1146 request_modules(dev); 1147 1148 mutex_unlock(&dev->lock); 1149 return 0; 1150 1151err: 1152 mutex_unlock(&dev->lock); 1153 return rc; 1154} 1155 1156/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ 1157#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) 1158 1159static void get_max_endpoint(struct usb_device *udev, 1160 struct usb_host_interface *alt, 1161 char *msgtype, 1162 struct usb_host_endpoint *curr_e, 1163 struct tm6000_endpoint *tm_ep) 1164{ 1165 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); 1166 unsigned int size = tmp & 0x7ff; 1167 1168 if (udev->speed == USB_SPEED_HIGH) 1169 size = size * hb_mult(tmp); 1170 1171 if (size > tm_ep->maxsize) { 1172 tm_ep->endp = curr_e; 1173 tm_ep->maxsize = size; 1174 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; 1175 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; 1176 1177 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", 1178 msgtype, curr_e->desc.bEndpointAddress, 1179 size); 1180 } 1181} 1182 1183/* 1184 * tm6000_usb_probe() 1185 * checks for supported devices 1186 */ 1187static int tm6000_usb_probe(struct usb_interface *interface, 1188 const struct usb_device_id *id) 1189{ 1190 struct usb_device *usbdev; 1191 struct tm6000_core *dev = NULL; 1192 int i, rc = 0; 1193 int nr = 0; 1194 char *speed; 1195 1196 usbdev = usb_get_dev(interface_to_usbdev(interface)); 1197 1198 /* Selects the proper interface */ 1199 rc = usb_set_interface(usbdev, 0, 1); 1200 if (rc < 0) 1201 goto err; 1202 1203 /* Check to see next free device and mark as used */ 1204 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); 1205 if (nr >= TM6000_MAXBOARDS) { 1206 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); 1207 usb_put_dev(usbdev); 1208 return -ENOMEM; 1209 } 1210 1211 /* Create and initialize dev struct */ 1212 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1213 if (dev == NULL) { 1214 printk(KERN_ERR "tm6000" ": out of memory!\n"); 1215 usb_put_dev(usbdev); 1216 return -ENOMEM; 1217 } 1218 spin_lock_init(&dev->slock); 1219 mutex_init(&dev->usb_lock); 1220 1221 /* Increment usage count */ 1222 set_bit(nr, &tm6000_devused); 1223 snprintf(dev->name, 29, "tm6000 #%d", nr); 1224 1225 dev->model = id->driver_info; 1226 if (card[nr] < ARRAY_SIZE(tm6000_boards)) 1227 dev->model = card[nr]; 1228 1229 dev->udev = usbdev; 1230 dev->devno = nr; 1231 1232 switch (usbdev->speed) { 1233 case USB_SPEED_LOW: 1234 speed = "1.5"; 1235 break; 1236 case USB_SPEED_UNKNOWN: 1237 case USB_SPEED_FULL: 1238 speed = "12"; 1239 break; 1240 case USB_SPEED_HIGH: 1241 speed = "480"; 1242 break; 1243 default: 1244 speed = "unknown"; 1245 } 1246 1247 /* Get endpoints */ 1248 for (i = 0; i < interface->num_altsetting; i++) { 1249 int ep; 1250 1251 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { 1252 struct usb_host_endpoint *e; 1253 int dir_out; 1254 1255 e = &interface->altsetting[i].endpoint[ep]; 1256 1257 dir_out = ((e->desc.bEndpointAddress & 1258 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); 1259 1260 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", 1261 i, 1262 interface->altsetting[i].desc.bInterfaceNumber, 1263 interface->altsetting[i].desc.bInterfaceClass); 1264 1265 switch (e->desc.bmAttributes) { 1266 case USB_ENDPOINT_XFER_BULK: 1267 if (!dir_out) { 1268 get_max_endpoint(usbdev, 1269 &interface->altsetting[i], 1270 "Bulk IN", e, 1271 &dev->bulk_in); 1272 } else { 1273 get_max_endpoint(usbdev, 1274 &interface->altsetting[i], 1275 "Bulk OUT", e, 1276 &dev->bulk_out); 1277 } 1278 break; 1279 case USB_ENDPOINT_XFER_ISOC: 1280 if (!dir_out) { 1281 get_max_endpoint(usbdev, 1282 &interface->altsetting[i], 1283 "ISOC IN", e, 1284 &dev->isoc_in); 1285 } else { 1286 get_max_endpoint(usbdev, 1287 &interface->altsetting[i], 1288 "ISOC OUT", e, 1289 &dev->isoc_out); 1290 } 1291 break; 1292 case USB_ENDPOINT_XFER_INT: 1293 if (!dir_out) { 1294 get_max_endpoint(usbdev, 1295 &interface->altsetting[i], 1296 "INT IN", e, 1297 &dev->int_in); 1298 } else { 1299 get_max_endpoint(usbdev, 1300 &interface->altsetting[i], 1301 "INT OUT", e, 1302 &dev->int_out); 1303 } 1304 break; 1305 } 1306 } 1307 } 1308 1309 1310 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", 1311 speed, 1312 le16_to_cpu(dev->udev->descriptor.idVendor), 1313 le16_to_cpu(dev->udev->descriptor.idProduct), 1314 interface->altsetting->desc.bInterfaceNumber); 1315 1316/* check if the the device has the iso in endpoint at the correct place */ 1317 if (!dev->isoc_in.endp) { 1318 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); 1319 rc = -ENODEV; 1320 1321 goto err; 1322 } 1323 1324 /* save our data pointer in this interface device */ 1325 usb_set_intfdata(interface, dev); 1326 1327 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); 1328 1329 rc = tm6000_init_dev(dev); 1330 if (rc < 0) 1331 goto err; 1332 1333 return 0; 1334 1335err: 1336 printk(KERN_ERR "tm6000: Error %d while registering\n", rc); 1337 1338 clear_bit(nr, &tm6000_devused); 1339 usb_put_dev(usbdev); 1340 1341 kfree(dev); 1342 return rc; 1343} 1344 1345/* 1346 * tm6000_usb_disconnect() 1347 * called when the device gets diconencted 1348 * video device will be unregistered on v4l2_close in case it is still open 1349 */ 1350static void tm6000_usb_disconnect(struct usb_interface *interface) 1351{ 1352 struct tm6000_core *dev = usb_get_intfdata(interface); 1353 usb_set_intfdata(interface, NULL); 1354 1355 if (!dev) 1356 return; 1357 1358 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); 1359 1360 flush_request_modules(dev); 1361 1362 tm6000_ir_fini(dev); 1363 1364 if (dev->gpio.power_led) { 1365 switch (dev->model) { 1366 case TM6010_BOARD_HAUPPAUGE_900H: 1367 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 1368 case TM6010_BOARD_TWINHAN_TU501: 1369 /* Power led off */ 1370 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 1371 dev->gpio.power_led, 0x01); 1372 msleep(15); 1373 break; 1374 case TM6010_BOARD_BEHOLD_WANDER: 1375 case TM6010_BOARD_BEHOLD_VOYAGER: 1376 case TM6010_BOARD_BEHOLD_WANDER_LITE: 1377 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 1378 /* Power led off */ 1379 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 1380 dev->gpio.power_led, 0x00); 1381 msleep(15); 1382 break; 1383 } 1384 } 1385 tm6000_v4l2_unregister(dev); 1386 1387 tm6000_i2c_unregister(dev); 1388 1389 v4l2_device_unregister(&dev->v4l2_dev); 1390 1391 dev->state |= DEV_DISCONNECTED; 1392 1393 usb_put_dev(dev->udev); 1394 1395 tm6000_close_extension(dev); 1396 tm6000_remove_from_devlist(dev); 1397 1398 clear_bit(dev->devno, &tm6000_devused); 1399 kfree(dev); 1400} 1401 1402static struct usb_driver tm6000_usb_driver = { 1403 .name = "tm6000", 1404 .probe = tm6000_usb_probe, 1405 .disconnect = tm6000_usb_disconnect, 1406 .id_table = tm6000_id_table, 1407}; 1408 1409module_usb_driver(tm6000_usb_driver); 1410 1411MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); 1412MODULE_AUTHOR("Mauro Carvalho Chehab"); 1413MODULE_LICENSE("GPL"); 1414