1/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
2 * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
3 *
4 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
5 *
6 * Thanks to Steve Chang from WideView for providing support for the WT-220U.
7 *
8 *	This program is free software; you can redistribute it and/or modify it
9 *	under the terms of the GNU General Public License as published by the Free
10 *	Software Foundation, version 2.
11 *
12 * see Documentation/dvb/README.dvb-usb for more information
13 */
14#include "dtt200u.h"
15
16/* debug */
17int dvb_usb_dtt200u_debug;
18module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
19MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
20
21DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
22
23static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
24{
25	u8 b = SET_INIT;
26
27	if (onoff)
28		dvb_usb_generic_write(d,&b,2);
29
30	return 0;
31}
32
33static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
34{
35	u8 b_streaming[2] = { SET_STREAMING, onoff };
36	u8 b_rst_pid = RESET_PID_FILTER;
37
38	dvb_usb_generic_write(adap->dev, b_streaming, 2);
39
40	if (onoff == 0)
41		dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
42	return 0;
43}
44
45static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
46{
47	u8 b_pid[4];
48	pid = onoff ? pid : 0;
49
50	b_pid[0] = SET_PID_FILTER;
51	b_pid[1] = index;
52	b_pid[2] = pid & 0xff;
53	b_pid[3] = (pid >> 8) & 0x1f;
54
55	return dvb_usb_generic_write(adap->dev, b_pid, 4);
56}
57
58/* remote control */
59/* key list for the tiny remote control (Yakumo, don't know about the others) */
60static struct rc_map_table rc_map_dtt200u_table[] = {
61	{ 0x8001, KEY_MUTE },
62	{ 0x8002, KEY_CHANNELDOWN },
63	{ 0x8003, KEY_VOLUMEDOWN },
64	{ 0x8004, KEY_1 },
65	{ 0x8005, KEY_2 },
66	{ 0x8006, KEY_3 },
67	{ 0x8007, KEY_4 },
68	{ 0x8008, KEY_5 },
69	{ 0x8009, KEY_6 },
70	{ 0x800a, KEY_7 },
71	{ 0x800c, KEY_ZOOM },
72	{ 0x800d, KEY_0 },
73	{ 0x800e, KEY_SELECT },
74	{ 0x8012, KEY_POWER },
75	{ 0x801a, KEY_CHANNELUP },
76	{ 0x801b, KEY_8 },
77	{ 0x801e, KEY_VOLUMEUP },
78	{ 0x801f, KEY_9 },
79};
80
81static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
82{
83	u8 key[5],cmd = GET_RC_CODE;
84	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
85	dvb_usb_nec_rc_key_to_event(d,key,event,state);
86	if (key[0] != 0)
87		deb_info("key: %*ph\n", 5, key);
88	return 0;
89}
90
91static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
92{
93	adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
94	return 0;
95}
96
97static struct dvb_usb_device_properties dtt200u_properties;
98static struct dvb_usb_device_properties wt220u_fc_properties;
99static struct dvb_usb_device_properties wt220u_properties;
100static struct dvb_usb_device_properties wt220u_zl0353_properties;
101static struct dvb_usb_device_properties wt220u_miglia_properties;
102
103static int dtt200u_usb_probe(struct usb_interface *intf,
104		const struct usb_device_id *id)
105{
106	if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
107				     THIS_MODULE, NULL, adapter_nr) ||
108	    0 == dvb_usb_device_init(intf, &wt220u_properties,
109				     THIS_MODULE, NULL, adapter_nr) ||
110	    0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
111				     THIS_MODULE, NULL, adapter_nr) ||
112	    0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
113				     THIS_MODULE, NULL, adapter_nr) ||
114	    0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
115				     THIS_MODULE, NULL, adapter_nr))
116		return 0;
117
118	return -ENODEV;
119}
120
121static struct usb_device_id dtt200u_usb_table [] = {
122	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
123	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
124	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD)  },
125	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
126	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD)  },
127	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM)  },
128	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
129	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
130	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
131	{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
132	{ 0 },
133};
134MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
135
136static struct dvb_usb_device_properties dtt200u_properties = {
137	.usb_ctrl = CYPRESS_FX2,
138	.firmware = "dvb-usb-dtt200u-01.fw",
139
140	.num_adapters = 1,
141	.adapter = {
142		{
143		.num_frontends = 1,
144		.fe = {{
145			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
146			.pid_filter_count = 15,
147
148	.streaming_ctrl  = dtt200u_streaming_ctrl,
149	.pid_filter      = dtt200u_pid_filter,
150	.frontend_attach = dtt200u_frontend_attach,
151	/* parameter for the MPEG2-data transfer */
152			.stream = {
153				.type = USB_BULK,
154		.count = 7,
155		.endpoint = 0x02,
156		.u = {
157			.bulk = {
158				.buffersize = 4096,
159			}
160		}
161	},
162		}},
163		}
164	},
165	.power_ctrl      = dtt200u_power_ctrl,
166
167	.rc.legacy = {
168		.rc_interval     = 300,
169		.rc_map_table    = rc_map_dtt200u_table,
170		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
171		.rc_query        = dtt200u_rc_query,
172	},
173
174	.generic_bulk_ctrl_endpoint = 0x01,
175
176	.num_device_descs = 1,
177	.devices = {
178		{ .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
179		  .cold_ids = { &dtt200u_usb_table[0], NULL },
180		  .warm_ids = { &dtt200u_usb_table[1], NULL },
181		},
182		{ NULL },
183	}
184};
185
186static struct dvb_usb_device_properties wt220u_properties = {
187	.usb_ctrl = CYPRESS_FX2,
188	.firmware = "dvb-usb-wt220u-02.fw",
189
190	.num_adapters = 1,
191	.adapter = {
192		{
193		.num_frontends = 1,
194		.fe = {{
195			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
196			.pid_filter_count = 15,
197
198	.streaming_ctrl  = dtt200u_streaming_ctrl,
199	.pid_filter      = dtt200u_pid_filter,
200	.frontend_attach = dtt200u_frontend_attach,
201	/* parameter for the MPEG2-data transfer */
202			.stream = {
203				.type = USB_BULK,
204		.count = 7,
205		.endpoint = 0x02,
206		.u = {
207			.bulk = {
208				.buffersize = 4096,
209			}
210		}
211	},
212		}},
213		}
214	},
215	.power_ctrl      = dtt200u_power_ctrl,
216
217	.rc.legacy = {
218		.rc_interval     = 300,
219		.rc_map_table      = rc_map_dtt200u_table,
220		.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
221		.rc_query        = dtt200u_rc_query,
222	},
223
224	.generic_bulk_ctrl_endpoint = 0x01,
225
226	.num_device_descs = 1,
227	.devices = {
228		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
229		  .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
230		  .warm_ids = { &dtt200u_usb_table[3], NULL },
231		},
232		{ NULL },
233	}
234};
235
236static struct dvb_usb_device_properties wt220u_fc_properties = {
237	.usb_ctrl = CYPRESS_FX2,
238	.firmware = "dvb-usb-wt220u-fc03.fw",
239
240	.num_adapters = 1,
241	.adapter = {
242		{
243		.num_frontends = 1,
244		.fe = {{
245			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
246			.pid_filter_count = 15,
247
248	.streaming_ctrl  = dtt200u_streaming_ctrl,
249	.pid_filter      = dtt200u_pid_filter,
250	.frontend_attach = dtt200u_frontend_attach,
251	/* parameter for the MPEG2-data transfer */
252			.stream = {
253				.type = USB_BULK,
254		.count = 7,
255				.endpoint = 0x06,
256		.u = {
257			.bulk = {
258				.buffersize = 4096,
259			}
260		}
261	},
262		}},
263		}
264	},
265	.power_ctrl      = dtt200u_power_ctrl,
266
267	.rc.legacy = {
268		.rc_interval     = 300,
269		.rc_map_table    = rc_map_dtt200u_table,
270		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
271		.rc_query        = dtt200u_rc_query,
272	},
273
274	.generic_bulk_ctrl_endpoint = 0x01,
275
276	.num_device_descs = 1,
277	.devices = {
278		{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
279		  .cold_ids = { &dtt200u_usb_table[6], NULL },
280		  .warm_ids = { &dtt200u_usb_table[7], NULL },
281		},
282		{ NULL },
283	}
284};
285
286static struct dvb_usb_device_properties wt220u_zl0353_properties = {
287	.usb_ctrl = CYPRESS_FX2,
288	.firmware = "dvb-usb-wt220u-zl0353-01.fw",
289
290	.num_adapters = 1,
291	.adapter = {
292		{
293		.num_frontends = 1,
294		.fe = {{
295			.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
296			.pid_filter_count = 15,
297
298			.streaming_ctrl  = dtt200u_streaming_ctrl,
299			.pid_filter      = dtt200u_pid_filter,
300			.frontend_attach = dtt200u_frontend_attach,
301			/* parameter for the MPEG2-data transfer */
302			.stream = {
303				.type = USB_BULK,
304				.count = 7,
305				.endpoint = 0x02,
306				.u = {
307					.bulk = {
308						.buffersize = 4096,
309					}
310				}
311			},
312		}},
313		}
314	},
315	.power_ctrl      = dtt200u_power_ctrl,
316
317	.rc.legacy = {
318		.rc_interval     = 300,
319		.rc_map_table    = rc_map_dtt200u_table,
320		.rc_map_size     = ARRAY_SIZE(rc_map_dtt200u_table),
321		.rc_query        = dtt200u_rc_query,
322	},
323
324	.generic_bulk_ctrl_endpoint = 0x01,
325
326	.num_device_descs = 1,
327	.devices = {
328		{ .name = "WideView WT-220U PenType Receiver (based on ZL353)",
329		  .cold_ids = { &dtt200u_usb_table[4], NULL },
330		  .warm_ids = { &dtt200u_usb_table[5], NULL },
331		},
332		{ NULL },
333	}
334};
335
336static struct dvb_usb_device_properties wt220u_miglia_properties = {
337	.usb_ctrl = CYPRESS_FX2,
338	.firmware = "dvb-usb-wt220u-miglia-01.fw",
339
340	.num_adapters = 1,
341	.generic_bulk_ctrl_endpoint = 0x01,
342
343	.num_device_descs = 1,
344	.devices = {
345		{ .name = "WideView WT-220U PenType Receiver (Miglia)",
346		  .cold_ids = { &dtt200u_usb_table[9], NULL },
347		  /* This device turns into WT220U_ZL0353_WARM when fw
348		     has been uploaded */
349		  .warm_ids = { NULL },
350		},
351		{ NULL },
352	}
353};
354
355/* usb specific object needed to register this driver with the usb subsystem */
356static struct usb_driver dtt200u_usb_driver = {
357	.name		= "dvb_usb_dtt200u",
358	.probe		= dtt200u_usb_probe,
359	.disconnect = dvb_usb_device_exit,
360	.id_table	= dtt200u_usb_table,
361};
362
363module_usb_driver(dtt200u_usb_driver);
364
365MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
366MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
367MODULE_VERSION("1.0");
368MODULE_LICENSE("GPL");
369