Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Line 6 Linux USB driver
0004  *
0005  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
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            Note that according to the MIDI specification 0xf2 is
0025            the "Song Position Pointer", but this is used by Line 6
0026            to send sysex messages to the host.
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     /* skip trailing active sense */
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             /* no buffer wraparound */
0110             memcpy(this->buf + this->pos_write, data, length);
0111             this->pos_write += length;
0112         } else {
0113             /* buffer wraparound */
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     /* we need to be able to store at least a 3 byte MIDI message */
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     /* check MIDI command length */
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         /* search for end of message */
0173         if (length < length1) {
0174             /* no buffer wraparound */
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             /* buffer wraparound */
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;   /* end of message not found */
0201     }
0202 
0203     if (midi_length < 0) {
0204         if (!this->split)
0205             return 0;   /* command is not yet complete */
0206     } else {
0207         if (length < midi_length)
0208             return 0;   /* command is not yet complete */
0209 
0210         length = midi_length;
0211     }
0212 
0213     if (length < length1) {
0214         /* no buffer wraparound */
0215         memcpy(data + repeat, this->buf + this->pos_read, length);
0216         this->pos_read += length;
0217     } else {
0218         /* buffer wraparound */
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 }