1/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
2 * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
3 *
4 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
5 *
6 * based on GPL code from DiBcom, which has
7 * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
8 *
9 *	This program is free software; you can redistribute it and/or modify it
10 *	under the terms of the GNU General Public License as published by the Free
11 *	Software Foundation, version 2.
12 *
13 * see Documentation/dvb/README.dvb-usb for more information
14 */
15#include "dibusb.h"
16
17DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
18
19static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
20{
21	struct dvb_usb_adapter *adap = fe->dvb->priv;
22	struct dibusb_state *st = adap->priv;
23
24	return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
25}
26
27static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
28{
29	struct dib3000_config demod_cfg;
30	struct dibusb_state *st = adap->priv;
31
32	demod_cfg.demod_address = 0x8;
33
34	adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
35					 &adap->dev->i2c_adap, &st->ops);
36	if ((adap->fe_adap[0].fe) == NULL)
37		return -ENODEV;
38
39	adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
40
41	return 0;
42}
43
44static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
45{
46	struct dibusb_state *st = adap->priv;
47
48	st->tuner_addr = 0x61;
49
50	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
51		   DVB_PLL_TUA6010XS);
52	return 0;
53}
54
55static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
56{
57	struct dibusb_state *st = adap->priv;
58
59	st->tuner_addr = 0x60;
60
61	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
62		   DVB_PLL_TDA665X);
63	return 0;
64}
65
66/* Some of the Artec 1.1 device aren't equipped with the default tuner
67 * (Thomson Cable), but with a Panasonic ENV77H11D5.  This function figures
68 * this out. */
69static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
70{
71	u8 b[2] = { 0,0 }, b2[1];
72	int ret = 0;
73	struct i2c_msg msg[2] = {
74		{ .flags = 0,        .buf = b,  .len = 2 },
75		{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
76	};
77	struct dibusb_state *st = adap->priv;
78
79	/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
80	msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
81
82	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
83		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
84
85	if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
86		err("tuner i2c write failed.");
87		ret = -EREMOTEIO;
88	}
89
90	if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
91		adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
92
93	if (b2[0] == 0xfe) {
94		info("This device has the Thomson Cable onboard. Which is default.");
95		ret = dibusb_thomson_tuner_attach(adap);
96	} else {
97		info("This device has the Panasonic ENV77H11D5 onboard.");
98		ret = dibusb_panasonic_tuner_attach(adap);
99	}
100
101	return ret;
102}
103
104/* USB Driver stuff */
105static struct dvb_usb_device_properties dibusb1_1_properties;
106static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
107static struct dvb_usb_device_properties dibusb2_0b_properties;
108static struct dvb_usb_device_properties artec_t1_usb2_properties;
109
110static int dibusb_probe(struct usb_interface *intf,
111		const struct usb_device_id *id)
112{
113	if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
114				     THIS_MODULE, NULL, adapter_nr) ||
115	    0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
116				     THIS_MODULE, NULL, adapter_nr) ||
117	    0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
118				     THIS_MODULE, NULL, adapter_nr) ||
119	    0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
120				     THIS_MODULE, NULL, adapter_nr))
121		return 0;
122
123	return -EINVAL;
124}
125
126/* do not change the order of the ID table */
127static struct usb_device_id dibusb_dib3000mb_table [] = {
128/* 00 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_COLD) },
129/* 01 */	{ USB_DEVICE(USB_VID_WIDEVIEW,		USB_PID_AVERMEDIA_DVBT_USB_WARM) },
130/* 02 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_COLD) },
131/* 03 */	{ USB_DEVICE(USB_VID_COMPRO,		USB_PID_COMPRO_DVBU2000_WARM) },
132/* 04 */	{ USB_DEVICE(USB_VID_COMPRO_UNK,	USB_PID_COMPRO_DVBU2000_UNK_COLD) },
133/* 05 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_COLD) },
134/* 06 */	{ USB_DEVICE(USB_VID_DIBCOM,		USB_PID_DIBCOM_MOD3000_WARM) },
135/* 07 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_COLD) },
136/* 08 */	{ USB_DEVICE(USB_VID_EMPIA,		USB_PID_KWORLD_VSTREAM_WARM) },
137/* 09 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_COLD) },
138/* 10 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_GRANDTEC_DVBT_USB_WARM) },
139/* 11 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_COLD) },
140/* 12 */	{ USB_DEVICE(USB_VID_GRANDTEC,		USB_PID_DIBCOM_MOD3000_WARM) },
141/* 13 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_COLD) },
142/* 14 */	{ USB_DEVICE(USB_VID_HYPER_PALTEK,	USB_PID_UNK_HYPER_PALTEK_WARM) },
143/* 15 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_COLD) },
144/* 16 */	{ USB_DEVICE(USB_VID_VISIONPLUS,	USB_PID_TWINHAN_VP7041_WARM) },
145/* 17 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_COLD) },
146/* 18 */	{ USB_DEVICE(USB_VID_TWINHAN,		USB_PID_TWINHAN_VP7041_WARM) },
147/* 19 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_COLD) },
148/* 20 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_WARM) },
149/* 21 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
150/* 22 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
151/* 23 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_COLD) },
152
153/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
154/* 24 */	{ USB_DEVICE(USB_VID_ADSTECH,		USB_PID_ADSTECH_USB2_WARM) },
155/* 25 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_COLD) },
156/* 26 */	{ USB_DEVICE(USB_VID_KYE,		USB_PID_KYE_DVB_T_WARM) },
157
158/* 27 */	{ USB_DEVICE(USB_VID_KWORLD,		USB_PID_KWORLD_VSTREAM_COLD) },
159
160/* 28 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_COLD) },
161/* 29 */	{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,	USB_PID_ULTIMA_TVBOX_USB2_WARM) },
162
163/*
164 * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
165 *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
166 *      have been left on the device. If you don't have such a device but an Artec
167 *      device that's supposed to work with this driver but is not detected by it,
168 *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
169 */
170
171#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
172/* 30 */	{ USB_DEVICE(USB_VID_ANCHOR,		USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
173#endif
174
175			{ }		/* Terminating entry */
176};
177MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
178
179static struct dvb_usb_device_properties dibusb1_1_properties = {
180	.caps =  DVB_USB_IS_AN_I2C_ADAPTER,
181
182	.usb_ctrl = CYPRESS_AN2135,
183
184	.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
185
186	.num_adapters = 1,
187	.adapter = {
188		{
189		.num_frontends = 1,
190		.fe = {{
191			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
192			.pid_filter_count = 16,
193
194			.streaming_ctrl   = dibusb_streaming_ctrl,
195			.pid_filter       = dibusb_pid_filter,
196			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
197			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
198			.tuner_attach     = dibusb_tuner_probe_and_attach,
199
200			/* parameter for the MPEG2-data transfer */
201			.stream = {
202				.type = USB_BULK,
203				.count = 7,
204				.endpoint = 0x02,
205				.u = {
206					.bulk = {
207						.buffersize = 4096,
208					}
209				}
210			},
211		}},
212			.size_of_priv     = sizeof(struct dibusb_state),
213		}
214	},
215
216	.power_ctrl       = dibusb_power_ctrl,
217
218	.rc.legacy = {
219		.rc_interval      = DEFAULT_RC_INTERVAL,
220		.rc_map_table     = rc_map_dibusb_table,
221		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
222		.rc_query         = dibusb_rc_query,
223	},
224
225	.i2c_algo         = &dibusb_i2c_algo,
226
227	.generic_bulk_ctrl_endpoint = 0x01,
228
229	.num_device_descs = 9,
230	.devices = {
231		{	"AVerMedia AverTV DVBT USB1.1",
232			{ &dibusb_dib3000mb_table[0],  NULL },
233			{ &dibusb_dib3000mb_table[1],  NULL },
234		},
235		{	"Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
236			{ &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
237			{ &dibusb_dib3000mb_table[3], NULL },
238		},
239		{	"DiBcom USB1.1 DVB-T reference design (MOD3000)",
240			{ &dibusb_dib3000mb_table[5],  NULL },
241			{ &dibusb_dib3000mb_table[6],  NULL },
242		},
243		{	"KWorld V-Stream XPERT DTV - DVB-T USB1.1",
244			{ &dibusb_dib3000mb_table[7], NULL },
245			{ &dibusb_dib3000mb_table[8], NULL },
246		},
247		{	"Grandtec USB1.1 DVB-T",
248			{ &dibusb_dib3000mb_table[9],  &dibusb_dib3000mb_table[11], NULL },
249			{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
250		},
251		{	"Unknown USB1.1 DVB-T device ???? please report the name to the author",
252			{ &dibusb_dib3000mb_table[13], NULL },
253			{ &dibusb_dib3000mb_table[14], NULL },
254		},
255		{	"TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
256			{ &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
257			{ &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
258		},
259		{	"Artec T1 USB1.1 TVBOX with AN2135",
260			{ &dibusb_dib3000mb_table[19], NULL },
261			{ &dibusb_dib3000mb_table[20], NULL },
262		},
263		{	"VideoWalker DVB-T USB",
264			{ &dibusb_dib3000mb_table[25], NULL },
265			{ &dibusb_dib3000mb_table[26], NULL },
266		},
267	}
268};
269
270static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
271	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
272	.usb_ctrl = CYPRESS_AN2235,
273
274	.firmware = "dvb-usb-dibusb-an2235-01.fw",
275
276	.num_adapters = 1,
277	.adapter = {
278		{
279		.num_frontends = 1,
280		.fe = {{
281			.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
282			.pid_filter_count = 16,
283
284			.streaming_ctrl   = dibusb_streaming_ctrl,
285			.pid_filter       = dibusb_pid_filter,
286			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
287			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
288			.tuner_attach     = dibusb_tuner_probe_and_attach,
289
290			/* parameter for the MPEG2-data transfer */
291			.stream = {
292				.type = USB_BULK,
293				.count = 7,
294				.endpoint = 0x02,
295				.u = {
296					.bulk = {
297						.buffersize = 4096,
298					}
299				}
300			},
301		}},
302			.size_of_priv     = sizeof(struct dibusb_state),
303		},
304	},
305	.power_ctrl       = dibusb_power_ctrl,
306
307	.rc.legacy = {
308		.rc_interval      = DEFAULT_RC_INTERVAL,
309		.rc_map_table     = rc_map_dibusb_table,
310		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
311		.rc_query         = dibusb_rc_query,
312	},
313
314	.i2c_algo         = &dibusb_i2c_algo,
315
316	.generic_bulk_ctrl_endpoint = 0x01,
317
318#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
319	.num_device_descs = 2,
320#else
321	.num_device_descs = 1,
322#endif
323	.devices = {
324		{	"Artec T1 USB1.1 TVBOX with AN2235",
325			{ &dibusb_dib3000mb_table[21], NULL },
326			{ &dibusb_dib3000mb_table[22], NULL },
327		},
328#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
329		{	"Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
330			{ &dibusb_dib3000mb_table[30], NULL },
331			{ NULL },
332		},
333		{ NULL },
334#endif
335	}
336};
337
338static struct dvb_usb_device_properties dibusb2_0b_properties = {
339	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
340
341	.usb_ctrl = CYPRESS_FX2,
342
343	.firmware = "dvb-usb-adstech-usb2-02.fw",
344
345	.num_adapters = 1,
346	.adapter = {
347		{
348		.num_frontends = 1,
349		.fe = {{
350			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
351			.pid_filter_count = 16,
352
353			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
354			.pid_filter       = dibusb_pid_filter,
355			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
356			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
357			.tuner_attach     = dibusb_thomson_tuner_attach,
358
359			/* parameter for the MPEG2-data transfer */
360			.stream = {
361				.type = USB_BULK,
362				.count = 7,
363				.endpoint = 0x06,
364				.u = {
365					.bulk = {
366						.buffersize = 4096,
367					}
368				}
369			},
370		}},
371			.size_of_priv     = sizeof(struct dibusb_state),
372		}
373	},
374	.power_ctrl       = dibusb2_0_power_ctrl,
375
376	.rc.legacy = {
377		.rc_interval      = DEFAULT_RC_INTERVAL,
378		.rc_map_table     = rc_map_dibusb_table,
379		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
380		.rc_query         = dibusb_rc_query,
381	},
382
383	.i2c_algo         = &dibusb_i2c_algo,
384
385	.generic_bulk_ctrl_endpoint = 0x01,
386
387	.num_device_descs = 2,
388	.devices = {
389		{	"KWorld/ADSTech Instant DVB-T USB2.0",
390			{ &dibusb_dib3000mb_table[23], NULL },
391			{ &dibusb_dib3000mb_table[24], NULL },
392		},
393		{	"KWorld Xpert DVB-T USB2.0",
394			{ &dibusb_dib3000mb_table[27], NULL },
395			{ NULL }
396		},
397		{ NULL },
398	}
399};
400
401static struct dvb_usb_device_properties artec_t1_usb2_properties = {
402	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
403
404	.usb_ctrl = CYPRESS_FX2,
405
406	.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
407
408	.num_adapters = 1,
409	.adapter = {
410		{
411		.num_frontends = 1,
412		.fe = {{
413			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
414			.pid_filter_count = 16,
415
416			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
417			.pid_filter       = dibusb_pid_filter,
418			.pid_filter_ctrl  = dibusb_pid_filter_ctrl,
419			.frontend_attach  = dibusb_dib3000mb_frontend_attach,
420			.tuner_attach     = dibusb_tuner_probe_and_attach,
421			/* parameter for the MPEG2-data transfer */
422			.stream = {
423				.type = USB_BULK,
424				.count = 7,
425				.endpoint = 0x06,
426				.u = {
427					.bulk = {
428						.buffersize = 4096,
429					}
430				}
431			},
432		}},
433			.size_of_priv     = sizeof(struct dibusb_state),
434		}
435	},
436	.power_ctrl       = dibusb2_0_power_ctrl,
437
438	.rc.legacy = {
439		.rc_interval      = DEFAULT_RC_INTERVAL,
440		.rc_map_table     = rc_map_dibusb_table,
441		.rc_map_size      = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
442		.rc_query         = dibusb_rc_query,
443	},
444
445	.i2c_algo         = &dibusb_i2c_algo,
446
447	.generic_bulk_ctrl_endpoint = 0x01,
448
449	.num_device_descs = 1,
450	.devices = {
451		{	"Artec T1 USB2.0",
452			{ &dibusb_dib3000mb_table[28], NULL },
453			{ &dibusb_dib3000mb_table[29], NULL },
454		},
455		{ NULL },
456	}
457};
458
459static struct usb_driver dibusb_driver = {
460	.name		= "dvb_usb_dibusb_mb",
461	.probe		= dibusb_probe,
462	.disconnect = dvb_usb_device_exit,
463	.id_table	= dibusb_dib3000mb_table,
464};
465
466module_usb_driver(dibusb_driver);
467
468MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
469MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
470MODULE_VERSION("1.0");
471MODULE_LICENSE("GPL");
472