0001
0002
0003
0004
0005
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/pci.h>
0009 #include <linux/delay.h>
0010 #include <linux/i2c.h>
0011 #include <linux/usb.h>
0012 #include <linux/slab.h>
0013 #include <media/v4l2-common.h>
0014 #include <media/tuner.h>
0015 #include <media/i2c/tvaudio.h>
0016 #include <media/rc-map.h>
0017
0018 #include "tm6000.h"
0019 #include "tm6000-regs.h"
0020 #include "xc2028.h"
0021 #include "xc5000.h"
0022
0023 #define TM6000_BOARD_UNKNOWN 0
0024 #define TM5600_BOARD_GENERIC 1
0025 #define TM6000_BOARD_GENERIC 2
0026 #define TM6010_BOARD_GENERIC 3
0027 #define TM5600_BOARD_10MOONS_UT821 4
0028 #define TM5600_BOARD_10MOONS_UT330 5
0029 #define TM6000_BOARD_ADSTECH_DUAL_TV 6
0030 #define TM6000_BOARD_FREECOM_AND_SIMILAR 7
0031 #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
0032 #define TM6010_BOARD_HAUPPAUGE_900H 9
0033 #define TM6010_BOARD_BEHOLD_WANDER 10
0034 #define TM6010_BOARD_BEHOLD_VOYAGER 11
0035 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
0036 #define TM6010_BOARD_TWINHAN_TU501 13
0037 #define TM6010_BOARD_BEHOLD_WANDER_LITE 14
0038 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
0039 #define TM5600_BOARD_TERRATEC_GRABSTER 16
0040
0041 #define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
0042 (model == TM5600_BOARD_GENERIC) || \
0043 (model == TM6000_BOARD_GENERIC) || \
0044 (model == TM6010_BOARD_GENERIC))
0045
0046 #define TM6000_MAXBOARDS 16
0047 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
0048
0049 module_param_array(card, int, NULL, 0444);
0050
0051 static unsigned long tm6000_devused;
0052
0053
0054 struct tm6000_board {
0055 char *name;
0056 char eename[16];
0057 unsigned eename_size;
0058 unsigned eename_pos;
0059
0060 struct tm6000_capabilities caps;
0061
0062 enum tm6000_devtype type;
0063 int tuner_type;
0064 int tuner_addr;
0065 int demod_addr;
0066
0067 struct tm6000_gpio gpio;
0068
0069 struct tm6000_input vinput[3];
0070 struct tm6000_input rinput;
0071
0072 char *ir_codes;
0073 };
0074
0075 static struct tm6000_board tm6000_boards[] = {
0076 [TM6000_BOARD_UNKNOWN] = {
0077 .name = "Unknown tm6000 video grabber",
0078 .caps = {
0079 .has_tuner = 1,
0080 .has_eeprom = 1,
0081 },
0082 .gpio = {
0083 .tuner_reset = TM6000_GPIO_1,
0084 },
0085 .vinput = { {
0086 .type = TM6000_INPUT_TV,
0087 .vmux = TM6000_VMUX_VIDEO_B,
0088 .amux = TM6000_AMUX_ADC1,
0089 }, {
0090 .type = TM6000_INPUT_COMPOSITE1,
0091 .vmux = TM6000_VMUX_VIDEO_A,
0092 .amux = TM6000_AMUX_ADC2,
0093 }, {
0094 .type = TM6000_INPUT_SVIDEO,
0095 .vmux = TM6000_VMUX_VIDEO_AB,
0096 .amux = TM6000_AMUX_ADC2,
0097 },
0098 },
0099 },
0100 [TM5600_BOARD_GENERIC] = {
0101 .name = "Generic tm5600 board",
0102 .type = TM5600,
0103 .tuner_type = TUNER_XC2028,
0104 .tuner_addr = 0xc2 >> 1,
0105 .caps = {
0106 .has_tuner = 1,
0107 .has_eeprom = 1,
0108 },
0109 .gpio = {
0110 .tuner_reset = TM6000_GPIO_1,
0111 },
0112 .vinput = { {
0113 .type = TM6000_INPUT_TV,
0114 .vmux = TM6000_VMUX_VIDEO_B,
0115 .amux = TM6000_AMUX_ADC1,
0116 }, {
0117 .type = TM6000_INPUT_COMPOSITE1,
0118 .vmux = TM6000_VMUX_VIDEO_A,
0119 .amux = TM6000_AMUX_ADC2,
0120 }, {
0121 .type = TM6000_INPUT_SVIDEO,
0122 .vmux = TM6000_VMUX_VIDEO_AB,
0123 .amux = TM6000_AMUX_ADC2,
0124 },
0125 },
0126 },
0127 [TM6000_BOARD_GENERIC] = {
0128 .name = "Generic tm6000 board",
0129 .tuner_type = TUNER_XC2028,
0130 .tuner_addr = 0xc2 >> 1,
0131 .caps = {
0132 .has_tuner = 1,
0133 .has_eeprom = 1,
0134 },
0135 .gpio = {
0136 .tuner_reset = TM6000_GPIO_1,
0137 },
0138 .vinput = { {
0139 .type = TM6000_INPUT_TV,
0140 .vmux = TM6000_VMUX_VIDEO_B,
0141 .amux = TM6000_AMUX_ADC1,
0142 }, {
0143 .type = TM6000_INPUT_COMPOSITE1,
0144 .vmux = TM6000_VMUX_VIDEO_A,
0145 .amux = TM6000_AMUX_ADC2,
0146 }, {
0147 .type = TM6000_INPUT_SVIDEO,
0148 .vmux = TM6000_VMUX_VIDEO_AB,
0149 .amux = TM6000_AMUX_ADC2,
0150 },
0151 },
0152 },
0153 [TM6010_BOARD_GENERIC] = {
0154 .name = "Generic tm6010 board",
0155 .type = TM6010,
0156 .tuner_type = TUNER_XC2028,
0157 .tuner_addr = 0xc2 >> 1,
0158 .demod_addr = 0x1e >> 1,
0159 .caps = {
0160 .has_tuner = 1,
0161 .has_dvb = 1,
0162 .has_zl10353 = 1,
0163 .has_eeprom = 1,
0164 .has_remote = 1,
0165 },
0166 .gpio = {
0167 .tuner_reset = TM6010_GPIO_2,
0168 .tuner_on = TM6010_GPIO_3,
0169 .demod_reset = TM6010_GPIO_1,
0170 .demod_on = TM6010_GPIO_4,
0171 .power_led = TM6010_GPIO_7,
0172 .dvb_led = TM6010_GPIO_5,
0173 .ir = TM6010_GPIO_0,
0174 },
0175 .vinput = { {
0176 .type = TM6000_INPUT_TV,
0177 .vmux = TM6000_VMUX_VIDEO_B,
0178 .amux = TM6000_AMUX_SIF1,
0179 }, {
0180 .type = TM6000_INPUT_COMPOSITE1,
0181 .vmux = TM6000_VMUX_VIDEO_A,
0182 .amux = TM6000_AMUX_ADC2,
0183 }, {
0184 .type = TM6000_INPUT_SVIDEO,
0185 .vmux = TM6000_VMUX_VIDEO_AB,
0186 .amux = TM6000_AMUX_ADC2,
0187 },
0188 },
0189 },
0190 [TM5600_BOARD_10MOONS_UT821] = {
0191 .name = "10Moons UT 821",
0192 .tuner_type = TUNER_XC2028,
0193 .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
0194 .eename_size = 14,
0195 .eename_pos = 0x14,
0196 .type = TM5600,
0197 .tuner_addr = 0xc2 >> 1,
0198 .caps = {
0199 .has_tuner = 1,
0200 .has_eeprom = 1,
0201 },
0202 .gpio = {
0203 .tuner_reset = TM6000_GPIO_1,
0204 },
0205 .vinput = { {
0206 .type = TM6000_INPUT_TV,
0207 .vmux = TM6000_VMUX_VIDEO_B,
0208 .amux = TM6000_AMUX_ADC1,
0209 }, {
0210 .type = TM6000_INPUT_COMPOSITE1,
0211 .vmux = TM6000_VMUX_VIDEO_A,
0212 .amux = TM6000_AMUX_ADC2,
0213 }, {
0214 .type = TM6000_INPUT_SVIDEO,
0215 .vmux = TM6000_VMUX_VIDEO_AB,
0216 .amux = TM6000_AMUX_ADC2,
0217 },
0218 },
0219 },
0220 [TM5600_BOARD_10MOONS_UT330] = {
0221 .name = "10Moons UT 330",
0222 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
0223 .tuner_addr = 0xc8 >> 1,
0224 .caps = {
0225 .has_tuner = 1,
0226 .has_dvb = 0,
0227 .has_zl10353 = 0,
0228 .has_eeprom = 1,
0229 },
0230 .vinput = { {
0231 .type = TM6000_INPUT_TV,
0232 .vmux = TM6000_VMUX_VIDEO_B,
0233 .amux = TM6000_AMUX_ADC1,
0234 }, {
0235 .type = TM6000_INPUT_COMPOSITE1,
0236 .vmux = TM6000_VMUX_VIDEO_A,
0237 .amux = TM6000_AMUX_ADC2,
0238 }, {
0239 .type = TM6000_INPUT_SVIDEO,
0240 .vmux = TM6000_VMUX_VIDEO_AB,
0241 .amux = TM6000_AMUX_ADC2,
0242 },
0243 },
0244 },
0245 [TM6000_BOARD_ADSTECH_DUAL_TV] = {
0246 .name = "ADSTECH Dual TV USB",
0247 .tuner_type = TUNER_XC2028,
0248 .tuner_addr = 0xc8 >> 1,
0249 .caps = {
0250 .has_tuner = 1,
0251 .has_tda9874 = 1,
0252 .has_dvb = 1,
0253 .has_zl10353 = 1,
0254 .has_eeprom = 1,
0255 },
0256 .vinput = { {
0257 .type = TM6000_INPUT_TV,
0258 .vmux = TM6000_VMUX_VIDEO_B,
0259 .amux = TM6000_AMUX_ADC1,
0260 }, {
0261 .type = TM6000_INPUT_COMPOSITE1,
0262 .vmux = TM6000_VMUX_VIDEO_A,
0263 .amux = TM6000_AMUX_ADC2,
0264 }, {
0265 .type = TM6000_INPUT_SVIDEO,
0266 .vmux = TM6000_VMUX_VIDEO_AB,
0267 .amux = TM6000_AMUX_ADC2,
0268 },
0269 },
0270 },
0271 [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
0272 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
0273 .tuner_type = TUNER_XC2028,
0274 .tuner_addr = 0xc2 >> 1,
0275 .demod_addr = 0x1e >> 1,
0276 .caps = {
0277 .has_tuner = 1,
0278 .has_dvb = 1,
0279 .has_zl10353 = 1,
0280 .has_eeprom = 0,
0281 .has_remote = 1,
0282 },
0283 .gpio = {
0284 .tuner_reset = TM6000_GPIO_4,
0285 },
0286 .vinput = { {
0287 .type = TM6000_INPUT_TV,
0288 .vmux = TM6000_VMUX_VIDEO_B,
0289 .amux = TM6000_AMUX_ADC1,
0290 }, {
0291 .type = TM6000_INPUT_COMPOSITE1,
0292 .vmux = TM6000_VMUX_VIDEO_A,
0293 .amux = TM6000_AMUX_ADC2,
0294 }, {
0295 .type = TM6000_INPUT_SVIDEO,
0296 .vmux = TM6000_VMUX_VIDEO_AB,
0297 .amux = TM6000_AMUX_ADC2,
0298 },
0299 },
0300 },
0301 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
0302 .name = "ADSTECH Mini Dual TV USB",
0303 .tuner_type = TUNER_XC2028,
0304 .tuner_addr = 0xc8 >> 1,
0305 .demod_addr = 0x1e >> 1,
0306 .caps = {
0307 .has_tuner = 1,
0308 .has_dvb = 1,
0309 .has_zl10353 = 1,
0310 .has_eeprom = 0,
0311 },
0312 .gpio = {
0313 .tuner_reset = TM6000_GPIO_4,
0314 },
0315 .vinput = { {
0316 .type = TM6000_INPUT_TV,
0317 .vmux = TM6000_VMUX_VIDEO_B,
0318 .amux = TM6000_AMUX_ADC1,
0319 }, {
0320 .type = TM6000_INPUT_COMPOSITE1,
0321 .vmux = TM6000_VMUX_VIDEO_A,
0322 .amux = TM6000_AMUX_ADC2,
0323 }, {
0324 .type = TM6000_INPUT_SVIDEO,
0325 .vmux = TM6000_VMUX_VIDEO_AB,
0326 .amux = TM6000_AMUX_ADC2,
0327 },
0328 },
0329 },
0330 [TM6010_BOARD_HAUPPAUGE_900H] = {
0331 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
0332 .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
0333 .eename_size = 14,
0334 .eename_pos = 0x42,
0335 .tuner_type = TUNER_XC2028,
0336 .tuner_addr = 0xc2 >> 1,
0337 .demod_addr = 0x1e >> 1,
0338 .type = TM6010,
0339 .ir_codes = RC_MAP_HAUPPAUGE,
0340 .caps = {
0341 .has_tuner = 1,
0342 .has_dvb = 1,
0343 .has_zl10353 = 1,
0344 .has_eeprom = 1,
0345 .has_remote = 1,
0346 },
0347 .gpio = {
0348 .tuner_reset = TM6010_GPIO_2,
0349 .tuner_on = TM6010_GPIO_3,
0350 .demod_reset = TM6010_GPIO_1,
0351 .demod_on = TM6010_GPIO_4,
0352 .power_led = TM6010_GPIO_7,
0353 .dvb_led = TM6010_GPIO_5,
0354 .ir = TM6010_GPIO_0,
0355 },
0356 .vinput = { {
0357 .type = TM6000_INPUT_TV,
0358 .vmux = TM6000_VMUX_VIDEO_B,
0359 .amux = TM6000_AMUX_SIF1,
0360 }, {
0361 .type = TM6000_INPUT_COMPOSITE1,
0362 .vmux = TM6000_VMUX_VIDEO_A,
0363 .amux = TM6000_AMUX_ADC2,
0364 }, {
0365 .type = TM6000_INPUT_SVIDEO,
0366 .vmux = TM6000_VMUX_VIDEO_AB,
0367 .amux = TM6000_AMUX_ADC2,
0368 },
0369 },
0370 },
0371 [TM6010_BOARD_BEHOLD_WANDER] = {
0372 .name = "Beholder Wander DVB-T/TV/FM USB2.0",
0373 .tuner_type = TUNER_XC5000,
0374 .tuner_addr = 0xc2 >> 1,
0375 .demod_addr = 0x1e >> 1,
0376 .type = TM6010,
0377 .caps = {
0378 .has_tuner = 1,
0379 .has_dvb = 1,
0380 .has_zl10353 = 1,
0381 .has_eeprom = 1,
0382 .has_remote = 1,
0383 .has_radio = 1,
0384 },
0385 .gpio = {
0386 .tuner_reset = TM6010_GPIO_0,
0387 .demod_reset = TM6010_GPIO_1,
0388 .power_led = TM6010_GPIO_6,
0389 },
0390 .vinput = { {
0391 .type = TM6000_INPUT_TV,
0392 .vmux = TM6000_VMUX_VIDEO_B,
0393 .amux = TM6000_AMUX_SIF1,
0394 }, {
0395 .type = TM6000_INPUT_COMPOSITE1,
0396 .vmux = TM6000_VMUX_VIDEO_A,
0397 .amux = TM6000_AMUX_ADC2,
0398 }, {
0399 .type = TM6000_INPUT_SVIDEO,
0400 .vmux = TM6000_VMUX_VIDEO_AB,
0401 .amux = TM6000_AMUX_ADC2,
0402 },
0403 },
0404 .rinput = {
0405 .type = TM6000_INPUT_RADIO,
0406 .amux = TM6000_AMUX_ADC1,
0407 },
0408 },
0409 [TM6010_BOARD_BEHOLD_VOYAGER] = {
0410 .name = "Beholder Voyager TV/FM USB2.0",
0411 .tuner_type = TUNER_XC5000,
0412 .tuner_addr = 0xc2 >> 1,
0413 .type = TM6010,
0414 .caps = {
0415 .has_tuner = 1,
0416 .has_dvb = 0,
0417 .has_zl10353 = 0,
0418 .has_eeprom = 1,
0419 .has_remote = 1,
0420 .has_radio = 1,
0421 },
0422 .gpio = {
0423 .tuner_reset = TM6010_GPIO_0,
0424 .power_led = TM6010_GPIO_6,
0425 },
0426 .vinput = { {
0427 .type = TM6000_INPUT_TV,
0428 .vmux = TM6000_VMUX_VIDEO_B,
0429 .amux = TM6000_AMUX_SIF1,
0430 }, {
0431 .type = TM6000_INPUT_COMPOSITE1,
0432 .vmux = TM6000_VMUX_VIDEO_A,
0433 .amux = TM6000_AMUX_ADC2,
0434 }, {
0435 .type = TM6000_INPUT_SVIDEO,
0436 .vmux = TM6000_VMUX_VIDEO_AB,
0437 .amux = TM6000_AMUX_ADC2,
0438 },
0439 },
0440 .rinput = {
0441 .type = TM6000_INPUT_RADIO,
0442 .amux = TM6000_AMUX_ADC1,
0443 },
0444 },
0445 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
0446 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
0447 .tuner_type = TUNER_XC2028,
0448 .tuner_addr = 0xc2 >> 1,
0449 .demod_addr = 0x1e >> 1,
0450 .type = TM6010,
0451 .caps = {
0452 .has_tuner = 1,
0453 .has_dvb = 1,
0454 .has_zl10353 = 1,
0455 .has_eeprom = 1,
0456 .has_remote = 1,
0457 .has_radio = 1,
0458 },
0459 .gpio = {
0460 .tuner_reset = TM6010_GPIO_2,
0461 .tuner_on = TM6010_GPIO_3,
0462 .demod_reset = TM6010_GPIO_1,
0463 .demod_on = TM6010_GPIO_4,
0464 .power_led = TM6010_GPIO_7,
0465 .dvb_led = TM6010_GPIO_5,
0466 .ir = TM6010_GPIO_0,
0467 },
0468 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
0469 .vinput = { {
0470 .type = TM6000_INPUT_TV,
0471 .vmux = TM6000_VMUX_VIDEO_B,
0472 .amux = TM6000_AMUX_SIF1,
0473 }, {
0474 .type = TM6000_INPUT_COMPOSITE1,
0475 .vmux = TM6000_VMUX_VIDEO_A,
0476 .amux = TM6000_AMUX_ADC2,
0477 }, {
0478 .type = TM6000_INPUT_SVIDEO,
0479 .vmux = TM6000_VMUX_VIDEO_AB,
0480 .amux = TM6000_AMUX_ADC2,
0481 },
0482 },
0483 .rinput = {
0484 .type = TM6000_INPUT_RADIO,
0485 .amux = TM6000_AMUX_SIF1,
0486 },
0487 },
0488 [TM5600_BOARD_TERRATEC_GRABSTER] = {
0489 .name = "Terratec Grabster AV 150/250 MX",
0490 .type = TM5600,
0491 .tuner_type = TUNER_ABSENT,
0492 .vinput = { {
0493 .type = TM6000_INPUT_TV,
0494 .vmux = TM6000_VMUX_VIDEO_B,
0495 .amux = TM6000_AMUX_ADC1,
0496 }, {
0497 .type = TM6000_INPUT_COMPOSITE1,
0498 .vmux = TM6000_VMUX_VIDEO_A,
0499 .amux = TM6000_AMUX_ADC2,
0500 }, {
0501 .type = TM6000_INPUT_SVIDEO,
0502 .vmux = TM6000_VMUX_VIDEO_AB,
0503 .amux = TM6000_AMUX_ADC2,
0504 },
0505 },
0506 },
0507 [TM6010_BOARD_TWINHAN_TU501] = {
0508 .name = "Twinhan TU501(704D1)",
0509 .tuner_type = TUNER_XC2028,
0510 .tuner_addr = 0xc2 >> 1,
0511 .demod_addr = 0x1e >> 1,
0512 .type = TM6010,
0513 .caps = {
0514 .has_tuner = 1,
0515 .has_dvb = 1,
0516 .has_zl10353 = 1,
0517 .has_eeprom = 1,
0518 .has_remote = 1,
0519 },
0520 .gpio = {
0521 .tuner_reset = TM6010_GPIO_2,
0522 .tuner_on = TM6010_GPIO_3,
0523 .demod_reset = TM6010_GPIO_1,
0524 .demod_on = TM6010_GPIO_4,
0525 .power_led = TM6010_GPIO_7,
0526 .dvb_led = TM6010_GPIO_5,
0527 .ir = TM6010_GPIO_0,
0528 },
0529 .vinput = { {
0530 .type = TM6000_INPUT_TV,
0531 .vmux = TM6000_VMUX_VIDEO_B,
0532 .amux = TM6000_AMUX_SIF1,
0533 }, {
0534 .type = TM6000_INPUT_COMPOSITE1,
0535 .vmux = TM6000_VMUX_VIDEO_A,
0536 .amux = TM6000_AMUX_ADC2,
0537 }, {
0538 .type = TM6000_INPUT_SVIDEO,
0539 .vmux = TM6000_VMUX_VIDEO_AB,
0540 .amux = TM6000_AMUX_ADC2,
0541 },
0542 },
0543 },
0544 [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
0545 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
0546 .tuner_type = TUNER_XC5000,
0547 .tuner_addr = 0xc2 >> 1,
0548 .demod_addr = 0x1e >> 1,
0549 .type = TM6010,
0550 .caps = {
0551 .has_tuner = 1,
0552 .has_dvb = 1,
0553 .has_zl10353 = 1,
0554 .has_eeprom = 1,
0555 .has_remote = 0,
0556 .has_radio = 1,
0557 },
0558 .gpio = {
0559 .tuner_reset = TM6010_GPIO_0,
0560 .demod_reset = TM6010_GPIO_1,
0561 .power_led = TM6010_GPIO_6,
0562 },
0563 .vinput = { {
0564 .type = TM6000_INPUT_TV,
0565 .vmux = TM6000_VMUX_VIDEO_B,
0566 .amux = TM6000_AMUX_SIF1,
0567 },
0568 },
0569 .rinput = {
0570 .type = TM6000_INPUT_RADIO,
0571 .amux = TM6000_AMUX_ADC1,
0572 },
0573 },
0574 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
0575 .name = "Beholder Voyager Lite TV/FM USB2.0",
0576 .tuner_type = TUNER_XC5000,
0577 .tuner_addr = 0xc2 >> 1,
0578 .type = TM6010,
0579 .caps = {
0580 .has_tuner = 1,
0581 .has_dvb = 0,
0582 .has_zl10353 = 0,
0583 .has_eeprom = 1,
0584 .has_remote = 0,
0585 .has_radio = 1,
0586 },
0587 .gpio = {
0588 .tuner_reset = TM6010_GPIO_0,
0589 .power_led = TM6010_GPIO_6,
0590 },
0591 .vinput = { {
0592 .type = TM6000_INPUT_TV,
0593 .vmux = TM6000_VMUX_VIDEO_B,
0594 .amux = TM6000_AMUX_SIF1,
0595 },
0596 },
0597 .rinput = {
0598 .type = TM6000_INPUT_RADIO,
0599 .amux = TM6000_AMUX_ADC1,
0600 },
0601 },
0602 };
0603
0604
0605 static const struct usb_device_id tm6000_id_table[] = {
0606 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
0607 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
0608 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
0609 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
0610 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
0611 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
0612 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
0613 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
0614 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
0615 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
0616 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
0617 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
0618 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
0619 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
0620 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
0621 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
0622 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
0623 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
0624 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
0625 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
0626 { }
0627 };
0628 MODULE_DEVICE_TABLE(usb, tm6000_id_table);
0629
0630
0631 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
0632 {
0633
0634 if (!dev->gpio.power_led)
0635 return;
0636
0637
0638 if (state) {
0639 switch (dev->model) {
0640 case TM6010_BOARD_HAUPPAUGE_900H:
0641 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0642 case TM6010_BOARD_TWINHAN_TU501:
0643 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0644 dev->gpio.power_led, 0x00);
0645 break;
0646 case TM6010_BOARD_BEHOLD_WANDER:
0647 case TM6010_BOARD_BEHOLD_VOYAGER:
0648 case TM6010_BOARD_BEHOLD_WANDER_LITE:
0649 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
0650 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0651 dev->gpio.power_led, 0x01);
0652 break;
0653 }
0654 }
0655
0656 else {
0657 switch (dev->model) {
0658 case TM6010_BOARD_HAUPPAUGE_900H:
0659 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0660 case TM6010_BOARD_TWINHAN_TU501:
0661 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0662 dev->gpio.power_led, 0x01);
0663 break;
0664 case TM6010_BOARD_BEHOLD_WANDER:
0665 case TM6010_BOARD_BEHOLD_VOYAGER:
0666 case TM6010_BOARD_BEHOLD_WANDER_LITE:
0667 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
0668 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0669 dev->gpio.power_led, 0x00);
0670 break;
0671 }
0672 }
0673 }
0674
0675
0676 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
0677 {
0678 int rc = 0;
0679 struct tm6000_core *dev = ptr;
0680
0681 if (dev->tuner_type != TUNER_XC5000)
0682 return 0;
0683
0684 switch (command) {
0685 case XC5000_TUNER_RESET:
0686 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0687 dev->gpio.tuner_reset, 0x01);
0688 msleep(15);
0689 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0690 dev->gpio.tuner_reset, 0x00);
0691 msleep(15);
0692 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0693 dev->gpio.tuner_reset, 0x01);
0694 break;
0695 }
0696 return rc;
0697 }
0698 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
0699
0700
0701
0702 int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
0703 {
0704 int rc = 0;
0705 struct tm6000_core *dev = ptr;
0706
0707 if (dev->tuner_type != TUNER_XC2028)
0708 return 0;
0709
0710 switch (command) {
0711 case XC2028_RESET_CLK:
0712 tm6000_ir_wait(dev, 0);
0713
0714 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
0715 0x02, arg);
0716 msleep(10);
0717 rc = tm6000_i2c_reset(dev, 10);
0718 break;
0719 case XC2028_TUNER_RESET:
0720
0721 switch (arg) {
0722 case 0:
0723
0724 switch (dev->model) {
0725 case TM5600_BOARD_10MOONS_UT821:
0726 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0727 dev->gpio.tuner_reset, 0x01);
0728 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0729 0x300, 0x01);
0730 msleep(10);
0731 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0732 dev->gpio.tuner_reset, 0x00);
0733 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0734 0x300, 0x00);
0735 msleep(10);
0736 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0737 dev->gpio.tuner_reset, 0x01);
0738 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0739 0x300, 0x01);
0740 break;
0741 case TM6010_BOARD_HAUPPAUGE_900H:
0742 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0743 case TM6010_BOARD_TWINHAN_TU501:
0744 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0745 dev->gpio.tuner_reset, 0x01);
0746 msleep(60);
0747 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0748 dev->gpio.tuner_reset, 0x00);
0749 msleep(75);
0750 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0751 dev->gpio.tuner_reset, 0x01);
0752 msleep(60);
0753 break;
0754 default:
0755 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0756 dev->gpio.tuner_reset, 0x00);
0757 msleep(130);
0758 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0759 dev->gpio.tuner_reset, 0x01);
0760 msleep(130);
0761 break;
0762 }
0763
0764 tm6000_ir_wait(dev, 1);
0765 break;
0766 case 1:
0767 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
0768 0x02, 0x01);
0769 msleep(10);
0770 break;
0771 case 2:
0772 rc = tm6000_i2c_reset(dev, 100);
0773 break;
0774 }
0775 break;
0776 case XC2028_I2C_FLUSH:
0777 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
0778 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
0779 break;
0780 }
0781 return rc;
0782 }
0783 EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
0784
0785 int tm6000_cards_setup(struct tm6000_core *dev)
0786 {
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796 switch (dev->model) {
0797 case TM6010_BOARD_HAUPPAUGE_900H:
0798 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0799 case TM6010_BOARD_TWINHAN_TU501:
0800 case TM6010_BOARD_GENERIC:
0801
0802 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
0803 msleep(15);
0804
0805 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
0806 msleep(15);
0807
0808 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
0809 msleep(50);
0810 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
0811 msleep(15);
0812
0813 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
0814 msleep(15);
0815
0816 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
0817 msleep(15);
0818
0819 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
0820 msleep(15);
0821
0822 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
0823 msleep(15);
0824
0825 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
0826 msleep(15);
0827 break;
0828 case TM6010_BOARD_BEHOLD_WANDER:
0829 case TM6010_BOARD_BEHOLD_WANDER_LITE:
0830
0831 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
0832 msleep(15);
0833
0834 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
0835 msleep(50);
0836 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
0837 msleep(15);
0838 break;
0839 case TM6010_BOARD_BEHOLD_VOYAGER:
0840 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
0841
0842 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
0843 msleep(15);
0844 break;
0845 default:
0846 break;
0847 }
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857 if (dev->gpio.tuner_reset) {
0858 int rc;
0859 int i;
0860
0861 for (i = 0; i < 2; i++) {
0862 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0863 dev->gpio.tuner_reset, 0x00);
0864 if (rc < 0) {
0865 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
0866 return rc;
0867 }
0868
0869 msleep(10);
0870 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
0871 dev->gpio.tuner_reset, 0x01);
0872 if (rc < 0) {
0873 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
0874 return rc;
0875 }
0876 }
0877 } else {
0878 printk(KERN_ERR "Tuner reset is not configured\n");
0879 return -1;
0880 }
0881
0882 msleep(50);
0883
0884 return 0;
0885 };
0886
0887 static void tm6000_config_tuner(struct tm6000_core *dev)
0888 {
0889 struct tuner_setup tun_setup;
0890
0891
0892 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
0893 "tuner", dev->tuner_addr, NULL);
0894
0895 memset(&tun_setup, 0, sizeof(tun_setup));
0896 tun_setup.type = dev->tuner_type;
0897 tun_setup.addr = dev->tuner_addr;
0898
0899 tun_setup.mode_mask = 0;
0900 if (dev->caps.has_tuner)
0901 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
0902
0903 switch (dev->tuner_type) {
0904 case TUNER_XC2028:
0905 tun_setup.tuner_callback = tm6000_tuner_callback;
0906 break;
0907 case TUNER_XC5000:
0908 tun_setup.tuner_callback = tm6000_xc5000_callback;
0909 break;
0910 }
0911
0912 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
0913
0914 switch (dev->tuner_type) {
0915 case TUNER_XC2028: {
0916 struct v4l2_priv_tun_config xc2028_cfg;
0917 struct xc2028_ctrl ctl;
0918
0919 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
0920 memset(&ctl, 0, sizeof(ctl));
0921
0922 ctl.demod = XC3028_FE_ZARLINK456;
0923
0924 xc2028_cfg.tuner = TUNER_XC2028;
0925 xc2028_cfg.priv = &ctl;
0926
0927 switch (dev->model) {
0928 case TM6010_BOARD_HAUPPAUGE_900H:
0929 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0930 case TM6010_BOARD_TWINHAN_TU501:
0931 ctl.max_len = 80;
0932 ctl.fname = "xc3028L-v36.fw";
0933 break;
0934 default:
0935 if (dev->dev_type == TM6010)
0936 ctl.fname = "xc3028-v27.fw";
0937 else
0938 ctl.fname = "xc3028-v24.fw";
0939 }
0940
0941 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
0942 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
0943 &xc2028_cfg);
0944
0945 }
0946 break;
0947 case TUNER_XC5000:
0948 {
0949 struct v4l2_priv_tun_config xc5000_cfg;
0950 struct xc5000_config ctl = {
0951 .i2c_address = dev->tuner_addr,
0952 .if_khz = 4570,
0953 .radio_input = XC5000_RADIO_FM1_MONO,
0954 };
0955
0956 xc5000_cfg.tuner = TUNER_XC5000;
0957 xc5000_cfg.priv = &ctl;
0958
0959 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
0960 &xc5000_cfg);
0961 }
0962 break;
0963 default:
0964 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
0965 break;
0966 }
0967 }
0968
0969 static int fill_board_specific_data(struct tm6000_core *dev)
0970 {
0971 int rc;
0972
0973 dev->dev_type = tm6000_boards[dev->model].type;
0974 dev->tuner_type = tm6000_boards[dev->model].tuner_type;
0975 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
0976
0977 dev->gpio = tm6000_boards[dev->model].gpio;
0978
0979 dev->ir_codes = tm6000_boards[dev->model].ir_codes;
0980
0981 dev->demod_addr = tm6000_boards[dev->model].demod_addr;
0982
0983 dev->caps = tm6000_boards[dev->model].caps;
0984
0985 dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
0986 dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
0987 dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
0988 dev->rinput = tm6000_boards[dev->model].rinput;
0989
0990
0991 switch (dev->model) {
0992 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
0993 case TM6010_BOARD_HAUPPAUGE_900H:
0994 dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
0995 break;
0996
0997 default:
0998 break;
0999 }
1000
1001
1002 rc = tm6000_init(dev);
1003 if (rc < 0)
1004 return rc;
1005
1006 return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
1007 }
1008
1009
1010 static void use_alternative_detection_method(struct tm6000_core *dev)
1011 {
1012 int i, model = -1;
1013
1014 if (!dev->eedata_size)
1015 return;
1016
1017 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
1018 if (!tm6000_boards[i].eename_size)
1019 continue;
1020 if (dev->eedata_size < tm6000_boards[i].eename_pos +
1021 tm6000_boards[i].eename_size)
1022 continue;
1023
1024 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
1025 tm6000_boards[i].eename,
1026 tm6000_boards[i].eename_size)) {
1027 model = i;
1028 break;
1029 }
1030 }
1031 if (model < 0) {
1032 printk(KERN_INFO "Device has eeprom but is currently unknown\n");
1033 return;
1034 }
1035
1036 dev->model = model;
1037
1038 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
1039 tm6000_boards[model].name, model);
1040 }
1041
1042 #if defined(CONFIG_MODULES) && defined(MODULE)
1043 static void request_module_async(struct work_struct *work)
1044 {
1045 struct tm6000_core *dev = container_of(work, struct tm6000_core,
1046 request_module_wk);
1047
1048 request_module("tm6000-alsa");
1049
1050 if (dev->caps.has_dvb)
1051 request_module("tm6000-dvb");
1052 }
1053
1054 static void request_modules(struct tm6000_core *dev)
1055 {
1056 INIT_WORK(&dev->request_module_wk, request_module_async);
1057 schedule_work(&dev->request_module_wk);
1058 }
1059
1060 static void flush_request_modules(struct tm6000_core *dev)
1061 {
1062 flush_work(&dev->request_module_wk);
1063 }
1064 #else
1065 #define request_modules(dev)
1066 #define flush_request_modules(dev)
1067 #endif
1068
1069 static int tm6000_init_dev(struct tm6000_core *dev)
1070 {
1071 struct v4l2_frequency f;
1072 int rc = 0;
1073
1074 mutex_init(&dev->lock);
1075 mutex_lock(&dev->lock);
1076
1077 if (!is_generic(dev->model)) {
1078 rc = fill_board_specific_data(dev);
1079 if (rc < 0)
1080 goto err;
1081
1082
1083 rc = tm6000_i2c_register(dev);
1084 if (rc < 0)
1085 goto err;
1086 } else {
1087
1088 rc = tm6000_i2c_register(dev);
1089 if (rc < 0)
1090 goto err;
1091
1092 use_alternative_detection_method(dev);
1093
1094 rc = fill_board_specific_data(dev);
1095 if (rc < 0)
1096 goto err;
1097 }
1098
1099
1100 dev->width = 720;
1101 dev->height = 480;
1102 dev->norm = V4L2_STD_NTSC_M;
1103
1104
1105 tm6000_config_tuner(dev);
1106
1107
1108 v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
1109
1110
1111 f.tuner = 0;
1112 f.type = V4L2_TUNER_ANALOG_TV;
1113 f.frequency = 3092;
1114 dev->freq = f.frequency;
1115 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1116
1117 if (dev->caps.has_tda9874)
1118 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1119 "tvaudio", I2C_ADDR_TDA9874, NULL);
1120
1121
1122 rc = tm6000_v4l2_register(dev);
1123 if (rc < 0)
1124 goto err;
1125
1126 tm6000_add_into_devlist(dev);
1127 tm6000_init_extension(dev);
1128
1129 tm6000_ir_init(dev);
1130
1131 request_modules(dev);
1132
1133 mutex_unlock(&dev->lock);
1134 return 0;
1135
1136 err:
1137 mutex_unlock(&dev->lock);
1138 return rc;
1139 }
1140
1141
1142 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1143
1144 static void get_max_endpoint(struct usb_device *udev,
1145 struct usb_host_interface *alt,
1146 char *msgtype,
1147 struct usb_host_endpoint *curr_e,
1148 struct tm6000_endpoint *tm_ep)
1149 {
1150 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1151 unsigned int size = tmp & 0x7ff;
1152
1153 if (udev->speed == USB_SPEED_HIGH)
1154 size = size * hb_mult(tmp);
1155
1156 if (size > tm_ep->maxsize) {
1157 tm_ep->endp = curr_e;
1158 tm_ep->maxsize = size;
1159 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1160 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1161
1162 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1163 msgtype, curr_e->desc.bEndpointAddress,
1164 size);
1165 }
1166 }
1167
1168
1169
1170
1171
1172 static int tm6000_usb_probe(struct usb_interface *interface,
1173 const struct usb_device_id *id)
1174 {
1175 struct usb_device *usbdev;
1176 struct tm6000_core *dev;
1177 int i, rc;
1178 int nr = 0;
1179 char *speed;
1180
1181 usbdev = usb_get_dev(interface_to_usbdev(interface));
1182
1183
1184 rc = usb_set_interface(usbdev, 0, 1);
1185 if (rc < 0)
1186 goto report_failure;
1187
1188
1189 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1190 if (nr >= TM6000_MAXBOARDS) {
1191 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1192 rc = -ENOMEM;
1193 goto put_device;
1194 }
1195
1196
1197 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1198 if (!dev) {
1199 rc = -ENOMEM;
1200 goto put_device;
1201 }
1202 spin_lock_init(&dev->slock);
1203 mutex_init(&dev->usb_lock);
1204
1205
1206 set_bit(nr, &tm6000_devused);
1207 snprintf(dev->name, 29, "tm6000 #%d", nr);
1208
1209 dev->model = id->driver_info;
1210 if (card[nr] < ARRAY_SIZE(tm6000_boards))
1211 dev->model = card[nr];
1212
1213 dev->udev = usbdev;
1214 dev->devno = nr;
1215
1216 switch (usbdev->speed) {
1217 case USB_SPEED_LOW:
1218 speed = "1.5";
1219 break;
1220 case USB_SPEED_UNKNOWN:
1221 case USB_SPEED_FULL:
1222 speed = "12";
1223 break;
1224 case USB_SPEED_HIGH:
1225 speed = "480";
1226 break;
1227 default:
1228 speed = "unknown";
1229 }
1230
1231
1232 for (i = 0; i < interface->num_altsetting; i++) {
1233 int ep;
1234
1235 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1236 struct usb_host_endpoint *e;
1237 int dir_out;
1238
1239 e = &interface->altsetting[i].endpoint[ep];
1240
1241 dir_out = ((e->desc.bEndpointAddress &
1242 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1243
1244 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1245 i,
1246 interface->altsetting[i].desc.bInterfaceNumber,
1247 interface->altsetting[i].desc.bInterfaceClass);
1248
1249 switch (e->desc.bmAttributes) {
1250 case USB_ENDPOINT_XFER_BULK:
1251 if (!dir_out) {
1252 get_max_endpoint(usbdev,
1253 &interface->altsetting[i],
1254 "Bulk IN", e,
1255 &dev->bulk_in);
1256 } else {
1257 get_max_endpoint(usbdev,
1258 &interface->altsetting[i],
1259 "Bulk OUT", e,
1260 &dev->bulk_out);
1261 }
1262 break;
1263 case USB_ENDPOINT_XFER_ISOC:
1264 if (!dir_out) {
1265 get_max_endpoint(usbdev,
1266 &interface->altsetting[i],
1267 "ISOC IN", e,
1268 &dev->isoc_in);
1269 } else {
1270 get_max_endpoint(usbdev,
1271 &interface->altsetting[i],
1272 "ISOC OUT", e,
1273 &dev->isoc_out);
1274 }
1275 break;
1276 case USB_ENDPOINT_XFER_INT:
1277 if (!dir_out) {
1278 get_max_endpoint(usbdev,
1279 &interface->altsetting[i],
1280 "INT IN", e,
1281 &dev->int_in);
1282 } else {
1283 get_max_endpoint(usbdev,
1284 &interface->altsetting[i],
1285 "INT OUT", e,
1286 &dev->int_out);
1287 }
1288 break;
1289 }
1290 }
1291 }
1292
1293
1294 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1295 speed,
1296 le16_to_cpu(dev->udev->descriptor.idVendor),
1297 le16_to_cpu(dev->udev->descriptor.idProduct),
1298 interface->altsetting->desc.bInterfaceNumber);
1299
1300
1301 if (!dev->isoc_in.endp) {
1302 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1303 rc = -ENODEV;
1304 goto free_device;
1305 }
1306
1307
1308 usb_set_intfdata(interface, dev);
1309
1310 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1311
1312 rc = tm6000_init_dev(dev);
1313 if (rc < 0)
1314 goto free_device;
1315
1316 return 0;
1317
1318 free_device:
1319 kfree(dev);
1320 report_failure:
1321 printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1322
1323 clear_bit(nr, &tm6000_devused);
1324 put_device:
1325 usb_put_dev(usbdev);
1326 return rc;
1327 }
1328
1329
1330
1331
1332
1333
1334 static void tm6000_usb_disconnect(struct usb_interface *interface)
1335 {
1336 struct tm6000_core *dev = usb_get_intfdata(interface);
1337 usb_set_intfdata(interface, NULL);
1338
1339 if (!dev)
1340 return;
1341
1342 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1343
1344 flush_request_modules(dev);
1345
1346 tm6000_ir_fini(dev);
1347
1348 if (dev->gpio.power_led) {
1349 switch (dev->model) {
1350 case TM6010_BOARD_HAUPPAUGE_900H:
1351 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1352 case TM6010_BOARD_TWINHAN_TU501:
1353
1354 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1355 dev->gpio.power_led, 0x01);
1356 msleep(15);
1357 break;
1358 case TM6010_BOARD_BEHOLD_WANDER:
1359 case TM6010_BOARD_BEHOLD_VOYAGER:
1360 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1361 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1362
1363 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1364 dev->gpio.power_led, 0x00);
1365 msleep(15);
1366 break;
1367 }
1368 }
1369 tm6000_v4l2_unregister(dev);
1370
1371 tm6000_i2c_unregister(dev);
1372
1373 v4l2_device_unregister(&dev->v4l2_dev);
1374
1375 dev->state |= DEV_DISCONNECTED;
1376
1377 usb_put_dev(dev->udev);
1378
1379 tm6000_close_extension(dev);
1380 tm6000_remove_from_devlist(dev);
1381
1382 clear_bit(dev->devno, &tm6000_devused);
1383 kfree(dev);
1384 }
1385
1386 static struct usb_driver tm6000_usb_driver = {
1387 .name = "tm6000",
1388 .probe = tm6000_usb_probe,
1389 .disconnect = tm6000_usb_disconnect,
1390 .id_table = tm6000_id_table,
1391 };
1392
1393 module_usb_driver(tm6000_usb_driver);
1394
1395 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1396 MODULE_AUTHOR("Mauro Carvalho Chehab");
1397 MODULE_LICENSE("GPL v2");