2 * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
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
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.
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.
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>
35 #include "tm6000-regs.h"
36 #include "tuner-xc2028.h"
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
57 #define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
58 (model == TM5600_BOARD_GENERIC) || \
59 (model == TM6000_BOARD_GENERIC) || \
60 (model == TM6010_BOARD_GENERIC))
62 #define TM6000_MAXBOARDS 16
63 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
65 module_param_array(card, int, NULL, 0444);
67 static unsigned long tm6000_devused;
72 char eename[16]; /* EEPROM name */
73 unsigned eename_size; /* size of EEPROM name */
74 unsigned eename_pos; /* Position where it appears at ROM */
76 struct tm6000_capabilities caps;
77 enum tm6000_inaudio aradio;
78 enum tm6000_inaudio avideo;
80 enum tm6000_devtype type; /* variant of the chipset */
81 int tuner_type; /* type of the tuner */
82 int tuner_addr; /* tuner address */
83 int demod_addr; /* demodulator address */
85 struct tm6000_gpio gpio;
90 struct tm6000_board tm6000_boards[] = {
91 [TM6000_BOARD_UNKNOWN] = {
92 .name = "Unknown tm6000 video grabber",
97 .tuner_reset = TM6000_GPIO_1,
100 [TM5600_BOARD_GENERIC] = {
101 .name = "Generic tm5600 board",
103 .tuner_type = TUNER_XC2028,
104 .tuner_addr = 0xc2 >> 1,
109 .tuner_reset = TM6000_GPIO_1,
112 [TM6000_BOARD_GENERIC] = {
113 .name = "Generic tm6000 board",
114 .tuner_type = TUNER_XC2028,
115 .tuner_addr = 0xc2 >> 1,
121 .tuner_reset = TM6000_GPIO_1,
124 [TM6010_BOARD_GENERIC] = {
125 .name = "Generic tm6010 board",
127 .tuner_type = TUNER_XC2028,
128 .tuner_addr = 0xc2 >> 1,
129 .demod_addr = 0x1e >> 1,
138 .tuner_reset = TM6010_GPIO_2,
139 .tuner_on = TM6010_GPIO_3,
140 .demod_reset = TM6010_GPIO_1,
141 .demod_on = TM6010_GPIO_4,
142 .power_led = TM6010_GPIO_7,
143 .dvb_led = TM6010_GPIO_5,
147 [TM5600_BOARD_10MOONS_UT821] = {
148 .name = "10Moons UT 821",
149 .tuner_type = TUNER_XC2028,
150 .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
154 .tuner_addr = 0xc2 >> 1,
160 .tuner_reset = TM6000_GPIO_1,
163 [TM5600_BOARD_10MOONS_UT330] = {
164 .name = "10Moons UT 330",
165 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
166 .tuner_addr = 0xc8 >> 1,
174 [TM6000_BOARD_ADSTECH_DUAL_TV] = {
175 .name = "ADSTECH Dual TV USB",
176 .tuner_type = TUNER_XC2028,
177 .tuner_addr = 0xc8 >> 1,
186 [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
187 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
188 .tuner_type = TUNER_XC2028, /* has a XC3028 */
189 .tuner_addr = 0xc2 >> 1,
190 .demod_addr = 0x1e >> 1,
199 .tuner_reset = TM6000_GPIO_4,
202 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
203 .name = "ADSTECH Mini Dual TV USB",
204 .tuner_type = TUNER_XC2028, /* has a XC3028 */
205 .tuner_addr = 0xc8 >> 1,
206 .demod_addr = 0x1e >> 1,
214 .tuner_reset = TM6000_GPIO_4,
217 [TM6010_BOARD_HAUPPAUGE_900H] = {
218 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
219 .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
222 .tuner_type = TUNER_XC2028, /* has a XC3028 */
223 .tuner_addr = 0xc2 >> 1,
224 .demod_addr = 0x1e >> 1,
234 .tuner_reset = TM6010_GPIO_2,
235 .tuner_on = TM6010_GPIO_3,
236 .demod_reset = TM6010_GPIO_1,
237 .demod_on = TM6010_GPIO_4,
238 .power_led = TM6010_GPIO_7,
239 .dvb_led = TM6010_GPIO_5,
243 [TM6010_BOARD_BEHOLD_WANDER] = {
244 .name = "Beholder Wander DVB-T/TV/FM USB2.0",
245 .tuner_type = TUNER_XC5000,
246 .tuner_addr = 0xc2 >> 1,
247 .demod_addr = 0x1e >> 1,
249 .avideo = TM6000_AIP_SIF1,
250 .aradio = TM6000_AIP_LINE1,
262 .tuner_reset = TM6010_GPIO_0,
263 .demod_reset = TM6010_GPIO_1,
264 .power_led = TM6010_GPIO_6,
267 [TM6010_BOARD_BEHOLD_VOYAGER] = {
268 .name = "Beholder Voyager TV/FM USB2.0",
269 .tuner_type = TUNER_XC5000,
270 .tuner_addr = 0xc2 >> 1,
272 .avideo = TM6000_AIP_SIF1,
273 .aradio = TM6000_AIP_LINE1,
285 .tuner_reset = TM6010_GPIO_0,
286 .power_led = TM6010_GPIO_6,
289 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
290 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
291 .tuner_type = TUNER_XC2028, /* has a XC3028 */
292 .tuner_addr = 0xc2 >> 1,
293 .demod_addr = 0x1e >> 1,
303 .tuner_reset = TM6010_GPIO_2,
304 .tuner_on = TM6010_GPIO_3,
305 .demod_reset = TM6010_GPIO_1,
306 .demod_on = TM6010_GPIO_4,
307 .power_led = TM6010_GPIO_7,
308 .dvb_led = TM6010_GPIO_5,
311 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
313 [TM5600_BOARD_TERRATEC_GRABSTER] = {
314 .name = "Terratec Grabster AV 150/250 MX",
316 .tuner_type = TUNER_ABSENT,
318 [TM6010_BOARD_TWINHAN_TU501] = {
319 .name = "Twinhan TU501(704D1)",
320 .tuner_type = TUNER_XC2028, /* has a XC3028 */
321 .tuner_addr = 0xc2 >> 1,
322 .demod_addr = 0x1e >> 1,
332 .tuner_reset = TM6010_GPIO_2,
333 .tuner_on = TM6010_GPIO_3,
334 .demod_reset = TM6010_GPIO_1,
335 .demod_on = TM6010_GPIO_4,
336 .power_led = TM6010_GPIO_7,
337 .dvb_led = TM6010_GPIO_5,
341 [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
342 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
343 .tuner_type = TUNER_XC5000,
344 .tuner_addr = 0xc2 >> 1,
345 .demod_addr = 0x1e >> 1,
347 .avideo = TM6000_AIP_SIF1,
348 .aradio = TM6000_AIP_LINE1,
360 .tuner_reset = TM6010_GPIO_0,
361 .demod_reset = TM6010_GPIO_1,
362 .power_led = TM6010_GPIO_6,
365 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
366 .name = "Beholder Voyager Lite TV/FM USB2.0",
367 .tuner_type = TUNER_XC5000,
368 .tuner_addr = 0xc2 >> 1,
370 .avideo = TM6000_AIP_SIF1,
371 .aradio = TM6000_AIP_LINE1,
383 .tuner_reset = TM6010_GPIO_0,
384 .power_led = TM6010_GPIO_6,
389 /* table of devices that work with this driver */
390 struct usb_device_id tm6000_id_table[] = {
391 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
392 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
393 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
394 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
395 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
396 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
397 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
398 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
399 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
400 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
401 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
402 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
403 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
404 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
405 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
406 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
407 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
408 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
409 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
410 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
414 /* Control power led for show some activity */
415 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
417 /* Power LED unconfigured */
418 if (!dev->gpio.power_led)
423 switch (dev->model) {
424 case TM6010_BOARD_HAUPPAUGE_900H:
425 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
426 case TM6010_BOARD_TWINHAN_TU501:
427 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
428 dev->gpio.power_led, 0x00);
430 case TM6010_BOARD_BEHOLD_WANDER:
431 case TM6010_BOARD_BEHOLD_VOYAGER:
432 case TM6010_BOARD_BEHOLD_WANDER_LITE:
433 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
434 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
435 dev->gpio.power_led, 0x01);
441 switch (dev->model) {
442 case TM6010_BOARD_HAUPPAUGE_900H:
443 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
444 case TM6010_BOARD_TWINHAN_TU501:
445 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
446 dev->gpio.power_led, 0x01);
448 case TM6010_BOARD_BEHOLD_WANDER:
449 case TM6010_BOARD_BEHOLD_VOYAGER:
450 case TM6010_BOARD_BEHOLD_WANDER_LITE:
451 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
452 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
453 dev->gpio.power_led, 0x00);
459 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
460 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
463 struct tm6000_core *dev = ptr;
465 if (dev->tuner_type != TUNER_XC5000)
469 case XC5000_TUNER_RESET:
470 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
471 dev->gpio.tuner_reset, 0x01);
473 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
474 dev->gpio.tuner_reset, 0x00);
476 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
477 dev->gpio.tuner_reset, 0x01);
482 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
484 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
486 int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
489 struct tm6000_core *dev = ptr;
491 if (dev->tuner_type != TUNER_XC2028)
495 case XC2028_RESET_CLK:
496 tm6000_ir_wait(dev, 0);
498 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
501 rc = tm6000_i2c_reset(dev, 10);
503 case XC2028_TUNER_RESET:
504 /* Reset codes during load firmware */
507 /* newer tuner can faster reset */
508 switch (dev->model) {
509 case TM5600_BOARD_10MOONS_UT821:
510 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
511 dev->gpio.tuner_reset, 0x01);
512 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
515 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
516 dev->gpio.tuner_reset, 0x00);
517 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
520 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
521 dev->gpio.tuner_reset, 0x01);
522 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
525 case TM6010_BOARD_HAUPPAUGE_900H:
526 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
527 case TM6010_BOARD_TWINHAN_TU501:
528 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
529 dev->gpio.tuner_reset, 0x01);
531 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
532 dev->gpio.tuner_reset, 0x00);
534 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
535 dev->gpio.tuner_reset, 0x01);
539 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
540 dev->gpio.tuner_reset, 0x00);
542 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
543 dev->gpio.tuner_reset, 0x01);
548 tm6000_ir_wait(dev, 1);
551 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
556 rc = tm6000_i2c_reset(dev, 100);
562 EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
564 int tm6000_cards_setup(struct tm6000_core *dev)
569 * Board-specific initialization sequence. Handles all GPIO
570 * initialization sequences that are board-specific.
571 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
572 * Probably, they're all based on some reference device. Due to that,
573 * there's a common routine at the end to handle those GPIO's. Devices
574 * that use different pinups or init sequences can just return at
575 * the board-specific session.
577 switch (dev->model) {
578 case TM6010_BOARD_HAUPPAUGE_900H:
579 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
580 case TM6010_BOARD_TWINHAN_TU501:
581 case TM6010_BOARD_GENERIC:
582 /* Turn xceive 3028 on */
583 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
585 /* Turn zarlink zl10353 on */
586 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
588 /* Reset zarlink zl10353 */
589 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
591 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
593 /* Turn zarlink zl10353 off */
594 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
597 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
599 /* Power led on (blue) */
600 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
602 /* DVB led off (orange) */
603 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
605 /* Turn zarlink zl10353 on */
606 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
609 case TM6010_BOARD_BEHOLD_WANDER:
610 case TM6010_BOARD_BEHOLD_WANDER_LITE:
611 /* Power led on (blue) */
612 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
614 /* Reset zarlink zl10353 */
615 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
617 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
620 case TM6010_BOARD_BEHOLD_VOYAGER:
621 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
622 /* Power led on (blue) */
623 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
631 * Default initialization. Most of the devices seem to use GPIO1
632 * and GPIO4.on the same way, so, this handles the common sequence
633 * used by most devices.
634 * If a device uses a different sequence or different GPIO pins for
635 * reset, just add the code at the board-specific part
638 if (dev->gpio.tuner_reset) {
639 for (i = 0; i < 2; i++) {
640 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
641 dev->gpio.tuner_reset, 0x00);
643 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
647 msleep(10); /* Just to be conservative */
648 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
649 dev->gpio.tuner_reset, 0x01);
651 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
656 printk(KERN_ERR "Tuner reset is not configured\n");
665 static void tm6000_config_tuner(struct tm6000_core *dev)
667 struct tuner_setup tun_setup;
669 /* Load tuner module */
670 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
671 "tuner", dev->tuner_addr, NULL);
673 memset(&tun_setup, 0, sizeof(tun_setup));
674 tun_setup.type = dev->tuner_type;
675 tun_setup.addr = dev->tuner_addr;
677 tun_setup.mode_mask = 0;
678 if (dev->caps.has_tuner)
679 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
681 switch (dev->tuner_type) {
683 tun_setup.tuner_callback = tm6000_tuner_callback;
686 tun_setup.tuner_callback = tm6000_xc5000_callback;
690 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
692 switch (dev->tuner_type) {
694 struct v4l2_priv_tun_config xc2028_cfg;
695 struct xc2028_ctrl ctl;
697 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
698 memset(&ctl, 0, sizeof(ctl));
701 ctl.read_not_reliable = 0;
703 ctl.demod = XC3028_FE_ZARLINK456;
706 xc2028_cfg.tuner = TUNER_XC2028;
707 xc2028_cfg.priv = &ctl;
709 switch (dev->model) {
710 case TM6010_BOARD_HAUPPAUGE_900H:
711 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
712 case TM6010_BOARD_TWINHAN_TU501:
713 ctl.fname = "xc3028L-v36.fw";
716 if (dev->dev_type == TM6010)
717 ctl.fname = "xc3028-v27.fw";
719 ctl.fname = "xc3028-v24.fw";
722 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
723 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
730 struct v4l2_priv_tun_config xc5000_cfg;
731 struct xc5000_config ctl = {
732 .i2c_address = dev->tuner_addr,
734 .radio_input = XC5000_RADIO_FM1_MONO,
737 xc5000_cfg.tuner = TUNER_XC5000;
738 xc5000_cfg.priv = &ctl;
740 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
745 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
750 static int fill_board_specific_data(struct tm6000_core *dev)
754 dev->dev_type = tm6000_boards[dev->model].type;
755 dev->tuner_type = tm6000_boards[dev->model].tuner_type;
756 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
758 dev->gpio = tm6000_boards[dev->model].gpio;
760 dev->ir_codes = tm6000_boards[dev->model].ir_codes;
762 dev->demod_addr = tm6000_boards[dev->model].demod_addr;
764 dev->caps = tm6000_boards[dev->model].caps;
766 dev->avideo = tm6000_boards[dev->model].avideo;
767 dev->aradio = tm6000_boards[dev->model].aradio;
768 /* initialize hardware */
769 rc = tm6000_init(dev);
773 rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
777 /* initialize hardware */
778 rc = tm6000_init(dev);
784 static void use_alternative_detection_method(struct tm6000_core *dev)
788 if (!dev->eedata_size)
791 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
792 if (!tm6000_boards[i].eename_size)
794 if (dev->eedata_size < tm6000_boards[i].eename_pos +
795 tm6000_boards[i].eename_size)
798 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
799 tm6000_boards[i].eename,
800 tm6000_boards[i].eename_size)) {
806 printk(KERN_INFO "Device has eeprom but is currently unknown\n");
812 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
813 tm6000_boards[model].name, model);
816 static int tm6000_init_dev(struct tm6000_core *dev)
818 struct v4l2_frequency f;
821 mutex_init(&dev->lock);
822 mutex_lock(&dev->lock);
824 if (!is_generic(dev->model)) {
825 rc = fill_board_specific_data(dev);
829 /* register i2c bus */
830 rc = tm6000_i2c_register(dev);
834 /* register i2c bus */
835 rc = tm6000_i2c_register(dev);
839 use_alternative_detection_method(dev);
841 rc = fill_board_specific_data(dev);
846 /* Default values for STD and resolutions */
849 dev->norm = V4L2_STD_PAL_M;
851 /* Configure tuner */
852 tm6000_config_tuner(dev);
854 /* Set video standard */
855 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
857 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
859 f.type = V4L2_TUNER_ANALOG_TV;
860 f.frequency = 3092; /* 193.25 MHz */
861 dev->freq = f.frequency;
862 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
864 if (dev->caps.has_tda9874)
865 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
866 "tvaudio", I2C_ADDR_TDA9874, NULL);
868 /* register and initialize V4L2 */
869 rc = tm6000_v4l2_register(dev);
873 tm6000_add_into_devlist(dev);
874 tm6000_init_extension(dev);
878 mutex_unlock(&dev->lock);
882 mutex_unlock(&dev->lock);
886 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
887 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
889 static void get_max_endpoint(struct usb_device *udev,
890 struct usb_host_interface *alt,
892 struct usb_host_endpoint *curr_e,
893 struct tm6000_endpoint *tm_ep)
895 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
896 unsigned int size = tmp & 0x7ff;
898 if (udev->speed == USB_SPEED_HIGH)
899 size = size * hb_mult(tmp);
901 if (size > tm_ep->maxsize) {
902 tm_ep->endp = curr_e;
903 tm_ep->maxsize = size;
904 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
905 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
907 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
908 msgtype, curr_e->desc.bEndpointAddress,
915 * checks for supported devices
917 static int tm6000_usb_probe(struct usb_interface *interface,
918 const struct usb_device_id *id)
920 struct usb_device *usbdev;
921 struct tm6000_core *dev = NULL;
926 usbdev = usb_get_dev(interface_to_usbdev(interface));
928 /* Selects the proper interface */
929 rc = usb_set_interface(usbdev, 0, 1);
933 /* Check to see next free device and mark as used */
934 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
935 if (nr >= TM6000_MAXBOARDS) {
936 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
941 /* Create and initialize dev struct */
942 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
944 printk(KERN_ERR "tm6000" ": out of memory!\n");
948 spin_lock_init(&dev->slock);
950 /* Increment usage count */
951 tm6000_devused |= 1<<nr;
952 snprintf(dev->name, 29, "tm6000 #%d", nr);
954 dev->model = id->driver_info;
955 if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards)))
956 dev->model = card[nr];
961 switch (usbdev->speed) {
965 case USB_SPEED_UNKNOWN:
979 for (i = 0; i < interface->num_altsetting; i++) {
982 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
983 struct usb_host_endpoint *e;
986 e = &interface->altsetting[i].endpoint[ep];
988 dir_out = ((e->desc.bEndpointAddress &
989 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
991 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
993 interface->altsetting[i].desc.bInterfaceNumber,
994 interface->altsetting[i].desc.bInterfaceClass);
996 switch (e->desc.bmAttributes) {
997 case USB_ENDPOINT_XFER_BULK:
999 get_max_endpoint(usbdev,
1000 &interface->altsetting[i],
1004 get_max_endpoint(usbdev,
1005 &interface->altsetting[i],
1010 case USB_ENDPOINT_XFER_ISOC:
1012 get_max_endpoint(usbdev,
1013 &interface->altsetting[i],
1017 get_max_endpoint(usbdev,
1018 &interface->altsetting[i],
1023 case USB_ENDPOINT_XFER_INT:
1025 get_max_endpoint(usbdev,
1026 &interface->altsetting[i],
1030 get_max_endpoint(usbdev,
1031 &interface->altsetting[i],
1041 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1043 le16_to_cpu(dev->udev->descriptor.idVendor),
1044 le16_to_cpu(dev->udev->descriptor.idProduct),
1045 interface->altsetting->desc.bInterfaceNumber);
1047 /* check if the the device has the iso in endpoint at the correct place */
1048 if (!dev->isoc_in.endp) {
1049 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1055 /* save our data pointer in this interface device */
1056 usb_set_intfdata(interface, dev);
1058 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1060 rc = tm6000_init_dev(dev);
1068 printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1070 tm6000_devused &= ~(1<<nr);
1071 usb_put_dev(usbdev);
1078 * tm6000_usb_disconnect()
1079 * called when the device gets diconencted
1080 * video device will be unregistered on v4l2_close in case it is still open
1082 static void tm6000_usb_disconnect(struct usb_interface *interface)
1084 struct tm6000_core *dev = usb_get_intfdata(interface);
1085 usb_set_intfdata(interface, NULL);
1090 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1092 tm6000_ir_fini(dev);
1094 if (dev->gpio.power_led) {
1095 switch (dev->model) {
1096 case TM6010_BOARD_HAUPPAUGE_900H:
1097 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1098 case TM6010_BOARD_TWINHAN_TU501:
1100 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1101 dev->gpio.power_led, 0x01);
1104 case TM6010_BOARD_BEHOLD_WANDER:
1105 case TM6010_BOARD_BEHOLD_VOYAGER:
1106 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1107 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1109 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1110 dev->gpio.power_led, 0x00);
1115 tm6000_v4l2_unregister(dev);
1117 tm6000_i2c_unregister(dev);
1119 v4l2_device_unregister(&dev->v4l2_dev);
1121 dev->state |= DEV_DISCONNECTED;
1123 usb_put_dev(dev->udev);
1125 tm6000_close_extension(dev);
1126 tm6000_remove_from_devlist(dev);
1131 static struct usb_driver tm6000_usb_driver = {
1133 .probe = tm6000_usb_probe,
1134 .disconnect = tm6000_usb_disconnect,
1135 .id_table = tm6000_id_table,
1138 static int __init tm6000_module_init(void)
1142 printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
1143 (TM6000_VERSION >> 16) & 0xff,
1144 (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
1146 /* register this driver with the USB subsystem */
1147 result = usb_register(&tm6000_usb_driver);
1149 printk(KERN_ERR "tm6000"
1150 " usb_register failed. Error number %d.\n", result);
1155 static void __exit tm6000_module_exit(void)
1157 /* deregister at USB subsystem */
1158 usb_deregister(&tm6000_usb_driver);
1161 module_init(tm6000_module_init);
1162 module_exit(tm6000_module_exit);
1164 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1165 MODULE_AUTHOR("Mauro Carvalho Chehab");
1166 MODULE_LICENSE("GPL");