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