Version:  2.0.40 2.2.26 2.4.37 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17

Linux/drivers/media/usb/tm6000/tm6000-cards.c

  1 /*
  2  *  tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
  3  *
  4  *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
  5  *
  6  *  This program is free software; you can redistribute it and/or modify
  7  *  it under the terms of the GNU General Public License as published by
  8  *  the Free Software Foundation version 2
  9  *
 10  *  This program is distributed in the hope that it will be useful,
 11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  *  GNU General Public License for more details.
 14  *
 15  *  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', '', 'M', 'O', 'O', 'N', 'S', '5', '6', '', '', 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, 'H', 0 },
348                 .eename_size  = 14,
349                 .eename_pos   = 0x42,
350                 .tuner_type   = TUNER_XC2028, /* has a XC3028 */
351                 .tuner_addr   = 0xc2 >> 1,
352                 .demod_addr   = 0x1e >> 1,
353                 .type         = TM6010,
354                 .ir_codes = RC_MAP_HAUPPAUGE,
355                 .caps = {
356                         .has_tuner    = 1,
357                         .has_dvb      = 1,
358                         .has_zl10353  = 1,
359                         .has_eeprom   = 1,
360                         .has_remote   = 1,
361                 },
362                 .gpio = {
363                         .tuner_reset    = TM6010_GPIO_2,
364                         .tuner_on       = TM6010_GPIO_3,
365                         .demod_reset    = TM6010_GPIO_1,
366                         .demod_on       = TM6010_GPIO_4,
367                         .power_led      = TM6010_GPIO_7,
368                         .dvb_led        = TM6010_GPIO_5,
369                         .ir             = TM6010_GPIO_0,
370                 },
371                 .vinput = { {
372                         .type   = TM6000_INPUT_TV,
373                         .vmux   = TM6000_VMUX_VIDEO_B,
374                         .amux   = TM6000_AMUX_SIF1,
375                         }, {
376                         .type   = TM6000_INPUT_COMPOSITE1,
377                         .vmux   = TM6000_VMUX_VIDEO_A,
378                         .amux   = TM6000_AMUX_ADC2,
379                         }, {
380                         .type   = TM6000_INPUT_SVIDEO,
381                         .vmux   = TM6000_VMUX_VIDEO_AB,
382                         .amux   = TM6000_AMUX_ADC2,
383                         },
384                 },
385         },
386         [TM6010_BOARD_BEHOLD_WANDER] = {
387                 .name         = "Beholder Wander DVB-T/TV/FM USB2.0",
388                 .tuner_type   = TUNER_XC5000,
389                 .tuner_addr   = 0xc2 >> 1,
390                 .demod_addr   = 0x1e >> 1,
391                 .type         = TM6010,
392                 .caps = {
393                         .has_tuner      = 1,
394                         .has_dvb        = 1,
395                         .has_zl10353    = 1,
396                         .has_eeprom     = 1,
397                         .has_remote     = 1,
398                         .has_radio      = 1,
399                 },
400                 .gpio = {
401                         .tuner_reset    = TM6010_GPIO_0,
402                         .demod_reset    = TM6010_GPIO_1,
403                         .power_led      = TM6010_GPIO_6,
404                 },
405                 .vinput = { {
406                         .type   = TM6000_INPUT_TV,
407                         .vmux   = TM6000_VMUX_VIDEO_B,
408                         .amux   = TM6000_AMUX_SIF1,
409                         }, {
410                         .type   = TM6000_INPUT_COMPOSITE1,
411                         .vmux   = TM6000_VMUX_VIDEO_A,
412                         .amux   = TM6000_AMUX_ADC2,
413                         }, {
414                         .type   = TM6000_INPUT_SVIDEO,
415                         .vmux   = TM6000_VMUX_VIDEO_AB,
416                         .amux   = TM6000_AMUX_ADC2,
417                         },
418                 },
419                 .rinput = {
420                         .type   = TM6000_INPUT_RADIO,
421                         .amux   = TM6000_AMUX_ADC1,
422                 },
423         },
424         [TM6010_BOARD_BEHOLD_VOYAGER] = {
425                 .name         = "Beholder Voyager TV/FM USB2.0",
426                 .tuner_type   = TUNER_XC5000,
427                 .tuner_addr   = 0xc2 >> 1,
428                 .type         = TM6010,
429                 .caps = {
430                         .has_tuner      = 1,
431                         .has_dvb        = 0,
432                         .has_zl10353    = 0,
433                         .has_eeprom     = 1,
434                         .has_remote     = 1,
435                         .has_radio      = 1,
436                 },
437                 .gpio = {
438                         .tuner_reset    = TM6010_GPIO_0,
439                         .power_led      = TM6010_GPIO_6,
440                 },
441                 .vinput = { {
442                         .type   = TM6000_INPUT_TV,
443                         .vmux   = TM6000_VMUX_VIDEO_B,
444                         .amux   = TM6000_AMUX_SIF1,
445                         }, {
446                         .type   = TM6000_INPUT_COMPOSITE1,
447                         .vmux   = TM6000_VMUX_VIDEO_A,
448                         .amux   = TM6000_AMUX_ADC2,
449                         }, {
450                         .type   = TM6000_INPUT_SVIDEO,
451                         .vmux   = TM6000_VMUX_VIDEO_AB,
452                         .amux   = TM6000_AMUX_ADC2,
453                         },
454                 },
455                 .rinput = {
456                         .type   = TM6000_INPUT_RADIO,
457                         .amux   = TM6000_AMUX_ADC1,
458                 },
459         },
460         [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
461                 .name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
462                 .tuner_type   = TUNER_XC2028, /* has a XC3028 */
463                 .tuner_addr   = 0xc2 >> 1,
464                 .demod_addr   = 0x1e >> 1,
465                 .type         = TM6010,
466                 .caps = {
467                         .has_tuner    = 1,
468                         .has_dvb      = 1,
469                         .has_zl10353  = 1,
470                         .has_eeprom   = 1,
471                         .has_remote   = 1,
472                         .has_radio    = 1,
473                 },
474                 .gpio = {
475                         .tuner_reset    = TM6010_GPIO_2,
476                         .tuner_on       = TM6010_GPIO_3,
477                         .demod_reset    = TM6010_GPIO_1,
478                         .demod_on       = TM6010_GPIO_4,
479                         .power_led      = TM6010_GPIO_7,
480                         .dvb_led        = TM6010_GPIO_5,
481                         .ir             = TM6010_GPIO_0,
482                 },
483                 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
484                 .vinput = { {
485                         .type   = TM6000_INPUT_TV,
486                         .vmux   = TM6000_VMUX_VIDEO_B,
487                         .amux   = TM6000_AMUX_SIF1,
488                         }, {
489                         .type   = TM6000_INPUT_COMPOSITE1,
490                         .vmux   = TM6000_VMUX_VIDEO_A,
491                         .amux   = TM6000_AMUX_ADC2,
492                         }, {
493                         .type   = TM6000_INPUT_SVIDEO,
494                         .vmux   = TM6000_VMUX_VIDEO_AB,
495                         .amux   = TM6000_AMUX_ADC2,
496                         },
497                 },
498                 .rinput = {
499                         .type = TM6000_INPUT_RADIO,
500                         .amux = TM6000_AMUX_SIF1,
501                 },
502         },
503         [TM5600_BOARD_TERRATEC_GRABSTER] = {
504                 .name         = "Terratec Grabster AV 150/250 MX",
505                 .type         = TM5600,
506                 .tuner_type   = TUNER_ABSENT,
507                 .vinput = { {
508                         .type   = TM6000_INPUT_TV,
509                         .vmux   = TM6000_VMUX_VIDEO_B,
510                         .amux   = TM6000_AMUX_ADC1,
511                         }, {
512                         .type   = TM6000_INPUT_COMPOSITE1,
513                         .vmux   = TM6000_VMUX_VIDEO_A,
514                         .amux   = TM6000_AMUX_ADC2,
515                         }, {
516                         .type   = TM6000_INPUT_SVIDEO,
517                         .vmux   = TM6000_VMUX_VIDEO_AB,
518                         .amux   = TM6000_AMUX_ADC2,
519                         },
520                 },
521         },
522         [TM6010_BOARD_TWINHAN_TU501] = {
523                 .name         = "Twinhan TU501(704D1)",
524                 .tuner_type   = TUNER_XC2028, /* has a XC3028 */
525                 .tuner_addr   = 0xc2 >> 1,
526                 .demod_addr   = 0x1e >> 1,
527                 .type         = TM6010,
528                 .caps = {
529                         .has_tuner    = 1,
530                         .has_dvb      = 1,
531                         .has_zl10353  = 1,
532                         .has_eeprom   = 1,
533                         .has_remote   = 1,
534                 },
535                 .gpio = {
536                         .tuner_reset    = TM6010_GPIO_2,
537                         .tuner_on       = TM6010_GPIO_3,
538                         .demod_reset    = TM6010_GPIO_1,
539                         .demod_on       = TM6010_GPIO_4,
540                         .power_led      = TM6010_GPIO_7,
541                         .dvb_led        = TM6010_GPIO_5,
542                         .ir             = TM6010_GPIO_0,
543                 },
544                 .vinput = { {
545                         .type   = TM6000_INPUT_TV,
546                         .vmux   = TM6000_VMUX_VIDEO_B,
547                         .amux   = TM6000_AMUX_SIF1,
548                         }, {
549                         .type   = TM6000_INPUT_COMPOSITE1,
550                         .vmux   = TM6000_VMUX_VIDEO_A,
551                         .amux   = TM6000_AMUX_ADC2,
552                         }, {
553                         .type   = TM6000_INPUT_SVIDEO,
554                         .vmux   = TM6000_VMUX_VIDEO_AB,
555                         .amux   = TM6000_AMUX_ADC2,
556                         },
557                 },
558         },
559         [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
560                 .name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
561                 .tuner_type   = TUNER_XC5000,
562                 .tuner_addr   = 0xc2 >> 1,
563                 .demod_addr   = 0x1e >> 1,
564                 .type         = TM6010,
565                 .caps = {
566                         .has_tuner      = 1,
567                         .has_dvb        = 1,
568                         .has_zl10353    = 1,
569                         .has_eeprom     = 1,
570                         .has_remote     = 0,
571                         .has_radio      = 1,
572                 },
573                 .gpio = {
574                         .tuner_reset    = TM6010_GPIO_0,
575                         .demod_reset    = TM6010_GPIO_1,
576                         .power_led      = TM6010_GPIO_6,
577                 },
578                 .vinput = { {
579                         .type   = TM6000_INPUT_TV,
580                         .vmux   = TM6000_VMUX_VIDEO_B,
581                         .amux   = TM6000_AMUX_SIF1,
582                         },
583                 },
584                 .rinput = {
585                         .type   = TM6000_INPUT_RADIO,
586                         .amux   = TM6000_AMUX_ADC1,
587                 },
588         },
589         [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
590                 .name         = "Beholder Voyager Lite TV/FM USB2.0",
591                 .tuner_type   = TUNER_XC5000,
592                 .tuner_addr   = 0xc2 >> 1,
593                 .type         = TM6010,
594                 .caps = {
595                         .has_tuner      = 1,
596                         .has_dvb        = 0,
597                         .has_zl10353    = 0,
598                         .has_eeprom     = 1,
599                         .has_remote     = 0,
600                         .has_radio      = 1,
601                 },
602                 .gpio = {
603                         .tuner_reset    = TM6010_GPIO_0,
604                         .power_led      = TM6010_GPIO_6,
605                 },
606                 .vinput = { {
607                         .type   = TM6000_INPUT_TV,
608                         .vmux   = TM6000_VMUX_VIDEO_B,
609                         .amux   = TM6000_AMUX_SIF1,
610                         },
611                 },
612                 .rinput = {
613                         .type   = TM6000_INPUT_RADIO,
614                         .amux   = TM6000_AMUX_ADC1,
615                 },
616         },
617 };
618 
619 /* table of devices that work with this driver */
620 static 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 MODULE_DEVICE_TABLE(usb, tm6000_id_table);
644 
645 /* Control power led for show some activity */
646 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
647 {
648         /* Power LED unconfigured */
649         if (!dev->gpio.power_led)
650                 return;
651 
652         /* ON Power LED */
653         if (state) {
654                 switch (dev->model) {
655                 case TM6010_BOARD_HAUPPAUGE_900H:
656                 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
657                 case TM6010_BOARD_TWINHAN_TU501:
658                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
659                                 dev->gpio.power_led, 0x00);
660                         break;
661                 case TM6010_BOARD_BEHOLD_WANDER:
662                 case TM6010_BOARD_BEHOLD_VOYAGER:
663                 case TM6010_BOARD_BEHOLD_WANDER_LITE:
664                 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
665                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
666                                 dev->gpio.power_led, 0x01);
667                         break;
668                 }
669         }
670         /* OFF Power LED */
671         else {
672                 switch (dev->model) {
673                 case TM6010_BOARD_HAUPPAUGE_900H:
674                 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
675                 case TM6010_BOARD_TWINHAN_TU501:
676                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
677                                 dev->gpio.power_led, 0x01);
678                         break;
679                 case TM6010_BOARD_BEHOLD_WANDER:
680                 case TM6010_BOARD_BEHOLD_VOYAGER:
681                 case TM6010_BOARD_BEHOLD_WANDER_LITE:
682                 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
683                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
684                                 dev->gpio.power_led, 0x00);
685                         break;
686                 }
687         }
688 }
689 
690 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
691 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
692 {
693         int rc = 0;
694         struct tm6000_core *dev = ptr;
695 
696         if (dev->tuner_type != TUNER_XC5000)
697                 return 0;
698 
699         switch (command) {
700         case XC5000_TUNER_RESET:
701                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
702                                dev->gpio.tuner_reset, 0x01);
703                 msleep(15);
704                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
705                                dev->gpio.tuner_reset, 0x00);
706                 msleep(15);
707                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
708                                dev->gpio.tuner_reset, 0x01);
709                 break;
710         }
711         return rc;
712 }
713 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
714 
715 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
716 
717 int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
718 {
719         int rc = 0;
720         struct tm6000_core *dev = ptr;
721 
722         if (dev->tuner_type != TUNER_XC2028)
723                 return 0;
724 
725         switch (command) {
726         case XC2028_RESET_CLK:
727                 tm6000_ir_wait(dev, 0);
728 
729                 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
730                                         0x02, arg);
731                 msleep(10);
732                 rc = tm6000_i2c_reset(dev, 10);
733                 break;
734         case XC2028_TUNER_RESET:
735                 /* Reset codes during load firmware */
736                 switch (arg) {
737                 case 0:
738                         /* newer tuner can faster reset */
739                         switch (dev->model) {
740                         case TM5600_BOARD_10MOONS_UT821:
741                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
742                                                dev->gpio.tuner_reset, 0x01);
743                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
744                                                0x300, 0x01);
745                                 msleep(10);
746                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
747                                                dev->gpio.tuner_reset, 0x00);
748                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
749                                                0x300, 0x00);
750                                 msleep(10);
751                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
752                                                dev->gpio.tuner_reset, 0x01);
753                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
754                                                0x300, 0x01);
755                                 break;
756                         case TM6010_BOARD_HAUPPAUGE_900H:
757                         case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
758                         case TM6010_BOARD_TWINHAN_TU501:
759                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
760                                                dev->gpio.tuner_reset, 0x01);
761                                 msleep(60);
762                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
763                                                dev->gpio.tuner_reset, 0x00);
764                                 msleep(75);
765                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
766                                                dev->gpio.tuner_reset, 0x01);
767                                 msleep(60);
768                                 break;
769                         default:
770                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
771                                                dev->gpio.tuner_reset, 0x00);
772                                 msleep(130);
773                                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
774                                                dev->gpio.tuner_reset, 0x01);
775                                 msleep(130);
776                                 break;
777                         }
778 
779                         tm6000_ir_wait(dev, 1);
780                         break;
781                 case 1:
782                         tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
783                                                 0x02, 0x01);
784                         msleep(10);
785                         break;
786                 case 2:
787                         rc = tm6000_i2c_reset(dev, 100);
788                         break;
789                 }
790                 break;
791         case XC2028_I2C_FLUSH:
792                 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
793                 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
794                 break;
795         }
796         return rc;
797 }
798 EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
799 
800 int tm6000_cards_setup(struct tm6000_core *dev)
801 {
802         /*
803          * Board-specific initialization sequence. Handles all GPIO
804          * initialization sequences that are board-specific.
805          * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
806          * Probably, they're all based on some reference device. Due to that,
807          * there's a common routine at the end to handle those GPIO's. Devices
808          * that use different pinups or init sequences can just return at
809          * the board-specific session.
810          */
811         switch (dev->model) {
812         case TM6010_BOARD_HAUPPAUGE_900H:
813         case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
814         case TM6010_BOARD_TWINHAN_TU501:
815         case TM6010_BOARD_GENERIC:
816                 /* Turn xceive 3028 on */
817                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
818                 msleep(15);
819                 /* Turn zarlink zl10353 on */
820                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
821                 msleep(15);
822                 /* Reset zarlink zl10353 */
823                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
824                 msleep(50);
825                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
826                 msleep(15);
827                 /* Turn zarlink zl10353 off */
828                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
829                 msleep(15);
830                 /* ir ? */
831                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
832                 msleep(15);
833                 /* Power led on (blue) */
834                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
835                 msleep(15);
836                 /* DVB led off (orange) */
837                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
838                 msleep(15);
839                 /* Turn zarlink zl10353 on */
840                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
841                 msleep(15);
842                 break;
843         case TM6010_BOARD_BEHOLD_WANDER:
844         case TM6010_BOARD_BEHOLD_WANDER_LITE:
845                 /* Power led on (blue) */
846                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
847                 msleep(15);
848                 /* Reset zarlink zl10353 */
849                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
850                 msleep(50);
851                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
852                 msleep(15);
853                 break;
854         case TM6010_BOARD_BEHOLD_VOYAGER:
855         case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
856                 /* Power led on (blue) */
857                 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
858                 msleep(15);
859                 break;
860         default:
861                 break;
862         }
863 
864         /*
865          * Default initialization. Most of the devices seem to use GPIO1
866          * and GPIO4.on the same way, so, this handles the common sequence
867          * used by most devices.
868          * If a device uses a different sequence or different GPIO pins for
869          * reset, just add the code at the board-specific part
870          */
871 
872         if (dev->gpio.tuner_reset) {
873                 int rc;
874                 int i;
875 
876                 for (i = 0; i < 2; i++) {
877                         rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
878                                                 dev->gpio.tuner_reset, 0x00);
879                         if (rc < 0) {
880                                 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
881                                 return rc;
882                         }
883 
884                         msleep(10); /* Just to be conservative */
885                         rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
886                                                 dev->gpio.tuner_reset, 0x01);
887                         if (rc < 0) {
888                                 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
889                                 return rc;
890                         }
891                 }
892         } else {
893                 printk(KERN_ERR "Tuner reset is not configured\n");
894                 return -1;
895         }
896 
897         msleep(50);
898 
899         return 0;
900 };
901 
902 static void tm6000_config_tuner(struct tm6000_core *dev)
903 {
904         struct tuner_setup tun_setup;
905 
906         /* Load tuner module */
907         v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
908                 "tuner", dev->tuner_addr, NULL);
909 
910         memset(&tun_setup, 0, sizeof(tun_setup));
911         tun_setup.type = dev->tuner_type;
912         tun_setup.addr = dev->tuner_addr;
913 
914         tun_setup.mode_mask = 0;
915         if (dev->caps.has_tuner)
916                 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
917 
918         switch (dev->tuner_type) {
919         case TUNER_XC2028:
920                 tun_setup.tuner_callback = tm6000_tuner_callback;
921                 break;
922         case TUNER_XC5000:
923                 tun_setup.tuner_callback = tm6000_xc5000_callback;
924                 break;
925         }
926 
927         v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
928 
929         switch (dev->tuner_type) {
930         case TUNER_XC2028: {
931                 struct v4l2_priv_tun_config xc2028_cfg;
932                 struct xc2028_ctrl ctl;
933 
934                 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
935                 memset(&ctl, 0, sizeof(ctl));
936 
937                 ctl.demod = XC3028_FE_ZARLINK456;
938 
939                 xc2028_cfg.tuner = TUNER_XC2028;
940                 xc2028_cfg.priv  = &ctl;
941 
942                 switch (dev->model) {
943                 case TM6010_BOARD_HAUPPAUGE_900H:
944                 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
945                 case TM6010_BOARD_TWINHAN_TU501:
946                         ctl.max_len = 80;
947                         ctl.fname = "xc3028L-v36.fw";
948                         break;
949                 default:
950                         if (dev->dev_type == TM6010)
951                                 ctl.fname = "xc3028-v27.fw";
952                         else
953                                 ctl.fname = "xc3028-v24.fw";
954                 }
955 
956                 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
957                 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
958                                      &xc2028_cfg);
959 
960                 }
961                 break;
962         case TUNER_XC5000:
963                 {
964                 struct v4l2_priv_tun_config  xc5000_cfg;
965                 struct xc5000_config ctl = {
966                         .i2c_address = dev->tuner_addr,
967                         .if_khz      = 4570,
968                         .radio_input = XC5000_RADIO_FM1_MONO,
969                         };
970 
971                 xc5000_cfg.tuner = TUNER_XC5000;
972                 xc5000_cfg.priv  = &ctl;
973 
974                 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
975                                      &xc5000_cfg);
976                 }
977                 break;
978         default:
979                 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
980                 break;
981         }
982 }
983 
984 static int fill_board_specific_data(struct tm6000_core *dev)
985 {
986         int rc;
987 
988         dev->dev_type   = tm6000_boards[dev->model].type;
989         dev->tuner_type = tm6000_boards[dev->model].tuner_type;
990         dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
991 
992         dev->gpio = tm6000_boards[dev->model].gpio;
993 
994         dev->ir_codes = tm6000_boards[dev->model].ir_codes;
995 
996         dev->demod_addr = tm6000_boards[dev->model].demod_addr;
997 
998         dev->caps = tm6000_boards[dev->model].caps;
999 
1000         dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
1001         dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
1002         dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
1003         dev->rinput = tm6000_boards[dev->model].rinput;
1004 
1005         /* setup per-model quirks */
1006         switch (dev->model) {
1007         case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1008         case TM6010_BOARD_HAUPPAUGE_900H:
1009                 dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
1010                 break;
1011 
1012         default:
1013                 break;
1014         }
1015 
1016         /* initialize hardware */
1017         rc = tm6000_init(dev);
1018         if (rc < 0)
1019                 return rc;
1020 
1021         return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
1022 }
1023 
1024 
1025 static void use_alternative_detection_method(struct tm6000_core *dev)
1026 {
1027         int i, model = -1;
1028 
1029         if (!dev->eedata_size)
1030                 return;
1031 
1032         for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
1033                 if (!tm6000_boards[i].eename_size)
1034                         continue;
1035                 if (dev->eedata_size < tm6000_boards[i].eename_pos +
1036                                        tm6000_boards[i].eename_size)
1037                         continue;
1038 
1039                 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
1040                             tm6000_boards[i].eename,
1041                             tm6000_boards[i].eename_size)) {
1042                         model = i;
1043                         break;
1044                 }
1045         }
1046         if (model < 0) {
1047                 printk(KERN_INFO "Device has eeprom but is currently unknown\n");
1048                 return;
1049         }
1050 
1051         dev->model = model;
1052 
1053         printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
1054                tm6000_boards[model].name, model);
1055 }
1056 
1057 #if defined(CONFIG_MODULES) && defined(MODULE)
1058 static void request_module_async(struct work_struct *work)
1059 {
1060         struct tm6000_core *dev = container_of(work, struct tm6000_core,
1061                                                request_module_wk);
1062 
1063         request_module("tm6000-alsa");
1064 
1065         if (dev->caps.has_dvb)
1066                 request_module("tm6000-dvb");
1067 }
1068 
1069 static void request_modules(struct tm6000_core *dev)
1070 {
1071         INIT_WORK(&dev->request_module_wk, request_module_async);
1072         schedule_work(&dev->request_module_wk);
1073 }
1074 
1075 static void flush_request_modules(struct tm6000_core *dev)
1076 {
1077         flush_work(&dev->request_module_wk);
1078 }
1079 #else
1080 #define request_modules(dev)
1081 #define flush_request_modules(dev)
1082 #endif /* CONFIG_MODULES */
1083 
1084 static int tm6000_init_dev(struct tm6000_core *dev)
1085 {
1086         struct v4l2_frequency f;
1087         int rc = 0;
1088 
1089         mutex_init(&dev->lock);
1090         mutex_lock(&dev->lock);
1091 
1092         if (!is_generic(dev->model)) {
1093                 rc = fill_board_specific_data(dev);
1094                 if (rc < 0)
1095                         goto err;
1096 
1097                 /* register i2c bus */
1098                 rc = tm6000_i2c_register(dev);
1099                 if (rc < 0)
1100                         goto err;
1101         } else {
1102                 /* register i2c bus */
1103                 rc = tm6000_i2c_register(dev);
1104                 if (rc < 0)
1105                         goto err;
1106 
1107                 use_alternative_detection_method(dev);
1108 
1109                 rc = fill_board_specific_data(dev);
1110                 if (rc < 0)
1111                         goto err;
1112         }
1113 
1114         /* Default values for STD and resolutions */
1115         dev->width = 720;
1116         dev->height = 480;
1117         dev->norm = V4L2_STD_NTSC_M;
1118 
1119         /* Configure tuner */
1120         tm6000_config_tuner(dev);
1121 
1122         /* Set video standard */
1123         v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
1124 
1125         /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1126         f.tuner = 0;
1127         f.type = V4L2_TUNER_ANALOG_TV;
1128         f.frequency = 3092;     /* 193.25 MHz */
1129         dev->freq = f.frequency;
1130         v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1131 
1132         if (dev->caps.has_tda9874)
1133                 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1134                         "tvaudio", I2C_ADDR_TDA9874, NULL);
1135 
1136         /* register and initialize V4L2 */
1137         rc = tm6000_v4l2_register(dev);
1138         if (rc < 0)
1139                 goto err;
1140 
1141         tm6000_add_into_devlist(dev);
1142         tm6000_init_extension(dev);
1143 
1144         tm6000_ir_init(dev);
1145 
1146         request_modules(dev);
1147 
1148         mutex_unlock(&dev->lock);
1149         return 0;
1150 
1151 err:
1152         mutex_unlock(&dev->lock);
1153         return rc;
1154 }
1155 
1156 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1157 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1158 
1159 static void get_max_endpoint(struct usb_device *udev,
1160                              struct usb_host_interface *alt,
1161                              char *msgtype,
1162                              struct usb_host_endpoint *curr_e,
1163                              struct tm6000_endpoint *tm_ep)
1164 {
1165         u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1166         unsigned int size = tmp & 0x7ff;
1167 
1168         if (udev->speed == USB_SPEED_HIGH)
1169                 size = size * hb_mult(tmp);
1170 
1171         if (size > tm_ep->maxsize) {
1172                 tm_ep->endp = curr_e;
1173                 tm_ep->maxsize = size;
1174                 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1175                 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1176 
1177                 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1178                                         msgtype, curr_e->desc.bEndpointAddress,
1179                                         size);
1180         }
1181 }
1182 
1183 /*
1184  * tm6000_usb_probe()
1185  * checks for supported devices
1186  */
1187 static int tm6000_usb_probe(struct usb_interface *interface,
1188                             const struct usb_device_id *id)
1189 {
1190         struct usb_device *usbdev;
1191         struct tm6000_core *dev = NULL;
1192         int i, rc = 0;
1193         int nr = 0;
1194         char *speed;
1195 
1196         usbdev = usb_get_dev(interface_to_usbdev(interface));
1197 
1198         /* Selects the proper interface */
1199         rc = usb_set_interface(usbdev, 0, 1);
1200         if (rc < 0)
1201                 goto err;
1202 
1203         /* Check to see next free device and mark as used */
1204         nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1205         if (nr >= TM6000_MAXBOARDS) {
1206                 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1207                 usb_put_dev(usbdev);
1208                 return -ENOMEM;
1209         }
1210 
1211         /* Create and initialize dev struct */
1212         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1213         if (dev == NULL) {
1214                 printk(KERN_ERR "tm6000" ": out of memory!\n");
1215                 usb_put_dev(usbdev);
1216                 return -ENOMEM;
1217         }
1218         spin_lock_init(&dev->slock);
1219         mutex_init(&dev->usb_lock);
1220 
1221         /* Increment usage count */
1222         set_bit(nr, &tm6000_devused);
1223         snprintf(dev->name, 29, "tm6000 #%d", nr);
1224 
1225         dev->model = id->driver_info;
1226         if (card[nr] < ARRAY_SIZE(tm6000_boards))
1227                 dev->model = card[nr];
1228 
1229         dev->udev = usbdev;
1230         dev->devno = nr;
1231 
1232         switch (usbdev->speed) {
1233         case USB_SPEED_LOW:
1234                 speed = "1.5";
1235                 break;
1236         case USB_SPEED_UNKNOWN:
1237         case USB_SPEED_FULL:
1238                 speed = "12";
1239                 break;
1240         case USB_SPEED_HIGH:
1241                 speed = "480";
1242                 break;
1243         default:
1244                 speed = "unknown";
1245         }
1246 
1247         /* Get endpoints */
1248         for (i = 0; i < interface->num_altsetting; i++) {
1249                 int ep;
1250 
1251                 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1252                         struct usb_host_endpoint        *e;
1253                         int dir_out;
1254 
1255                         e = &interface->altsetting[i].endpoint[ep];
1256 
1257                         dir_out = ((e->desc.bEndpointAddress &
1258                                         USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1259 
1260                         printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1261                                i,
1262                                interface->altsetting[i].desc.bInterfaceNumber,
1263                                interface->altsetting[i].desc.bInterfaceClass);
1264 
1265                         switch (e->desc.bmAttributes) {
1266                         case USB_ENDPOINT_XFER_BULK:
1267                                 if (!dir_out) {
1268                                         get_max_endpoint(usbdev,
1269                                                          &interface->altsetting[i],
1270                                                          "Bulk IN", e,
1271                                                          &dev->bulk_in);
1272                                 } else {
1273                                         get_max_endpoint(usbdev,
1274                                                          &interface->altsetting[i],
1275                                                          "Bulk OUT", e,
1276                                                          &dev->bulk_out);
1277                                 }
1278                                 break;
1279                         case USB_ENDPOINT_XFER_ISOC:
1280                                 if (!dir_out) {
1281                                         get_max_endpoint(usbdev,
1282                                                          &interface->altsetting[i],
1283                                                          "ISOC IN", e,
1284                                                          &dev->isoc_in);
1285                                 } else {
1286                                         get_max_endpoint(usbdev,
1287                                                          &interface->altsetting[i],
1288                                                          "ISOC OUT", e,
1289                                                          &dev->isoc_out);
1290                                 }
1291                                 break;
1292                         case USB_ENDPOINT_XFER_INT:
1293                                 if (!dir_out) {
1294                                         get_max_endpoint(usbdev,
1295                                                         &interface->altsetting[i],
1296                                                         "INT IN", e,
1297                                                         &dev->int_in);
1298                                 } else {
1299                                         get_max_endpoint(usbdev,
1300                                                         &interface->altsetting[i],
1301                                                         "INT OUT", e,
1302                                                         &dev->int_out);
1303                                 }
1304                                 break;
1305                         }
1306                 }
1307         }
1308 
1309 
1310         printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1311                 speed,
1312                 le16_to_cpu(dev->udev->descriptor.idVendor),
1313                 le16_to_cpu(dev->udev->descriptor.idProduct),
1314                 interface->altsetting->desc.bInterfaceNumber);
1315 
1316 /* check if the the device has the iso in endpoint at the correct place */
1317         if (!dev->isoc_in.endp) {
1318                 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1319                 rc = -ENODEV;
1320 
1321                 goto err;
1322         }
1323 
1324         /* save our data pointer in this interface device */
1325         usb_set_intfdata(interface, dev);
1326 
1327         printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1328 
1329         rc = tm6000_init_dev(dev);
1330         if (rc < 0)
1331                 goto err;
1332 
1333         return 0;
1334 
1335 err:
1336         printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1337 
1338         clear_bit(nr, &tm6000_devused);
1339         usb_put_dev(usbdev);
1340 
1341         kfree(dev);
1342         return rc;
1343 }
1344 
1345 /*
1346  * tm6000_usb_disconnect()
1347  * called when the device gets diconencted
1348  * video device will be unregistered on v4l2_close in case it is still open
1349  */
1350 static void tm6000_usb_disconnect(struct usb_interface *interface)
1351 {
1352         struct tm6000_core *dev = usb_get_intfdata(interface);
1353         usb_set_intfdata(interface, NULL);
1354 
1355         if (!dev)
1356                 return;
1357 
1358         printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1359 
1360         flush_request_modules(dev);
1361 
1362         tm6000_ir_fini(dev);
1363 
1364         if (dev->gpio.power_led) {
1365                 switch (dev->model) {
1366                 case TM6010_BOARD_HAUPPAUGE_900H:
1367                 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1368                 case TM6010_BOARD_TWINHAN_TU501:
1369                         /* Power led off */
1370                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1371                                 dev->gpio.power_led, 0x01);
1372                         msleep(15);
1373                         break;
1374                 case TM6010_BOARD_BEHOLD_WANDER:
1375                 case TM6010_BOARD_BEHOLD_VOYAGER:
1376                 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1377                 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1378                         /* Power led off */
1379                         tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1380                                 dev->gpio.power_led, 0x00);
1381                         msleep(15);
1382                         break;
1383                 }
1384         }
1385         tm6000_v4l2_unregister(dev);
1386 
1387         tm6000_i2c_unregister(dev);
1388 
1389         v4l2_device_unregister(&dev->v4l2_dev);
1390 
1391         dev->state |= DEV_DISCONNECTED;
1392 
1393         usb_put_dev(dev->udev);
1394 
1395         tm6000_close_extension(dev);
1396         tm6000_remove_from_devlist(dev);
1397 
1398         clear_bit(dev->devno, &tm6000_devused);
1399         kfree(dev);
1400 }
1401 
1402 static struct usb_driver tm6000_usb_driver = {
1403                 .name = "tm6000",
1404                 .probe = tm6000_usb_probe,
1405                 .disconnect = tm6000_usb_disconnect,
1406                 .id_table = tm6000_id_table,
1407 };
1408 
1409 module_usb_driver(tm6000_usb_driver);
1410 
1411 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1412 MODULE_AUTHOR("Mauro Carvalho Chehab");
1413 MODULE_LICENSE("GPL");
1414 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us