2011-01-24 20:45:30 +03:00
/*
* Linux driver for TerraTec DMX 6F ire USB
*
* Rawmidi driver
*
* Author : Torsten Schenk < torsten . schenk @ zoho . com >
* Created : Jan 01 , 2011
* Copyright : ( C ) Torsten Schenk
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <sound/rawmidi.h>
# include "midi.h"
# include "chip.h"
# include "comm.h"
2013-08-11 13:11:35 +04:00
enum {
MIDI_BUFSIZE = 64
} ;
2011-01-24 20:45:30 +03:00
static void usb6fire_midi_out_handler ( struct urb * urb )
{
struct midi_runtime * rt = urb - > context ;
int ret ;
unsigned long flags ;
spin_lock_irqsave ( & rt - > out_lock , flags ) ;
if ( rt - > out ) {
ret = snd_rawmidi_transmit ( rt - > out , rt - > out_buffer + 4 ,
MIDI_BUFSIZE - 4 ) ;
if ( ret > 0 ) { /* more data available, send next packet */
rt - > out_buffer [ 1 ] = ret + 2 ;
rt - > out_buffer [ 3 ] = rt - > out_serial + + ;
urb - > transfer_buffer_length = ret + 4 ;
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( ret < 0 )
2014-02-26 18:51:04 +04:00
dev_err ( & urb - > dev - > dev ,
" midi out urb submit failed: %d \n " ,
ret ) ;
2011-01-24 20:45:30 +03:00
} else /* no more data to transmit */
rt - > out = NULL ;
}
spin_unlock_irqrestore ( & rt - > out_lock , flags ) ;
}
static void usb6fire_midi_in_received (
struct midi_runtime * rt , u8 * data , int length )
{
unsigned long flags ;
spin_lock_irqsave ( & rt - > in_lock , flags ) ;
if ( rt - > in )
snd_rawmidi_receive ( rt - > in , data , length ) ;
spin_unlock_irqrestore ( & rt - > in_lock , flags ) ;
}
static int usb6fire_midi_out_open ( struct snd_rawmidi_substream * alsa_sub )
{
return 0 ;
}
static int usb6fire_midi_out_close ( struct snd_rawmidi_substream * alsa_sub )
{
return 0 ;
}
static void usb6fire_midi_out_trigger (
struct snd_rawmidi_substream * alsa_sub , int up )
{
struct midi_runtime * rt = alsa_sub - > rmidi - > private_data ;
struct urb * urb = & rt - > out_urb ;
__s8 ret ;
unsigned long flags ;
spin_lock_irqsave ( & rt - > out_lock , flags ) ;
if ( up ) { /* start transfer */
if ( rt - > out ) { /* we are already transmitting so just return */
spin_unlock_irqrestore ( & rt - > out_lock , flags ) ;
return ;
}
ret = snd_rawmidi_transmit ( alsa_sub , rt - > out_buffer + 4 ,
MIDI_BUFSIZE - 4 ) ;
if ( ret > 0 ) {
rt - > out_buffer [ 1 ] = ret + 2 ;
rt - > out_buffer [ 3 ] = rt - > out_serial + + ;
urb - > transfer_buffer_length = ret + 4 ;
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( ret < 0 )
2014-02-26 18:51:04 +04:00
dev_err ( & urb - > dev - > dev ,
" midi out urb submit failed: %d \n " ,
ret ) ;
2011-01-24 20:45:30 +03:00
else
rt - > out = alsa_sub ;
}
} else if ( rt - > out = = alsa_sub )
rt - > out = NULL ;
spin_unlock_irqrestore ( & rt - > out_lock , flags ) ;
}
static void usb6fire_midi_out_drain ( struct snd_rawmidi_substream * alsa_sub )
{
struct midi_runtime * rt = alsa_sub - > rmidi - > private_data ;
int retry = 0 ;
while ( rt - > out & & retry + + < 100 )
msleep ( 10 ) ;
}
static int usb6fire_midi_in_open ( struct snd_rawmidi_substream * alsa_sub )
{
return 0 ;
}
static int usb6fire_midi_in_close ( struct snd_rawmidi_substream * alsa_sub )
{
return 0 ;
}
static void usb6fire_midi_in_trigger (
struct snd_rawmidi_substream * alsa_sub , int up )
{
struct midi_runtime * rt = alsa_sub - > rmidi - > private_data ;
unsigned long flags ;
spin_lock_irqsave ( & rt - > in_lock , flags ) ;
if ( up )
rt - > in = alsa_sub ;
else
rt - > in = NULL ;
spin_unlock_irqrestore ( & rt - > in_lock , flags ) ;
}
static struct snd_rawmidi_ops out_ops = {
. open = usb6fire_midi_out_open ,
. close = usb6fire_midi_out_close ,
. trigger = usb6fire_midi_out_trigger ,
. drain = usb6fire_midi_out_drain
} ;
static struct snd_rawmidi_ops in_ops = {
. open = usb6fire_midi_in_open ,
. close = usb6fire_midi_in_close ,
. trigger = usb6fire_midi_in_trigger
} ;
2012-12-06 21:35:28 +04:00
int usb6fire_midi_init ( struct sfire_chip * chip )
2011-01-24 20:45:30 +03:00
{
int ret ;
struct midi_runtime * rt = kzalloc ( sizeof ( struct midi_runtime ) ,
GFP_KERNEL ) ;
struct comm_runtime * comm_rt = chip - > comm ;
if ( ! rt )
return - ENOMEM ;
2013-08-11 13:11:35 +04:00
rt - > out_buffer = kzalloc ( MIDI_BUFSIZE , GFP_KERNEL ) ;
if ( ! rt - > out_buffer ) {
kfree ( rt ) ;
return - ENOMEM ;
}
2011-01-24 20:45:30 +03:00
rt - > chip = chip ;
rt - > in_received = usb6fire_midi_in_received ;
rt - > out_buffer [ 0 ] = 0x80 ; /* 'send midi' command */
rt - > out_buffer [ 1 ] = 0x00 ; /* size of data */
rt - > out_buffer [ 2 ] = 0x00 ; /* always 0 */
spin_lock_init ( & rt - > in_lock ) ;
spin_lock_init ( & rt - > out_lock ) ;
comm_rt - > init_urb ( comm_rt , & rt - > out_urb , rt - > out_buffer , rt ,
usb6fire_midi_out_handler ) ;
ret = snd_rawmidi_new ( chip - > card , " 6FireUSB " , 0 , 1 , 1 , & rt - > instance ) ;
if ( ret < 0 ) {
2013-08-11 13:11:35 +04:00
kfree ( rt - > out_buffer ) ;
2011-01-24 20:45:30 +03:00
kfree ( rt ) ;
2014-02-26 18:51:04 +04:00
dev_err ( & chip - > dev - > dev , " unable to create midi. \n " ) ;
2011-01-24 20:45:30 +03:00
return ret ;
}
rt - > instance - > private_data = rt ;
strcpy ( rt - > instance - > name , " DMX6FireUSB MIDI " ) ;
rt - > instance - > info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX ;
snd_rawmidi_set_ops ( rt - > instance , SNDRV_RAWMIDI_STREAM_OUTPUT ,
& out_ops ) ;
snd_rawmidi_set_ops ( rt - > instance , SNDRV_RAWMIDI_STREAM_INPUT ,
& in_ops ) ;
chip - > midi = rt ;
return 0 ;
}
void usb6fire_midi_abort ( struct sfire_chip * chip )
{
struct midi_runtime * rt = chip - > midi ;
if ( rt )
usb_poison_urb ( & rt - > out_urb ) ;
}
void usb6fire_midi_destroy ( struct sfire_chip * chip )
{
2013-08-11 13:11:35 +04:00
struct midi_runtime * rt = chip - > midi ;
kfree ( rt - > out_buffer ) ;
kfree ( rt ) ;
2011-01-24 20:45:30 +03:00
chip - > midi = NULL ;
}