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