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