Full support for Ginger Console
[linux-ginger.git] / drivers / staging / line6 / midibuf.c
blobab0a5f30fbca895da03672f8efbd3d1c3faa150f
1 /*
2 * Line6 Linux USB driver - 0.8.0
4 * Copyright (C) 2004-2009 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 "config.h"
14 #include <linux/slab.h>
16 #include "midibuf.h"
19 static int midibuf_message_length(unsigned char code)
21 if (code < 0x80)
22 return -1;
23 else if (code < 0xf0) {
24 static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
25 return length[(code >> 4) - 8];
26 } else {
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,
33 1, 1, 1, -1, 1, 1 };
34 return length[code & 0x0f];
38 void midibuf_reset(struct MidiBuffer *this)
40 this->pos_read = this->pos_write = this->full = 0;
41 this->command_prev = -1;
44 int midibuf_init(struct MidiBuffer *this, int size, int split)
46 this->buf = kmalloc(size, GFP_KERNEL);
48 if (this->buf == NULL)
49 return -ENOMEM;
51 this->size = size;
52 this->split = split;
53 midibuf_reset(this);
54 return 0;
57 void midibuf_status(struct MidiBuffer *this)
59 printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d "
60 "full=%d command_prev=%02x\n", this->size, this->split,
61 this->pos_read, this->pos_write, this->full, this->command_prev);
64 static int midibuf_is_empty(struct MidiBuffer *this)
66 return (this->pos_read == this->pos_write) && !this->full;
69 static int midibuf_is_full(struct MidiBuffer *this)
71 return this->full;
74 int midibuf_bytes_free(struct MidiBuffer *this)
76 return
77 midibuf_is_full(this) ?
78 0 :
79 (this->pos_read - this->pos_write + this->size - 1) % this->size + 1;
82 int midibuf_bytes_used(struct MidiBuffer *this)
84 return
85 midibuf_is_empty(this) ?
86 0 :
87 (this->pos_write - this->pos_read + this->size - 1) % this->size + 1;
90 int midibuf_write(struct MidiBuffer *this, unsigned char *data, int length)
92 int bytes_free;
93 int length1, length2;
94 int skip_active_sense = 0;
96 if (midibuf_is_full(this) || (length <= 0))
97 return 0;
99 /* skip trailing active sense */
100 if (data[length - 1] == 0xfe) {
101 --length;
102 skip_active_sense = 1;
105 bytes_free = midibuf_bytes_free(this);
107 if (length > bytes_free)
108 length = bytes_free;
110 if (length > 0) {
111 length1 = this->size - this->pos_write;
113 if (length < length1) {
114 /* no buffer wraparound */
115 memcpy(this->buf + this->pos_write, data, length);
116 this->pos_write += length;
117 } else {
118 /* buffer wraparound */
119 length2 = length - length1;
120 memcpy(this->buf + this->pos_write, data, length1);
121 memcpy(this->buf, data + length1, length2);
122 this->pos_write = length2;
125 if (this->pos_write == this->pos_read)
126 this->full = 1;
129 return length + skip_active_sense;
132 int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
134 int bytes_used;
135 int length1, length2;
136 int command;
137 int midi_length;
138 int repeat = 0;
139 int i;
141 /* we need to be able to store at least a 3 byte MIDI message */
142 if (length < 3)
143 return -EINVAL;
145 if (midibuf_is_empty(this))
146 return 0;
148 bytes_used = midibuf_bytes_used(this);
150 if (length > bytes_used)
151 length = bytes_used;
153 length1 = this->size - this->pos_read;
155 /* check MIDI command length */
156 command = this->buf[this->pos_read];
158 if (command & 0x80) {
159 midi_length = midibuf_message_length(command);
160 this->command_prev = command;
161 } else {
162 if (this->command_prev > 0) {
163 int midi_length_prev = midibuf_message_length(this->command_prev);
165 if (midi_length_prev > 0) {
166 midi_length = midi_length_prev - 1;
167 repeat = 1;
168 } else
169 midi_length = -1;
170 } else
171 midi_length = -1;
174 if (midi_length < 0) {
175 /* search for end of message */
176 if (length < length1) {
177 /* no buffer wraparound */
178 for (i = 1; i < length; ++i)
179 if (this->buf[this->pos_read + i] & 0x80)
180 break;
182 midi_length = i;
183 } else {
184 /* buffer wraparound */
185 length2 = length - length1;
187 for (i = 1; i < length1; ++i)
188 if (this->buf[this->pos_read + i] & 0x80)
189 break;
191 if (i < length1)
192 midi_length = i;
193 else {
194 for (i = 0; i < length2; ++i)
195 if (this->buf[i] & 0x80)
196 break;
198 midi_length = length1 + i;
202 if (midi_length == length)
203 midi_length = -1; /* end of message not found */
206 if (midi_length < 0) {
207 if (!this->split)
208 return 0; /* command is not yet complete */
209 } else {
210 if (length < midi_length)
211 return 0; /* command is not yet complete */
213 length = midi_length;
216 if (length < length1) {
217 /* no buffer wraparound */
218 memcpy(data + repeat, this->buf + this->pos_read, length);
219 this->pos_read += length;
220 } else {
221 /* buffer wraparound */
222 length2 = length - length1;
223 memcpy(data + repeat, this->buf + this->pos_read, length1);
224 memcpy(data + repeat + length1, this->buf, length2);
225 this->pos_read = length2;
228 if (repeat)
229 data[0] = this->command_prev;
231 this->full = 0;
232 return length + repeat;
235 int midibuf_ignore(struct MidiBuffer *this, int length)
237 int bytes_used = midibuf_bytes_used(this);
239 if (length > bytes_used)
240 length = bytes_used;
242 this->pos_read = (this->pos_read + length) % this->size;
243 this->full = 0;
244 return length;
247 int midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
249 int cmd = this->command_prev;
251 if ((cmd >= 0x80) && (cmd < 0xf0))
252 if ((mask & (1 << (cmd & 0x0f))) == 0)
253 return 1;
255 return 0;
258 void midibuf_destroy(struct MidiBuffer *this)
260 kfree(this->buf);
261 this->buf = NULL;