blob: baa2938db151d7a265790874708d8968f9f9afad [file] [log] [blame]
Antti Palosaaric79b3392012-05-23 10:06:09 -03001/* usb-urb.c is part of the DVB USB library.
2 *
3 * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
4 * see dvb-usb-init.c for copyright information.
5 *
6 * This file keeps functions for initializing and handling the
7 * BULK and ISOC USB data transfers in a generic way.
8 * Can be used for DVB-only and also, that's the plan, for
9 * Hybrid USB devices (analog and DVB).
10 */
11#include "dvb_usb_common.h"
12
13/* URB stuff for streaming */
Antti Palosaaribce1c022012-05-28 17:25:40 -030014
15int usb_urb_reconfig(struct usb_data_stream *stream,
16 struct usb_data_stream_properties *props);
17
Antti Palosaaric79b3392012-05-23 10:06:09 -030018static void usb_urb_complete(struct urb *urb)
19{
20 struct usb_data_stream *stream = urb->context;
21 int ptype = usb_pipetype(urb->pipe);
22 int i;
23 u8 *b;
24
Antti Palosaari23d8e632012-06-06 22:46:38 -030025 pr_debug("%s: %s urb completed status=%d length=%d/%d" \
26 " pack_num=%d errors=%d\n", __func__,
27 ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
28 urb->status, urb->actual_length,
29 urb->transfer_buffer_length,
30 urb->number_of_packets, urb->error_count);
Antti Palosaaric79b3392012-05-23 10:06:09 -030031
32 switch (urb->status) {
Antti Palosaari4e60d952012-05-24 14:44:21 -030033 case 0: /* success */
34 case -ETIMEDOUT: /* NAK */
35 break;
36 case -ECONNRESET: /* kill */
37 case -ENOENT:
38 case -ESHUTDOWN:
39 return;
40 default: /* error */
Antti Palosaari15072bb2012-05-28 18:23:17 -030041 pr_debug("%s: URB completition failed=%d\n", __func__,
42 urb->status);
Antti Palosaari4e60d952012-05-24 14:44:21 -030043 break;
Antti Palosaaric79b3392012-05-23 10:06:09 -030044 }
45
46 b = (u8 *) urb->transfer_buffer;
47 switch (ptype) {
Antti Palosaari4e60d952012-05-24 14:44:21 -030048 case PIPE_ISOCHRONOUS:
49 for (i = 0; i < urb->number_of_packets; i++) {
50 if (urb->iso_frame_desc[i].status != 0)
Antti Palosaari23d8e632012-06-06 22:46:38 -030051 pr_debug("%s: iso frame descriptor has an " \
52 "error=%d\n", __func__,
Antti Palosaari15072bb2012-05-28 18:23:17 -030053 urb->iso_frame_desc[i].status);
Antti Palosaari4e60d952012-05-24 14:44:21 -030054 else if (urb->iso_frame_desc[i].actual_length > 0)
55 stream->complete(stream,
56 b + urb->iso_frame_desc[i].offset,
57 urb->iso_frame_desc[i].actual_length);
Antti Palosaaric79b3392012-05-23 10:06:09 -030058
Antti Palosaari4e60d952012-05-24 14:44:21 -030059 urb->iso_frame_desc[i].status = 0;
60 urb->iso_frame_desc[i].actual_length = 0;
61 }
Antti Palosaari4e60d952012-05-24 14:44:21 -030062 break;
63 case PIPE_BULK:
64 if (urb->actual_length > 0)
65 stream->complete(stream, b, urb->actual_length);
66 break;
67 default:
Antti Palosaari23d8e632012-06-06 22:46:38 -030068 pr_err("%s: unknown endpoint type in completition handler",
69 KBUILD_MODNAME);
Antti Palosaari4e60d952012-05-24 14:44:21 -030070 return;
Antti Palosaaric79b3392012-05-23 10:06:09 -030071 }
Antti Palosaari4e60d952012-05-24 14:44:21 -030072 usb_submit_urb(urb, GFP_ATOMIC);
Antti Palosaaric79b3392012-05-23 10:06:09 -030073}
74
75int usb_urb_kill(struct usb_data_stream *stream)
76{
77 int i;
78 for (i = 0; i < stream->urbs_submitted; i++) {
Antti Palosaari15072bb2012-05-28 18:23:17 -030079 pr_debug("%s: kill URB=%d\n", __func__, i);
Antti Palosaaric79b3392012-05-23 10:06:09 -030080 /* stop the URB */
81 usb_kill_urb(stream->urb_list[i]);
82 }
83 stream->urbs_submitted = 0;
84 return 0;
85}
86
Antti Palosaaribce1c022012-05-28 17:25:40 -030087int usb_urb_submit(struct usb_data_stream *stream,
88 struct usb_data_stream_properties *props)
Antti Palosaaric79b3392012-05-23 10:06:09 -030089{
Antti Palosaari4e60d952012-05-24 14:44:21 -030090 int i, ret;
Antti Palosaaribce1c022012-05-28 17:25:40 -030091
92 if (props) {
93 ret = usb_urb_reconfig(stream, props);
94 if (ret < 0)
95 return ret;
96 }
97
Antti Palosaaric79b3392012-05-23 10:06:09 -030098 for (i = 0; i < stream->urbs_initialized; i++) {
Antti Palosaari15072bb2012-05-28 18:23:17 -030099 pr_debug("%s: submit URB=%d\n", __func__, i);
Antti Palosaari4e60d952012-05-24 14:44:21 -0300100 ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
101 if (ret) {
Antti Palosaari23d8e632012-06-06 22:46:38 -0300102 pr_err("%s: could not submit URB no. %d - get them " \
103 "all back", KBUILD_MODNAME, i);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300104 usb_urb_kill(stream);
105 return ret;
106 }
107 stream->urbs_submitted++;
108 }
109 return 0;
110}
111
Antti Palosaaribce1c022012-05-28 17:25:40 -0300112int usb_urb_free_urbs(struct usb_data_stream *stream)
113{
114 int i;
115
116 usb_urb_kill(stream);
117
118 for (i = 0; i < stream->urbs_initialized; i++) {
119 if (stream->urb_list[i] != NULL) {
Antti Palosaaribce1c022012-05-28 17:25:40 -0300120 pr_debug("%s: free URB=%d\n", __func__, i);
121 /* free the URBs */
122 usb_free_urb(stream->urb_list[i]);
123 }
124 }
125 stream->urbs_initialized = 0;
126
127 return 0;
128}
129
130static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
131{
132 int i, j;
133
134 /* allocate the URBs */
135 for (i = 0; i < stream->props.count; i++) {
136 pr_debug("%s: alloc URB=%d\n", __func__, i);
137 stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
138 if (!stream->urb_list[i]) {
Antti Palosaari15072bb2012-05-28 18:23:17 -0300139 pr_debug("%s: failed\n", __func__);
Antti Palosaaribce1c022012-05-28 17:25:40 -0300140 for (j = 0; j < i; j++)
141 usb_free_urb(stream->urb_list[j]);
142 return -ENOMEM;
143 }
144 usb_fill_bulk_urb(stream->urb_list[i],
145 stream->udev,
146 usb_rcvbulkpipe(stream->udev,
147 stream->props.endpoint),
148 stream->buf_list[i],
149 stream->props.u.bulk.buffersize,
150 usb_urb_complete, stream);
151
152 stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
153 stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
154 stream->urbs_initialized++;
155 }
156 return 0;
157}
158
159static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
160{
161 int i, j;
162
163 /* allocate the URBs */
164 for (i = 0; i < stream->props.count; i++) {
165 struct urb *urb;
166 int frame_offset = 0;
167 pr_debug("%s: alloc URB=%d\n", __func__, i);
168 stream->urb_list[i] = usb_alloc_urb(
169 stream->props.u.isoc.framesperurb, GFP_ATOMIC);
170 if (!stream->urb_list[i]) {
Antti Palosaari15072bb2012-05-28 18:23:17 -0300171 pr_debug("%s: failed\n", __func__);
Antti Palosaaribce1c022012-05-28 17:25:40 -0300172 for (j = 0; j < i; j++)
173 usb_free_urb(stream->urb_list[j]);
174 return -ENOMEM;
175 }
176
177 urb = stream->urb_list[i];
178
179 urb->dev = stream->udev;
180 urb->context = stream;
181 urb->complete = usb_urb_complete;
182 urb->pipe = usb_rcvisocpipe(stream->udev,
183 stream->props.endpoint);
184 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
185 urb->interval = stream->props.u.isoc.interval;
186 urb->number_of_packets = stream->props.u.isoc.framesperurb;
187 urb->transfer_buffer_length = stream->props.u.isoc.framesize *
188 stream->props.u.isoc.framesperurb;
189 urb->transfer_buffer = stream->buf_list[i];
190 urb->transfer_dma = stream->dma_addr[i];
191
192 for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
193 urb->iso_frame_desc[j].offset = frame_offset;
194 urb->iso_frame_desc[j].length =
195 stream->props.u.isoc.framesize;
196 frame_offset += stream->props.u.isoc.framesize;
197 }
198
199 stream->urbs_initialized++;
200 }
201 return 0;
202}
203
204int usb_free_stream_buffers(struct usb_data_stream *stream)
Antti Palosaaric79b3392012-05-23 10:06:09 -0300205{
206 if (stream->state & USB_STATE_URB_BUF) {
207 while (stream->buf_num) {
208 stream->buf_num--;
Antti Palosaari15072bb2012-05-28 18:23:17 -0300209 pr_debug("%s: free buf=%d\n", __func__,
210 stream->buf_num);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300211 usb_free_coherent(stream->udev, stream->buf_size,
212 stream->buf_list[stream->buf_num],
213 stream->dma_addr[stream->buf_num]);
214 }
215 }
216
217 stream->state &= ~USB_STATE_URB_BUF;
218
219 return 0;
220}
221
Antti Palosaaribce1c022012-05-28 17:25:40 -0300222int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
Antti Palosaari4e60d952012-05-24 14:44:21 -0300223 unsigned long size)
Antti Palosaaric79b3392012-05-23 10:06:09 -0300224{
225 stream->buf_num = 0;
226 stream->buf_size = size;
227
Antti Palosaari15072bb2012-05-28 18:23:17 -0300228 pr_debug("%s: all in all I will use %lu bytes for streaming\n",
229 __func__, num * size);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300230
231 for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
Antti Palosaari15072bb2012-05-28 18:23:17 -0300232 pr_debug("%s: alloc buf=%d\n", __func__, stream->buf_num);
Antti Palosaari4e60d952012-05-24 14:44:21 -0300233 stream->buf_list[stream->buf_num] = usb_alloc_coherent(
234 stream->udev, size, GFP_ATOMIC,
235 &stream->dma_addr[stream->buf_num]);
236 if (stream->buf_list[stream->buf_num] == NULL) {
Antti Palosaari15072bb2012-05-28 18:23:17 -0300237 pr_debug("%s: failed\n", __func__);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300238 usb_free_stream_buffers(stream);
239 return -ENOMEM;
240 }
Antti Palosaari15072bb2012-05-28 18:23:17 -0300241
242 pr_debug("%s: buf %d: %p (dma %llu)\n", __func__,
Antti Palosaari4e60d952012-05-24 14:44:21 -0300243 stream->buf_num,
244 stream->buf_list[stream->buf_num],
245 (long long)stream->dma_addr[stream->buf_num]);
246 memset(stream->buf_list[stream->buf_num], 0, size);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300247 stream->state |= USB_STATE_URB_BUF;
248 }
Antti Palosaaric79b3392012-05-23 10:06:09 -0300249
250 return 0;
251}
252
Antti Palosaaribce1c022012-05-28 17:25:40 -0300253int usb_urb_reconfig(struct usb_data_stream *stream,
254 struct usb_data_stream_properties *props)
Antti Palosaaric79b3392012-05-23 10:06:09 -0300255{
Antti Palosaaribce1c022012-05-28 17:25:40 -0300256 int buf_size;
Antti Palosaaric79b3392012-05-23 10:06:09 -0300257
Antti Palosaaribce1c022012-05-28 17:25:40 -0300258 if (props == NULL)
259 return 0;
Antti Palosaaric79b3392012-05-23 10:06:09 -0300260
Antti Palosaaribce1c022012-05-28 17:25:40 -0300261 /* check allocated buffers are large enough for the request */
Antti Palosaari15072bb2012-05-28 18:23:17 -0300262 if (props->type == USB_BULK) {
Antti Palosaaribce1c022012-05-28 17:25:40 -0300263 buf_size = stream->props.u.bulk.buffersize;
Antti Palosaari15072bb2012-05-28 18:23:17 -0300264 } else if (props->type == USB_ISOC) {
Antti Palosaaribce1c022012-05-28 17:25:40 -0300265 buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
Antti Palosaari15072bb2012-05-28 18:23:17 -0300266 } else {
Antti Palosaari23d8e632012-06-06 22:46:38 -0300267 pr_err("%s: invalid endpoint type=%d", KBUILD_MODNAME,
268 props->type);
Antti Palosaaribce1c022012-05-28 17:25:40 -0300269 return -EINVAL;
Antti Palosaari15072bb2012-05-28 18:23:17 -0300270 }
Antti Palosaaric79b3392012-05-23 10:06:09 -0300271
Antti Palosaaribce1c022012-05-28 17:25:40 -0300272 if (stream->buf_num < props->count || stream->buf_size < buf_size) {
Antti Palosaari23d8e632012-06-06 22:46:38 -0300273 pr_err("%s: cannot reconfigure as allocated buffers are too " \
274 "small", KBUILD_MODNAME);
Antti Palosaaribce1c022012-05-28 17:25:40 -0300275 return -EINVAL;
Antti Palosaaric79b3392012-05-23 10:06:09 -0300276 }
Antti Palosaaric79b3392012-05-23 10:06:09 -0300277
Antti Palosaaribce1c022012-05-28 17:25:40 -0300278 /* check if all fields are same */
279 if (stream->props.type == props->type &&
280 stream->props.count == props->count &&
281 stream->props.endpoint == props->endpoint) {
282 if (props->type == USB_BULK &&
283 props->u.bulk.buffersize ==
284 stream->props.u.bulk.buffersize)
285 return 0;
286 else if (props->type == USB_ISOC &&
287 props->u.isoc.framesperurb ==
288 stream->props.u.isoc.framesperurb &&
289 props->u.isoc.framesize ==
290 stream->props.u.isoc.framesize &&
291 props->u.isoc.interval ==
292 stream->props.u.isoc.interval)
293 return 0;
Antti Palosaaric79b3392012-05-23 10:06:09 -0300294 }
Antti Palosaaribce1c022012-05-28 17:25:40 -0300295
296 pr_debug("%s: re-alloc URBs\n", __func__);
297
298 usb_urb_free_urbs(stream);
299 memcpy(&stream->props, props, sizeof(*props));
300 if (props->type == USB_BULK)
301 return usb_urb_alloc_bulk_urbs(stream);
302 else if (props->type == USB_ISOC)
303 return usb_urb_alloc_isoc_urbs(stream);
304
Antti Palosaaric79b3392012-05-23 10:06:09 -0300305 return 0;
306}
307
Antti Palosaari4e60d952012-05-24 14:44:21 -0300308int usb_urb_init(struct usb_data_stream *stream,
309 struct usb_data_stream_properties *props)
Antti Palosaaric79b3392012-05-23 10:06:09 -0300310{
Antti Palosaaribce1c022012-05-28 17:25:40 -0300311 int ret;
312
Antti Palosaaric79b3392012-05-23 10:06:09 -0300313 if (stream == NULL || props == NULL)
314 return -EINVAL;
315
316 memcpy(&stream->props, props, sizeof(*props));
317
Antti Palosaari4e60d952012-05-24 14:44:21 -0300318 usb_clear_halt(stream->udev, usb_rcvbulkpipe(stream->udev,
319 stream->props.endpoint));
Antti Palosaaric79b3392012-05-23 10:06:09 -0300320
321 if (stream->complete == NULL) {
Antti Palosaari23d8e632012-06-06 22:46:38 -0300322 pr_err("%s: there is no data callback - this doesn't make " \
323 "sense", KBUILD_MODNAME);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300324 return -EINVAL;
325 }
326
327 switch (stream->props.type) {
Antti Palosaari4e60d952012-05-24 14:44:21 -0300328 case USB_BULK:
Antti Palosaaribce1c022012-05-28 17:25:40 -0300329 ret = usb_alloc_stream_buffers(stream, stream->props.count,
330 stream->props.u.bulk.buffersize);
331 if (ret < 0)
332 return ret;
333
334 return usb_urb_alloc_bulk_urbs(stream);
Antti Palosaari4e60d952012-05-24 14:44:21 -0300335 case USB_ISOC:
Antti Palosaaribce1c022012-05-28 17:25:40 -0300336 ret = usb_alloc_stream_buffers(stream, stream->props.count,
337 stream->props.u.isoc.framesize *
338 stream->props.u.isoc.framesperurb);
339 if (ret < 0)
340 return ret;
341
342 return usb_urb_alloc_isoc_urbs(stream);
Antti Palosaari4e60d952012-05-24 14:44:21 -0300343 default:
Antti Palosaari23d8e632012-06-06 22:46:38 -0300344 pr_err("%s: unknown URB-type for data transfer",
345 KBUILD_MODNAME);
Antti Palosaari4e60d952012-05-24 14:44:21 -0300346 return -EINVAL;
Antti Palosaaric79b3392012-05-23 10:06:09 -0300347 }
348}
349
350int usb_urb_exit(struct usb_data_stream *stream)
351{
Antti Palosaaribce1c022012-05-28 17:25:40 -0300352 usb_urb_free_urbs(stream);
Antti Palosaaric79b3392012-05-23 10:06:09 -0300353 usb_free_stream_buffers(stream);
Antti Palosaaribce1c022012-05-28 17:25:40 -0300354
Antti Palosaaric79b3392012-05-23 10:06:09 -0300355 return 0;
356}