cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tm6000-cards.c (35644B)


      1// SPDX-License-Identifier: GPL-2.0
      2// tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
      3//
      4// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
      5
      6#include <linux/init.h>
      7#include <linux/module.h>
      8#include <linux/pci.h>
      9#include <linux/delay.h>
     10#include <linux/i2c.h>
     11#include <linux/usb.h>
     12#include <linux/slab.h>
     13#include <media/v4l2-common.h>
     14#include <media/tuner.h>
     15#include <media/i2c/tvaudio.h>
     16#include <media/rc-map.h>
     17
     18#include "tm6000.h"
     19#include "tm6000-regs.h"
     20#include "xc2028.h"
     21#include "xc5000.h"
     22
     23#define TM6000_BOARD_UNKNOWN			0
     24#define TM5600_BOARD_GENERIC			1
     25#define TM6000_BOARD_GENERIC			2
     26#define TM6010_BOARD_GENERIC			3
     27#define TM5600_BOARD_10MOONS_UT821		4
     28#define TM5600_BOARD_10MOONS_UT330		5
     29#define TM6000_BOARD_ADSTECH_DUAL_TV		6
     30#define TM6000_BOARD_FREECOM_AND_SIMILAR	7
     31#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV	8
     32#define TM6010_BOARD_HAUPPAUGE_900H		9
     33#define TM6010_BOARD_BEHOLD_WANDER		10
     34#define TM6010_BOARD_BEHOLD_VOYAGER		11
     35#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE	12
     36#define TM6010_BOARD_TWINHAN_TU501		13
     37#define TM6010_BOARD_BEHOLD_WANDER_LITE		14
     38#define TM6010_BOARD_BEHOLD_VOYAGER_LITE	15
     39#define TM5600_BOARD_TERRATEC_GRABSTER		16
     40
     41#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
     42			   (model == TM5600_BOARD_GENERIC) || \
     43			   (model == TM6000_BOARD_GENERIC) || \
     44			   (model == TM6010_BOARD_GENERIC))
     45
     46#define TM6000_MAXBOARDS        16
     47static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
     48
     49module_param_array(card,  int, NULL, 0444);
     50
     51static unsigned long tm6000_devused;
     52
     53
     54struct tm6000_board {
     55	char            *name;
     56	char		eename[16];		/* EEPROM name */
     57	unsigned	eename_size;		/* size of EEPROM name */
     58	unsigned	eename_pos;		/* Position where it appears at ROM */
     59
     60	struct tm6000_capabilities caps;
     61
     62	enum		tm6000_devtype type;	/* variant of the chipset */
     63	int             tuner_type;     /* type of the tuner */
     64	int             tuner_addr;     /* tuner address */
     65	int             demod_addr;     /* demodulator address */
     66
     67	struct tm6000_gpio gpio;
     68
     69	struct tm6000_input	vinput[3];
     70	struct tm6000_input	rinput;
     71
     72	char		*ir_codes;
     73};
     74
     75static struct tm6000_board tm6000_boards[] = {
     76	[TM6000_BOARD_UNKNOWN] = {
     77		.name         = "Unknown tm6000 video grabber",
     78		.caps = {
     79			.has_tuner	= 1,
     80			.has_eeprom	= 1,
     81		},
     82		.gpio = {
     83			.tuner_reset	= TM6000_GPIO_1,
     84		},
     85		.vinput = { {
     86			.type	= TM6000_INPUT_TV,
     87			.vmux	= TM6000_VMUX_VIDEO_B,
     88			.amux	= TM6000_AMUX_ADC1,
     89			}, {
     90			.type	= TM6000_INPUT_COMPOSITE1,
     91			.vmux	= TM6000_VMUX_VIDEO_A,
     92			.amux	= TM6000_AMUX_ADC2,
     93			}, {
     94			.type	= TM6000_INPUT_SVIDEO,
     95			.vmux	= TM6000_VMUX_VIDEO_AB,
     96			.amux	= TM6000_AMUX_ADC2,
     97			},
     98		},
     99	},
    100	[TM5600_BOARD_GENERIC] = {
    101		.name         = "Generic tm5600 board",
    102		.type         = TM5600,
    103		.tuner_type   = TUNER_XC2028,
    104		.tuner_addr   = 0xc2 >> 1,
    105		.caps = {
    106			.has_tuner	= 1,
    107			.has_eeprom	= 1,
    108		},
    109		.gpio = {
    110			.tuner_reset	= TM6000_GPIO_1,
    111		},
    112		.vinput = { {
    113			.type	= TM6000_INPUT_TV,
    114			.vmux	= TM6000_VMUX_VIDEO_B,
    115			.amux	= TM6000_AMUX_ADC1,
    116			}, {
    117			.type	= TM6000_INPUT_COMPOSITE1,
    118			.vmux	= TM6000_VMUX_VIDEO_A,
    119			.amux	= TM6000_AMUX_ADC2,
    120			}, {
    121			.type	= TM6000_INPUT_SVIDEO,
    122			.vmux	= TM6000_VMUX_VIDEO_AB,
    123			.amux	= TM6000_AMUX_ADC2,
    124			},
    125		},
    126	},
    127	[TM6000_BOARD_GENERIC] = {
    128		.name         = "Generic tm6000 board",
    129		.tuner_type   = TUNER_XC2028,
    130		.tuner_addr   = 0xc2 >> 1,
    131		.caps = {
    132			.has_tuner	= 1,
    133			.has_eeprom	= 1,
    134		},
    135		.gpio = {
    136			.tuner_reset	= TM6000_GPIO_1,
    137		},
    138		.vinput = { {
    139			.type	= TM6000_INPUT_TV,
    140			.vmux	= TM6000_VMUX_VIDEO_B,
    141			.amux	= TM6000_AMUX_ADC1,
    142			}, {
    143			.type	= TM6000_INPUT_COMPOSITE1,
    144			.vmux	= TM6000_VMUX_VIDEO_A,
    145			.amux	= TM6000_AMUX_ADC2,
    146			}, {
    147			.type	= TM6000_INPUT_SVIDEO,
    148			.vmux	= TM6000_VMUX_VIDEO_AB,
    149			.amux	= TM6000_AMUX_ADC2,
    150			},
    151		},
    152	},
    153	[TM6010_BOARD_GENERIC] = {
    154		.name         = "Generic tm6010 board",
    155		.type         = TM6010,
    156		.tuner_type   = TUNER_XC2028,
    157		.tuner_addr   = 0xc2 >> 1,
    158		.demod_addr   = 0x1e >> 1,
    159		.caps = {
    160			.has_tuner	= 1,
    161			.has_dvb	= 1,
    162			.has_zl10353	= 1,
    163			.has_eeprom	= 1,
    164			.has_remote	= 1,
    165		},
    166		.gpio = {
    167			.tuner_reset	= TM6010_GPIO_2,
    168			.tuner_on	= TM6010_GPIO_3,
    169			.demod_reset	= TM6010_GPIO_1,
    170			.demod_on	= TM6010_GPIO_4,
    171			.power_led	= TM6010_GPIO_7,
    172			.dvb_led	= TM6010_GPIO_5,
    173			.ir		= TM6010_GPIO_0,
    174		},
    175		.vinput = { {
    176			.type	= TM6000_INPUT_TV,
    177			.vmux	= TM6000_VMUX_VIDEO_B,
    178			.amux	= TM6000_AMUX_SIF1,
    179			}, {
    180			.type	= TM6000_INPUT_COMPOSITE1,
    181			.vmux	= TM6000_VMUX_VIDEO_A,
    182			.amux	= TM6000_AMUX_ADC2,
    183			}, {
    184			.type	= TM6000_INPUT_SVIDEO,
    185			.vmux	= TM6000_VMUX_VIDEO_AB,
    186			.amux	= TM6000_AMUX_ADC2,
    187			},
    188		},
    189	},
    190	[TM5600_BOARD_10MOONS_UT821] = {
    191		.name         = "10Moons UT 821",
    192		.tuner_type   = TUNER_XC2028,
    193		.eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
    194		.eename_size  = 14,
    195		.eename_pos   = 0x14,
    196		.type         = TM5600,
    197		.tuner_addr   = 0xc2 >> 1,
    198		.caps = {
    199			.has_tuner    = 1,
    200			.has_eeprom   = 1,
    201		},
    202		.gpio = {
    203			.tuner_reset	= TM6000_GPIO_1,
    204		},
    205		.vinput = { {
    206			.type	= TM6000_INPUT_TV,
    207			.vmux	= TM6000_VMUX_VIDEO_B,
    208			.amux	= TM6000_AMUX_ADC1,
    209			}, {
    210			.type	= TM6000_INPUT_COMPOSITE1,
    211			.vmux	= TM6000_VMUX_VIDEO_A,
    212			.amux	= TM6000_AMUX_ADC2,
    213			}, {
    214			.type	= TM6000_INPUT_SVIDEO,
    215			.vmux	= TM6000_VMUX_VIDEO_AB,
    216			.amux	= TM6000_AMUX_ADC2,
    217			},
    218		},
    219	},
    220	[TM5600_BOARD_10MOONS_UT330] = {
    221		.name         = "10Moons UT 330",
    222		.tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
    223		.tuner_addr   = 0xc8 >> 1,
    224		.caps = {
    225			.has_tuner    = 1,
    226			.has_dvb      = 0,
    227			.has_zl10353  = 0,
    228			.has_eeprom   = 1,
    229		},
    230		.vinput = { {
    231			.type	= TM6000_INPUT_TV,
    232			.vmux	= TM6000_VMUX_VIDEO_B,
    233			.amux	= TM6000_AMUX_ADC1,
    234			}, {
    235			.type	= TM6000_INPUT_COMPOSITE1,
    236			.vmux	= TM6000_VMUX_VIDEO_A,
    237			.amux	= TM6000_AMUX_ADC2,
    238			}, {
    239			.type	= TM6000_INPUT_SVIDEO,
    240			.vmux	= TM6000_VMUX_VIDEO_AB,
    241			.amux	= TM6000_AMUX_ADC2,
    242			},
    243		},
    244	},
    245	[TM6000_BOARD_ADSTECH_DUAL_TV] = {
    246		.name         = "ADSTECH Dual TV USB",
    247		.tuner_type   = TUNER_XC2028,
    248		.tuner_addr   = 0xc8 >> 1,
    249		.caps = {
    250			.has_tuner    = 1,
    251			.has_tda9874  = 1,
    252			.has_dvb      = 1,
    253			.has_zl10353  = 1,
    254			.has_eeprom   = 1,
    255		},
    256		.vinput = { {
    257			.type	= TM6000_INPUT_TV,
    258			.vmux	= TM6000_VMUX_VIDEO_B,
    259			.amux	= TM6000_AMUX_ADC1,
    260			}, {
    261			.type	= TM6000_INPUT_COMPOSITE1,
    262			.vmux	= TM6000_VMUX_VIDEO_A,
    263			.amux	= TM6000_AMUX_ADC2,
    264			}, {
    265			.type	= TM6000_INPUT_SVIDEO,
    266			.vmux	= TM6000_VMUX_VIDEO_AB,
    267			.amux	= TM6000_AMUX_ADC2,
    268			},
    269		},
    270	},
    271	[TM6000_BOARD_FREECOM_AND_SIMILAR] = {
    272		.name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
    273		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
    274		.tuner_addr   = 0xc2 >> 1,
    275		.demod_addr   = 0x1e >> 1,
    276		.caps = {
    277			.has_tuner    = 1,
    278			.has_dvb      = 1,
    279			.has_zl10353  = 1,
    280			.has_eeprom   = 0,
    281			.has_remote   = 1,
    282		},
    283		.gpio = {
    284			.tuner_reset	= TM6000_GPIO_4,
    285		},
    286		.vinput = { {
    287			.type	= TM6000_INPUT_TV,
    288			.vmux	= TM6000_VMUX_VIDEO_B,
    289			.amux	= TM6000_AMUX_ADC1,
    290			}, {
    291			.type	= TM6000_INPUT_COMPOSITE1,
    292			.vmux	= TM6000_VMUX_VIDEO_A,
    293			.amux	= TM6000_AMUX_ADC2,
    294			}, {
    295			.type	= TM6000_INPUT_SVIDEO,
    296			.vmux	= TM6000_VMUX_VIDEO_AB,
    297			.amux	= TM6000_AMUX_ADC2,
    298			},
    299		},
    300	},
    301	[TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
    302		.name         = "ADSTECH Mini Dual TV USB",
    303		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
    304		.tuner_addr   = 0xc8 >> 1,
    305		.demod_addr   = 0x1e >> 1,
    306		.caps = {
    307			.has_tuner    = 1,
    308			.has_dvb      = 1,
    309			.has_zl10353  = 1,
    310			.has_eeprom   = 0,
    311		},
    312		.gpio = {
    313			.tuner_reset	= TM6000_GPIO_4,
    314		},
    315		.vinput = { {
    316			.type	= TM6000_INPUT_TV,
    317			.vmux	= TM6000_VMUX_VIDEO_B,
    318			.amux	= TM6000_AMUX_ADC1,
    319			}, {
    320			.type	= TM6000_INPUT_COMPOSITE1,
    321			.vmux	= TM6000_VMUX_VIDEO_A,
    322			.amux	= TM6000_AMUX_ADC2,
    323			}, {
    324			.type	= TM6000_INPUT_SVIDEO,
    325			.vmux	= TM6000_VMUX_VIDEO_AB,
    326			.amux	= TM6000_AMUX_ADC2,
    327			},
    328		},
    329	},
    330	[TM6010_BOARD_HAUPPAUGE_900H] = {
    331		.name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
    332		.eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
    333		.eename_size  = 14,
    334		.eename_pos   = 0x42,
    335		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
    336		.tuner_addr   = 0xc2 >> 1,
    337		.demod_addr   = 0x1e >> 1,
    338		.type         = TM6010,
    339		.ir_codes = RC_MAP_HAUPPAUGE,
    340		.caps = {
    341			.has_tuner    = 1,
    342			.has_dvb      = 1,
    343			.has_zl10353  = 1,
    344			.has_eeprom   = 1,
    345			.has_remote   = 1,
    346		},
    347		.gpio = {
    348			.tuner_reset	= TM6010_GPIO_2,
    349			.tuner_on	= TM6010_GPIO_3,
    350			.demod_reset	= TM6010_GPIO_1,
    351			.demod_on	= TM6010_GPIO_4,
    352			.power_led	= TM6010_GPIO_7,
    353			.dvb_led	= TM6010_GPIO_5,
    354			.ir		= TM6010_GPIO_0,
    355		},
    356		.vinput = { {
    357			.type	= TM6000_INPUT_TV,
    358			.vmux	= TM6000_VMUX_VIDEO_B,
    359			.amux	= TM6000_AMUX_SIF1,
    360			}, {
    361			.type	= TM6000_INPUT_COMPOSITE1,
    362			.vmux	= TM6000_VMUX_VIDEO_A,
    363			.amux	= TM6000_AMUX_ADC2,
    364			}, {
    365			.type	= TM6000_INPUT_SVIDEO,
    366			.vmux	= TM6000_VMUX_VIDEO_AB,
    367			.amux	= TM6000_AMUX_ADC2,
    368			},
    369		},
    370	},
    371	[TM6010_BOARD_BEHOLD_WANDER] = {
    372		.name         = "Beholder Wander DVB-T/TV/FM USB2.0",
    373		.tuner_type   = TUNER_XC5000,
    374		.tuner_addr   = 0xc2 >> 1,
    375		.demod_addr   = 0x1e >> 1,
    376		.type         = TM6010,
    377		.caps = {
    378			.has_tuner      = 1,
    379			.has_dvb        = 1,
    380			.has_zl10353    = 1,
    381			.has_eeprom     = 1,
    382			.has_remote     = 1,
    383			.has_radio	= 1,
    384		},
    385		.gpio = {
    386			.tuner_reset	= TM6010_GPIO_0,
    387			.demod_reset	= TM6010_GPIO_1,
    388			.power_led	= TM6010_GPIO_6,
    389		},
    390		.vinput = { {
    391			.type	= TM6000_INPUT_TV,
    392			.vmux	= TM6000_VMUX_VIDEO_B,
    393			.amux	= TM6000_AMUX_SIF1,
    394			}, {
    395			.type	= TM6000_INPUT_COMPOSITE1,
    396			.vmux	= TM6000_VMUX_VIDEO_A,
    397			.amux	= TM6000_AMUX_ADC2,
    398			}, {
    399			.type	= TM6000_INPUT_SVIDEO,
    400			.vmux	= TM6000_VMUX_VIDEO_AB,
    401			.amux	= TM6000_AMUX_ADC2,
    402			},
    403		},
    404		.rinput = {
    405			.type	= TM6000_INPUT_RADIO,
    406			.amux	= TM6000_AMUX_ADC1,
    407		},
    408	},
    409	[TM6010_BOARD_BEHOLD_VOYAGER] = {
    410		.name         = "Beholder Voyager TV/FM USB2.0",
    411		.tuner_type   = TUNER_XC5000,
    412		.tuner_addr   = 0xc2 >> 1,
    413		.type         = TM6010,
    414		.caps = {
    415			.has_tuner      = 1,
    416			.has_dvb        = 0,
    417			.has_zl10353    = 0,
    418			.has_eeprom     = 1,
    419			.has_remote     = 1,
    420			.has_radio	= 1,
    421		},
    422		.gpio = {
    423			.tuner_reset	= TM6010_GPIO_0,
    424			.power_led	= TM6010_GPIO_6,
    425		},
    426		.vinput = { {
    427			.type	= TM6000_INPUT_TV,
    428			.vmux	= TM6000_VMUX_VIDEO_B,
    429			.amux	= TM6000_AMUX_SIF1,
    430			}, {
    431			.type	= TM6000_INPUT_COMPOSITE1,
    432			.vmux	= TM6000_VMUX_VIDEO_A,
    433			.amux	= TM6000_AMUX_ADC2,
    434			}, {
    435			.type	= TM6000_INPUT_SVIDEO,
    436			.vmux	= TM6000_VMUX_VIDEO_AB,
    437			.amux	= TM6000_AMUX_ADC2,
    438			},
    439		},
    440		.rinput = {
    441			.type	= TM6000_INPUT_RADIO,
    442			.amux	= TM6000_AMUX_ADC1,
    443		},
    444	},
    445	[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
    446		.name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
    447		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
    448		.tuner_addr   = 0xc2 >> 1,
    449		.demod_addr   = 0x1e >> 1,
    450		.type         = TM6010,
    451		.caps = {
    452			.has_tuner    = 1,
    453			.has_dvb      = 1,
    454			.has_zl10353  = 1,
    455			.has_eeprom   = 1,
    456			.has_remote   = 1,
    457			.has_radio    = 1,
    458		},
    459		.gpio = {
    460			.tuner_reset	= TM6010_GPIO_2,
    461			.tuner_on	= TM6010_GPIO_3,
    462			.demod_reset	= TM6010_GPIO_1,
    463			.demod_on	= TM6010_GPIO_4,
    464			.power_led	= TM6010_GPIO_7,
    465			.dvb_led	= TM6010_GPIO_5,
    466			.ir		= TM6010_GPIO_0,
    467		},
    468		.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
    469		.vinput = { {
    470			.type	= TM6000_INPUT_TV,
    471			.vmux	= TM6000_VMUX_VIDEO_B,
    472			.amux	= TM6000_AMUX_SIF1,
    473			}, {
    474			.type	= TM6000_INPUT_COMPOSITE1,
    475			.vmux	= TM6000_VMUX_VIDEO_A,
    476			.amux	= TM6000_AMUX_ADC2,
    477			}, {
    478			.type	= TM6000_INPUT_SVIDEO,
    479			.vmux	= TM6000_VMUX_VIDEO_AB,
    480			.amux	= TM6000_AMUX_ADC2,
    481			},
    482		},
    483		.rinput = {
    484			.type = TM6000_INPUT_RADIO,
    485			.amux = TM6000_AMUX_SIF1,
    486		},
    487	},
    488	[TM5600_BOARD_TERRATEC_GRABSTER] = {
    489		.name         = "Terratec Grabster AV 150/250 MX",
    490		.type         = TM5600,
    491		.tuner_type   = TUNER_ABSENT,
    492		.vinput = { {
    493			.type	= TM6000_INPUT_TV,
    494			.vmux	= TM6000_VMUX_VIDEO_B,
    495			.amux	= TM6000_AMUX_ADC1,
    496			}, {
    497			.type	= TM6000_INPUT_COMPOSITE1,
    498			.vmux	= TM6000_VMUX_VIDEO_A,
    499			.amux	= TM6000_AMUX_ADC2,
    500			}, {
    501			.type	= TM6000_INPUT_SVIDEO,
    502			.vmux	= TM6000_VMUX_VIDEO_AB,
    503			.amux	= TM6000_AMUX_ADC2,
    504			},
    505		},
    506	},
    507	[TM6010_BOARD_TWINHAN_TU501] = {
    508		.name         = "Twinhan TU501(704D1)",
    509		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
    510		.tuner_addr   = 0xc2 >> 1,
    511		.demod_addr   = 0x1e >> 1,
    512		.type         = TM6010,
    513		.caps = {
    514			.has_tuner    = 1,
    515			.has_dvb      = 1,
    516			.has_zl10353  = 1,
    517			.has_eeprom   = 1,
    518			.has_remote   = 1,
    519		},
    520		.gpio = {
    521			.tuner_reset	= TM6010_GPIO_2,
    522			.tuner_on	= TM6010_GPIO_3,
    523			.demod_reset	= TM6010_GPIO_1,
    524			.demod_on	= TM6010_GPIO_4,
    525			.power_led	= TM6010_GPIO_7,
    526			.dvb_led	= TM6010_GPIO_5,
    527			.ir		= TM6010_GPIO_0,
    528		},
    529		.vinput = { {
    530			.type	= TM6000_INPUT_TV,
    531			.vmux	= TM6000_VMUX_VIDEO_B,
    532			.amux	= TM6000_AMUX_SIF1,
    533			}, {
    534			.type	= TM6000_INPUT_COMPOSITE1,
    535			.vmux	= TM6000_VMUX_VIDEO_A,
    536			.amux	= TM6000_AMUX_ADC2,
    537			}, {
    538			.type	= TM6000_INPUT_SVIDEO,
    539			.vmux	= TM6000_VMUX_VIDEO_AB,
    540			.amux	= TM6000_AMUX_ADC2,
    541			},
    542		},
    543	},
    544	[TM6010_BOARD_BEHOLD_WANDER_LITE] = {
    545		.name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
    546		.tuner_type   = TUNER_XC5000,
    547		.tuner_addr   = 0xc2 >> 1,
    548		.demod_addr   = 0x1e >> 1,
    549		.type         = TM6010,
    550		.caps = {
    551			.has_tuner      = 1,
    552			.has_dvb        = 1,
    553			.has_zl10353    = 1,
    554			.has_eeprom     = 1,
    555			.has_remote     = 0,
    556			.has_radio	= 1,
    557		},
    558		.gpio = {
    559			.tuner_reset	= TM6010_GPIO_0,
    560			.demod_reset	= TM6010_GPIO_1,
    561			.power_led	= TM6010_GPIO_6,
    562		},
    563		.vinput = { {
    564			.type	= TM6000_INPUT_TV,
    565			.vmux	= TM6000_VMUX_VIDEO_B,
    566			.amux	= TM6000_AMUX_SIF1,
    567			},
    568		},
    569		.rinput = {
    570			.type	= TM6000_INPUT_RADIO,
    571			.amux	= TM6000_AMUX_ADC1,
    572		},
    573	},
    574	[TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
    575		.name         = "Beholder Voyager Lite TV/FM USB2.0",
    576		.tuner_type   = TUNER_XC5000,
    577		.tuner_addr   = 0xc2 >> 1,
    578		.type         = TM6010,
    579		.caps = {
    580			.has_tuner      = 1,
    581			.has_dvb        = 0,
    582			.has_zl10353    = 0,
    583			.has_eeprom     = 1,
    584			.has_remote     = 0,
    585			.has_radio	= 1,
    586		},
    587		.gpio = {
    588			.tuner_reset	= TM6010_GPIO_0,
    589			.power_led	= TM6010_GPIO_6,
    590		},
    591		.vinput = { {
    592			.type	= TM6000_INPUT_TV,
    593			.vmux	= TM6000_VMUX_VIDEO_B,
    594			.amux	= TM6000_AMUX_SIF1,
    595			},
    596		},
    597		.rinput = {
    598			.type	= TM6000_INPUT_RADIO,
    599			.amux	= TM6000_AMUX_ADC1,
    600		},
    601	},
    602};
    603
    604/* table of devices that work with this driver */
    605static const struct usb_device_id tm6000_id_table[] = {
    606	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
    607	{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
    608	{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
    609	{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
    610	{ USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
    611	{ USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
    612	{ USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
    613	{ USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
    614	{ USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
    615	{ USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
    616	{ USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
    617	{ USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
    618	{ USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
    619	{ USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
    620	{ USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
    621	{ USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
    622	{ USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
    623	{ USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
    624	{ USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
    625	{ USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
    626	{ }
    627};
    628MODULE_DEVICE_TABLE(usb, tm6000_id_table);
    629
    630/* Control power led for show some activity */
    631void tm6000_flash_led(struct tm6000_core *dev, u8 state)
    632{
    633	/* Power LED unconfigured */
    634	if (!dev->gpio.power_led)
    635		return;
    636
    637	/* ON Power LED */
    638	if (state) {
    639		switch (dev->model) {
    640		case TM6010_BOARD_HAUPPAUGE_900H:
    641		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    642		case TM6010_BOARD_TWINHAN_TU501:
    643			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    644				dev->gpio.power_led, 0x00);
    645			break;
    646		case TM6010_BOARD_BEHOLD_WANDER:
    647		case TM6010_BOARD_BEHOLD_VOYAGER:
    648		case TM6010_BOARD_BEHOLD_WANDER_LITE:
    649		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
    650			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    651				dev->gpio.power_led, 0x01);
    652			break;
    653		}
    654	}
    655	/* OFF Power LED */
    656	else {
    657		switch (dev->model) {
    658		case TM6010_BOARD_HAUPPAUGE_900H:
    659		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    660		case TM6010_BOARD_TWINHAN_TU501:
    661			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    662				dev->gpio.power_led, 0x01);
    663			break;
    664		case TM6010_BOARD_BEHOLD_WANDER:
    665		case TM6010_BOARD_BEHOLD_VOYAGER:
    666		case TM6010_BOARD_BEHOLD_WANDER_LITE:
    667		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
    668			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    669				dev->gpio.power_led, 0x00);
    670			break;
    671		}
    672	}
    673}
    674
    675/* Tuner callback to provide the proper gpio changes needed for xc5000 */
    676int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
    677{
    678	int rc = 0;
    679	struct tm6000_core *dev = ptr;
    680
    681	if (dev->tuner_type != TUNER_XC5000)
    682		return 0;
    683
    684	switch (command) {
    685	case XC5000_TUNER_RESET:
    686		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    687			       dev->gpio.tuner_reset, 0x01);
    688		msleep(15);
    689		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    690			       dev->gpio.tuner_reset, 0x00);
    691		msleep(15);
    692		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    693			       dev->gpio.tuner_reset, 0x01);
    694		break;
    695	}
    696	return rc;
    697}
    698EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
    699
    700/* Tuner callback to provide the proper gpio changes needed for xc2028 */
    701
    702int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
    703{
    704	int rc = 0;
    705	struct tm6000_core *dev = ptr;
    706
    707	if (dev->tuner_type != TUNER_XC2028)
    708		return 0;
    709
    710	switch (command) {
    711	case XC2028_RESET_CLK:
    712		tm6000_ir_wait(dev, 0);
    713
    714		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
    715					0x02, arg);
    716		msleep(10);
    717		rc = tm6000_i2c_reset(dev, 10);
    718		break;
    719	case XC2028_TUNER_RESET:
    720		/* Reset codes during load firmware */
    721		switch (arg) {
    722		case 0:
    723			/* newer tuner can faster reset */
    724			switch (dev->model) {
    725			case TM5600_BOARD_10MOONS_UT821:
    726				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    727					       dev->gpio.tuner_reset, 0x01);
    728				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    729					       0x300, 0x01);
    730				msleep(10);
    731				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    732					       dev->gpio.tuner_reset, 0x00);
    733				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    734					       0x300, 0x00);
    735				msleep(10);
    736				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    737					       dev->gpio.tuner_reset, 0x01);
    738				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    739					       0x300, 0x01);
    740				break;
    741			case TM6010_BOARD_HAUPPAUGE_900H:
    742			case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    743			case TM6010_BOARD_TWINHAN_TU501:
    744				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    745					       dev->gpio.tuner_reset, 0x01);
    746				msleep(60);
    747				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    748					       dev->gpio.tuner_reset, 0x00);
    749				msleep(75);
    750				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    751					       dev->gpio.tuner_reset, 0x01);
    752				msleep(60);
    753				break;
    754			default:
    755				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    756					       dev->gpio.tuner_reset, 0x00);
    757				msleep(130);
    758				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    759					       dev->gpio.tuner_reset, 0x01);
    760				msleep(130);
    761				break;
    762			}
    763
    764			tm6000_ir_wait(dev, 1);
    765			break;
    766		case 1:
    767			tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
    768						0x02, 0x01);
    769			msleep(10);
    770			break;
    771		case 2:
    772			rc = tm6000_i2c_reset(dev, 100);
    773			break;
    774		}
    775		break;
    776	case XC2028_I2C_FLUSH:
    777		tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
    778		tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
    779		break;
    780	}
    781	return rc;
    782}
    783EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
    784
    785int tm6000_cards_setup(struct tm6000_core *dev)
    786{
    787	/*
    788	 * Board-specific initialization sequence. Handles all GPIO
    789	 * initialization sequences that are board-specific.
    790	 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
    791	 * Probably, they're all based on some reference device. Due to that,
    792	 * there's a common routine at the end to handle those GPIO's. Devices
    793	 * that use different pinups or init sequences can just return at
    794	 * the board-specific session.
    795	 */
    796	switch (dev->model) {
    797	case TM6010_BOARD_HAUPPAUGE_900H:
    798	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    799	case TM6010_BOARD_TWINHAN_TU501:
    800	case TM6010_BOARD_GENERIC:
    801		/* Turn xceive 3028 on */
    802		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
    803		msleep(15);
    804		/* Turn zarlink zl10353 on */
    805		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
    806		msleep(15);
    807		/* Reset zarlink zl10353 */
    808		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
    809		msleep(50);
    810		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
    811		msleep(15);
    812		/* Turn zarlink zl10353 off */
    813		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
    814		msleep(15);
    815		/* ir ? */
    816		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
    817		msleep(15);
    818		/* Power led on (blue) */
    819		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
    820		msleep(15);
    821		/* DVB led off (orange) */
    822		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
    823		msleep(15);
    824		/* Turn zarlink zl10353 on */
    825		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
    826		msleep(15);
    827		break;
    828	case TM6010_BOARD_BEHOLD_WANDER:
    829	case TM6010_BOARD_BEHOLD_WANDER_LITE:
    830		/* Power led on (blue) */
    831		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
    832		msleep(15);
    833		/* Reset zarlink zl10353 */
    834		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
    835		msleep(50);
    836		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
    837		msleep(15);
    838		break;
    839	case TM6010_BOARD_BEHOLD_VOYAGER:
    840	case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
    841		/* Power led on (blue) */
    842		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
    843		msleep(15);
    844		break;
    845	default:
    846		break;
    847	}
    848
    849	/*
    850	 * Default initialization. Most of the devices seem to use GPIO1
    851	 * and GPIO4.on the same way, so, this handles the common sequence
    852	 * used by most devices.
    853	 * If a device uses a different sequence or different GPIO pins for
    854	 * reset, just add the code at the board-specific part
    855	 */
    856
    857	if (dev->gpio.tuner_reset) {
    858		int rc;
    859		int i;
    860
    861		for (i = 0; i < 2; i++) {
    862			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    863						dev->gpio.tuner_reset, 0x00);
    864			if (rc < 0) {
    865				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
    866				return rc;
    867			}
    868
    869			msleep(10); /* Just to be conservative */
    870			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
    871						dev->gpio.tuner_reset, 0x01);
    872			if (rc < 0) {
    873				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
    874				return rc;
    875			}
    876		}
    877	} else {
    878		printk(KERN_ERR "Tuner reset is not configured\n");
    879		return -1;
    880	}
    881
    882	msleep(50);
    883
    884	return 0;
    885};
    886
    887static void tm6000_config_tuner(struct tm6000_core *dev)
    888{
    889	struct tuner_setup tun_setup;
    890
    891	/* Load tuner module */
    892	v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
    893		"tuner", dev->tuner_addr, NULL);
    894
    895	memset(&tun_setup, 0, sizeof(tun_setup));
    896	tun_setup.type = dev->tuner_type;
    897	tun_setup.addr = dev->tuner_addr;
    898
    899	tun_setup.mode_mask = 0;
    900	if (dev->caps.has_tuner)
    901		tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
    902
    903	switch (dev->tuner_type) {
    904	case TUNER_XC2028:
    905		tun_setup.tuner_callback = tm6000_tuner_callback;
    906		break;
    907	case TUNER_XC5000:
    908		tun_setup.tuner_callback = tm6000_xc5000_callback;
    909		break;
    910	}
    911
    912	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
    913
    914	switch (dev->tuner_type) {
    915	case TUNER_XC2028: {
    916		struct v4l2_priv_tun_config xc2028_cfg;
    917		struct xc2028_ctrl ctl;
    918
    919		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
    920		memset(&ctl, 0, sizeof(ctl));
    921
    922		ctl.demod = XC3028_FE_ZARLINK456;
    923
    924		xc2028_cfg.tuner = TUNER_XC2028;
    925		xc2028_cfg.priv  = &ctl;
    926
    927		switch (dev->model) {
    928		case TM6010_BOARD_HAUPPAUGE_900H:
    929		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    930		case TM6010_BOARD_TWINHAN_TU501:
    931			ctl.max_len = 80;
    932			ctl.fname = "xc3028L-v36.fw";
    933			break;
    934		default:
    935			if (dev->dev_type == TM6010)
    936				ctl.fname = "xc3028-v27.fw";
    937			else
    938				ctl.fname = "xc3028-v24.fw";
    939		}
    940
    941		printk(KERN_INFO "Setting firmware parameters for xc2028\n");
    942		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
    943				     &xc2028_cfg);
    944
    945		}
    946		break;
    947	case TUNER_XC5000:
    948		{
    949		struct v4l2_priv_tun_config  xc5000_cfg;
    950		struct xc5000_config ctl = {
    951			.i2c_address = dev->tuner_addr,
    952			.if_khz      = 4570,
    953			.radio_input = XC5000_RADIO_FM1_MONO,
    954			};
    955
    956		xc5000_cfg.tuner = TUNER_XC5000;
    957		xc5000_cfg.priv  = &ctl;
    958
    959		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
    960				     &xc5000_cfg);
    961		}
    962		break;
    963	default:
    964		printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
    965		break;
    966	}
    967}
    968
    969static int fill_board_specific_data(struct tm6000_core *dev)
    970{
    971	int rc;
    972
    973	dev->dev_type   = tm6000_boards[dev->model].type;
    974	dev->tuner_type = tm6000_boards[dev->model].tuner_type;
    975	dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
    976
    977	dev->gpio = tm6000_boards[dev->model].gpio;
    978
    979	dev->ir_codes = tm6000_boards[dev->model].ir_codes;
    980
    981	dev->demod_addr = tm6000_boards[dev->model].demod_addr;
    982
    983	dev->caps = tm6000_boards[dev->model].caps;
    984
    985	dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
    986	dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
    987	dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
    988	dev->rinput = tm6000_boards[dev->model].rinput;
    989
    990	/* setup per-model quirks */
    991	switch (dev->model) {
    992	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
    993	case TM6010_BOARD_HAUPPAUGE_900H:
    994		dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
    995		break;
    996
    997	default:
    998		break;
    999	}
   1000
   1001	/* initialize hardware */
   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
   1010static 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)
   1043static 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
   1054static 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
   1060static 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 /* CONFIG_MODULES */
   1068
   1069static 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		/* register i2c bus */
   1083		rc = tm6000_i2c_register(dev);
   1084		if (rc < 0)
   1085			goto err;
   1086	} else {
   1087		/* register i2c bus */
   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	/* Default values for STD and resolutions */
   1100	dev->width = 720;
   1101	dev->height = 480;
   1102	dev->norm = V4L2_STD_NTSC_M;
   1103
   1104	/* Configure tuner */
   1105	tm6000_config_tuner(dev);
   1106
   1107	/* Set video standard */
   1108	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
   1109
   1110	/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
   1111	f.tuner = 0;
   1112	f.type = V4L2_TUNER_ANALOG_TV;
   1113	f.frequency = 3092;	/* 193.25 MHz */
   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	/* register and initialize V4L2 */
   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
   1136err:
   1137	mutex_unlock(&dev->lock);
   1138	return rc;
   1139}
   1140
   1141/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
   1142#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
   1143
   1144static 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 * tm6000_usb_probe()
   1170 * checks for supported devices
   1171 */
   1172static 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	/* Selects the proper interface */
   1184	rc = usb_set_interface(usbdev, 0, 1);
   1185	if (rc < 0)
   1186		goto report_failure;
   1187
   1188	/* Check to see next free device and mark as used */
   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	/* Create and initialize dev struct */
   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	/* Increment usage count */
   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	/* Get endpoints */
   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/* check if the the device has the iso in endpoint at the correct place */
   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	/* save our data pointer in this interface device */
   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
   1318free_device:
   1319	kfree(dev);
   1320report_failure:
   1321	printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
   1322
   1323	clear_bit(nr, &tm6000_devused);
   1324put_device:
   1325	usb_put_dev(usbdev);
   1326	return rc;
   1327}
   1328
   1329/*
   1330 * tm6000_usb_disconnect()
   1331 * called when the device gets disconnected
   1332 * video device will be unregistered on v4l2_close in case it is still open
   1333 */
   1334static 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			/* Power led off */
   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			/* Power led off */
   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
   1386static 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
   1393module_usb_driver(tm6000_usb_driver);
   1394
   1395MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
   1396MODULE_AUTHOR("Mauro Carvalho Chehab");
   1397MODULE_LICENSE("GPL v2");