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