cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usb-urb.c (7109B)


      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 */
     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}