2019-05-31 01:09:32 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2009-02-27 19:43:04 -08:00
/*
2015-01-20 02:20:50 -06:00
* Line 6 Linux USB driver
2009-02-27 19:43:04 -08:00
*
2010-08-12 01:35:30 +02:00
* Copyright ( C ) 2004 - 2010 Markus Grabner ( grabner @ icg . tugraz . at )
2009-02-27 19:43:04 -08:00
*/
# include <linux/slab.h>
# include "midibuf.h"
2009-02-27 20:45:03 -08:00
static int midibuf_message_length ( unsigned char code )
2009-02-27 19:43:04 -08:00
{
2014-09-20 14:40:38 +02:00
int message_length ;
2009-02-27 22:43:11 -08:00
if ( code < 0x80 )
2014-09-20 14:40:38 +02:00
message_length = - 1 ;
2009-02-27 22:43:11 -08:00
else if ( code < 0xf0 ) {
2009-02-27 19:43:04 -08:00
static const int length [ ] = { 3 , 3 , 3 , 3 , 2 , 2 , 3 } ;
2014-09-20 14:40:38 +02:00
message_length = length [ ( code > > 4 ) - 8 ] ;
2009-02-27 22:43:11 -08:00
} else {
2009-02-27 19:43:04 -08:00
/*
2010-08-23 01:08:25 +02:00
Note that according to the MIDI specification 0xf2 is
2015-01-20 02:20:49 -06:00
the " Song Position Pointer " , but this is used by Line 6
2010-08-23 01:08:25 +02:00
to send sysex messages to the host .
*/
2009-02-27 22:43:11 -08:00
static const int length [ ] = { - 1 , 2 , - 1 , 2 , - 1 , - 1 , 1 , 1 , 1 , 1 ,
2010-08-23 01:08:25 +02:00
1 , 1 , 1 , - 1 , 1 , 1
} ;
2014-09-20 14:40:38 +02:00
message_length = length [ code & 0x0f ] ;
2009-02-27 19:43:04 -08:00
}
2014-09-20 14:40:38 +02:00
return message_length ;
2009-02-27 19:43:04 -08:00
}
2013-01-11 23:08:09 +01:00
static int midibuf_is_empty ( struct midi_buffer * this )
2010-08-12 01:35:30 +02:00
{
return ( this - > pos_read = = this - > pos_write ) & & ! this - > full ;
}
2013-01-11 23:08:09 +01:00
static int midibuf_is_full ( struct midi_buffer * this )
2010-08-12 01:35:30 +02:00
{
return this - > full ;
}
2013-01-11 23:08:09 +01:00
void line6_midibuf_reset ( struct midi_buffer * this )
2009-02-27 19:43:04 -08:00
{
this - > pos_read = this - > pos_write = this - > full = 0 ;
this - > command_prev = - 1 ;
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_init ( struct midi_buffer * this , int size , int split )
2009-02-27 19:43:04 -08:00
{
2009-02-27 22:43:11 -08:00
this - > buf = kmalloc ( size , GFP_KERNEL ) ;
2009-02-27 19:43:04 -08:00
2009-02-27 20:49:46 -08:00
if ( this - > buf = = NULL )
2009-02-27 19:43:04 -08:00
return - ENOMEM ;
this - > size = size ;
this - > split = split ;
2010-08-12 01:35:30 +02:00
line6_midibuf_reset ( this ) ;
2009-02-27 19:43:04 -08:00
return 0 ;
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_bytes_free ( struct midi_buffer * this )
2009-02-27 19:43:04 -08:00
{
return
2010-08-23 01:08:25 +02:00
midibuf_is_full ( this ) ?
0 :
( this - > pos_read - this - > pos_write + this - > size - 1 ) % this - > size +
1 ;
2009-02-27 19:43:04 -08:00
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_bytes_used ( struct midi_buffer * this )
2009-02-27 19:43:04 -08:00
{
return
2010-08-23 01:08:25 +02:00
midibuf_is_empty ( this ) ?
0 :
( this - > pos_write - this - > pos_read + this - > size - 1 ) % this - > size +
1 ;
2009-02-27 19:43:04 -08:00
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_write ( struct midi_buffer * this , unsigned char * data ,
2010-08-23 01:08:25 +02:00
int length )
2009-02-27 19:43:04 -08:00
{
int bytes_free ;
int length1 , length2 ;
int skip_active_sense = 0 ;
2009-02-27 22:43:11 -08:00
if ( midibuf_is_full ( this ) | | ( length < = 0 ) )
2009-02-27 19:43:04 -08:00
return 0 ;
/* skip trailing active sense */
2009-02-27 22:43:11 -08:00
if ( data [ length - 1 ] = = 0xfe ) {
2009-02-27 19:43:04 -08:00
- - length ;
skip_active_sense = 1 ;
}
2010-08-12 01:35:30 +02:00
bytes_free = line6_midibuf_bytes_free ( this ) ;
2009-02-27 19:43:04 -08:00
2009-02-27 22:43:11 -08:00
if ( length > bytes_free )
2009-02-27 19:43:04 -08:00
length = bytes_free ;
2009-02-27 22:43:11 -08:00
if ( length > 0 ) {
2009-02-27 19:43:04 -08:00
length1 = this - > size - this - > pos_write ;
2009-02-27 22:43:11 -08:00
if ( length < length1 ) {
2009-02-27 19:43:04 -08:00
/* no buffer wraparound */
memcpy ( this - > buf + this - > pos_write , data , length ) ;
this - > pos_write + = length ;
2009-02-27 22:43:11 -08:00
} else {
2009-02-27 19:43:04 -08:00
/* buffer wraparound */
length2 = length - length1 ;
memcpy ( this - > buf + this - > pos_write , data , length1 ) ;
memcpy ( this - > buf , data + length1 , length2 ) ;
this - > pos_write = length2 ;
}
2009-02-27 22:43:11 -08:00
if ( this - > pos_write = = this - > pos_read )
2009-02-27 19:43:04 -08:00
this - > full = 1 ;
}
return length + skip_active_sense ;
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_read ( struct midi_buffer * this , unsigned char * data ,
int length )
2009-02-27 19:43:04 -08:00
{
int bytes_used ;
int length1 , length2 ;
int command ;
int midi_length ;
int repeat = 0 ;
int i ;
2009-02-27 22:43:11 -08:00
/* we need to be able to store at least a 3 byte MIDI message */
if ( length < 3 )
return - EINVAL ;
2009-02-27 19:43:04 -08:00
2009-02-27 22:43:11 -08:00
if ( midibuf_is_empty ( this ) )
2009-02-27 19:43:04 -08:00
return 0 ;
2010-08-12 01:35:30 +02:00
bytes_used = line6_midibuf_bytes_used ( this ) ;
2009-02-27 19:43:04 -08:00
2009-02-27 22:43:11 -08:00
if ( length > bytes_used )
2009-02-27 19:43:04 -08:00
length = bytes_used ;
length1 = this - > size - this - > pos_read ;
/* check MIDI command length */
command = this - > buf [ this - > pos_read ] ;
2009-02-27 22:43:11 -08:00
if ( command & 0x80 ) {
2009-02-27 19:43:04 -08:00
midi_length = midibuf_message_length ( command ) ;
this - > command_prev = command ;
2009-02-27 22:43:11 -08:00
} else {
if ( this - > command_prev > 0 ) {
2010-08-23 01:08:25 +02:00
int midi_length_prev =
midibuf_message_length ( this - > command_prev ) ;
2009-02-27 19:43:04 -08:00
2020-03-09 10:59:22 +01:00
if ( midi_length_prev > 1 ) {
2009-02-27 19:43:04 -08:00
midi_length = midi_length_prev - 1 ;
repeat = 1 ;
2009-02-27 22:43:11 -08:00
} else
2009-02-27 19:43:04 -08:00
midi_length = - 1 ;
2009-02-27 22:43:11 -08:00
} else
2009-02-27 19:43:04 -08:00
midi_length = - 1 ;
}
2009-02-27 22:43:11 -08:00
if ( midi_length < 0 ) {
2009-02-27 19:43:04 -08:00
/* search for end of message */
2009-02-27 22:43:11 -08:00
if ( length < length1 ) {
2009-02-27 19:43:04 -08:00
/* no buffer wraparound */
2009-02-27 22:43:11 -08:00
for ( i = 1 ; i < length ; + + i )
if ( this - > buf [ this - > pos_read + i ] & 0x80 )
2009-02-27 19:43:04 -08:00
break ;
midi_length = i ;
2009-02-27 22:43:11 -08:00
} else {
2009-02-27 19:43:04 -08:00
/* buffer wraparound */
length2 = length - length1 ;
2009-02-27 22:43:11 -08:00
for ( i = 1 ; i < length1 ; + + i )
if ( this - > buf [ this - > pos_read + i ] & 0x80 )
2009-02-27 19:43:04 -08:00
break ;
2009-02-27 22:43:11 -08:00
if ( i < length1 )
2009-02-27 19:43:04 -08:00
midi_length = i ;
else {
2009-02-27 22:43:11 -08:00
for ( i = 0 ; i < length2 ; + + i )
if ( this - > buf [ i ] & 0x80 )
2009-02-27 19:43:04 -08:00
break ;
midi_length = length1 + i ;
}
}
2009-02-27 22:43:11 -08:00
if ( midi_length = = length )
2010-08-23 01:08:25 +02:00
midi_length = - 1 ; /* end of message not found */
2009-02-27 19:43:04 -08:00
}
2009-02-27 22:43:11 -08:00
if ( midi_length < 0 ) {
if ( ! this - > split )
2010-08-23 01:08:25 +02:00
return 0 ; /* command is not yet complete */
2009-02-27 22:43:11 -08:00
} else {
if ( length < midi_length )
2010-08-23 01:08:25 +02:00
return 0 ; /* command is not yet complete */
2009-02-27 19:43:04 -08:00
length = midi_length ;
}
2009-02-27 22:43:11 -08:00
if ( length < length1 ) {
2009-02-27 19:43:04 -08:00
/* no buffer wraparound */
memcpy ( data + repeat , this - > buf + this - > pos_read , length ) ;
this - > pos_read + = length ;
2009-02-27 22:43:11 -08:00
} else {
2009-02-27 19:43:04 -08:00
/* buffer wraparound */
length2 = length - length1 ;
memcpy ( data + repeat , this - > buf + this - > pos_read , length1 ) ;
memcpy ( data + repeat + length1 , this - > buf , length2 ) ;
this - > pos_read = length2 ;
}
2009-02-27 22:43:11 -08:00
if ( repeat )
2009-02-27 19:43:04 -08:00
data [ 0 ] = this - > command_prev ;
this - > full = 0 ;
return length + repeat ;
}
2013-01-11 23:08:09 +01:00
int line6_midibuf_ignore ( struct midi_buffer * this , int length )
2009-02-27 19:43:04 -08:00
{
2010-08-12 01:35:30 +02:00
int bytes_used = line6_midibuf_bytes_used ( this ) ;
2009-02-27 19:43:04 -08:00
2009-02-27 22:43:11 -08:00
if ( length > bytes_used )
2009-02-27 19:43:04 -08:00
length = bytes_used ;
this - > pos_read = ( this - > pos_read + length ) % this - > size ;
this - > full = 0 ;
return length ;
}
2013-01-11 23:08:09 +01:00
void line6_midibuf_destroy ( struct midi_buffer * this )
2009-02-27 19:43:04 -08:00
{
2009-02-27 20:49:46 -08:00
kfree ( this - > buf ) ;
this - > buf = NULL ;
2009-02-27 19:43:04 -08:00
}