Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
midibuf.c
Go to the documentation of this file.
1 /*
2  * Line6 Linux USB driver - 0.9.1beta
3  *
4  * Copyright (C) 2004-2010 Markus Grabner ([email protected])
5  *
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.
9  *
10  */
11 
12 #include <linux/slab.h>
13 
14 #include "midibuf.h"
15 
16 static int midibuf_message_length(unsigned char code)
17 {
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 {
24  /*
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.
28  */
29  static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
30  1, 1, 1, -1, 1, 1
31  };
32  return length[code & 0x0f];
33  }
34 }
35 
36 static int midibuf_is_empty(struct MidiBuffer *this)
37 {
38  return (this->pos_read == this->pos_write) && !this->full;
39 }
40 
41 static int midibuf_is_full(struct MidiBuffer *this)
42 {
43  return this->full;
44 }
45 
46 void line6_midibuf_reset(struct MidiBuffer *this)
47 {
48  this->pos_read = this->pos_write = this->full = 0;
49  this->command_prev = -1;
50 }
51 
52 int line6_midibuf_init(struct MidiBuffer *this, int size, int split)
53 {
54  this->buf = kmalloc(size, GFP_KERNEL);
55 
56  if (this->buf == NULL)
57  return -ENOMEM;
58 
59  this->size = size;
60  this->split = split;
61  line6_midibuf_reset(this);
62  return 0;
63 }
64 
65 void line6_midibuf_status(struct MidiBuffer *this)
66 {
67  pr_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);
70 }
71 
73 {
74  return
75  midibuf_is_full(this) ?
76  0 :
77  (this->pos_read - this->pos_write + this->size - 1) % this->size +
78  1;
79 }
80 
82 {
83  return
84  midibuf_is_empty(this) ?
85  0 :
86  (this->pos_write - this->pos_read + this->size - 1) % this->size +
87  1;
88 }
89 
90 int line6_midibuf_write(struct MidiBuffer *this, unsigned char *data,
91  int length)
92 {
93  int bytes_free;
94  int length1, length2;
95  int skip_active_sense = 0;
96 
97  if (midibuf_is_full(this) || (length <= 0))
98  return 0;
99 
100  /* skip trailing active sense */
101  if (data[length - 1] == 0xfe) {
102  --length;
103  skip_active_sense = 1;
104  }
105 
106  bytes_free = line6_midibuf_bytes_free(this);
107 
108  if (length > bytes_free)
109  length = bytes_free;
110 
111  if (length > 0) {
112  length1 = this->size - this->pos_write;
113 
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;
124  }
125 
126  if (this->pos_write == this->pos_read)
127  this->full = 1;
128  }
129 
130  return length + skip_active_sense;
131 }
132 
133 int line6_midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
134 {
135  int bytes_used;
136  int length1, length2;
137  int command;
138  int midi_length;
139  int repeat = 0;
140  int i;
141 
142  /* we need to be able to store at least a 3 byte MIDI message */
143  if (length < 3)
144  return -EINVAL;
145 
146  if (midibuf_is_empty(this))
147  return 0;
148 
149  bytes_used = line6_midibuf_bytes_used(this);
150 
151  if (length > bytes_used)
152  length = bytes_used;
153 
154  length1 = this->size - this->pos_read;
155 
156  /* check MIDI command length */
157  command = this->buf[this->pos_read];
158 
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);
166 
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;
174  }
175 
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;
183 
184  midi_length = i;
185  } else {
186  /* buffer wraparound */
187  length2 = length - length1;
188 
189  for (i = 1; i < length1; ++i)
190  if (this->buf[this->pos_read + i] & 0x80)
191  break;
192 
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;
199 
200  midi_length = length1 + i;
201  }
202  }
203 
204  if (midi_length == length)
205  midi_length = -1; /* end of message not found */
206  }
207 
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 */
214 
215  length = midi_length;
216  }
217 
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;
228  }
229 
230  if (repeat)
231  data[0] = this->command_prev;
232 
233  this->full = 0;
234  return length + repeat;
235 }
236 
237 int line6_midibuf_ignore(struct MidiBuffer *this, int length)
238 {
240 
241  if (length > bytes_used)
242  length = bytes_used;
243 
244  this->pos_read = (this->pos_read + length) % this->size;
245  this->full = 0;
246  return length;
247 }
248 
249 int line6_midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
250 {
251  int cmd = this->command_prev;
252 
253  if ((cmd >= 0x80) && (cmd < 0xf0))
254  if ((mask & (1 << (cmd & 0x0f))) == 0)
255  return 1;
256 
257  return 0;
258 }
259 
261 {
262  kfree(this->buf);
263  this->buf = NULL;
264 }