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