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