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