Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* usb-urb.c is part of the DVB USB library.
0003  *
0004  * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
0005  * see dvb-usb-init.c for copyright information.
0006  *
0007  * This file keeps functions for initializing and handling the
0008  * BULK and ISOC USB data transfers in a generic way.
0009  * Can be used for DVB-only and also, that's the plan, for
0010  * Hybrid USB devices (analog and DVB).
0011  */
0012 #include "dvb_usb_common.h"
0013 
0014 /* URB stuff for streaming */
0015 
0016 int usb_urb_reconfig(struct usb_data_stream *stream,
0017         struct usb_data_stream_properties *props);
0018 
0019 static void usb_urb_complete(struct urb *urb)
0020 {
0021     struct usb_data_stream *stream = urb->context;
0022     int ptype = usb_pipetype(urb->pipe);
0023     int i;
0024     u8 *b;
0025 
0026     dev_dbg_ratelimited(&stream->udev->dev,
0027             "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
0028             __func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
0029             urb->status, urb->actual_length,
0030             urb->transfer_buffer_length,
0031             urb->number_of_packets, urb->error_count);
0032 
0033     switch (urb->status) {
0034     case 0:         /* success */
0035     case -ETIMEDOUT:    /* NAK */
0036         break;
0037     case -ECONNRESET:   /* kill */
0038     case -ENOENT:
0039     case -ESHUTDOWN:
0040         return;
0041     default:        /* error */
0042         dev_dbg_ratelimited(&stream->udev->dev,
0043                 "%s: urb completion failed=%d\n",
0044                 __func__, urb->status);
0045         break;
0046     }
0047 
0048     b = (u8 *) urb->transfer_buffer;
0049     switch (ptype) {
0050     case PIPE_ISOCHRONOUS:
0051         for (i = 0; i < urb->number_of_packets; i++) {
0052             if (urb->iso_frame_desc[i].status != 0)
0053                 dev_dbg(&stream->udev->dev,
0054                         "%s: iso frame descriptor has an error=%d\n",
0055                         __func__,
0056                         urb->iso_frame_desc[i].status);
0057             else if (urb->iso_frame_desc[i].actual_length > 0)
0058                 stream->complete(stream,
0059                     b + urb->iso_frame_desc[i].offset,
0060                     urb->iso_frame_desc[i].actual_length);
0061 
0062             urb->iso_frame_desc[i].status = 0;
0063             urb->iso_frame_desc[i].actual_length = 0;
0064         }
0065         break;
0066     case PIPE_BULK:
0067         if (urb->actual_length > 0)
0068             stream->complete(stream, b, urb->actual_length);
0069         break;
0070     default:
0071         dev_err(&stream->udev->dev,
0072                 "%s: unknown endpoint type in completion handler\n",
0073                 KBUILD_MODNAME);
0074         return;
0075     }
0076     usb_submit_urb(urb, GFP_ATOMIC);
0077 }
0078 
0079 int usb_urb_killv2(struct usb_data_stream *stream)
0080 {
0081     int i;
0082     for (i = 0; i < stream->urbs_submitted; i++) {
0083         dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
0084         /* stop the URB */
0085         usb_kill_urb(stream->urb_list[i]);
0086     }
0087     stream->urbs_submitted = 0;
0088     return 0;
0089 }
0090 
0091 int usb_urb_submitv2(struct usb_data_stream *stream,
0092         struct usb_data_stream_properties *props)
0093 {
0094     int i, ret;
0095 
0096     if (props) {
0097         ret = usb_urb_reconfig(stream, props);
0098         if (ret < 0)
0099             return ret;
0100     }
0101 
0102     for (i = 0; i < stream->urbs_initialized; i++) {
0103         dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
0104         ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
0105         if (ret) {
0106             dev_err(&stream->udev->dev,
0107                     "%s: could not submit urb no. %d - get them all back\n",
0108                     KBUILD_MODNAME, i);
0109             usb_urb_killv2(stream);
0110             return ret;
0111         }
0112         stream->urbs_submitted++;
0113     }
0114     return 0;
0115 }
0116 
0117 static int usb_urb_free_urbs(struct usb_data_stream *stream)
0118 {
0119     int i;
0120 
0121     usb_urb_killv2(stream);
0122 
0123     for (i = stream->urbs_initialized - 1; i >= 0; i--) {
0124         if (stream->urb_list[i]) {
0125             dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
0126                     __func__, i);
0127             /* free the URBs */
0128             usb_free_urb(stream->urb_list[i]);
0129         }
0130     }
0131     stream->urbs_initialized = 0;
0132 
0133     return 0;
0134 }
0135 
0136 static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
0137 {
0138     int i, j;
0139 
0140     /* allocate the URBs */
0141     for (i = 0; i < stream->props.count; i++) {
0142         dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
0143         stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
0144         if (!stream->urb_list[i]) {
0145             dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
0146             for (j = 0; j < i; j++)
0147                 usb_free_urb(stream->urb_list[j]);
0148             return -ENOMEM;
0149         }
0150         usb_fill_bulk_urb(stream->urb_list[i],
0151                 stream->udev,
0152                 usb_rcvbulkpipe(stream->udev,
0153                         stream->props.endpoint),
0154                 stream->buf_list[i],
0155                 stream->props.u.bulk.buffersize,
0156                 usb_urb_complete, stream);
0157 
0158         stream->urbs_initialized++;
0159     }
0160     return 0;
0161 }
0162 
0163 static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
0164 {
0165     int i, j;
0166 
0167     /* allocate the URBs */
0168     for (i = 0; i < stream->props.count; i++) {
0169         struct urb *urb;
0170         int frame_offset = 0;
0171         dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
0172         stream->urb_list[i] = usb_alloc_urb(
0173                 stream->props.u.isoc.framesperurb, GFP_ATOMIC);
0174         if (!stream->urb_list[i]) {
0175             dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
0176             for (j = 0; j < i; j++)
0177                 usb_free_urb(stream->urb_list[j]);
0178             return -ENOMEM;
0179         }
0180 
0181         urb = stream->urb_list[i];
0182 
0183         urb->dev = stream->udev;
0184         urb->context = stream;
0185         urb->complete = usb_urb_complete;
0186         urb->pipe = usb_rcvisocpipe(stream->udev,
0187                 stream->props.endpoint);
0188         urb->transfer_flags = URB_ISO_ASAP;
0189         urb->interval = stream->props.u.isoc.interval;
0190         urb->number_of_packets = stream->props.u.isoc.framesperurb;
0191         urb->transfer_buffer_length = stream->props.u.isoc.framesize *
0192                 stream->props.u.isoc.framesperurb;
0193         urb->transfer_buffer = stream->buf_list[i];
0194 
0195         for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
0196             urb->iso_frame_desc[j].offset = frame_offset;
0197             urb->iso_frame_desc[j].length =
0198                     stream->props.u.isoc.framesize;
0199             frame_offset += stream->props.u.isoc.framesize;
0200         }
0201 
0202         stream->urbs_initialized++;
0203     }
0204     return 0;
0205 }
0206 
0207 static int usb_free_stream_buffers(struct usb_data_stream *stream)
0208 {
0209     if (stream->state & USB_STATE_URB_BUF) {
0210         while (stream->buf_num) {
0211             stream->buf_num--;
0212             kfree(stream->buf_list[stream->buf_num]);
0213         }
0214     }
0215 
0216     stream->state &= ~USB_STATE_URB_BUF;
0217 
0218     return 0;
0219 }
0220 
0221 static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
0222                     unsigned long size)
0223 {
0224     stream->buf_num = 0;
0225     stream->buf_size = size;
0226 
0227     dev_dbg(&stream->udev->dev,
0228             "%s: all in all I will use %lu bytes for streaming\n",
0229             __func__,  num * size);
0230 
0231     for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
0232         stream->buf_list[stream->buf_num] = kzalloc(size, GFP_ATOMIC);
0233         if (!stream->buf_list[stream->buf_num]) {
0234             dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
0235                     __func__, stream->buf_num);
0236             usb_free_stream_buffers(stream);
0237             return -ENOMEM;
0238         }
0239 
0240         dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
0241                 __func__, stream->buf_num,
0242                 stream->buf_list[stream->buf_num],
0243                 (long long)stream->dma_addr[stream->buf_num]);
0244         stream->state |= USB_STATE_URB_BUF;
0245     }
0246 
0247     return 0;
0248 }
0249 
0250 int usb_urb_reconfig(struct usb_data_stream *stream,
0251         struct usb_data_stream_properties *props)
0252 {
0253     int buf_size;
0254 
0255     if (!props)
0256         return 0;
0257 
0258     /* check allocated buffers are large enough for the request */
0259     if (props->type == USB_BULK) {
0260         buf_size = stream->props.u.bulk.buffersize;
0261     } else if (props->type == USB_ISOC) {
0262         buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
0263     } else {
0264         dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
0265                 KBUILD_MODNAME, props->type);
0266         return -EINVAL;
0267     }
0268 
0269     if (stream->buf_num < props->count || stream->buf_size < buf_size) {
0270         dev_err(&stream->udev->dev,
0271                 "%s: cannot reconfigure as allocated buffers are too small\n",
0272                 KBUILD_MODNAME);
0273         return -EINVAL;
0274     }
0275 
0276     /* check if all fields are same */
0277     if (stream->props.type == props->type &&
0278             stream->props.count == props->count &&
0279             stream->props.endpoint == props->endpoint) {
0280         if (props->type == USB_BULK &&
0281                 props->u.bulk.buffersize ==
0282                 stream->props.u.bulk.buffersize)
0283             return 0;
0284         else if (props->type == USB_ISOC &&
0285                 props->u.isoc.framesperurb ==
0286                 stream->props.u.isoc.framesperurb &&
0287                 props->u.isoc.framesize ==
0288                 stream->props.u.isoc.framesize &&
0289                 props->u.isoc.interval ==
0290                 stream->props.u.isoc.interval)
0291             return 0;
0292     }
0293 
0294     dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
0295 
0296     usb_urb_free_urbs(stream);
0297     memcpy(&stream->props, props, sizeof(*props));
0298     if (props->type == USB_BULK)
0299         return usb_urb_alloc_bulk_urbs(stream);
0300     else if (props->type == USB_ISOC)
0301         return usb_urb_alloc_isoc_urbs(stream);
0302 
0303     return 0;
0304 }
0305 
0306 int usb_urb_initv2(struct usb_data_stream *stream,
0307         const struct usb_data_stream_properties *props)
0308 {
0309     int ret;
0310 
0311     if (!stream || !props)
0312         return -EINVAL;
0313 
0314     memcpy(&stream->props, props, sizeof(*props));
0315 
0316     if (!stream->complete) {
0317         dev_err(&stream->udev->dev,
0318                 "%s: there is no data callback - this doesn't make sense\n",
0319                 KBUILD_MODNAME);
0320         return -EINVAL;
0321     }
0322 
0323     switch (stream->props.type) {
0324     case USB_BULK:
0325         ret = usb_alloc_stream_buffers(stream, stream->props.count,
0326                 stream->props.u.bulk.buffersize);
0327         if (ret < 0)
0328             return ret;
0329 
0330         return usb_urb_alloc_bulk_urbs(stream);
0331     case USB_ISOC:
0332         ret = usb_alloc_stream_buffers(stream, stream->props.count,
0333                 stream->props.u.isoc.framesize *
0334                 stream->props.u.isoc.framesperurb);
0335         if (ret < 0)
0336             return ret;
0337 
0338         return usb_urb_alloc_isoc_urbs(stream);
0339     default:
0340         dev_err(&stream->udev->dev,
0341                 "%s: unknown urb-type for data transfer\n",
0342                 KBUILD_MODNAME);
0343         return -EINVAL;
0344     }
0345 }
0346 
0347 int usb_urb_exitv2(struct usb_data_stream *stream)
0348 {
0349     usb_urb_free_urbs(stream);
0350     usb_free_stream_buffers(stream);
0351 
0352     return 0;
0353 }