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 */
15
16int usb_urb_reconfig(struct usb_data_stream *stream,
17		struct usb_data_stream_properties *props);
18
19static void usb_urb_complete(struct urb *urb)
20{
21	struct usb_data_stream *stream = urb->context;
22	int ptype = usb_pipetype(urb->pipe);
23	int i;
24	u8 *b;
25
26	dev_dbg_ratelimited(&stream->udev->dev,
27			"%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
28			__func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
29			urb->status, urb->actual_length,
30			urb->transfer_buffer_length,
31			urb->number_of_packets, urb->error_count);
32
33	switch (urb->status) {
34	case 0:         /* success */
35	case -ETIMEDOUT:    /* NAK */
36		break;
37	case -ECONNRESET:   /* kill */
38	case -ENOENT:
39	case -ESHUTDOWN:
40		return;
41	default:        /* error */
42		dev_dbg_ratelimited(&stream->udev->dev,
43				"%s: urb completion failed=%d\n",
44				__func__, urb->status);
45		break;
46	}
47
48	b = (u8 *) urb->transfer_buffer;
49	switch (ptype) {
50	case PIPE_ISOCHRONOUS:
51		for (i = 0; i < urb->number_of_packets; i++) {
52			if (urb->iso_frame_desc[i].status != 0)
53				dev_dbg(&stream->udev->dev,
54						"%s: iso frame descriptor has an error=%d\n",
55						__func__,
56						urb->iso_frame_desc[i].status);
57			else if (urb->iso_frame_desc[i].actual_length > 0)
58				stream->complete(stream,
59					b + urb->iso_frame_desc[i].offset,
60					urb->iso_frame_desc[i].actual_length);
61
62			urb->iso_frame_desc[i].status = 0;
63			urb->iso_frame_desc[i].actual_length = 0;
64		}
65		break;
66	case PIPE_BULK:
67		if (urb->actual_length > 0)
68			stream->complete(stream, b, urb->actual_length);
69		break;
70	default:
71		dev_err(&stream->udev->dev,
72				"%s: unknown endpoint type in completion handler\n",
73				KBUILD_MODNAME);
74		return;
75	}
76	usb_submit_urb(urb, GFP_ATOMIC);
77}
78
79int usb_urb_killv2(struct usb_data_stream *stream)
80{
81	int i;
82	for (i = 0; i < stream->urbs_submitted; i++) {
83		dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
84		/* stop the URB */
85		usb_kill_urb(stream->urb_list[i]);
86	}
87	stream->urbs_submitted = 0;
88	return 0;
89}
90
91int usb_urb_submitv2(struct usb_data_stream *stream,
92		struct usb_data_stream_properties *props)
93{
94	int i, ret;
95
96	if (props) {
97		ret = usb_urb_reconfig(stream, props);
98		if (ret < 0)
99			return ret;
100	}
101
102	for (i = 0; i < stream->urbs_initialized; i++) {
103		dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
104		ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
105		if (ret) {
106			dev_err(&stream->udev->dev,
107					"%s: could not submit urb no. %d - get them all back\n",
108					KBUILD_MODNAME, i);
109			usb_urb_killv2(stream);
110			return ret;
111		}
112		stream->urbs_submitted++;
113	}
114	return 0;
115}
116
117static int usb_urb_free_urbs(struct usb_data_stream *stream)
118{
119	int i;
120
121	usb_urb_killv2(stream);
122
123	for (i = stream->urbs_initialized - 1; i >= 0; i--) {
124		if (stream->urb_list[i]) {
125			dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
126					__func__, i);
127			/* free the URBs */
128			usb_free_urb(stream->urb_list[i]);
129		}
130	}
131	stream->urbs_initialized = 0;
132
133	return 0;
134}
135
136static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
137{
138	int i, j;
139
140	/* allocate the URBs */
141	for (i = 0; i < stream->props.count; i++) {
142		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
143		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
144		if (!stream->urb_list[i]) {
145			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
146			for (j = 0; j < i; j++)
147				usb_free_urb(stream->urb_list[j]);
148			return -ENOMEM;
149		}
150		usb_fill_bulk_urb(stream->urb_list[i],
151				stream->udev,
152				usb_rcvbulkpipe(stream->udev,
153						stream->props.endpoint),
154				stream->buf_list[i],
155				stream->props.u.bulk.buffersize,
156				usb_urb_complete, stream);
157
158		stream->urbs_initialized++;
159	}
160	return 0;
161}
162
163static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
164{
165	int i, j;
166
167	/* allocate the URBs */
168	for (i = 0; i < stream->props.count; i++) {
169		struct urb *urb;
170		int frame_offset = 0;
171		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
172		stream->urb_list[i] = usb_alloc_urb(
173				stream->props.u.isoc.framesperurb, GFP_ATOMIC);
174		if (!stream->urb_list[i]) {
175			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
176			for (j = 0; j < i; j++)
177				usb_free_urb(stream->urb_list[j]);
178			return -ENOMEM;
179		}
180
181		urb = stream->urb_list[i];
182
183		urb->dev = stream->udev;
184		urb->context = stream;
185		urb->complete = usb_urb_complete;
186		urb->pipe = usb_rcvisocpipe(stream->udev,
187				stream->props.endpoint);
188		urb->transfer_flags = URB_ISO_ASAP;
189		urb->interval = stream->props.u.isoc.interval;
190		urb->number_of_packets = stream->props.u.isoc.framesperurb;
191		urb->transfer_buffer_length = stream->props.u.isoc.framesize *
192				stream->props.u.isoc.framesperurb;
193		urb->transfer_buffer = stream->buf_list[i];
194
195		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
196			urb->iso_frame_desc[j].offset = frame_offset;
197			urb->iso_frame_desc[j].length =
198					stream->props.u.isoc.framesize;
199			frame_offset += stream->props.u.isoc.framesize;
200		}
201
202		stream->urbs_initialized++;
203	}
204	return 0;
205}
206
207static int usb_free_stream_buffers(struct usb_data_stream *stream)
208{
209	if (stream->state & USB_STATE_URB_BUF) {
210		while (stream->buf_num) {
211			stream->buf_num--;
212			kfree(stream->buf_list[stream->buf_num]);
213		}
214	}
215
216	stream->state &= ~USB_STATE_URB_BUF;
217
218	return 0;
219}
220
221static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
222				    unsigned long size)
223{
224	stream->buf_num = 0;
225	stream->buf_size = size;
226
227	dev_dbg(&stream->udev->dev,
228			"%s: all in all I will use %lu bytes for streaming\n",
229			__func__,  num * size);
230
231	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
232		stream->buf_list[stream->buf_num] = kzalloc(size, GFP_ATOMIC);
233		if (!stream->buf_list[stream->buf_num]) {
234			dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
235					__func__, stream->buf_num);
236			usb_free_stream_buffers(stream);
237			return -ENOMEM;
238		}
239
240		dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
241				__func__, stream->buf_num,
242				stream->buf_list[stream->buf_num],
243				(long long)stream->dma_addr[stream->buf_num]);
244		stream->state |= USB_STATE_URB_BUF;
245	}
246
247	return 0;
248}
249
250int usb_urb_reconfig(struct usb_data_stream *stream,
251		struct usb_data_stream_properties *props)
252{
253	int buf_size;
254
255	if (!props)
256		return 0;
257
258	/* check allocated buffers are large enough for the request */
259	if (props->type == USB_BULK) {
260		buf_size = stream->props.u.bulk.buffersize;
261	} else if (props->type == USB_ISOC) {
262		buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
263	} else {
264		dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
265				KBUILD_MODNAME, props->type);
266		return -EINVAL;
267	}
268
269	if (stream->buf_num < props->count || stream->buf_size < buf_size) {
270		dev_err(&stream->udev->dev,
271				"%s: cannot reconfigure as allocated buffers are too small\n",
272				KBUILD_MODNAME);
273		return -EINVAL;
274	}
275
276	/* check if all fields are same */
277	if (stream->props.type == props->type &&
278			stream->props.count == props->count &&
279			stream->props.endpoint == props->endpoint) {
280		if (props->type == USB_BULK &&
281				props->u.bulk.buffersize ==
282				stream->props.u.bulk.buffersize)
283			return 0;
284		else if (props->type == USB_ISOC &&
285				props->u.isoc.framesperurb ==
286				stream->props.u.isoc.framesperurb &&
287				props->u.isoc.framesize ==
288				stream->props.u.isoc.framesize &&
289				props->u.isoc.interval ==
290				stream->props.u.isoc.interval)
291			return 0;
292	}
293
294	dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
295
296	usb_urb_free_urbs(stream);
297	memcpy(&stream->props, props, sizeof(*props));
298	if (props->type == USB_BULK)
299		return usb_urb_alloc_bulk_urbs(stream);
300	else if (props->type == USB_ISOC)
301		return usb_urb_alloc_isoc_urbs(stream);
302
303	return 0;
304}
305
306int usb_urb_initv2(struct usb_data_stream *stream,
307		const struct usb_data_stream_properties *props)
308{
309	int ret;
310
311	if (!stream || !props)
312		return -EINVAL;
313
314	memcpy(&stream->props, props, sizeof(*props));
315
316	if (!stream->complete) {
317		dev_err(&stream->udev->dev,
318				"%s: there is no data callback - this doesn't make sense\n",
319				KBUILD_MODNAME);
320		return -EINVAL;
321	}
322
323	switch (stream->props.type) {
324	case USB_BULK:
325		ret = usb_alloc_stream_buffers(stream, stream->props.count,
326				stream->props.u.bulk.buffersize);
327		if (ret < 0)
328			return ret;
329
330		return usb_urb_alloc_bulk_urbs(stream);
331	case USB_ISOC:
332		ret = usb_alloc_stream_buffers(stream, stream->props.count,
333				stream->props.u.isoc.framesize *
334				stream->props.u.isoc.framesperurb);
335		if (ret < 0)
336			return ret;
337
338		return usb_urb_alloc_isoc_urbs(stream);
339	default:
340		dev_err(&stream->udev->dev,
341				"%s: unknown urb-type for data transfer\n",
342				KBUILD_MODNAME);
343		return -EINVAL;
344	}
345}
346
347int usb_urb_exitv2(struct usb_data_stream *stream)
348{
349	usb_urb_free_urbs(stream);
350	usb_free_stream_buffers(stream);
351
352	return 0;
353}
354