aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/dibusb/dvb-dibusb-usb.c')
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-usb.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
new file mode 100644
index 000000000000..642f0596a5ba
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
@@ -0,0 +1,303 @@
1/*
2 * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
3 * based on reference design made by DiBcom (http://www.dibcom.fr/)
4 *
5 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
6 *
7 * see dvb-dibusb-core.c for more copyright details.
8 *
9 * This file contains functions for initializing and handling the
10 * usb specific stuff.
11 */
12#include "dvb-dibusb.h"
13
14#include <linux/version.h>
15#include <linux/pci.h>
16
17int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
18 u16 rlen)
19{
20 int actlen,ret = -ENOMEM;
21
22 if (wbuf == NULL || wlen == 0)
23 return -EINVAL;
24
25 if ((ret = down_interruptible(&dib->usb_sem)))
26 return ret;
27
28 debug_dump(wbuf,wlen);
29
30 ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
31 dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
32 DIBUSB_I2C_TIMEOUT);
33
34 if (ret)
35 err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
36 else
37 ret = actlen != wlen ? -1 : 0;
38
39 /* an answer is expected, and no error before */
40 if (!ret && rbuf && rlen) {
41 ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
42 dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen,
43 DIBUSB_I2C_TIMEOUT);
44
45 if (ret)
46 err("recv bulk message failed: %d",ret);
47 else {
48 deb_alot("rlen: %d\n",rlen);
49 debug_dump(rbuf,actlen);
50 }
51 }
52
53 up(&dib->usb_sem);
54 return ret;
55}
56
57/*
58 * Cypress controls
59 */
60int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
61{
62 return dibusb_readwrite_usb(dib,buf,len,NULL,0);
63}
64
65#if 0
66/*
67 * #if 0'ing the following functions as they are not in use _now_,
68 * but probably will be sometime.
69 */
70/*
71 * do not use this, just a workaround for a bug,
72 * which will hopefully never occur :).
73 */
74int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
75{
76 u8 b[1] = { DIBUSB_REQ_INTR_READ };
77 return dibusb_write_usb(dib,b,1);
78}
79#endif
80
81/*
82 * ioctl for the firmware
83 */
84static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
85{
86 u8 b[34];
87 int size = plen > 32 ? 32 : plen;
88 memset(b,0,34);
89 b[0] = DIBUSB_REQ_SET_IOCTL;
90 b[1] = cmd;
91
92 if (size > 0)
93 memcpy(&b[2],param,size);
94
95 return dibusb_write_usb(dib,b,34); //2+size);
96}
97
98/*
99 * ioctl for power control
100 */
101int dibusb_hw_wakeup(struct dvb_frontend *fe)
102{
103 struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
104 u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
105 deb_info("dibusb-device is getting up.\n");
106
107 switch (dib->dibdev->dev_cl->id) {
108 case DTT200U:
109 break;
110 default:
111 dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
112 break;
113 }
114
115 if (dib->fe_init)
116 return dib->fe_init(fe);
117
118 return 0;
119}
120
121int dibusb_hw_sleep(struct dvb_frontend *fe)
122{
123 struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
124 u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
125 deb_info("dibusb-device is going to bed.\n");
126 /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
127 switch (dib->dibdev->dev_cl->id) {
128 case DIBUSB1_1:
129 case NOVAT_USB2:
130 case DTT200U:
131 break;
132 default:
133 dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
134 break;
135 }
136 if (dib->fe_sleep)
137 return dib->fe_sleep(fe);
138
139 return 0;
140}
141
142int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
143{
144 u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
145 return dibusb_readwrite_usb(dib,b,2,NULL,0);
146}
147
148static int dibusb_urb_kill(struct usb_dibusb *dib)
149{
150 int i;
151deb_info("trying to kill urbs\n");
152 if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
153 for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
154 deb_info("killing URB no. %d.\n",i);
155
156 /* stop the URB */
157 usb_kill_urb(dib->urb_list[i]);
158 }
159 } else
160 deb_info(" URBs not killed.\n");
161 dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
162 return 0;
163}
164
165static int dibusb_urb_submit(struct usb_dibusb *dib)
166{
167 int i,ret;
168 if (dib->init_state & DIBUSB_STATE_URB_INIT) {
169 for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
170 deb_info("submitting URB no. %d\n",i);
171 if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
172 err("could not submit buffer urb no. %d - get them all back\n",i);
173 dibusb_urb_kill(dib);
174 return ret;
175 }
176 dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
177 }
178 }
179 return 0;
180}
181
182int dibusb_streaming(struct usb_dibusb *dib,int onoff)
183{
184 if (onoff)
185 dibusb_urb_submit(dib);
186 else
187 dibusb_urb_kill(dib);
188
189 switch (dib->dibdev->dev_cl->id) {
190 case DIBUSB2_0:
191 case DIBUSB2_0B:
192 case NOVAT_USB2:
193 case UMT2_0:
194 if (onoff)
195 return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
196 else
197 return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
198 break;
199 default:
200 break;
201 }
202 return 0;
203}
204
205int dibusb_urb_init(struct usb_dibusb *dib)
206{
207 int i,bufsize,def_pid_parse = 1;
208
209 /*
210 * when reloading the driver w/o replugging the device
211 * a timeout occures, this helps
212 */
213 usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
214 usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
215 usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
216
217 /* allocate the array for the data transfer URBs */
218 dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
219 if (dib->urb_list == NULL)
220 return -ENOMEM;
221 memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
222
223 dib->init_state |= DIBUSB_STATE_URB_LIST;
224
225 bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
226 deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
227 /* allocate the actual buffer for the URBs */
228 if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
229 deb_info("not enough memory.\n");
230 return -ENOMEM;
231 }
232 deb_info("allocation complete\n");
233 memset(dib->buffer,0,bufsize);
234
235 dib->init_state |= DIBUSB_STATE_URB_BUF;
236
237 /* allocate and submit the URBs */
238 for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
239 if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
240 return -ENOMEM;
241 }
242
243 usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
244 usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
245 &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
246 dib->dibdev->dev_cl->urb_buffer_size,
247 dibusb_urb_complete, dib);
248
249 dib->urb_list[i]->transfer_flags = 0;
250
251 dib->init_state |= DIBUSB_STATE_URB_INIT;
252 }
253
254 /* dib->pid_parse here contains the value of the module parameter */
255 /* decide if pid parsing can be deactivated:
256 * is possible (by device type) and wanted (by user)
257 */
258 switch (dib->dibdev->dev_cl->id) {
259 case DIBUSB2_0:
260 case DIBUSB2_0B:
261 if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
262 def_pid_parse = 0;
263 info("running at HIGH speed, will deliver the complete TS.");
264 } else
265 info("will use pid_parsing.");
266 break;
267 default:
268 break;
269 }
270 /* from here on it contains the device and user decision */
271 dib->pid_parse = def_pid_parse;
272
273 return 0;
274}
275
276int dibusb_urb_exit(struct usb_dibusb *dib)
277{
278 int i;
279
280 dibusb_urb_kill(dib);
281
282 if (dib->init_state & DIBUSB_STATE_URB_LIST) {
283 for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
284 if (dib->urb_list[i] != NULL) {
285 deb_info("freeing URB no. %d.\n",i);
286 /* free the URBs */
287 usb_free_urb(dib->urb_list[i]);
288 }
289 }
290 /* free the urb array */
291 kfree(dib->urb_list);
292 dib->init_state &= ~DIBUSB_STATE_URB_LIST;
293 }
294
295 if (dib->init_state & DIBUSB_STATE_URB_BUF)
296 pci_free_consistent(NULL,
297 dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
298 dib->buffer,dib->dma_handle);
299
300 dib->init_state &= ~DIBUSB_STATE_URB_BUF;
301 dib->init_state &= ~DIBUSB_STATE_URB_INIT;
302 return 0;
303}