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 "tuner-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");
1398