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
)
20 else if (code
< 0xf0) {
21 static const int length
[] = { 3, 3, 3, 3, 2, 2, 3 };
22 return length
[(code
>> 4) - 8];
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,
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)
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
)
61 line6_midibuf_reset(this);
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)
75 midibuf_is_full(this) ?
77 (this->pos_read
- this->pos_write
+ this->size
- 1) % this->size
+
81 int line6_midibuf_bytes_used(struct MidiBuffer
*this)
84 midibuf_is_empty(this) ?
86 (this->pos_write
- this->pos_read
+ this->size
- 1) % this->size
+
90 int line6_midibuf_write(struct MidiBuffer
*this, unsigned char *data
,
95 int skip_active_sense
= 0;
97 if (midibuf_is_full(this) || (length
<= 0))
100 /* skip trailing active sense */
101 if (data
[length
- 1] == 0xfe) {
103 skip_active_sense
= 1;
106 bytes_free
= line6_midibuf_bytes_free(this);
108 if (length
> bytes_free
)
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
;
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
)
130 return length
+ skip_active_sense
;
133 int line6_midibuf_read(struct MidiBuffer
*this, unsigned char *data
, int length
)
136 int length1
, length2
;
142 /* we need to be able to store at least a 3 byte MIDI message */
146 if (midibuf_is_empty(this))
149 bytes_used
= line6_midibuf_bytes_used(this);
151 if (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
;
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;
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)
186 /* buffer wraparound */
187 length2
= length
- length1
;
189 for (i
= 1; i
< length1
; ++i
)
190 if (this->buf
[this->pos_read
+ i
] & 0x80)
196 for (i
= 0; i
< length2
; ++i
)
197 if (this->buf
[i
] & 0x80)
200 midi_length
= length1
+ i
;
204 if (midi_length
== length
)
205 midi_length
= -1; /* end of message not found */
208 if (midi_length
< 0) {
210 return 0; /* command is not yet complete */
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
;
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
;
231 data
[0] = this->command_prev
;
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
)
244 this->pos_read
= (this->pos_read
+ length
) % this->size
;
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)
260 void line6_midibuf_destroy(struct MidiBuffer
*this)