Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc3 1382 lines 36 kB view raw
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 90struct 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 .caps = { 355 .has_tuner = 1, 356 .has_dvb = 1, 357 .has_zl10353 = 1, 358 .has_eeprom = 1, 359 .has_remote = 1, 360 }, 361 .gpio = { 362 .tuner_reset = TM6010_GPIO_2, 363 .tuner_on = TM6010_GPIO_3, 364 .demod_reset = TM6010_GPIO_1, 365 .demod_on = TM6010_GPIO_4, 366 .power_led = TM6010_GPIO_7, 367 .dvb_led = TM6010_GPIO_5, 368 .ir = TM6010_GPIO_0, 369 }, 370 .vinput = { { 371 .type = TM6000_INPUT_TV, 372 .vmux = TM6000_VMUX_VIDEO_B, 373 .amux = TM6000_AMUX_SIF1, 374 }, { 375 .type = TM6000_INPUT_COMPOSITE1, 376 .vmux = TM6000_VMUX_VIDEO_A, 377 .amux = TM6000_AMUX_ADC2, 378 }, { 379 .type = TM6000_INPUT_SVIDEO, 380 .vmux = TM6000_VMUX_VIDEO_AB, 381 .amux = TM6000_AMUX_ADC2, 382 }, 383 }, 384 }, 385 [TM6010_BOARD_BEHOLD_WANDER] = { 386 .name = "Beholder Wander DVB-T/TV/FM USB2.0", 387 .tuner_type = TUNER_XC5000, 388 .tuner_addr = 0xc2 >> 1, 389 .demod_addr = 0x1e >> 1, 390 .type = TM6010, 391 .caps = { 392 .has_tuner = 1, 393 .has_dvb = 1, 394 .has_zl10353 = 1, 395 .has_eeprom = 1, 396 .has_remote = 1, 397 .has_radio = 1. 398 }, 399 .gpio = { 400 .tuner_reset = TM6010_GPIO_0, 401 .demod_reset = TM6010_GPIO_1, 402 .power_led = TM6010_GPIO_6, 403 }, 404 .vinput = { { 405 .type = TM6000_INPUT_TV, 406 .vmux = TM6000_VMUX_VIDEO_B, 407 .amux = TM6000_AMUX_SIF1, 408 }, { 409 .type = TM6000_INPUT_COMPOSITE1, 410 .vmux = TM6000_VMUX_VIDEO_A, 411 .amux = TM6000_AMUX_ADC2, 412 }, { 413 .type = TM6000_INPUT_SVIDEO, 414 .vmux = TM6000_VMUX_VIDEO_AB, 415 .amux = TM6000_AMUX_ADC2, 416 }, 417 }, 418 .rinput = { 419 .type = TM6000_INPUT_RADIO, 420 .amux = TM6000_AMUX_ADC1, 421 }, 422 }, 423 [TM6010_BOARD_BEHOLD_VOYAGER] = { 424 .name = "Beholder Voyager TV/FM USB2.0", 425 .tuner_type = TUNER_XC5000, 426 .tuner_addr = 0xc2 >> 1, 427 .type = TM6010, 428 .caps = { 429 .has_tuner = 1, 430 .has_dvb = 0, 431 .has_zl10353 = 0, 432 .has_eeprom = 1, 433 .has_remote = 1, 434 .has_radio = 1, 435 }, 436 .gpio = { 437 .tuner_reset = TM6010_GPIO_0, 438 .power_led = TM6010_GPIO_6, 439 }, 440 .vinput = { { 441 .type = TM6000_INPUT_TV, 442 .vmux = TM6000_VMUX_VIDEO_B, 443 .amux = TM6000_AMUX_SIF1, 444 }, { 445 .type = TM6000_INPUT_COMPOSITE1, 446 .vmux = TM6000_VMUX_VIDEO_A, 447 .amux = TM6000_AMUX_ADC2, 448 }, { 449 .type = TM6000_INPUT_SVIDEO, 450 .vmux = TM6000_VMUX_VIDEO_AB, 451 .amux = TM6000_AMUX_ADC2, 452 }, 453 }, 454 .rinput = { 455 .type = TM6000_INPUT_RADIO, 456 .amux = TM6000_AMUX_ADC1, 457 }, 458 }, 459 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { 460 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", 461 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 462 .tuner_addr = 0xc2 >> 1, 463 .demod_addr = 0x1e >> 1, 464 .type = TM6010, 465 .caps = { 466 .has_tuner = 1, 467 .has_dvb = 1, 468 .has_zl10353 = 1, 469 .has_eeprom = 1, 470 .has_remote = 1, 471 }, 472 .gpio = { 473 .tuner_reset = TM6010_GPIO_2, 474 .tuner_on = TM6010_GPIO_3, 475 .demod_reset = TM6010_GPIO_1, 476 .demod_on = TM6010_GPIO_4, 477 .power_led = TM6010_GPIO_7, 478 .dvb_led = TM6010_GPIO_5, 479 .ir = TM6010_GPIO_0, 480 }, 481 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, 482 .vinput = { { 483 .type = TM6000_INPUT_TV, 484 .vmux = TM6000_VMUX_VIDEO_B, 485 .amux = TM6000_AMUX_SIF1, 486 }, { 487 .type = TM6000_INPUT_COMPOSITE1, 488 .vmux = TM6000_VMUX_VIDEO_A, 489 .amux = TM6000_AMUX_ADC2, 490 }, { 491 .type = TM6000_INPUT_SVIDEO, 492 .vmux = TM6000_VMUX_VIDEO_AB, 493 .amux = TM6000_AMUX_ADC2, 494 }, 495 }, 496 }, 497 [TM5600_BOARD_TERRATEC_GRABSTER] = { 498 .name = "Terratec Grabster AV 150/250 MX", 499 .type = TM5600, 500 .tuner_type = TUNER_ABSENT, 501 .vinput = { { 502 .type = TM6000_INPUT_TV, 503 .vmux = TM6000_VMUX_VIDEO_B, 504 .amux = TM6000_AMUX_ADC1, 505 }, { 506 .type = TM6000_INPUT_COMPOSITE1, 507 .vmux = TM6000_VMUX_VIDEO_A, 508 .amux = TM6000_AMUX_ADC2, 509 }, { 510 .type = TM6000_INPUT_SVIDEO, 511 .vmux = TM6000_VMUX_VIDEO_AB, 512 .amux = TM6000_AMUX_ADC2, 513 }, 514 }, 515 }, 516 [TM6010_BOARD_TWINHAN_TU501] = { 517 .name = "Twinhan TU501(704D1)", 518 .tuner_type = TUNER_XC2028, /* has a XC3028 */ 519 .tuner_addr = 0xc2 >> 1, 520 .demod_addr = 0x1e >> 1, 521 .type = TM6010, 522 .caps = { 523 .has_tuner = 1, 524 .has_dvb = 1, 525 .has_zl10353 = 1, 526 .has_eeprom = 1, 527 .has_remote = 1, 528 }, 529 .gpio = { 530 .tuner_reset = TM6010_GPIO_2, 531 .tuner_on = TM6010_GPIO_3, 532 .demod_reset = TM6010_GPIO_1, 533 .demod_on = TM6010_GPIO_4, 534 .power_led = TM6010_GPIO_7, 535 .dvb_led = TM6010_GPIO_5, 536 .ir = TM6010_GPIO_0, 537 }, 538 .vinput = { { 539 .type = TM6000_INPUT_TV, 540 .vmux = TM6000_VMUX_VIDEO_B, 541 .amux = TM6000_AMUX_SIF1, 542 }, { 543 .type = TM6000_INPUT_COMPOSITE1, 544 .vmux = TM6000_VMUX_VIDEO_A, 545 .amux = TM6000_AMUX_ADC2, 546 }, { 547 .type = TM6000_INPUT_SVIDEO, 548 .vmux = TM6000_VMUX_VIDEO_AB, 549 .amux = TM6000_AMUX_ADC2, 550 }, 551 }, 552 }, 553 [TM6010_BOARD_BEHOLD_WANDER_LITE] = { 554 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", 555 .tuner_type = TUNER_XC5000, 556 .tuner_addr = 0xc2 >> 1, 557 .demod_addr = 0x1e >> 1, 558 .type = TM6010, 559 .caps = { 560 .has_tuner = 1, 561 .has_dvb = 1, 562 .has_zl10353 = 1, 563 .has_eeprom = 1, 564 .has_remote = 0, 565 .has_radio = 1, 566 }, 567 .gpio = { 568 .tuner_reset = TM6010_GPIO_0, 569 .demod_reset = TM6010_GPIO_1, 570 .power_led = TM6010_GPIO_6, 571 }, 572 .vinput = { { 573 .type = TM6000_INPUT_TV, 574 .vmux = TM6000_VMUX_VIDEO_B, 575 .amux = TM6000_AMUX_SIF1, 576 }, 577 }, 578 .rinput = { 579 .type = TM6000_INPUT_RADIO, 580 .amux = TM6000_AMUX_ADC1, 581 }, 582 }, 583 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { 584 .name = "Beholder Voyager Lite TV/FM USB2.0", 585 .tuner_type = TUNER_XC5000, 586 .tuner_addr = 0xc2 >> 1, 587 .type = TM6010, 588 .caps = { 589 .has_tuner = 1, 590 .has_dvb = 0, 591 .has_zl10353 = 0, 592 .has_eeprom = 1, 593 .has_remote = 0, 594 .has_radio = 1, 595 }, 596 .gpio = { 597 .tuner_reset = TM6010_GPIO_0, 598 .power_led = TM6010_GPIO_6, 599 }, 600 .vinput = { { 601 .type = TM6000_INPUT_TV, 602 .vmux = TM6000_VMUX_VIDEO_B, 603 .amux = TM6000_AMUX_SIF1, 604 }, 605 }, 606 .rinput = { 607 .type = TM6000_INPUT_RADIO, 608 .amux = TM6000_AMUX_ADC1, 609 }, 610 }, 611}; 612 613/* table of devices that work with this driver */ 614struct usb_device_id tm6000_id_table[] = { 615 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, 616 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, 617 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, 618 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, 619 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, 620 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 621 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 622 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 623 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, 624 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, 625 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, 626 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 627 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, 628 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, 629 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 630 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 631 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 632 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, 633 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, 634 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, 635 { }, 636}; 637 638/* Control power led for show some activity */ 639void tm6000_flash_led(struct tm6000_core *dev, u8 state) 640{ 641 /* Power LED unconfigured */ 642 if (!dev->gpio.power_led) 643 return; 644 645 /* ON Power LED */ 646 if (state) { 647 switch (dev->model) { 648 case TM6010_BOARD_HAUPPAUGE_900H: 649 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 650 case TM6010_BOARD_TWINHAN_TU501: 651 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 652 dev->gpio.power_led, 0x00); 653 break; 654 case TM6010_BOARD_BEHOLD_WANDER: 655 case TM6010_BOARD_BEHOLD_VOYAGER: 656 case TM6010_BOARD_BEHOLD_WANDER_LITE: 657 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 658 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 659 dev->gpio.power_led, 0x01); 660 break; 661 } 662 } 663 /* OFF Power LED */ 664 else { 665 switch (dev->model) { 666 case TM6010_BOARD_HAUPPAUGE_900H: 667 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 668 case TM6010_BOARD_TWINHAN_TU501: 669 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 670 dev->gpio.power_led, 0x01); 671 break; 672 case TM6010_BOARD_BEHOLD_WANDER: 673 case TM6010_BOARD_BEHOLD_VOYAGER: 674 case TM6010_BOARD_BEHOLD_WANDER_LITE: 675 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 676 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 677 dev->gpio.power_led, 0x00); 678 break; 679 } 680 } 681} 682 683/* Tuner callback to provide the proper gpio changes needed for xc5000 */ 684int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) 685{ 686 int rc = 0; 687 struct tm6000_core *dev = ptr; 688 689 if (dev->tuner_type != TUNER_XC5000) 690 return 0; 691 692 switch (command) { 693 case XC5000_TUNER_RESET: 694 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 695 dev->gpio.tuner_reset, 0x01); 696 msleep(15); 697 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 698 dev->gpio.tuner_reset, 0x00); 699 msleep(15); 700 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 701 dev->gpio.tuner_reset, 0x01); 702 break; 703 } 704 return rc; 705} 706EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); 707 708/* Tuner callback to provide the proper gpio changes needed for xc2028 */ 709 710int tm6000_tuner_callback(void *ptr, int component, int command, int arg) 711{ 712 int rc = 0; 713 struct tm6000_core *dev = ptr; 714 715 if (dev->tuner_type != TUNER_XC2028) 716 return 0; 717 718 switch (command) { 719 case XC2028_RESET_CLK: 720 tm6000_ir_wait(dev, 0); 721 722 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 723 0x02, arg); 724 msleep(10); 725 rc = tm6000_i2c_reset(dev, 10); 726 break; 727 case XC2028_TUNER_RESET: 728 /* Reset codes during load firmware */ 729 switch (arg) { 730 case 0: 731 /* newer tuner can faster reset */ 732 switch (dev->model) { 733 case TM5600_BOARD_10MOONS_UT821: 734 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 735 dev->gpio.tuner_reset, 0x01); 736 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 737 0x300, 0x01); 738 msleep(10); 739 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 740 dev->gpio.tuner_reset, 0x00); 741 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 742 0x300, 0x00); 743 msleep(10); 744 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 745 dev->gpio.tuner_reset, 0x01); 746 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 747 0x300, 0x01); 748 break; 749 case TM6010_BOARD_HAUPPAUGE_900H: 750 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 751 case TM6010_BOARD_TWINHAN_TU501: 752 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 753 dev->gpio.tuner_reset, 0x01); 754 msleep(60); 755 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 756 dev->gpio.tuner_reset, 0x00); 757 msleep(75); 758 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 759 dev->gpio.tuner_reset, 0x01); 760 msleep(60); 761 break; 762 default: 763 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 764 dev->gpio.tuner_reset, 0x00); 765 msleep(130); 766 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 767 dev->gpio.tuner_reset, 0x01); 768 msleep(130); 769 break; 770 } 771 772 tm6000_ir_wait(dev, 1); 773 break; 774 case 1: 775 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 776 0x02, 0x01); 777 msleep(10); 778 break; 779 case 2: 780 rc = tm6000_i2c_reset(dev, 100); 781 break; 782 } 783 } 784 return rc; 785} 786EXPORT_SYMBOL_GPL(tm6000_tuner_callback); 787 788int tm6000_cards_setup(struct tm6000_core *dev) 789{ 790 int i, rc; 791 792 /* 793 * Board-specific initialization sequence. Handles all GPIO 794 * initialization sequences that are board-specific. 795 * Up to now, all found devices use GPIO1 and GPIO4 at the same way. 796 * Probably, they're all based on some reference device. Due to that, 797 * there's a common routine at the end to handle those GPIO's. Devices 798 * that use different pinups or init sequences can just return at 799 * the board-specific session. 800 */ 801 switch (dev->model) { 802 case TM6010_BOARD_HAUPPAUGE_900H: 803 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 804 case TM6010_BOARD_TWINHAN_TU501: 805 case TM6010_BOARD_GENERIC: 806 /* Turn xceive 3028 on */ 807 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); 808 msleep(15); 809 /* Turn zarlink zl10353 on */ 810 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 811 msleep(15); 812 /* Reset zarlink zl10353 */ 813 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 814 msleep(50); 815 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 816 msleep(15); 817 /* Turn zarlink zl10353 off */ 818 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); 819 msleep(15); 820 /* ir ? */ 821 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); 822 msleep(15); 823 /* Power led on (blue) */ 824 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); 825 msleep(15); 826 /* DVB led off (orange) */ 827 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); 828 msleep(15); 829 /* Turn zarlink zl10353 on */ 830 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); 831 msleep(15); 832 break; 833 case TM6010_BOARD_BEHOLD_WANDER: 834 case TM6010_BOARD_BEHOLD_WANDER_LITE: 835 /* Power led on (blue) */ 836 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 837 msleep(15); 838 /* Reset zarlink zl10353 */ 839 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); 840 msleep(50); 841 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); 842 msleep(15); 843 break; 844 case TM6010_BOARD_BEHOLD_VOYAGER: 845 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 846 /* Power led on (blue) */ 847 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); 848 msleep(15); 849 break; 850 default: 851 break; 852 } 853 854 /* 855 * Default initialization. Most of the devices seem to use GPIO1 856 * and GPIO4.on the same way, so, this handles the common sequence 857 * used by most devices. 858 * If a device uses a different sequence or different GPIO pins for 859 * reset, just add the code at the board-specific part 860 */ 861 862 if (dev->gpio.tuner_reset) { 863 for (i = 0; i < 2; i++) { 864 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 865 dev->gpio.tuner_reset, 0x00); 866 if (rc < 0) { 867 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 868 return rc; 869 } 870 871 msleep(10); /* Just to be conservative */ 872 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 873 dev->gpio.tuner_reset, 0x01); 874 if (rc < 0) { 875 printk(KERN_ERR "Error %i doing tuner reset\n", rc); 876 return rc; 877 } 878 } 879 } else { 880 printk(KERN_ERR "Tuner reset is not configured\n"); 881 return -1; 882 } 883 884 msleep(50); 885 886 return 0; 887}; 888 889static void tm6000_config_tuner(struct tm6000_core *dev) 890{ 891 struct tuner_setup tun_setup; 892 893 /* Load tuner module */ 894 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 895 "tuner", dev->tuner_addr, NULL); 896 897 memset(&tun_setup, 0, sizeof(tun_setup)); 898 tun_setup.type = dev->tuner_type; 899 tun_setup.addr = dev->tuner_addr; 900 901 tun_setup.mode_mask = 0; 902 if (dev->caps.has_tuner) 903 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); 904 905 switch (dev->tuner_type) { 906 case TUNER_XC2028: 907 tun_setup.tuner_callback = tm6000_tuner_callback; 908 break; 909 case TUNER_XC5000: 910 tun_setup.tuner_callback = tm6000_xc5000_callback; 911 break; 912 } 913 914 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); 915 916 switch (dev->tuner_type) { 917 case TUNER_XC2028: { 918 struct v4l2_priv_tun_config xc2028_cfg; 919 struct xc2028_ctrl ctl; 920 921 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); 922 memset(&ctl, 0, sizeof(ctl)); 923 924 ctl.demod = XC3028_FE_ZARLINK456; 925 926 xc2028_cfg.tuner = TUNER_XC2028; 927 xc2028_cfg.priv = &ctl; 928 929 switch (dev->model) { 930 case TM6010_BOARD_HAUPPAUGE_900H: 931 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 932 case TM6010_BOARD_TWINHAN_TU501: 933 ctl.fname = "xc3028L-v36.fw"; 934 break; 935 default: 936 if (dev->dev_type == TM6010) 937 ctl.fname = "xc3028-v27.fw"; 938 else 939 ctl.fname = "xc3028-v24.fw"; 940 } 941 942 printk(KERN_INFO "Setting firmware parameters for xc2028\n"); 943 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 944 &xc2028_cfg); 945 946 } 947 break; 948 case TUNER_XC5000: 949 { 950 struct v4l2_priv_tun_config xc5000_cfg; 951 struct xc5000_config ctl = { 952 .i2c_address = dev->tuner_addr, 953 .if_khz = 4570, 954 .radio_input = XC5000_RADIO_FM1_MONO, 955 }; 956 957 xc5000_cfg.tuner = TUNER_XC5000; 958 xc5000_cfg.priv = &ctl; 959 960 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 961 &xc5000_cfg); 962 } 963 break; 964 default: 965 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); 966 break; 967 } 968} 969 970static int fill_board_specific_data(struct tm6000_core *dev) 971{ 972 int rc; 973 974 dev->dev_type = tm6000_boards[dev->model].type; 975 dev->tuner_type = tm6000_boards[dev->model].tuner_type; 976 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; 977 978 dev->gpio = tm6000_boards[dev->model].gpio; 979 980 dev->ir_codes = tm6000_boards[dev->model].ir_codes; 981 982 dev->demod_addr = tm6000_boards[dev->model].demod_addr; 983 984 dev->caps = tm6000_boards[dev->model].caps; 985 986 dev->vinput[0] = tm6000_boards[dev->model].vinput[0]; 987 dev->vinput[1] = tm6000_boards[dev->model].vinput[1]; 988 dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; 989 dev->rinput = tm6000_boards[dev->model].rinput; 990 991 /* initialize hardware */ 992 rc = tm6000_init(dev); 993 if (rc < 0) 994 return rc; 995 996 return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); 997} 998 999 1000static void use_alternative_detection_method(struct tm6000_core *dev) 1001{ 1002 int i, model = -1; 1003 1004 if (!dev->eedata_size) 1005 return; 1006 1007 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) { 1008 if (!tm6000_boards[i].eename_size) 1009 continue; 1010 if (dev->eedata_size < tm6000_boards[i].eename_pos + 1011 tm6000_boards[i].eename_size) 1012 continue; 1013 1014 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos], 1015 tm6000_boards[i].eename, 1016 tm6000_boards[i].eename_size)) { 1017 model = i; 1018 break; 1019 } 1020 } 1021 if (model < 0) { 1022 printk(KERN_INFO "Device has eeprom but is currently unknown\n"); 1023 return; 1024 } 1025 1026 dev->model = model; 1027 1028 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n", 1029 tm6000_boards[model].name, model); 1030} 1031 1032static int tm6000_init_dev(struct tm6000_core *dev) 1033{ 1034 struct v4l2_frequency f; 1035 int rc = 0; 1036 1037 mutex_init(&dev->lock); 1038 mutex_lock(&dev->lock); 1039 1040 if (!is_generic(dev->model)) { 1041 rc = fill_board_specific_data(dev); 1042 if (rc < 0) 1043 goto err; 1044 1045 /* register i2c bus */ 1046 rc = tm6000_i2c_register(dev); 1047 if (rc < 0) 1048 goto err; 1049 } else { 1050 /* register i2c bus */ 1051 rc = tm6000_i2c_register(dev); 1052 if (rc < 0) 1053 goto err; 1054 1055 use_alternative_detection_method(dev); 1056 1057 rc = fill_board_specific_data(dev); 1058 if (rc < 0) 1059 goto err; 1060 } 1061 1062 /* Default values for STD and resolutions */ 1063 dev->width = 720; 1064 dev->height = 480; 1065 dev->norm = V4L2_STD_PAL_M; 1066 1067 /* Configure tuner */ 1068 tm6000_config_tuner(dev); 1069 1070 /* Set video standard */ 1071 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); 1072 1073 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ 1074 f.tuner = 0; 1075 f.type = V4L2_TUNER_ANALOG_TV; 1076 f.frequency = 3092; /* 193.25 MHz */ 1077 dev->freq = f.frequency; 1078 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); 1079 1080 if (dev->caps.has_tda9874) 1081 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 1082 "tvaudio", I2C_ADDR_TDA9874, NULL); 1083 1084 /* register and initialize V4L2 */ 1085 rc = tm6000_v4l2_register(dev); 1086 if (rc < 0) 1087 goto err; 1088 1089 tm6000_add_into_devlist(dev); 1090 tm6000_init_extension(dev); 1091 1092 tm6000_ir_init(dev); 1093 1094 mutex_unlock(&dev->lock); 1095 return 0; 1096 1097err: 1098 mutex_unlock(&dev->lock); 1099 return rc; 1100} 1101 1102/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ 1103#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) 1104 1105static void get_max_endpoint(struct usb_device *udev, 1106 struct usb_host_interface *alt, 1107 char *msgtype, 1108 struct usb_host_endpoint *curr_e, 1109 struct tm6000_endpoint *tm_ep) 1110{ 1111 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); 1112 unsigned int size = tmp & 0x7ff; 1113 1114 if (udev->speed == USB_SPEED_HIGH) 1115 size = size * hb_mult(tmp); 1116 1117 if (size > tm_ep->maxsize) { 1118 tm_ep->endp = curr_e; 1119 tm_ep->maxsize = size; 1120 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; 1121 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; 1122 1123 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", 1124 msgtype, curr_e->desc.bEndpointAddress, 1125 size); 1126 } 1127} 1128 1129/* 1130 * tm6000_usb_probe() 1131 * checks for supported devices 1132 */ 1133static int tm6000_usb_probe(struct usb_interface *interface, 1134 const struct usb_device_id *id) 1135{ 1136 struct usb_device *usbdev; 1137 struct tm6000_core *dev = NULL; 1138 int i, rc = 0; 1139 int nr = 0; 1140 char *speed; 1141 1142 usbdev = usb_get_dev(interface_to_usbdev(interface)); 1143 1144 /* Selects the proper interface */ 1145 rc = usb_set_interface(usbdev, 0, 1); 1146 if (rc < 0) 1147 goto err; 1148 1149 /* Check to see next free device and mark as used */ 1150 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); 1151 if (nr >= TM6000_MAXBOARDS) { 1152 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); 1153 usb_put_dev(usbdev); 1154 return -ENOMEM; 1155 } 1156 1157 /* Create and initialize dev struct */ 1158 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1159 if (dev == NULL) { 1160 printk(KERN_ERR "tm6000" ": out of memory!\n"); 1161 usb_put_dev(usbdev); 1162 return -ENOMEM; 1163 } 1164 spin_lock_init(&dev->slock); 1165 1166 /* Increment usage count */ 1167 tm6000_devused |= 1<<nr; 1168 snprintf(dev->name, 29, "tm6000 #%d", nr); 1169 1170 dev->model = id->driver_info; 1171 if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards))) 1172 dev->model = card[nr]; 1173 1174 dev->udev = usbdev; 1175 dev->devno = nr; 1176 1177 switch (usbdev->speed) { 1178 case USB_SPEED_LOW: 1179 speed = "1.5"; 1180 break; 1181 case USB_SPEED_UNKNOWN: 1182 case USB_SPEED_FULL: 1183 speed = "12"; 1184 break; 1185 case USB_SPEED_HIGH: 1186 speed = "480"; 1187 break; 1188 default: 1189 speed = "unknown"; 1190 } 1191 1192 1193 1194 /* Get endpoints */ 1195 for (i = 0; i < interface->num_altsetting; i++) { 1196 int ep; 1197 1198 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { 1199 struct usb_host_endpoint *e; 1200 int dir_out; 1201 1202 e = &interface->altsetting[i].endpoint[ep]; 1203 1204 dir_out = ((e->desc.bEndpointAddress & 1205 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); 1206 1207 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", 1208 i, 1209 interface->altsetting[i].desc.bInterfaceNumber, 1210 interface->altsetting[i].desc.bInterfaceClass); 1211 1212 switch (e->desc.bmAttributes) { 1213 case USB_ENDPOINT_XFER_BULK: 1214 if (!dir_out) { 1215 get_max_endpoint(usbdev, 1216 &interface->altsetting[i], 1217 "Bulk IN", e, 1218 &dev->bulk_in); 1219 } else { 1220 get_max_endpoint(usbdev, 1221 &interface->altsetting[i], 1222 "Bulk OUT", e, 1223 &dev->bulk_out); 1224 } 1225 break; 1226 case USB_ENDPOINT_XFER_ISOC: 1227 if (!dir_out) { 1228 get_max_endpoint(usbdev, 1229 &interface->altsetting[i], 1230 "ISOC IN", e, 1231 &dev->isoc_in); 1232 } else { 1233 get_max_endpoint(usbdev, 1234 &interface->altsetting[i], 1235 "ISOC OUT", e, 1236 &dev->isoc_out); 1237 } 1238 break; 1239 case USB_ENDPOINT_XFER_INT: 1240 if (!dir_out) { 1241 get_max_endpoint(usbdev, 1242 &interface->altsetting[i], 1243 "INT IN", e, 1244 &dev->int_in); 1245 } else { 1246 get_max_endpoint(usbdev, 1247 &interface->altsetting[i], 1248 "INT OUT", e, 1249 &dev->int_out); 1250 } 1251 break; 1252 } 1253 } 1254 } 1255 1256 1257 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", 1258 speed, 1259 le16_to_cpu(dev->udev->descriptor.idVendor), 1260 le16_to_cpu(dev->udev->descriptor.idProduct), 1261 interface->altsetting->desc.bInterfaceNumber); 1262 1263/* check if the the device has the iso in endpoint at the correct place */ 1264 if (!dev->isoc_in.endp) { 1265 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); 1266 rc = -ENODEV; 1267 1268 goto err; 1269 } 1270 1271 /* save our data pointer in this interface device */ 1272 usb_set_intfdata(interface, dev); 1273 1274 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); 1275 1276 rc = tm6000_init_dev(dev); 1277 1278 if (rc < 0) 1279 goto err; 1280 1281 return 0; 1282 1283err: 1284 printk(KERN_ERR "tm6000: Error %d while registering\n", rc); 1285 1286 tm6000_devused &= ~(1<<nr); 1287 usb_put_dev(usbdev); 1288 1289 kfree(dev); 1290 return rc; 1291} 1292 1293/* 1294 * tm6000_usb_disconnect() 1295 * called when the device gets diconencted 1296 * video device will be unregistered on v4l2_close in case it is still open 1297 */ 1298static void tm6000_usb_disconnect(struct usb_interface *interface) 1299{ 1300 struct tm6000_core *dev = usb_get_intfdata(interface); 1301 usb_set_intfdata(interface, NULL); 1302 1303 if (!dev) 1304 return; 1305 1306 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); 1307 1308 tm6000_ir_fini(dev); 1309 1310 if (dev->gpio.power_led) { 1311 switch (dev->model) { 1312 case TM6010_BOARD_HAUPPAUGE_900H: 1313 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: 1314 case TM6010_BOARD_TWINHAN_TU501: 1315 /* Power led off */ 1316 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 1317 dev->gpio.power_led, 0x01); 1318 msleep(15); 1319 break; 1320 case TM6010_BOARD_BEHOLD_WANDER: 1321 case TM6010_BOARD_BEHOLD_VOYAGER: 1322 case TM6010_BOARD_BEHOLD_WANDER_LITE: 1323 case TM6010_BOARD_BEHOLD_VOYAGER_LITE: 1324 /* Power led off */ 1325 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 1326 dev->gpio.power_led, 0x00); 1327 msleep(15); 1328 break; 1329 } 1330 } 1331 tm6000_v4l2_unregister(dev); 1332 1333 tm6000_i2c_unregister(dev); 1334 1335 v4l2_device_unregister(&dev->v4l2_dev); 1336 1337 dev->state |= DEV_DISCONNECTED; 1338 1339 usb_put_dev(dev->udev); 1340 1341 tm6000_close_extension(dev); 1342 tm6000_remove_from_devlist(dev); 1343 1344 kfree(dev); 1345} 1346 1347static struct usb_driver tm6000_usb_driver = { 1348 .name = "tm6000", 1349 .probe = tm6000_usb_probe, 1350 .disconnect = tm6000_usb_disconnect, 1351 .id_table = tm6000_id_table, 1352}; 1353 1354static int __init tm6000_module_init(void) 1355{ 1356 int result; 1357 1358 printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n", 1359 (TM6000_VERSION >> 16) & 0xff, 1360 (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff); 1361 1362 /* register this driver with the USB subsystem */ 1363 result = usb_register(&tm6000_usb_driver); 1364 if (result) 1365 printk(KERN_ERR "tm6000" 1366 " usb_register failed. Error number %d.\n", result); 1367 1368 return result; 1369} 1370 1371static void __exit tm6000_module_exit(void) 1372{ 1373 /* deregister at USB subsystem */ 1374 usb_deregister(&tm6000_usb_driver); 1375} 1376 1377module_init(tm6000_module_init); 1378module_exit(tm6000_module_exit); 1379 1380MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); 1381MODULE_AUTHOR("Mauro Carvalho Chehab"); 1382MODULE_LICENSE("GPL");