256 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 the8 * BULK and ISOC USB data transfers in a generic way.9 * Can be used for DVB-only and also, that's the plan, for10 * 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