linux/drivers/media/dvb/dvb-usb/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@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 */
  14static void usb_urb_complete(struct urb *urb)
  15{
  16        struct usb_data_stream *stream = urb->context;
  17        int ptype = usb_pipetype(urb->pipe);
  18        int i;
  19        u8 *b;
  20
  21        deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
  22                ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
  23                urb->status,urb->actual_length,urb->transfer_buffer_length,
  24                urb->number_of_packets,urb->error_count);
  25
  26        switch (urb->status) {
  27                case 0:         /* success */
  28                case -ETIMEDOUT:    /* NAK */
  29                        break;
  30                case -ECONNRESET:   /* kill */
  31                case -ENOENT:
  32                case -ESHUTDOWN:
  33                        return;
  34                default:        /* error */
  35                        deb_ts("urb completition error %d.\n", urb->status);
  36                        break;
  37        }
  38
  39        b = (u8 *) urb->transfer_buffer;
  40        switch (ptype) {
  41                case PIPE_ISOCHRONOUS:
  42                        for (i = 0; i < urb->number_of_packets; i++) {
  43
  44                                if (urb->iso_frame_desc[i].status != 0)
  45                                        deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
  46                                else if (urb->iso_frame_desc[i].actual_length > 0)
  47                                        stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
  48
  49                                urb->iso_frame_desc[i].status = 0;
  50                                urb->iso_frame_desc[i].actual_length = 0;
  51                        }
  52                        debug_dump(b,20,deb_uxfer);
  53                        break;
  54                case PIPE_BULK:
  55                        if (urb->actual_length > 0)
  56                                stream->complete(stream, b, urb->actual_length);
  57                        break;
  58                default:
  59                        err("unkown endpoint type in completition handler.");
  60                        return;
  61        }
  62        usb_submit_urb(urb,GFP_ATOMIC);
  63}
  64
  65int usb_urb_kill(struct usb_data_stream *stream)
  66{
  67        int i;
  68        for (i = 0; i < stream->urbs_submitted; i++) {
  69                deb_ts("killing URB no. %d.\n",i);
  70
  71                /* stop the URB */
  72                usb_kill_urb(stream->urb_list[i]);
  73        }
  74        stream->urbs_submitted = 0;
  75        return 0;
  76}
  77
  78int usb_urb_submit(struct usb_data_stream *stream)
  79{
  80        int i,ret;
  81        for (i = 0; i < stream->urbs_initialized; i++) {
  82                deb_ts("submitting URB no. %d\n",i);
  83                if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
  84                        err("could not submit URB no. %d - get them all back",i);
  85                        usb_urb_kill(stream);
  86                        return ret;
  87                }
  88                stream->urbs_submitted++;
  89        }
  90        return 0;
  91}
  92
  93static int usb_free_stream_buffers(struct usb_data_stream *stream)
  94{
  95        if (stream->state & USB_STATE_URB_BUF) {
  96                while (stream->buf_num) {
  97                        stream->buf_num--;
  98                        deb_mem("freeing buffer %d\n",stream->buf_num);
  99                        usb_buffer_free(stream->udev, stream->buf_size,
 100                                        stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
 101                }
 102        }
 103
 104        stream->state &= ~USB_STATE_URB_BUF;
 105
 106        return 0;
 107}
 108
 109static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
 110{
 111        stream->buf_num = 0;
 112        stream->buf_size = size;
 113
 114        deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
 115
 116        for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
 117                deb_mem("allocating buffer %d\n",stream->buf_num);
 118                if (( stream->buf_list[stream->buf_num] =
 119                                        usb_buffer_alloc(stream->udev, size, GFP_ATOMIC,
 120                                        &stream->dma_addr[stream->buf_num]) ) == NULL) {
 121                        deb_mem("not enough memory for urb-buffer allocation.\n");
 122                        usb_free_stream_buffers(stream);
 123                        return -ENOMEM;
 124                }
 125                deb_mem("buffer %d: %p (dma: %Lu)\n",
 126                        stream->buf_num,
 127stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
 128                memset(stream->buf_list[stream->buf_num],0,size);
 129                stream->state |= USB_STATE_URB_BUF;
 130        }
 131        deb_mem("allocation successful\n");
 132
 133        return 0;
 134}
 135
 136static int usb_bulk_urb_init(struct usb_data_stream *stream)
 137{
 138        int i;
 139
 140        if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
 141                                        stream->props.u.bulk.buffersize)) < 0)
 142                return i;
 143
 144        /* allocate the URBs */
 145        for (i = 0; i < stream->props.count; i++) {
 146                if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
 147                        return -ENOMEM;
 148
 149                usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
 150                                usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
 151                                stream->buf_list[i],
 152                                stream->props.u.bulk.buffersize,
 153                                usb_urb_complete, stream);
 154
 155                stream->urb_list[i]->transfer_flags = 0;
 156                stream->urbs_initialized++;
 157        }
 158        return 0;
 159}
 160
 161static int usb_isoc_urb_init(struct usb_data_stream *stream)
 162{
 163        int i,j;
 164
 165        if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
 166                                        stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
 167                return i;
 168
 169        /* allocate the URBs */
 170        for (i = 0; i < stream->props.count; i++) {
 171                struct urb *urb;
 172                int frame_offset = 0;
 173                if ((stream->urb_list[i] =
 174                                        usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
 175                        return -ENOMEM;
 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,stream->props.endpoint);
 183                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 184                urb->interval = stream->props.u.isoc.interval;
 185                urb->number_of_packets = stream->props.u.isoc.framesperurb;
 186                urb->transfer_buffer_length = stream->buf_size;
 187                urb->transfer_buffer = stream->buf_list[i];
 188                urb->transfer_dma = stream->dma_addr[i];
 189
 190                for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
 191                        urb->iso_frame_desc[j].offset = frame_offset;
 192                        urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
 193                        frame_offset += stream->props.u.isoc.framesize;
 194                }
 195
 196                stream->urbs_initialized++;
 197        }
 198        return 0;
 199}
 200
 201int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
 202{
 203        if (stream == NULL || props == NULL)
 204                return -EINVAL;
 205
 206        memcpy(&stream->props, props, sizeof(*props));
 207
 208        usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
 209
 210        if (stream->complete == NULL) {
 211                err("there is no data callback - this doesn't make sense.");
 212                return -EINVAL;
 213        }
 214
 215        switch (stream->props.type) {
 216                case USB_BULK:
 217                        return usb_bulk_urb_init(stream);
 218                case USB_ISOC:
 219                        return usb_isoc_urb_init(stream);
 220                default:
 221                        err("unkown URB-type for data transfer.");
 222                        return -EINVAL;
 223        }
 224}
 225
 226int usb_urb_exit(struct usb_data_stream *stream)
 227{
 228        int i;
 229
 230        usb_urb_kill(stream);
 231
 232        for (i = 0; i < stream->urbs_initialized; i++) {
 233                if (stream->urb_list[i] != NULL) {
 234                        deb_mem("freeing URB no. %d.\n",i);
 235                        /* free the URBs */
 236                        usb_free_urb(stream->urb_list[i]);
 237                }
 238        }
 239        stream->urbs_initialized = 0;
 240
 241        usb_free_stream_buffers(stream);
 242        return 0;
 243}
 244