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

midibuf.c (5229B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Line 6 Linux USB driver
      4 *
      5 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
      6 */
      7
      8#include <linux/slab.h>
      9
     10#include "midibuf.h"
     11
     12static int midibuf_message_length(unsigned char code)
     13{
     14	int message_length;
     15
     16	if (code < 0x80)
     17		message_length = -1;
     18	else if (code < 0xf0) {
     19		static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
     20
     21		message_length = length[(code >> 4) - 8];
     22	} else {
     23		/*
     24		   Note that according to the MIDI specification 0xf2 is
     25		   the "Song Position Pointer", but this is used by Line 6
     26		   to send sysex messages to the host.
     27		 */
     28		static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
     29			1, 1, 1, -1, 1, 1
     30		};
     31		message_length = length[code & 0x0f];
     32	}
     33
     34	return message_length;
     35}
     36
     37static int midibuf_is_empty(struct midi_buffer *this)
     38{
     39	return (this->pos_read == this->pos_write) && !this->full;
     40}
     41
     42static int midibuf_is_full(struct midi_buffer *this)
     43{
     44	return this->full;
     45}
     46
     47void line6_midibuf_reset(struct midi_buffer *this)
     48{
     49	this->pos_read = this->pos_write = this->full = 0;
     50	this->command_prev = -1;
     51}
     52
     53int line6_midibuf_init(struct midi_buffer *this, int size, int split)
     54{
     55	this->buf = kmalloc(size, GFP_KERNEL);
     56
     57	if (this->buf == NULL)
     58		return -ENOMEM;
     59
     60	this->size = size;
     61	this->split = split;
     62	line6_midibuf_reset(this);
     63	return 0;
     64}
     65
     66int line6_midibuf_bytes_free(struct midi_buffer *this)
     67{
     68	return
     69	    midibuf_is_full(this) ?
     70	    0 :
     71	    (this->pos_read - this->pos_write + this->size - 1) % this->size +
     72	    1;
     73}
     74
     75int line6_midibuf_bytes_used(struct midi_buffer *this)
     76{
     77	return
     78	    midibuf_is_empty(this) ?
     79	    0 :
     80	    (this->pos_write - this->pos_read + this->size - 1) % this->size +
     81	    1;
     82}
     83
     84int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
     85			int length)
     86{
     87	int bytes_free;
     88	int length1, length2;
     89	int skip_active_sense = 0;
     90
     91	if (midibuf_is_full(this) || (length <= 0))
     92		return 0;
     93
     94	/* skip trailing active sense */
     95	if (data[length - 1] == 0xfe) {
     96		--length;
     97		skip_active_sense = 1;
     98	}
     99
    100	bytes_free = line6_midibuf_bytes_free(this);
    101
    102	if (length > bytes_free)
    103		length = bytes_free;
    104
    105	if (length > 0) {
    106		length1 = this->size - this->pos_write;
    107
    108		if (length < length1) {
    109			/* no buffer wraparound */
    110			memcpy(this->buf + this->pos_write, data, length);
    111			this->pos_write += length;
    112		} else {
    113			/* buffer wraparound */
    114			length2 = length - length1;
    115			memcpy(this->buf + this->pos_write, data, length1);
    116			memcpy(this->buf, data + length1, length2);
    117			this->pos_write = length2;
    118		}
    119
    120		if (this->pos_write == this->pos_read)
    121			this->full = 1;
    122	}
    123
    124	return length + skip_active_sense;
    125}
    126
    127int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
    128		       int length)
    129{
    130	int bytes_used;
    131	int length1, length2;
    132	int command;
    133	int midi_length;
    134	int repeat = 0;
    135	int i;
    136
    137	/* we need to be able to store at least a 3 byte MIDI message */
    138	if (length < 3)
    139		return -EINVAL;
    140
    141	if (midibuf_is_empty(this))
    142		return 0;
    143
    144	bytes_used = line6_midibuf_bytes_used(this);
    145
    146	if (length > bytes_used)
    147		length = bytes_used;
    148
    149	length1 = this->size - this->pos_read;
    150
    151	/* check MIDI command length */
    152	command = this->buf[this->pos_read];
    153
    154	if (command & 0x80) {
    155		midi_length = midibuf_message_length(command);
    156		this->command_prev = command;
    157	} else {
    158		if (this->command_prev > 0) {
    159			int midi_length_prev =
    160			    midibuf_message_length(this->command_prev);
    161
    162			if (midi_length_prev > 1) {
    163				midi_length = midi_length_prev - 1;
    164				repeat = 1;
    165			} else
    166				midi_length = -1;
    167		} else
    168			midi_length = -1;
    169	}
    170
    171	if (midi_length < 0) {
    172		/* search for end of message */
    173		if (length < length1) {
    174			/* no buffer wraparound */
    175			for (i = 1; i < length; ++i)
    176				if (this->buf[this->pos_read + i] & 0x80)
    177					break;
    178
    179			midi_length = i;
    180		} else {
    181			/* buffer wraparound */
    182			length2 = length - length1;
    183
    184			for (i = 1; i < length1; ++i)
    185				if (this->buf[this->pos_read + i] & 0x80)
    186					break;
    187
    188			if (i < length1)
    189				midi_length = i;
    190			else {
    191				for (i = 0; i < length2; ++i)
    192					if (this->buf[i] & 0x80)
    193						break;
    194
    195				midi_length = length1 + i;
    196			}
    197		}
    198
    199		if (midi_length == length)
    200			midi_length = -1;	/* end of message not found */
    201	}
    202
    203	if (midi_length < 0) {
    204		if (!this->split)
    205			return 0;	/* command is not yet complete */
    206	} else {
    207		if (length < midi_length)
    208			return 0;	/* command is not yet complete */
    209
    210		length = midi_length;
    211	}
    212
    213	if (length < length1) {
    214		/* no buffer wraparound */
    215		memcpy(data + repeat, this->buf + this->pos_read, length);
    216		this->pos_read += length;
    217	} else {
    218		/* buffer wraparound */
    219		length2 = length - length1;
    220		memcpy(data + repeat, this->buf + this->pos_read, length1);
    221		memcpy(data + repeat + length1, this->buf, length2);
    222		this->pos_read = length2;
    223	}
    224
    225	if (repeat)
    226		data[0] = this->command_prev;
    227
    228	this->full = 0;
    229	return length + repeat;
    230}
    231
    232int line6_midibuf_ignore(struct midi_buffer *this, int length)
    233{
    234	int bytes_used = line6_midibuf_bytes_used(this);
    235
    236	if (length > bytes_used)
    237		length = bytes_used;
    238
    239	this->pos_read = (this->pos_read + length) % this->size;
    240	this->full = 0;
    241	return length;
    242}
    243
    244void line6_midibuf_destroy(struct midi_buffer *this)
    245{
    246	kfree(this->buf);
    247	this->buf = NULL;
    248}