18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* usb-urb.c is part of the DVB USB library. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) 58c2ecf20Sopenharmony_ci * see dvb-usb-init.c for copyright information. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file keeps functions for initializing and handling the 88c2ecf20Sopenharmony_ci * BULK and ISOC USB data transfers in a generic way. 98c2ecf20Sopenharmony_ci * Can be used for DVB-only and also, that's the plan, for 108c2ecf20Sopenharmony_ci * Hybrid USB devices (analog and DVB). 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include "dvb_usb_common.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* URB stuff for streaming */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint usb_urb_reconfig(struct usb_data_stream *stream, 178c2ecf20Sopenharmony_ci struct usb_data_stream_properties *props); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic void usb_urb_complete(struct urb *urb) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct usb_data_stream *stream = urb->context; 228c2ecf20Sopenharmony_ci int ptype = usb_pipetype(urb->pipe); 238c2ecf20Sopenharmony_ci int i; 248c2ecf20Sopenharmony_ci u8 *b; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci dev_dbg_ratelimited(&stream->udev->dev, 278c2ecf20Sopenharmony_ci "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n", 288c2ecf20Sopenharmony_ci __func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", 298c2ecf20Sopenharmony_ci urb->status, urb->actual_length, 308c2ecf20Sopenharmony_ci urb->transfer_buffer_length, 318c2ecf20Sopenharmony_ci urb->number_of_packets, urb->error_count); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci switch (urb->status) { 348c2ecf20Sopenharmony_ci case 0: /* success */ 358c2ecf20Sopenharmony_ci case -ETIMEDOUT: /* NAK */ 368c2ecf20Sopenharmony_ci break; 378c2ecf20Sopenharmony_ci case -ECONNRESET: /* kill */ 388c2ecf20Sopenharmony_ci case -ENOENT: 398c2ecf20Sopenharmony_ci case -ESHUTDOWN: 408c2ecf20Sopenharmony_ci return; 418c2ecf20Sopenharmony_ci default: /* error */ 428c2ecf20Sopenharmony_ci dev_dbg_ratelimited(&stream->udev->dev, 438c2ecf20Sopenharmony_ci "%s: urb completion failed=%d\n", 448c2ecf20Sopenharmony_ci __func__, urb->status); 458c2ecf20Sopenharmony_ci break; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci b = (u8 *) urb->transfer_buffer; 498c2ecf20Sopenharmony_ci switch (ptype) { 508c2ecf20Sopenharmony_ci case PIPE_ISOCHRONOUS: 518c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 528c2ecf20Sopenharmony_ci if (urb->iso_frame_desc[i].status != 0) 538c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, 548c2ecf20Sopenharmony_ci "%s: iso frame descriptor has an error=%d\n", 558c2ecf20Sopenharmony_ci __func__, 568c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].status); 578c2ecf20Sopenharmony_ci else if (urb->iso_frame_desc[i].actual_length > 0) 588c2ecf20Sopenharmony_ci stream->complete(stream, 598c2ecf20Sopenharmony_ci b + urb->iso_frame_desc[i].offset, 608c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].actual_length); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].status = 0; 638c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].actual_length = 0; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci case PIPE_BULK: 678c2ecf20Sopenharmony_ci if (urb->actual_length > 0) 688c2ecf20Sopenharmony_ci stream->complete(stream, b, urb->actual_length); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci default: 718c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, 728c2ecf20Sopenharmony_ci "%s: unknown endpoint type in completion handler\n", 738c2ecf20Sopenharmony_ci KBUILD_MODNAME); 748c2ecf20Sopenharmony_ci return; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci usb_submit_urb(urb, GFP_ATOMIC); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint usb_urb_killv2(struct usb_data_stream *stream) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int i; 828c2ecf20Sopenharmony_ci for (i = 0; i < stream->urbs_submitted; i++) { 838c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); 848c2ecf20Sopenharmony_ci /* stop the URB */ 858c2ecf20Sopenharmony_ci usb_kill_urb(stream->urb_list[i]); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci stream->urbs_submitted = 0; 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciint usb_urb_submitv2(struct usb_data_stream *stream, 928c2ecf20Sopenharmony_ci struct usb_data_stream_properties *props) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int i, ret; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (props) { 978c2ecf20Sopenharmony_ci ret = usb_urb_reconfig(stream, props); 988c2ecf20Sopenharmony_ci if (ret < 0) 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci for (i = 0; i < stream->urbs_initialized; i++) { 1038c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); 1048c2ecf20Sopenharmony_ci ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); 1058c2ecf20Sopenharmony_ci if (ret) { 1068c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, 1078c2ecf20Sopenharmony_ci "%s: could not submit urb no. %d - get them all back\n", 1088c2ecf20Sopenharmony_ci KBUILD_MODNAME, i); 1098c2ecf20Sopenharmony_ci usb_urb_killv2(stream); 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci stream->urbs_submitted++; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int usb_urb_free_urbs(struct usb_data_stream *stream) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci int i; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci usb_urb_killv2(stream); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (i = stream->urbs_initialized - 1; i >= 0; i--) { 1248c2ecf20Sopenharmony_ci if (stream->urb_list[i]) { 1258c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", 1268c2ecf20Sopenharmony_ci __func__, i); 1278c2ecf20Sopenharmony_ci /* free the URBs */ 1288c2ecf20Sopenharmony_ci usb_free_urb(stream->urb_list[i]); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci stream->urbs_initialized = 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int i, j; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* allocate the URBs */ 1418c2ecf20Sopenharmony_ci for (i = 0; i < stream->props.count; i++) { 1428c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); 1438c2ecf20Sopenharmony_ci stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); 1448c2ecf20Sopenharmony_ci if (!stream->urb_list[i]) { 1458c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); 1468c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 1478c2ecf20Sopenharmony_ci usb_free_urb(stream->urb_list[j]); 1488c2ecf20Sopenharmony_ci return -ENOMEM; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci usb_fill_bulk_urb(stream->urb_list[i], 1518c2ecf20Sopenharmony_ci stream->udev, 1528c2ecf20Sopenharmony_ci usb_rcvbulkpipe(stream->udev, 1538c2ecf20Sopenharmony_ci stream->props.endpoint), 1548c2ecf20Sopenharmony_ci stream->buf_list[i], 1558c2ecf20Sopenharmony_ci stream->props.u.bulk.buffersize, 1568c2ecf20Sopenharmony_ci usb_urb_complete, stream); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci stream->urbs_initialized++; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i, j; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* allocate the URBs */ 1688c2ecf20Sopenharmony_ci for (i = 0; i < stream->props.count; i++) { 1698c2ecf20Sopenharmony_ci struct urb *urb; 1708c2ecf20Sopenharmony_ci int frame_offset = 0; 1718c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); 1728c2ecf20Sopenharmony_ci stream->urb_list[i] = usb_alloc_urb( 1738c2ecf20Sopenharmony_ci stream->props.u.isoc.framesperurb, GFP_ATOMIC); 1748c2ecf20Sopenharmony_ci if (!stream->urb_list[i]) { 1758c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); 1768c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 1778c2ecf20Sopenharmony_ci usb_free_urb(stream->urb_list[j]); 1788c2ecf20Sopenharmony_ci return -ENOMEM; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci urb = stream->urb_list[i]; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci urb->dev = stream->udev; 1848c2ecf20Sopenharmony_ci urb->context = stream; 1858c2ecf20Sopenharmony_ci urb->complete = usb_urb_complete; 1868c2ecf20Sopenharmony_ci urb->pipe = usb_rcvisocpipe(stream->udev, 1878c2ecf20Sopenharmony_ci stream->props.endpoint); 1888c2ecf20Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP; 1898c2ecf20Sopenharmony_ci urb->interval = stream->props.u.isoc.interval; 1908c2ecf20Sopenharmony_ci urb->number_of_packets = stream->props.u.isoc.framesperurb; 1918c2ecf20Sopenharmony_ci urb->transfer_buffer_length = stream->props.u.isoc.framesize * 1928c2ecf20Sopenharmony_ci stream->props.u.isoc.framesperurb; 1938c2ecf20Sopenharmony_ci urb->transfer_buffer = stream->buf_list[i]; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { 1968c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].offset = frame_offset; 1978c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].length = 1988c2ecf20Sopenharmony_ci stream->props.u.isoc.framesize; 1998c2ecf20Sopenharmony_ci frame_offset += stream->props.u.isoc.framesize; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci stream->urbs_initialized++; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int usb_free_stream_buffers(struct usb_data_stream *stream) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci if (stream->state & USB_STATE_URB_BUF) { 2108c2ecf20Sopenharmony_ci while (stream->buf_num) { 2118c2ecf20Sopenharmony_ci stream->buf_num--; 2128c2ecf20Sopenharmony_ci kfree(stream->buf_list[stream->buf_num]); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci stream->state &= ~USB_STATE_URB_BUF; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, 2228c2ecf20Sopenharmony_ci unsigned long size) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci stream->buf_num = 0; 2258c2ecf20Sopenharmony_ci stream->buf_size = size; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, 2288c2ecf20Sopenharmony_ci "%s: all in all I will use %lu bytes for streaming\n", 2298c2ecf20Sopenharmony_ci __func__, num * size); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { 2328c2ecf20Sopenharmony_ci stream->buf_list[stream->buf_num] = kzalloc(size, GFP_ATOMIC); 2338c2ecf20Sopenharmony_ci if (!stream->buf_list[stream->buf_num]) { 2348c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", 2358c2ecf20Sopenharmony_ci __func__, stream->buf_num); 2368c2ecf20Sopenharmony_ci usb_free_stream_buffers(stream); 2378c2ecf20Sopenharmony_ci return -ENOMEM; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", 2418c2ecf20Sopenharmony_ci __func__, stream->buf_num, 2428c2ecf20Sopenharmony_ci stream->buf_list[stream->buf_num], 2438c2ecf20Sopenharmony_ci (long long)stream->dma_addr[stream->buf_num]); 2448c2ecf20Sopenharmony_ci stream->state |= USB_STATE_URB_BUF; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciint usb_urb_reconfig(struct usb_data_stream *stream, 2518c2ecf20Sopenharmony_ci struct usb_data_stream_properties *props) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci int buf_size; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!props) 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* check allocated buffers are large enough for the request */ 2598c2ecf20Sopenharmony_ci if (props->type == USB_BULK) { 2608c2ecf20Sopenharmony_ci buf_size = stream->props.u.bulk.buffersize; 2618c2ecf20Sopenharmony_ci } else if (props->type == USB_ISOC) { 2628c2ecf20Sopenharmony_ci buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; 2638c2ecf20Sopenharmony_ci } else { 2648c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", 2658c2ecf20Sopenharmony_ci KBUILD_MODNAME, props->type); 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (stream->buf_num < props->count || stream->buf_size < buf_size) { 2708c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, 2718c2ecf20Sopenharmony_ci "%s: cannot reconfigure as allocated buffers are too small\n", 2728c2ecf20Sopenharmony_ci KBUILD_MODNAME); 2738c2ecf20Sopenharmony_ci return -EINVAL; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* check if all fields are same */ 2778c2ecf20Sopenharmony_ci if (stream->props.type == props->type && 2788c2ecf20Sopenharmony_ci stream->props.count == props->count && 2798c2ecf20Sopenharmony_ci stream->props.endpoint == props->endpoint) { 2808c2ecf20Sopenharmony_ci if (props->type == USB_BULK && 2818c2ecf20Sopenharmony_ci props->u.bulk.buffersize == 2828c2ecf20Sopenharmony_ci stream->props.u.bulk.buffersize) 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci else if (props->type == USB_ISOC && 2858c2ecf20Sopenharmony_ci props->u.isoc.framesperurb == 2868c2ecf20Sopenharmony_ci stream->props.u.isoc.framesperurb && 2878c2ecf20Sopenharmony_ci props->u.isoc.framesize == 2888c2ecf20Sopenharmony_ci stream->props.u.isoc.framesize && 2898c2ecf20Sopenharmony_ci props->u.isoc.interval == 2908c2ecf20Sopenharmony_ci stream->props.u.isoc.interval) 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci usb_urb_free_urbs(stream); 2978c2ecf20Sopenharmony_ci memcpy(&stream->props, props, sizeof(*props)); 2988c2ecf20Sopenharmony_ci if (props->type == USB_BULK) 2998c2ecf20Sopenharmony_ci return usb_urb_alloc_bulk_urbs(stream); 3008c2ecf20Sopenharmony_ci else if (props->type == USB_ISOC) 3018c2ecf20Sopenharmony_ci return usb_urb_alloc_isoc_urbs(stream); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciint usb_urb_initv2(struct usb_data_stream *stream, 3078c2ecf20Sopenharmony_ci const struct usb_data_stream_properties *props) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!stream || !props) 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci memcpy(&stream->props, props, sizeof(*props)); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!stream->complete) { 3178c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, 3188c2ecf20Sopenharmony_ci "%s: there is no data callback - this doesn't make sense\n", 3198c2ecf20Sopenharmony_ci KBUILD_MODNAME); 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci switch (stream->props.type) { 3248c2ecf20Sopenharmony_ci case USB_BULK: 3258c2ecf20Sopenharmony_ci ret = usb_alloc_stream_buffers(stream, stream->props.count, 3268c2ecf20Sopenharmony_ci stream->props.u.bulk.buffersize); 3278c2ecf20Sopenharmony_ci if (ret < 0) 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return usb_urb_alloc_bulk_urbs(stream); 3318c2ecf20Sopenharmony_ci case USB_ISOC: 3328c2ecf20Sopenharmony_ci ret = usb_alloc_stream_buffers(stream, stream->props.count, 3338c2ecf20Sopenharmony_ci stream->props.u.isoc.framesize * 3348c2ecf20Sopenharmony_ci stream->props.u.isoc.framesperurb); 3358c2ecf20Sopenharmony_ci if (ret < 0) 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return usb_urb_alloc_isoc_urbs(stream); 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci dev_err(&stream->udev->dev, 3418c2ecf20Sopenharmony_ci "%s: unknown urb-type for data transfer\n", 3428c2ecf20Sopenharmony_ci KBUILD_MODNAME); 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciint usb_urb_exitv2(struct usb_data_stream *stream) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci usb_urb_free_urbs(stream); 3508c2ecf20Sopenharmony_ci usb_free_stream_buffers(stream); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 354