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