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