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, j;
 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                stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
 147                if (!stream->urb_list[i]) {
 148                        deb_mem("not enough memory for urb_alloc_urb!.\n");
 149                        for (j = 0; j < i; j++)
 150                                usb_free_urb(stream->urb_list[i]);
 151                        return -ENOMEM;
 152                }
 153                usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
 154                                usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
 155                                stream->buf_list[i],
 156                                stream->props.u.bulk.buffersize,
 157                                usb_urb_complete, stream);
 158
 159                stream->urb_list[i]->transfer_flags = 0;
 160                stream->urbs_initialized++;
 161        }
 162        return 0;
 163}
 164
 165static int usb_isoc_urb_init(struct usb_data_stream *stream)
 166{
 167        int i,j;
 168
 169        if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
 170                                        stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
 171                return i;
 172
 173        /* allocate the URBs */
 174        for (i = 0; i < stream->props.count; i++) {
 175                struct urb *urb;
 176                int frame_offset = 0;
 177
 178                stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC);
 179                if (!stream->urb_list[i]) {
 180                        deb_mem("not enough memory for urb_alloc_urb!\n");
 181                        for (j = 0; j < i; j++)
 182                                usb_free_urb(stream->urb_list[i]);
 183                        return -ENOMEM;
 184                }
 185
 186                urb = stream->urb_list[i];
 187
 188                urb->dev = stream->udev;
 189                urb->context = stream;
 190                urb->complete = usb_urb_complete;
 191                urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
 192                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 193                urb->interval = stream->props.u.isoc.interval;
 194                urb->number_of_packets = stream->props.u.isoc.framesperurb;
 195                urb->transfer_buffer_length = stream->buf_size;
 196                urb->transfer_buffer = stream->buf_list[i];
 197                urb->transfer_dma = stream->dma_addr[i];
 198
 199                for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
 200                        urb->iso_frame_desc[j].offset = frame_offset;
 201                        urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
 202                        frame_offset += stream->props.u.isoc.framesize;
 203                }
 204
 205                stream->urbs_initialized++;
 206        }
 207        return 0;
 208}
 209
 210int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
 211{
 212        if (stream == NULL || props == NULL)
 213                return -EINVAL;
 214
 215        memcpy(&stream->props, props, sizeof(*props));
 216
 217        usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
 218
 219        if (stream->complete == NULL) {
 220                err("there is no data callback - this doesn't make sense.");
 221                return -EINVAL;
 222        }
 223
 224        switch (stream->props.type) {
 225                case USB_BULK:
 226                        return usb_bulk_urb_init(stream);
 227                case USB_ISOC:
 228                        return usb_isoc_urb_init(stream);
 229                default:
 230                        err("unkown URB-type for data transfer.");
 231                        return -EINVAL;
 232        }
 233}
 234
 235int usb_urb_exit(struct usb_data_stream *stream)
 236{
 237        int i;
 238
 239        usb_urb_kill(stream);
 240
 241        for (i = 0; i < stream->urbs_initialized; i++) {
 242                if (stream->urb_list[i] != NULL) {
 243                        deb_mem("freeing URB no. %d.\n",i);
 244                        /* free the URBs */
 245                        usb_free_urb(stream->urb_list[i]);
 246                }
 247        }
 248        stream->urbs_initialized = 0;
 249
 250        usb_free_stream_buffers(stream);
 251        return 0;
 252}
 253
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.