~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/media/video/tm6000/tm6000-cards.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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