linux/drivers/media/usb/dvb-usb-v2/usb_urb.c
<<
>>
Prefs
   1/* usb-urb.c is part of the DVB USB library.
   2 *
   3 * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.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 */
  14
  15int usb_urb_reconfig(struct usb_data_stream *stream,
  16                struct usb_data_stream_properties *props);
  17
  18static 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
  25        dev_dbg_ratelimited(&stream->udev->dev,
  26                        "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
  27                        __func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
  28                        urb->status, urb->actual_length,
  29                        urb->transfer_buffer_length,
  30                        urb->number_of_packets, urb->error_count);
  31
  32        switch (urb->status) {
  33        case 0:         /* success */
  34        case -ETIMEDOUT:    /* NAK */
  35                break;
  36        case -ECONNRESET:   /* kill */
  37        case -ENOENT:
  38        case -ESHUTDOWN:
  39                return;
  40        default:        /* error */
  41                dev_dbg_ratelimited(&stream->udev->dev,
  42                                "%s: urb completition failed=%d\n",
  43                                __func__, urb->status);
  44                break;
  45        }
  46
  47        b = (u8 *) urb->transfer_buffer;
  48        switch (ptype) {
  49        case PIPE_ISOCHRONOUS:
  50                for (i = 0; i < urb->number_of_packets; i++) {
  51                        if (urb->iso_frame_desc[i].status != 0)
  52                                dev_dbg(&stream->udev->dev,
  53                                                "%s: iso frame descriptor has an error=%d\n",
  54                                                __func__,
  55                                                urb->iso_frame_desc[i].status);
  56                        else if (urb->iso_frame_desc[i].actual_length > 0)
  57                                stream->complete(stream,
  58                                        b + urb->iso_frame_desc[i].offset,
  59                                        urb->iso_frame_desc[i].actual_length);
  60
  61                        urb->iso_frame_desc[i].status = 0;
  62                        urb->iso_frame_desc[i].actual_length = 0;
  63                }
  64                break;
  65        case PIPE_BULK:
  66                if (urb->actual_length > 0)
  67                        stream->complete(stream, b, urb->actual_length);
  68                break;
  69        default:
  70                dev_err(&stream->udev->dev,
  71                                "%s: unknown endpoint type in completition handler\n",
  72                                KBUILD_MODNAME);
  73                return;
  74        }
  75        usb_submit_urb(urb, GFP_ATOMIC);
  76}
  77
  78int usb_urb_killv2(struct usb_data_stream *stream)
  79{
  80        int i;
  81        for (i = 0; i < stream->urbs_submitted; i++) {
  82                dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
  83                /* stop the URB */
  84                usb_kill_urb(stream->urb_list[i]);
  85        }
  86        stream->urbs_submitted = 0;
  87        return 0;
  88}
  89
  90int usb_urb_submitv2(struct usb_data_stream *stream,
  91                struct usb_data_stream_properties *props)
  92{
  93        int i, ret;
  94
  95        if (props) {
  96                ret = usb_urb_reconfig(stream, props);
  97                if (ret < 0)
  98                        return ret;
  99        }
 100
 101        for (i = 0; i < stream->urbs_initialized; i++) {
 102                dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
 103                ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
 104                if (ret) {
 105                        dev_err(&stream->udev->dev,
 106                                        "%s: could not submit urb no. %d - get them all back\n",
 107                                        KBUILD_MODNAME, i);
 108                        usb_urb_killv2(stream);
 109                        return ret;
 110                }
 111                stream->urbs_submitted++;
 112        }
 113        return 0;
 114}
 115
 116static int usb_urb_free_urbs(struct usb_data_stream *stream)
 117{
 118        int i;
 119
 120        usb_urb_killv2(stream);
 121
 122        for (i = stream->urbs_initialized - 1; i >= 0; i--) {
 123                if (stream->urb_list[i]) {
 124                        dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
 125                                        __func__, i);
 126                        /* free the URBs */
 127                        usb_free_urb(stream->urb_list[i]);
 128                }
 129        }
 130        stream->urbs_initialized = 0;
 131
 132        return 0;
 133}
 134
 135static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
 136{
 137        int i, j;
 138
 139        /* allocate the URBs */
 140        for (i = 0; i < stream->props.count; i++) {
 141                dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
 142                stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
 143                if (!stream->urb_list[i]) {
 144                        dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
 145                        for (j = 0; j < i; j++)
 146                                usb_free_urb(stream->urb_list[j]);
 147                        return -ENOMEM;
 148                }
 149                usb_fill_bulk_urb(stream->urb_list[i],
 150                                stream->udev,
 151                                usb_rcvbulkpipe(stream->udev,
 152                                                stream->props.endpoint),
 153                                stream->buf_list[i],
 154                                stream->props.u.bulk.buffersize,
 155                                usb_urb_complete, stream);
 156
 157                stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 158                stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
 159                stream->urbs_initialized++;
 160        }
 161        return 0;
 162}
 163
 164static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
 165{
 166        int i, j;
 167
 168        /* allocate the URBs */
 169        for (i = 0; i < stream->props.count; i++) {
 170                struct urb *urb;
 171                int frame_offset = 0;
 172                dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
 173                stream->urb_list[i] = usb_alloc_urb(
 174                                stream->props.u.isoc.framesperurb, GFP_ATOMIC);
 175                if (!stream->urb_list[i]) {
 176                        dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
 177                        for (j = 0; j < i; j++)
 178                                usb_free_urb(stream->urb_list[j]);
 179                        return -ENOMEM;
 180                }
 181
 182                urb = stream->urb_list[i];
 183
 184                urb->dev = stream->udev;
 185                urb->context = stream;
 186                urb->complete = usb_urb_complete;
 187                urb->pipe = usb_rcvisocpipe(stream->udev,
 188                                stream->props.endpoint);
 189                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 190                urb->interval = stream->props.u.isoc.interval;
 191                urb->number_of_packets = stream->props.u.isoc.framesperurb;
 192                urb->transfer_buffer_length = stream->props.u.isoc.framesize *
 193                                stream->props.u.isoc.framesperurb;
 194                urb->transfer_buffer = stream->buf_list[i];
 195                urb->transfer_dma = stream->dma_addr[i];
 196
 197                for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
 198                        urb->iso_frame_desc[j].offset = frame_offset;
 199                        urb->iso_frame_desc[j].length =
 200                                        stream->props.u.isoc.framesize;
 201                        frame_offset += stream->props.u.isoc.framesize;
 202                }
 203
 204                stream->urbs_initialized++;
 205        }
 206        return 0;
 207}
 208
 209static int usb_free_stream_buffers(struct usb_data_stream *stream)
 210{
 211        if (stream->state & USB_STATE_URB_BUF) {
 212                while (stream->buf_num) {
 213                        stream->buf_num--;
 214                        dev_dbg(&stream->udev->dev, "%s: free buf=%d\n",
 215                                __func__, stream->buf_num);
 216                        usb_free_coherent(stream->udev, stream->buf_size,
 217                                          stream->buf_list[stream->buf_num],
 218                                          stream->dma_addr[stream->buf_num]);
 219                }
 220        }
 221
 222        stream->state &= ~USB_STATE_URB_BUF;
 223
 224        return 0;
 225}
 226
 227static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
 228                                    unsigned long size)
 229{
 230        stream->buf_num = 0;
 231        stream->buf_size = size;
 232
 233        dev_dbg(&stream->udev->dev,
 234                        "%s: all in all I will use %lu bytes for streaming\n",
 235                        __func__,  num * size);
 236
 237        for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
 238                stream->buf_list[stream->buf_num] = usb_alloc_coherent(
 239                                stream->udev, size, GFP_ATOMIC,
 240                                &stream->dma_addr[stream->buf_num]);
 241                if (!stream->buf_list[stream->buf_num]) {
 242                        dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
 243                                        __func__, stream->buf_num);
 244                        usb_free_stream_buffers(stream);
 245                        return -ENOMEM;
 246                }
 247
 248                dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
 249                                __func__, stream->buf_num,
 250                                stream->buf_list[stream->buf_num],
 251                                (long long)stream->dma_addr[stream->buf_num]);
 252                memset(stream->buf_list[stream->buf_num], 0, size);
 253                stream->state |= USB_STATE_URB_BUF;
 254        }
 255
 256        return 0;
 257}
 258
 259int usb_urb_reconfig(struct usb_data_stream *stream,
 260                struct usb_data_stream_properties *props)
 261{
 262        int buf_size;
 263
 264        if (!props)
 265                return 0;
 266
 267        /* check allocated buffers are large enough for the request */
 268        if (props->type == USB_BULK) {
 269                buf_size = stream->props.u.bulk.buffersize;
 270        } else if (props->type == USB_ISOC) {
 271                buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
 272        } else {
 273                dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
 274                                KBUILD_MODNAME, props->type);
 275                return -EINVAL;
 276        }
 277
 278        if (stream->buf_num < props->count || stream->buf_size < buf_size) {
 279                dev_err(&stream->udev->dev,
 280                                "%s: cannot reconfigure as allocated buffers are too small\n",
 281                                KBUILD_MODNAME);
 282                return -EINVAL;
 283        }
 284
 285        /* check if all fields are same */
 286        if (stream->props.type == props->type &&
 287                        stream->props.count == props->count &&
 288                        stream->props.endpoint == props->endpoint) {
 289                if (props->type == USB_BULK &&
 290                                props->u.bulk.buffersize ==
 291                                stream->props.u.bulk.buffersize)
 292                        return 0;
 293                else if (props->type == USB_ISOC &&
 294                                props->u.isoc.framesperurb ==
 295                                stream->props.u.isoc.framesperurb &&
 296                                props->u.isoc.framesize ==
 297                                stream->props.u.isoc.framesize &&
 298                                props->u.isoc.interval ==
 299                                stream->props.u.isoc.interval)
 300                        return 0;
 301        }
 302
 303        dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
 304
 305        usb_urb_free_urbs(stream);
 306        memcpy(&stream->props, props, sizeof(*props));
 307        if (props->type == USB_BULK)
 308                return usb_urb_alloc_bulk_urbs(stream);
 309        else if (props->type == USB_ISOC)
 310                return usb_urb_alloc_isoc_urbs(stream);
 311
 312        return 0;
 313}
 314
 315int usb_urb_initv2(struct usb_data_stream *stream,
 316                const struct usb_data_stream_properties *props)
 317{
 318        int ret;
 319
 320        if (!stream || !props)
 321                return -EINVAL;
 322
 323        memcpy(&stream->props, props, sizeof(*props));
 324
 325        if (!stream->complete) {
 326                dev_err(&stream->udev->dev,
 327                                "%s: there is no data callback - this doesn't make sense\n",
 328                                KBUILD_MODNAME);
 329                return -EINVAL;
 330        }
 331
 332        switch (stream->props.type) {
 333        case USB_BULK:
 334                ret = usb_alloc_stream_buffers(stream, stream->props.count,
 335                                stream->props.u.bulk.buffersize);
 336                if (ret < 0)
 337                        return ret;
 338
 339                return usb_urb_alloc_bulk_urbs(stream);
 340        case USB_ISOC:
 341                ret = usb_alloc_stream_buffers(stream, stream->props.count,
 342                                stream->props.u.isoc.framesize *
 343                                stream->props.u.isoc.framesperurb);
 344                if (ret < 0)
 345                        return ret;
 346
 347                return usb_urb_alloc_isoc_urbs(stream);
 348        default:
 349                dev_err(&stream->udev->dev,
 350                                "%s: unknown urb-type for data transfer\n",
 351                                KBUILD_MODNAME);
 352                return -EINVAL;
 353        }
 354}
 355
 356int usb_urb_exitv2(struct usb_data_stream *stream)
 357{
 358        usb_urb_free_urbs(stream);
 359        usb_free_stream_buffers(stream);
 360
 361        return 0;
 362}
 363