Merge tag 'gpio-v3.13-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6.git] / drivers / staging / line6 / midibuf.c
blobf0adb7baa603b3ae060cf6e0397a628af6b980e3
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 midi_buffer *this)
38 return (this->pos_read == this->pos_write) && !this->full;
41 static int midibuf_is_full(struct midi_buffer *this)
43 return this->full;
46 void line6_midibuf_reset(struct midi_buffer *this)
48 this->pos_read = this->pos_write = this->full = 0;
49 this->command_prev = -1;
52 int line6_midibuf_init(struct midi_buffer *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 midi_buffer *this)
67 pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
68 this->size, this->split, this->pos_read, this->pos_write,
69 this->full, this->command_prev);
72 int line6_midibuf_bytes_free(struct midi_buffer *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 midi_buffer *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 midi_buffer *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 midi_buffer *this, unsigned char *data,
134 int length)
136 int bytes_used;
137 int length1, length2;
138 int command;
139 int midi_length;
140 int repeat = 0;
141 int i;
143 /* we need to be able to store at least a 3 byte MIDI message */
144 if (length < 3)
145 return -EINVAL;
147 if (midibuf_is_empty(this))
148 return 0;
150 bytes_used = line6_midibuf_bytes_used(this);
152 if (length > bytes_used)
153 length = bytes_used;
155 length1 = this->size - this->pos_read;
157 /* check MIDI command length */
158 command = this->buf[this->pos_read];
160 if (command & 0x80) {
161 midi_length = midibuf_message_length(command);
162 this->command_prev = command;
163 } else {
164 if (this->command_prev > 0) {
165 int midi_length_prev =
166 midibuf_message_length(this->command_prev);
168 if (midi_length_prev > 0) {
169 midi_length = midi_length_prev - 1;
170 repeat = 1;
171 } else
172 midi_length = -1;
173 } else
174 midi_length = -1;
177 if (midi_length < 0) {
178 /* search for end of message */
179 if (length < length1) {
180 /* no buffer wraparound */
181 for (i = 1; i < length; ++i)
182 if (this->buf[this->pos_read + i] & 0x80)
183 break;
185 midi_length = i;
186 } else {
187 /* buffer wraparound */
188 length2 = length - length1;
190 for (i = 1; i < length1; ++i)
191 if (this->buf[this->pos_read + i] & 0x80)
192 break;
194 if (i < length1)
195 midi_length = i;
196 else {
197 for (i = 0; i < length2; ++i)
198 if (this->buf[i] & 0x80)
199 break;
201 midi_length = length1 + i;
205 if (midi_length == length)
206 midi_length = -1; /* end of message not found */
209 if (midi_length < 0) {
210 if (!this->split)
211 return 0; /* command is not yet complete */
212 } else {
213 if (length < midi_length)
214 return 0; /* command is not yet complete */
216 length = midi_length;
219 if (length < length1) {
220 /* no buffer wraparound */
221 memcpy(data + repeat, this->buf + this->pos_read, length);
222 this->pos_read += length;
223 } else {
224 /* buffer wraparound */
225 length2 = length - length1;
226 memcpy(data + repeat, this->buf + this->pos_read, length1);
227 memcpy(data + repeat + length1, this->buf, length2);
228 this->pos_read = length2;
231 if (repeat)
232 data[0] = this->command_prev;
234 this->full = 0;
235 return length + repeat;
238 int line6_midibuf_ignore(struct midi_buffer *this, int length)
240 int bytes_used = line6_midibuf_bytes_used(this);
242 if (length > bytes_used)
243 length = bytes_used;
245 this->pos_read = (this->pos_read + length) % this->size;
246 this->full = 0;
247 return length;
250 int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
252 int cmd = this->command_prev;
254 if ((cmd >= 0x80) && (cmd < 0xf0))
255 if ((mask & (1 << (cmd & 0x0f))) == 0)
256 return 1;
258 return 0;
261 void line6_midibuf_destroy(struct midi_buffer *this)
263 kfree(this->buf);
264 this->buf = NULL;