2 * Line6 Linux USB driver - 0.9.1beta
4 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
12 #include <linux/slab.h>
16 static int midibuf_message_length(unsigned char code)
22 else if (code < 0xf0) {
23 static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
25 message_length = length[(code >> 4) - 8];
28 Note that according to the MIDI specification 0xf2 is
29 the "Song Position Pointer", but this is used by Line6
30 to send sysex messages to the host.
32 static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
35 message_length = length[code & 0x0f];
38 return message_length;
41 static int midibuf_is_empty(struct midi_buffer *this)
43 return (this->pos_read == this->pos_write) && !this->full;
46 static int midibuf_is_full(struct midi_buffer *this)
51 void line6_midibuf_reset(struct midi_buffer *this)
53 this->pos_read = this->pos_write = this->full = 0;
54 this->command_prev = -1;
57 int line6_midibuf_init(struct midi_buffer *this, int size, int split)
59 this->buf = kmalloc(size, GFP_KERNEL);
61 if (this->buf == NULL)
66 line6_midibuf_reset(this);
70 void line6_midibuf_status(struct midi_buffer *this)
72 pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
73 this->size, this->split, this->pos_read, this->pos_write,
74 this->full, this->command_prev);
77 int line6_midibuf_bytes_free(struct midi_buffer *this)
80 midibuf_is_full(this) ?
82 (this->pos_read - this->pos_write + this->size - 1) % this->size +
86 int line6_midibuf_bytes_used(struct midi_buffer *this)
89 midibuf_is_empty(this) ?
91 (this->pos_write - this->pos_read + this->size - 1) % this->size +
95 int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
100 int skip_active_sense = 0;
102 if (midibuf_is_full(this) || (length <= 0))
105 /* skip trailing active sense */
106 if (data[length - 1] == 0xfe) {
108 skip_active_sense = 1;
111 bytes_free = line6_midibuf_bytes_free(this);
113 if (length > bytes_free)
117 length1 = this->size - this->pos_write;
119 if (length < length1) {
120 /* no buffer wraparound */
121 memcpy(this->buf + this->pos_write, data, length);
122 this->pos_write += length;
124 /* buffer wraparound */
125 length2 = length - length1;
126 memcpy(this->buf + this->pos_write, data, length1);
127 memcpy(this->buf, data + length1, length2);
128 this->pos_write = length2;
131 if (this->pos_write == this->pos_read)
135 return length + skip_active_sense;
138 int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
142 int length1, length2;
148 /* we need to be able to store at least a 3 byte MIDI message */
152 if (midibuf_is_empty(this))
155 bytes_used = line6_midibuf_bytes_used(this);
157 if (length > bytes_used)
160 length1 = this->size - this->pos_read;
162 /* check MIDI command length */
163 command = this->buf[this->pos_read];
165 if (command & 0x80) {
166 midi_length = midibuf_message_length(command);
167 this->command_prev = command;
169 if (this->command_prev > 0) {
170 int midi_length_prev =
171 midibuf_message_length(this->command_prev);
173 if (midi_length_prev > 0) {
174 midi_length = midi_length_prev - 1;
182 if (midi_length < 0) {
183 /* search for end of message */
184 if (length < length1) {
185 /* no buffer wraparound */
186 for (i = 1; i < length; ++i)
187 if (this->buf[this->pos_read + i] & 0x80)
192 /* buffer wraparound */
193 length2 = length - length1;
195 for (i = 1; i < length1; ++i)
196 if (this->buf[this->pos_read + i] & 0x80)
202 for (i = 0; i < length2; ++i)
203 if (this->buf[i] & 0x80)
206 midi_length = length1 + i;
210 if (midi_length == length)
211 midi_length = -1; /* end of message not found */
214 if (midi_length < 0) {
216 return 0; /* command is not yet complete */
218 if (length < midi_length)
219 return 0; /* command is not yet complete */
221 length = midi_length;
224 if (length < length1) {
225 /* no buffer wraparound */
226 memcpy(data + repeat, this->buf + this->pos_read, length);
227 this->pos_read += length;
229 /* buffer wraparound */
230 length2 = length - length1;
231 memcpy(data + repeat, this->buf + this->pos_read, length1);
232 memcpy(data + repeat + length1, this->buf, length2);
233 this->pos_read = length2;
237 data[0] = this->command_prev;
240 return length + repeat;
243 int line6_midibuf_ignore(struct midi_buffer *this, int length)
245 int bytes_used = line6_midibuf_bytes_used(this);
247 if (length > bytes_used)
250 this->pos_read = (this->pos_read + length) % this->size;
255 int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
257 int cmd = this->command_prev;
259 if ((cmd >= 0x80) && (cmd < 0xf0))
260 if ((mask & (1 << (cmd & 0x0f))) == 0)
266 void line6_midibuf_destroy(struct midi_buffer *this)