midibuf.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * Line 6 Linux USB driver
  3. *
  4. * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  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. #include <linux/slab.h>
  12. #include "midibuf.h"
  13. static int midibuf_message_length(unsigned char code)
  14. {
  15. int message_length;
  16. if (code < 0x80)
  17. message_length = -1;
  18. else if (code < 0xf0) {
  19. static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
  20. message_length = length[(code >> 4) - 8];
  21. } else {
  22. /*
  23. Note that according to the MIDI specification 0xf2 is
  24. the "Song Position Pointer", but this is used by Line 6
  25. to send sysex messages to the host.
  26. */
  27. static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
  28. 1, 1, 1, -1, 1, 1
  29. };
  30. message_length = length[code & 0x0f];
  31. }
  32. return message_length;
  33. }
  34. static int midibuf_is_empty(struct midi_buffer *this)
  35. {
  36. return (this->pos_read == this->pos_write) && !this->full;
  37. }
  38. static int midibuf_is_full(struct midi_buffer *this)
  39. {
  40. return this->full;
  41. }
  42. void line6_midibuf_reset(struct midi_buffer *this)
  43. {
  44. this->pos_read = this->pos_write = this->full = 0;
  45. this->command_prev = -1;
  46. }
  47. int line6_midibuf_init(struct midi_buffer *this, int size, int split)
  48. {
  49. this->buf = kmalloc(size, GFP_KERNEL);
  50. if (this->buf == NULL)
  51. return -ENOMEM;
  52. this->size = size;
  53. this->split = split;
  54. line6_midibuf_reset(this);
  55. return 0;
  56. }
  57. int line6_midibuf_bytes_free(struct midi_buffer *this)
  58. {
  59. return
  60. midibuf_is_full(this) ?
  61. 0 :
  62. (this->pos_read - this->pos_write + this->size - 1) % this->size +
  63. 1;
  64. }
  65. int line6_midibuf_bytes_used(struct midi_buffer *this)
  66. {
  67. return
  68. midibuf_is_empty(this) ?
  69. 0 :
  70. (this->pos_write - this->pos_read + this->size - 1) % this->size +
  71. 1;
  72. }
  73. int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
  74. int length)
  75. {
  76. int bytes_free;
  77. int length1, length2;
  78. int skip_active_sense = 0;
  79. if (midibuf_is_full(this) || (length <= 0))
  80. return 0;
  81. /* skip trailing active sense */
  82. if (data[length - 1] == 0xfe) {
  83. --length;
  84. skip_active_sense = 1;
  85. }
  86. bytes_free = line6_midibuf_bytes_free(this);
  87. if (length > bytes_free)
  88. length = bytes_free;
  89. if (length > 0) {
  90. length1 = this->size - this->pos_write;
  91. if (length < length1) {
  92. /* no buffer wraparound */
  93. memcpy(this->buf + this->pos_write, data, length);
  94. this->pos_write += length;
  95. } else {
  96. /* buffer wraparound */
  97. length2 = length - length1;
  98. memcpy(this->buf + this->pos_write, data, length1);
  99. memcpy(this->buf, data + length1, length2);
  100. this->pos_write = length2;
  101. }
  102. if (this->pos_write == this->pos_read)
  103. this->full = 1;
  104. }
  105. return length + skip_active_sense;
  106. }
  107. int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
  108. int length)
  109. {
  110. int bytes_used;
  111. int length1, length2;
  112. int command;
  113. int midi_length;
  114. int repeat = 0;
  115. int i;
  116. /* we need to be able to store at least a 3 byte MIDI message */
  117. if (length < 3)
  118. return -EINVAL;
  119. if (midibuf_is_empty(this))
  120. return 0;
  121. bytes_used = line6_midibuf_bytes_used(this);
  122. if (length > bytes_used)
  123. length = bytes_used;
  124. length1 = this->size - this->pos_read;
  125. /* check MIDI command length */
  126. command = this->buf[this->pos_read];
  127. if (command & 0x80) {
  128. midi_length = midibuf_message_length(command);
  129. this->command_prev = command;
  130. } else {
  131. if (this->command_prev > 0) {
  132. int midi_length_prev =
  133. midibuf_message_length(this->command_prev);
  134. if (midi_length_prev > 0) {
  135. midi_length = midi_length_prev - 1;
  136. repeat = 1;
  137. } else
  138. midi_length = -1;
  139. } else
  140. midi_length = -1;
  141. }
  142. if (midi_length < 0) {
  143. /* search for end of message */
  144. if (length < length1) {
  145. /* no buffer wraparound */
  146. for (i = 1; i < length; ++i)
  147. if (this->buf[this->pos_read + i] & 0x80)
  148. break;
  149. midi_length = i;
  150. } else {
  151. /* buffer wraparound */
  152. length2 = length - length1;
  153. for (i = 1; i < length1; ++i)
  154. if (this->buf[this->pos_read + i] & 0x80)
  155. break;
  156. if (i < length1)
  157. midi_length = i;
  158. else {
  159. for (i = 0; i < length2; ++i)
  160. if (this->buf[i] & 0x80)
  161. break;
  162. midi_length = length1 + i;
  163. }
  164. }
  165. if (midi_length == length)
  166. midi_length = -1; /* end of message not found */
  167. }
  168. if (midi_length < 0) {
  169. if (!this->split)
  170. return 0; /* command is not yet complete */
  171. } else {
  172. if (length < midi_length)
  173. return 0; /* command is not yet complete */
  174. length = midi_length;
  175. }
  176. if (length < length1) {
  177. /* no buffer wraparound */
  178. memcpy(data + repeat, this->buf + this->pos_read, length);
  179. this->pos_read += length;
  180. } else {
  181. /* buffer wraparound */
  182. length2 = length - length1;
  183. memcpy(data + repeat, this->buf + this->pos_read, length1);
  184. memcpy(data + repeat + length1, this->buf, length2);
  185. this->pos_read = length2;
  186. }
  187. if (repeat)
  188. data[0] = this->command_prev;
  189. this->full = 0;
  190. return length + repeat;
  191. }
  192. int line6_midibuf_ignore(struct midi_buffer *this, int length)
  193. {
  194. int bytes_used = line6_midibuf_bytes_used(this);
  195. if (length > bytes_used)
  196. length = bytes_used;
  197. this->pos_read = (this->pos_read + length) % this->size;
  198. this->full = 0;
  199. return length;
  200. }
  201. void line6_midibuf_destroy(struct midi_buffer *this)
  202. {
  203. kfree(this->buf);
  204. this->buf = NULL;
  205. }