0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009
0010 #include "midibuf.h"
0011
0012 static int midibuf_message_length(unsigned char code)
0013 {
0014 int message_length;
0015
0016 if (code < 0x80)
0017 message_length = -1;
0018 else if (code < 0xf0) {
0019 static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
0020
0021 message_length = length[(code >> 4) - 8];
0022 } else {
0023
0024
0025
0026
0027
0028 static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
0029 1, 1, 1, -1, 1, 1
0030 };
0031 message_length = length[code & 0x0f];
0032 }
0033
0034 return message_length;
0035 }
0036
0037 static int midibuf_is_empty(struct midi_buffer *this)
0038 {
0039 return (this->pos_read == this->pos_write) && !this->full;
0040 }
0041
0042 static int midibuf_is_full(struct midi_buffer *this)
0043 {
0044 return this->full;
0045 }
0046
0047 void line6_midibuf_reset(struct midi_buffer *this)
0048 {
0049 this->pos_read = this->pos_write = this->full = 0;
0050 this->command_prev = -1;
0051 }
0052
0053 int line6_midibuf_init(struct midi_buffer *this, int size, int split)
0054 {
0055 this->buf = kmalloc(size, GFP_KERNEL);
0056
0057 if (this->buf == NULL)
0058 return -ENOMEM;
0059
0060 this->size = size;
0061 this->split = split;
0062 line6_midibuf_reset(this);
0063 return 0;
0064 }
0065
0066 int line6_midibuf_bytes_free(struct midi_buffer *this)
0067 {
0068 return
0069 midibuf_is_full(this) ?
0070 0 :
0071 (this->pos_read - this->pos_write + this->size - 1) % this->size +
0072 1;
0073 }
0074
0075 int line6_midibuf_bytes_used(struct midi_buffer *this)
0076 {
0077 return
0078 midibuf_is_empty(this) ?
0079 0 :
0080 (this->pos_write - this->pos_read + this->size - 1) % this->size +
0081 1;
0082 }
0083
0084 int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
0085 int length)
0086 {
0087 int bytes_free;
0088 int length1, length2;
0089 int skip_active_sense = 0;
0090
0091 if (midibuf_is_full(this) || (length <= 0))
0092 return 0;
0093
0094
0095 if (data[length - 1] == 0xfe) {
0096 --length;
0097 skip_active_sense = 1;
0098 }
0099
0100 bytes_free = line6_midibuf_bytes_free(this);
0101
0102 if (length > bytes_free)
0103 length = bytes_free;
0104
0105 if (length > 0) {
0106 length1 = this->size - this->pos_write;
0107
0108 if (length < length1) {
0109
0110 memcpy(this->buf + this->pos_write, data, length);
0111 this->pos_write += length;
0112 } else {
0113
0114 length2 = length - length1;
0115 memcpy(this->buf + this->pos_write, data, length1);
0116 memcpy(this->buf, data + length1, length2);
0117 this->pos_write = length2;
0118 }
0119
0120 if (this->pos_write == this->pos_read)
0121 this->full = 1;
0122 }
0123
0124 return length + skip_active_sense;
0125 }
0126
0127 int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
0128 int length)
0129 {
0130 int bytes_used;
0131 int length1, length2;
0132 int command;
0133 int midi_length;
0134 int repeat = 0;
0135 int i;
0136
0137
0138 if (length < 3)
0139 return -EINVAL;
0140
0141 if (midibuf_is_empty(this))
0142 return 0;
0143
0144 bytes_used = line6_midibuf_bytes_used(this);
0145
0146 if (length > bytes_used)
0147 length = bytes_used;
0148
0149 length1 = this->size - this->pos_read;
0150
0151
0152 command = this->buf[this->pos_read];
0153
0154 if (command & 0x80) {
0155 midi_length = midibuf_message_length(command);
0156 this->command_prev = command;
0157 } else {
0158 if (this->command_prev > 0) {
0159 int midi_length_prev =
0160 midibuf_message_length(this->command_prev);
0161
0162 if (midi_length_prev > 1) {
0163 midi_length = midi_length_prev - 1;
0164 repeat = 1;
0165 } else
0166 midi_length = -1;
0167 } else
0168 midi_length = -1;
0169 }
0170
0171 if (midi_length < 0) {
0172
0173 if (length < length1) {
0174
0175 for (i = 1; i < length; ++i)
0176 if (this->buf[this->pos_read + i] & 0x80)
0177 break;
0178
0179 midi_length = i;
0180 } else {
0181
0182 length2 = length - length1;
0183
0184 for (i = 1; i < length1; ++i)
0185 if (this->buf[this->pos_read + i] & 0x80)
0186 break;
0187
0188 if (i < length1)
0189 midi_length = i;
0190 else {
0191 for (i = 0; i < length2; ++i)
0192 if (this->buf[i] & 0x80)
0193 break;
0194
0195 midi_length = length1 + i;
0196 }
0197 }
0198
0199 if (midi_length == length)
0200 midi_length = -1;
0201 }
0202
0203 if (midi_length < 0) {
0204 if (!this->split)
0205 return 0;
0206 } else {
0207 if (length < midi_length)
0208 return 0;
0209
0210 length = midi_length;
0211 }
0212
0213 if (length < length1) {
0214
0215 memcpy(data + repeat, this->buf + this->pos_read, length);
0216 this->pos_read += length;
0217 } else {
0218
0219 length2 = length - length1;
0220 memcpy(data + repeat, this->buf + this->pos_read, length1);
0221 memcpy(data + repeat + length1, this->buf, length2);
0222 this->pos_read = length2;
0223 }
0224
0225 if (repeat)
0226 data[0] = this->command_prev;
0227
0228 this->full = 0;
0229 return length + repeat;
0230 }
0231
0232 int line6_midibuf_ignore(struct midi_buffer *this, int length)
0233 {
0234 int bytes_used = line6_midibuf_bytes_used(this);
0235
0236 if (length > bytes_used)
0237 length = bytes_used;
0238
0239 this->pos_read = (this->pos_read + length) % this->size;
0240 this->full = 0;
0241 return length;
0242 }
0243
0244 void line6_midibuf_destroy(struct midi_buffer *this)
0245 {
0246 kfree(this->buf);
0247 this->buf = NULL;
0248 }