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 midi_buffer
*this)
38 return (this->pos_read
== this->pos_write
) && !this->full
;
41 static int midibuf_is_full(struct midi_buffer
*this)
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
)
61 line6_midibuf_reset(this);
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)
75 midibuf_is_full(this) ?
77 (this->pos_read
- this->pos_write
+ this->size
- 1) % this->size
+
81 int line6_midibuf_bytes_used(struct midi_buffer
*this)
84 midibuf_is_empty(this) ?
86 (this->pos_write
- this->pos_read
+ this->size
- 1) % this->size
+
90 int line6_midibuf_write(struct midi_buffer
*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 midi_buffer
*this, unsigned char *data
,
137 int length1
, length2
;
143 /* we need to be able to store at least a 3 byte MIDI message */
147 if (midibuf_is_empty(this))
150 bytes_used
= line6_midibuf_bytes_used(this);
152 if (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
;
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;
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)
187 /* buffer wraparound */
188 length2
= length
- length1
;
190 for (i
= 1; i
< length1
; ++i
)
191 if (this->buf
[this->pos_read
+ i
] & 0x80)
197 for (i
= 0; i
< length2
; ++i
)
198 if (this->buf
[i
] & 0x80)
201 midi_length
= length1
+ i
;
205 if (midi_length
== length
)
206 midi_length
= -1; /* end of message not found */
209 if (midi_length
< 0) {
211 return 0; /* command is not yet complete */
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
;
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
;
232 data
[0] = this->command_prev
;
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
)
245 this->pos_read
= (this->pos_read
+ length
) % this->size
;
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)
261 void line6_midibuf_destroy(struct midi_buffer
*this)