diff options
Diffstat (limited to 'drivers/media/dvb/dibusb/dvb-dibusb-usb.c')
-rw-r--r-- | drivers/media/dvb/dibusb/dvb-dibusb-usb.c | 303 |
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 | |||
17 | int 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 | */ | ||
60 | int 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 | */ | ||
74 | int 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 | */ | ||
84 | static 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 | */ | ||
101 | int 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 | |||
121 | int 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 | |||
142 | int 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 | |||
148 | static int dibusb_urb_kill(struct usb_dibusb *dib) | ||
149 | { | ||
150 | int i; | ||
151 | deb_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 | |||
165 | static 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 | |||
182 | int 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 | |||
205 | int 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 | |||
276 | int 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 | } | ||