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