ocfs2: Make the left masklogs compat.
[taoma-kernel.git] / drivers / staging / line6 / midibuf.c
blob7b532e5ce8b4461cdf273e2f2688e2bc2c92dd35
1 /*
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>
14 #include "midibuf.h"
16 static int midibuf_message_length(unsigned char code)
18 if (code < 0x80)
19 return -1;
20 else if (code < 0xf0) {
21 static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
22 return length[(code >> 4) - 8];
23 } else {
25 Note that according to the MIDI specification 0xf2 is
26 the "Song Position Pointer", but this is used by Line6
27 to send sysex messages to the host.
29 static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
30 1, 1, 1, -1, 1, 1
32 return length[code & 0x0f];
36 static int midibuf_is_empty(struct MidiBuffer *this)
38 return (this->pos_read == this->pos_write) && !this->full;
41 static int midibuf_is_full(struct MidiBuffer *this)
43 return this->full;
46 void line6_midibuf_reset(struct MidiBuffer *this)
48 this->pos_read = this->pos_write = this->full = 0;
49 this->command_prev = -1;
52 int line6_midibuf_init(struct MidiBuffer *this, int size, int split)
54 this->buf = kmalloc(size, GFP_KERNEL);
56 if (this->buf == NULL)
57 return -ENOMEM;
59 this->size = size;
60 this->split = split;
61 line6_midibuf_reset(this);
62 return 0;
65 void line6_midibuf_status(struct MidiBuffer *this)
67 printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d "
68 "full=%d command_prev=%02x\n", this->size, this->split,
69 this->pos_read, this->pos_write, this->full, this->command_prev);
72 int line6_midibuf_bytes_free(struct MidiBuffer *this)
74 return
75 midibuf_is_full(this) ?
76 0 :
77 (this->pos_read - this->pos_write + this->size - 1) % this->size +
81 int line6_midibuf_bytes_used(struct MidiBuffer *this)
83 return
84 midibuf_is_empty(this) ?
85 0 :
86 (this->pos_write - this->pos_read + this->size - 1) % this->size +
90 int line6_midibuf_write(struct MidiBuffer *this, unsigned char *data,
91 int length)
93 int bytes_free;
94 int length1, length2;
95 int skip_active_sense = 0;
97 if (midibuf_is_full(this) || (length <= 0))
98 return 0;
100 /* skip trailing active sense */
101 if (data[length - 1] == 0xfe) {
102 --length;
103 skip_active_sense = 1;
106 bytes_free = line6_midibuf_bytes_free(this);
108 if (length > bytes_free)
109 length = bytes_free;
111 if (length > 0) {
112 length1 = this->size - this->pos_write;
114 if (length < length1) {
115 /* no buffer wraparound */
116 memcpy(this->buf + this->pos_write, data, length);
117 this->pos_write += length;
118 } else {
119 /* buffer wraparound */
120 length2 = length - length1;
121 memcpy(this->buf + this->pos_write, data, length1);
122 memcpy(this->buf, data + length1, length2);
123 this->pos_write = length2;
126 if (this->pos_write == this->pos_read)
127 this->full = 1;
130 return length + skip_active_sense;
133 int line6_midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
135 int bytes_used;
136 int length1, length2;
137 int command;
138 int midi_length;
139 int repeat = 0;
140 int i;
142 /* we need to be able to store at least a 3 byte MIDI message */
143 if (length < 3)
144 return -EINVAL;
146 if (midibuf_is_empty(this))
147 return 0;
149 bytes_used = line6_midibuf_bytes_used(this);
151 if (length > bytes_used)
152 length = bytes_used;
154 length1 = this->size - this->pos_read;
156 /* check MIDI command length */
157 command = this->buf[this->pos_read];
159 if (command & 0x80) {
160 midi_length = midibuf_message_length(command);
161 this->command_prev = command;
162 } else {
163 if (this->command_prev > 0) {
164 int midi_length_prev =
165 midibuf_message_length(this->command_prev);
167 if (midi_length_prev > 0) {
168 midi_length = midi_length_prev - 1;
169 repeat = 1;
170 } else
171 midi_length = -1;
172 } else
173 midi_length = -1;
176 if (midi_length < 0) {
177 /* search for end of message */
178 if (length < length1) {
179 /* no buffer wraparound */
180 for (i = 1; i < length; ++i)
181 if (this->buf[this->pos_read + i] & 0x80)
182 break;
184 midi_length = i;
185 } else {
186 /* buffer wraparound */
187 length2 = length - length1;
189 for (i = 1; i < length1; ++i)
190 if (this->buf[this->pos_read + i] & 0x80)
191 break;
193 if (i < length1)
194 midi_length = i;
195 else {
196 for (i = 0; i < length2; ++i)
197 if (this->buf[i] & 0x80)
198 break;
200 midi_length = length1 + i;
204 if (midi_length == length)
205 midi_length = -1; /* end of message not found */
208 if (midi_length < 0) {
209 if (!this->split)
210 return 0; /* command is not yet complete */
211 } else {
212 if (length < midi_length)
213 return 0; /* command is not yet complete */
215 length = midi_length;
218 if (length < length1) {
219 /* no buffer wraparound */
220 memcpy(data + repeat, this->buf + this->pos_read, length);
221 this->pos_read += length;
222 } else {
223 /* buffer wraparound */
224 length2 = length - length1;
225 memcpy(data + repeat, this->buf + this->pos_read, length1);
226 memcpy(data + repeat + length1, this->buf, length2);
227 this->pos_read = length2;
230 if (repeat)
231 data[0] = this->command_prev;
233 this->full = 0;
234 return length + repeat;
237 int line6_midibuf_ignore(struct MidiBuffer *this, int length)
239 int bytes_used = line6_midibuf_bytes_used(this);
241 if (length > bytes_used)
242 length = bytes_used;
244 this->pos_read = (this->pos_read + length) % this->size;
245 this->full = 0;
246 return length;
249 int line6_midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
251 int cmd = this->command_prev;
253 if ((cmd >= 0x80) && (cmd < 0xf0))
254 if ((mask & (1 << (cmd & 0x0f))) == 0)
255 return 1;
257 return 0;
260 void line6_midibuf_destroy(struct MidiBuffer *this)
262 kfree(this->buf);
263 this->buf = NULL;