aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dvb-usb/vp702x.c
diff options
context:
space:
mode:
authorPatrick Boettcher <pb@linuxtv.org>2005-09-09 16:02:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:57:40 -0400
commit3706a4da2012679631da6d22e86c6a34cde7419a (patch)
tree45bf457db581f3b30d9ba49e1f4f1ad7f99f894c /drivers/media/dvb/dvb-usb/vp702x.c
parent80e27e20619902b11aa255081fd83eab10fc0839 (diff)
[PATCH] dvb: usb: add TwinhanDTV StarBox support
Add driver for the TwinhanDTV StarBox and clones. Thanks to Ralph Metzler for his initial work on this box and thanks to Twinhan for their support. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/vp702x.c')
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
new file mode 100644
index 000000000000..1f5034ca1152
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -0,0 +1,290 @@
1/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
2 * receiver.
3 *
4 * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
5 * Metzler Brothers Systementwicklung GbR
6 *
7 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
8 *
9 * Thanks to Twinhan who kindly provided hardware and information.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation, version 2.
14 *
15 * see Documentation/dvb/README.dvb-usb for more information
16 */
17#include "vp702x.h"
18
19/* debug */
20int dvb_usb_vp702x_debug;
21module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
22MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
23
24struct vp702x_state {
25 u8 pid_table[17]; /* [16] controls the pid_table state */
26};
27
28/* check for mutex FIXME */
29int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
30{
31 int ret = 0,try = 0;
32
33 while (ret >= 0 && ret != blen && try < 3) {
34 ret = usb_control_msg(d->udev,
35 usb_rcvctrlpipe(d->udev,0),
36 req,
37 USB_TYPE_VENDOR | USB_DIR_IN,
38 value,index,b,blen,
39 2000);
40 deb_info("reading number %d (ret: %d)\n",try,ret);
41 try++;
42 }
43
44 if (ret < 0 || ret != blen) {
45 warn("usb in operation failed.");
46 ret = -EIO;
47 } else
48 ret = 0;
49
50 deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
51 debug_dump(b,blen,deb_xfer);
52
53 return ret;
54}
55
56int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
57{
58 deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
59 debug_dump(b,blen,deb_xfer);
60
61 if (usb_control_msg(d->udev,
62 usb_sndctrlpipe(d->udev,0),
63 req,
64 USB_TYPE_VENDOR | USB_DIR_OUT,
65 value,index,b,blen,
66 2000) != blen) {
67 warn("usb out operation failed.");
68 return -EIO;
69 } else
70 return 0;
71}
72
73int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
74{
75 int ret;
76
77 if ((ret = down_interruptible(&d->usb_sem)))
78 return ret;
79
80 if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
81 goto unlock;
82 msleep(msec);
83 ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
84
85unlock:
86 up(&d->usb_sem);
87
88 return ret;
89}
90
91int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, int olen, u8 *i, int ilen, int msec)
92{
93 u8 bout[olen+2];
94 u8 bin[ilen+1];
95 int ret = 0;
96
97 bout[0] = 0x00;
98 bout[1] = cmd;
99 memcpy(&bout[2],o,olen);
100
101 ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
102
103 if (ret == 0)
104 memcpy(i,&bin[1],ilen);
105
106 return ret;
107}
108
109static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
110{
111 struct vp702x_state *st = d->priv;
112 u8 buf[9];
113
114 if (onoff) {
115 st->pid_table[16] |= 1 << index;
116 st->pid_table[index*2] = (pid >> 8) & 0xff;
117 st->pid_table[index*2+1] = pid & 0xff;
118 } else {
119 st->pid_table[16] &= ~(1 << index);
120 st->pid_table[index*2] = st->pid_table[index*2+1] = 0;
121 }
122
123 return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10);
124}
125
126static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
127{
128 vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0);
129
130 vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
131 return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
132}
133
134/* keys for the enclosed remote control */
135static struct dvb_usb_rc_key vp702x_rc_keys[] = {
136 { 0x00, 0x01, KEY_1 },
137 { 0x00, 0x02, KEY_2 },
138};
139
140/* remote control stuff (does not work with my box) */
141static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
142{
143 u8 key[10];
144 int i;
145
146/* remove the following return to enabled remote querying */
147 return 0;
148
149 vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
150
151 deb_rc("remote query key: %x %d\n",key[1],key[1]);
152
153 if (key[1] == 0x44) {
154 *state = REMOTE_NO_KEY_PRESSED;
155 return 0;
156 }
157
158 for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
159 if (vp702x_rc_keys[i].custom == key[1]) {
160 *state = REMOTE_KEY_PRESSED;
161 *event = vp702x_rc_keys[i].event;
162 break;
163 }
164 return 0;
165}
166
167static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
168{
169 u8 macb[9];
170 if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10))
171 return -EIO;
172 memcpy(mac,&macb[3],6);
173 return 0;
174}
175
176static int vp702x_frontend_attach(struct dvb_usb_device *d)
177{
178 u8 buf[9] = { 0 };
179
180 if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10))
181 return -EIO;
182
183 buf[8] = '\0';
184 info("system string: %s",&buf[1]);
185
186 d->fe = vp702x_fe_attach(d);
187 return 0;
188}
189
190static struct dvb_usb_properties vp702x_properties;
191
192static int vp702x_usb_probe(struct usb_interface *intf,
193 const struct usb_device_id *id)
194{
195 struct usb_device *udev = interface_to_usbdev(intf);
196
197 usb_clear_halt(udev,usb_sndctrlpipe(udev,0));
198 usb_clear_halt(udev,usb_rcvctrlpipe(udev,0));
199
200 return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE);
201}
202
203static struct usb_device_id vp702x_usb_table [] = {
204 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
205 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) },
206 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
207 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
208 { 0 },
209};
210MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
211
212static struct dvb_usb_properties vp702x_properties = {
213 .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
214 .pid_filter_count = 8, /* !!! */
215
216 .usb_ctrl = CYPRESS_FX2,
217 .firmware = "dvb-usb-vp702x-01.fw",
218
219 .pid_filter = vp702x_pid_filter,
220 .power_ctrl = vp702x_power_ctrl,
221 .frontend_attach = vp702x_frontend_attach,
222 .read_mac_address = vp702x_read_mac_addr,
223
224 .rc_key_map = vp702x_rc_keys,
225 .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
226 .rc_interval = 400,
227 .rc_query = vp702x_rc_query,
228
229 .size_of_priv = sizeof(struct vp702x_state),
230
231 /* parameter for the MPEG2-data transfer */
232 .urb = {
233 .type = DVB_USB_BULK,
234 .count = 7,
235 .endpoint = 0x02,
236 .u = {
237 .bulk = {
238 .buffersize = 4096,
239 }
240 }
241 },
242
243 .num_device_descs = 2,
244 .devices = {
245 { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
246 .cold_ids = { &vp702x_usb_table[0], NULL },
247 .warm_ids = { &vp702x_usb_table[1], NULL },
248 },
249 { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
250 .cold_ids = { &vp702x_usb_table[2], NULL },
251 .warm_ids = { &vp702x_usb_table[3], NULL },
252 },
253 { 0 },
254 }
255};
256
257/* usb specific object needed to register this driver with the usb subsystem */
258static struct usb_driver vp702x_usb_driver = {
259 .owner = THIS_MODULE,
260 .name = "dvb-usb-vp702x",
261 .probe = vp702x_usb_probe,
262 .disconnect = dvb_usb_device_exit,
263 .id_table = vp702x_usb_table,
264};
265
266/* module stuff */
267static int __init vp702x_usb_module_init(void)
268{
269 int result;
270 if ((result = usb_register(&vp702x_usb_driver))) {
271 err("usb_register failed. (%d)",result);
272 return result;
273 }
274
275 return 0;
276}
277
278static void __exit vp702x_usb_module_exit(void)
279{
280 /* deregister this driver from the USB subsystem */
281 usb_deregister(&vp702x_usb_driver);
282}
283
284module_init(vp702x_usb_module_init);
285module_exit(vp702x_usb_module_exit);
286
287MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
288MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
289MODULE_VERSION("1.0-alpha");
290MODULE_LICENSE("GPL");