File Index
Files and directories
Sign in
FILE

usb_urb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/usb/dvb-usb-v2/usb_urb.c C
  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}
~/ Read-only file preview.