2005-04-17 02:20:36 +04:00
/*
* sound / mpu401 . c
*
* The low level driver for Roland MPU - 401 compatible Midi cards .
*/
/*
* Copyright ( C ) by Hannu Savolainen 1993 - 1997
*
* OSS / Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE ( GPL )
* Version 2 ( June 1991 ) . See the " COPYING " file distributed with this software
* for more info .
*
*
* Thomas Sailer ioctl code reworked ( vmalloc / vfree removed )
* Alan Cox modularisation , use normal request_irq , use dev_id
* Bartlomiej Zolnierkiewicz removed some __init to allow using many drivers
* Chris Rankin Update the module - usage counter for the coprocessor
* Zwane Mwaikambo Changed attach / unload resource freeing
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# define USE_SEQ_MACROS
# define USE_SIMPLE_MACROS
# include "sound_config.h"
# include "coproc.h"
# include "mpu401.h"
static int timer_mode = TMR_INTERNAL , timer_caps = TMR_INTERNAL ;
struct mpu_config
{
int base ; /*
* I / O base
*/
int irq ;
int opened ; /*
* Open mode
*/
int devno ;
int synthno ;
int uart_mode ;
int initialized ;
int mode ;
# define MODE_MIDI 1
# define MODE_SYNTH 2
unsigned char version , revision ;
unsigned int capabilities ;
# define MPU_CAP_INTLG 0x10000000
# define MPU_CAP_SYNC 0x00000010
# define MPU_CAP_FSK 0x00000020
# define MPU_CAP_CLS 0x00000040
# define MPU_CAP_SMPTE 0x00000080
# define MPU_CAP_2PORT 0x00000001
int timer_flag ;
# define MBUF_MAX 10
# define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
{ printk ( " MPU: Invalid buffer pointer %d/%d, s=%d \n " , dc - > m_ptr , dc - > m_left , dc - > m_state ) ; dc - > m_ptr - - ; }
int m_busy ;
unsigned char m_buf [ MBUF_MAX ] ;
int m_ptr ;
int m_state ;
int m_left ;
unsigned char last_status ;
void ( * inputintr ) ( int dev , unsigned char data ) ;
int shared_irq ;
int * osp ;
spinlock_t lock ;
} ;
# define DATAPORT(base) (base)
# define COMDPORT(base) (base+1)
# define STATPORT(base) (base+1)
static void mpu401_close ( int dev ) ;
static inline int mpu401_status ( struct mpu_config * devc )
{
return inb ( STATPORT ( devc - > base ) ) ;
}
# define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL))
# define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY))
static inline void write_command ( struct mpu_config * devc , unsigned char cmd )
{
outb ( cmd , COMDPORT ( devc - > base ) ) ;
}
static inline int read_data ( struct mpu_config * devc )
{
return inb ( DATAPORT ( devc - > base ) ) ;
}
static inline void write_data ( struct mpu_config * devc , unsigned char byte )
{
outb ( byte , DATAPORT ( devc - > base ) ) ;
}
# define OUTPUT_READY 0x40
# define INPUT_AVAIL 0x80
# define MPU_ACK 0xFE
# define MPU_RESET 0xFF
# define UART_MODE_ON 0x3F
static struct mpu_config dev_conf [ MAX_MIDI_DEV ] ;
static int n_mpu_devs ;
static int reset_mpu401 ( struct mpu_config * devc ) ;
static void set_uart_mode ( int dev , struct mpu_config * devc , int arg ) ;
static int mpu_timer_init ( int midi_dev ) ;
static void mpu_timer_interrupt ( void ) ;
static void timer_ext_event ( struct mpu_config * devc , int event , int parm ) ;
static struct synth_info mpu_synth_info_proto = {
" MPU-401 MIDI interface " ,
0 ,
SYNTH_TYPE_MIDI ,
MIDI_TYPE_MPU401 ,
0 , 128 ,
0 , 128 ,
SYNTH_CAP_INPUT
} ;
static struct synth_info mpu_synth_info [ MAX_MIDI_DEV ] ;
/*
* States for the input scanner
*/
# define ST_INIT 0 /* Ready for timing byte or msg */
# define ST_TIMED 1 /* Leading timing byte rcvd */
# define ST_DATABYTE 2 /* Waiting for (nr_left) data bytes */
# define ST_SYSMSG 100 /* System message (sysx etc). */
# define ST_SYSEX 101 /* System exclusive msg */
# define ST_MTC 102 /* Midi Time Code (MTC) qframe msg */
# define ST_SONGSEL 103 /* Song select */
# define ST_SONGPOS 104 /* Song position pointer */
static unsigned char len_tab [ ] = /* # of data bytes following a status
*/
{
2 , /* 8x */
2 , /* 9x */
2 , /* Ax */
2 , /* Bx */
1 , /* Cx */
1 , /* Dx */
2 , /* Ex */
0 /* Fx */
} ;
# define STORE(cmd) \
{ \
int len ; \
unsigned char obuf [ 8 ] ; \
cmd ; \
seq_input_event ( obuf , len ) ; \
}
# define _seqbuf obuf
# define _seqbufptr 0
# define _SEQ_ADVBUF(x) len=x
static int mpu_input_scanner ( struct mpu_config * devc , unsigned char midic )
{
switch ( devc - > m_state )
{
case ST_INIT :
switch ( midic )
{
case 0xf8 :
/* Timer overflow */
break ;
case 0xfc :
printk ( " <all end> " ) ;
break ;
case 0xfd :
if ( devc - > timer_flag )
mpu_timer_interrupt ( ) ;
break ;
case 0xfe :
return MPU_ACK ;
case 0xf0 :
case 0xf1 :
case 0xf2 :
case 0xf3 :
case 0xf4 :
case 0xf5 :
case 0xf6 :
case 0xf7 :
printk ( " <Trk data rq #%d> " , midic & 0x0f ) ;
break ;
case 0xf9 :
printk ( " <conductor rq> " ) ;
break ;
case 0xff :
devc - > m_state = ST_SYSMSG ;
break ;
default :
if ( midic < = 0xef )
{
/* printk( "mpu time: %d ", midic); */
devc - > m_state = ST_TIMED ;
}
else
printk ( " <MPU: Unknown event %02x> " , midic ) ;
}
break ;
case ST_TIMED :
{
int msg = ( ( int ) ( midic & 0xf0 ) > > 4 ) ;
devc - > m_state = ST_DATABYTE ;
if ( msg < 8 ) /* Data byte */
{
/* printk( "midi msg (running status) "); */
msg = ( ( int ) ( devc - > last_status & 0xf0 ) > > 4 ) ;
msg - = 8 ;
devc - > m_left = len_tab [ msg ] - 1 ;
devc - > m_ptr = 2 ;
devc - > m_buf [ 0 ] = devc - > last_status ;
devc - > m_buf [ 1 ] = midic ;
if ( devc - > m_left < = 0 )
{
devc - > m_state = ST_INIT ;
do_midi_msg ( devc - > synthno , devc - > m_buf , devc - > m_ptr ) ;
devc - > m_ptr = 0 ;
}
}
else if ( msg = = 0xf ) /* MPU MARK */
{
devc - > m_state = ST_INIT ;
switch ( midic )
{
case 0xf8 :
/* printk( "NOP "); */
break ;
case 0xf9 :
/* printk( "meas end "); */
break ;
case 0xfc :
/* printk( "data end "); */
break ;
default :
printk ( " Unknown MPU mark %02x \n " , midic ) ;
}
}
else
{
devc - > last_status = midic ;
/* printk( "midi msg "); */
msg - = 8 ;
devc - > m_left = len_tab [ msg ] ;
devc - > m_ptr = 1 ;
devc - > m_buf [ 0 ] = midic ;
if ( devc - > m_left < = 0 )
{
devc - > m_state = ST_INIT ;
do_midi_msg ( devc - > synthno , devc - > m_buf , devc - > m_ptr ) ;
devc - > m_ptr = 0 ;
}
}
}
break ;
case ST_SYSMSG :
switch ( midic )
{
case 0xf0 :
printk ( " <SYX> " ) ;
devc - > m_state = ST_SYSEX ;
break ;
case 0xf1 :
devc - > m_state = ST_MTC ;
break ;
case 0xf2 :
devc - > m_state = ST_SONGPOS ;
devc - > m_ptr = 0 ;
break ;
case 0xf3 :
devc - > m_state = ST_SONGSEL ;
break ;
case 0xf6 :
/* printk( "tune_request\n"); */
devc - > m_state = ST_INIT ;
/*
* Real time messages
*/
case 0xf8 :
/* midi clock */
devc - > m_state = ST_INIT ;
timer_ext_event ( devc , TMR_CLOCK , 0 ) ;
break ;
case 0xfA :
devc - > m_state = ST_INIT ;
timer_ext_event ( devc , TMR_START , 0 ) ;
break ;
case 0xFB :
devc - > m_state = ST_INIT ;
timer_ext_event ( devc , TMR_CONTINUE , 0 ) ;
break ;
case 0xFC :
devc - > m_state = ST_INIT ;
timer_ext_event ( devc , TMR_STOP , 0 ) ;
break ;
case 0xFE :
/* active sensing */
devc - > m_state = ST_INIT ;
break ;
case 0xff :
/* printk( "midi hard reset"); */
devc - > m_state = ST_INIT ;
break ;
default :
printk ( " unknown MIDI sysmsg %0x \n " , midic ) ;
devc - > m_state = ST_INIT ;
}
break ;
case ST_MTC :
devc - > m_state = ST_INIT ;
printk ( " MTC frame %x02 \n " , midic ) ;
break ;
case ST_SYSEX :
if ( midic = = 0xf7 )
{
printk ( " <EOX> " ) ;
devc - > m_state = ST_INIT ;
}
else
printk ( " %02x " , midic ) ;
break ;
case ST_SONGPOS :
BUFTEST ( devc ) ;
devc - > m_buf [ devc - > m_ptr + + ] = midic ;
if ( devc - > m_ptr = = 2 )
{
devc - > m_state = ST_INIT ;
devc - > m_ptr = 0 ;
timer_ext_event ( devc , TMR_SPP ,
( ( devc - > m_buf [ 1 ] & 0x7f ) < < 7 ) |
( devc - > m_buf [ 0 ] & 0x7f ) ) ;
}
break ;
case ST_DATABYTE :
BUFTEST ( devc ) ;
devc - > m_buf [ devc - > m_ptr + + ] = midic ;
if ( ( - - devc - > m_left ) < = 0 )
{
devc - > m_state = ST_INIT ;
do_midi_msg ( devc - > synthno , devc - > m_buf , devc - > m_ptr ) ;
devc - > m_ptr = 0 ;
}
break ;
default :
printk ( " Bad state %d " , devc - > m_state ) ;
devc - > m_state = ST_INIT ;
}
return 1 ;
}
static void mpu401_input_loop ( struct mpu_config * devc )
{
unsigned long flags ;
int busy ;
int n ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
busy = devc - > m_busy ;
devc - > m_busy = 1 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
if ( busy ) /* Already inside the scanner */
return ;
n = 50 ;
while ( input_avail ( devc ) & & n - - > 0 )
{
unsigned char c = read_data ( devc ) ;
if ( devc - > mode = = MODE_SYNTH )
{
mpu_input_scanner ( devc , c ) ;
}
else if ( devc - > opened & OPEN_READ & & devc - > inputintr ! = NULL )
devc - > inputintr ( devc - > devno , c ) ;
}
devc - > m_busy = 0 ;
}
int intchk_mpu401 ( void * dev_id )
{
struct mpu_config * devc ;
int dev = ( int ) dev_id ;
devc = & dev_conf [ dev ] ;
return input_avail ( devc ) ;
}
irqreturn_t mpuintr ( int irq , void * dev_id , struct pt_regs * dummy )
{
struct mpu_config * devc ;
int dev = ( int ) dev_id ;
int handled = 0 ;
devc = & dev_conf [ dev ] ;
if ( input_avail ( devc ) )
{
handled = 1 ;
if ( devc - > base ! = 0 & & ( devc - > opened & OPEN_READ | | devc - > mode = = MODE_SYNTH ) )
mpu401_input_loop ( devc ) ;
else
{
/* Dummy read (just to acknowledge the interrupt) */
read_data ( devc ) ;
}
}
return IRQ_RETVAL ( handled ) ;
}
static int mpu401_open ( int dev , int mode ,
void ( * input ) ( int dev , unsigned char data ) ,
void ( * output ) ( int dev )
)
{
int err ;
struct mpu_config * devc ;
struct coproc_operations * coprocessor ;
if ( dev < 0 | | dev > = num_midis | | midi_devs [ dev ] = = NULL )
return - ENXIO ;
devc = & dev_conf [ dev ] ;
if ( devc - > opened )
return - EBUSY ;
/*
* Verify that the device is really running .
* Some devices ( such as Ensoniq SoundScape don ' t
* work before the on board processor ( OBP ) is initialized
* by downloading its microcode .
*/
if ( ! devc - > initialized )
{
if ( mpu401_status ( devc ) = = 0xff ) /* Bus float */
{
printk ( KERN_ERR " mpu401: Device not initialized properly \n " ) ;
return - EIO ;
}
reset_mpu401 ( devc ) ;
}
if ( ( coprocessor = midi_devs [ dev ] - > coproc ) ! = NULL )
{
if ( ! try_module_get ( coprocessor - > owner ) ) {
mpu401_close ( dev ) ;
return - ENODEV ;
}
if ( ( err = coprocessor - > open ( coprocessor - > devc , COPR_MIDI ) ) < 0 )
{
printk ( KERN_WARNING " MPU-401: Can't access coprocessor device \n " ) ;
mpu401_close ( dev ) ;
return err ;
}
}
set_uart_mode ( dev , devc , 1 ) ;
devc - > mode = MODE_MIDI ;
devc - > synthno = 0 ;
mpu401_input_loop ( devc ) ;
devc - > inputintr = input ;
devc - > opened = mode ;
return 0 ;
}
static void mpu401_close ( int dev )
{
struct mpu_config * devc ;
struct coproc_operations * coprocessor ;
devc = & dev_conf [ dev ] ;
if ( devc - > uart_mode )
reset_mpu401 ( devc ) ; /*
* This disables the UART mode
*/
devc - > mode = 0 ;
devc - > inputintr = NULL ;
coprocessor = midi_devs [ dev ] - > coproc ;
if ( coprocessor ) {
coprocessor - > close ( coprocessor - > devc , COPR_MIDI ) ;
module_put ( coprocessor - > owner ) ;
}
devc - > opened = 0 ;
}
static int mpu401_out ( int dev , unsigned char midi_byte )
{
int timeout ;
unsigned long flags ;
struct mpu_config * devc ;
devc = & dev_conf [ dev ] ;
/*
* Sometimes it takes about 30000 loops before the output becomes ready
* ( After reset ) . Normally it takes just about 10 loops .
*/
for ( timeout = 30000 ; timeout > 0 & & ! output_ready ( devc ) ; timeout - - ) ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( ! output_ready ( devc ) )
{
printk ( KERN_WARNING " mpu401: Send data timeout \n " ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return 0 ;
}
write_data ( devc , midi_byte ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return 1 ;
}
static int mpu401_command ( int dev , mpu_command_rec * cmd )
{
int i , timeout , ok ;
int ret = 0 ;
unsigned long flags ;
struct mpu_config * devc ;
devc = & dev_conf [ dev ] ;
if ( devc - > uart_mode ) /*
* Not possible in UART mode
*/
{
printk ( KERN_WARNING " mpu401: commands not possible in the UART mode \n " ) ;
return - EINVAL ;
}
/*
* Test for input since pending input seems to block the output .
*/
if ( input_avail ( devc ) )
mpu401_input_loop ( devc ) ;
/*
* Sometimes it takes about 50000 loops before the output becomes ready
* ( After reset ) . Normally it takes just about 10 loops .
*/
timeout = 50000 ;
retry :
if ( timeout - - < = 0 )
{
printk ( KERN_WARNING " mpu401: Command (0x%x) timeout \n " , ( int ) cmd - > cmd ) ;
return - EIO ;
}
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( ! output_ready ( devc ) )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
goto retry ;
}
write_command ( devc , cmd - > cmd ) ;
ok = 0 ;
for ( timeout = 50000 ; timeout > 0 & & ! ok ; timeout - - )
{
if ( input_avail ( devc ) )
{
if ( devc - > opened & & devc - > mode = = MODE_SYNTH )
{
if ( mpu_input_scanner ( devc , read_data ( devc ) ) = = MPU_ACK )
ok = 1 ;
}
else
{
/* Device is not currently open. Use simpler method */
if ( read_data ( devc ) = = MPU_ACK )
ok = 1 ;
}
}
}
if ( ! ok )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return - EIO ;
}
if ( cmd - > nr_args )
{
for ( i = 0 ; i < cmd - > nr_args ; i + + )
{
for ( timeout = 3000 ; timeout > 0 & & ! output_ready ( devc ) ; timeout - - ) ;
if ( ! mpu401_out ( dev , cmd - > data [ i ] ) )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
printk ( KERN_WARNING " mpu401: Command (0x%x), parm send failed. \n " , ( int ) cmd - > cmd ) ;
return - EIO ;
}
}
}
ret = 0 ;
cmd - > data [ 0 ] = 0 ;
if ( cmd - > nr_returns )
{
for ( i = 0 ; i < cmd - > nr_returns ; i + + )
{
ok = 0 ;
for ( timeout = 5000 ; timeout > 0 & & ! ok ; timeout - - )
if ( input_avail ( devc ) )
{
cmd - > data [ i ] = read_data ( devc ) ;
ok = 1 ;
}
if ( ! ok )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return - EIO ;
}
}
}
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return ret ;
}
static int mpu_cmd ( int dev , int cmd , int data )
{
int ret ;
static mpu_command_rec rec ;
rec . cmd = cmd & 0xff ;
rec . nr_args = ( ( cmd & 0xf0 ) = = 0xE0 ) ;
rec . nr_returns = ( ( cmd & 0xf0 ) = = 0xA0 ) ;
rec . data [ 0 ] = data & 0xff ;
if ( ( ret = mpu401_command ( dev , & rec ) ) < 0 )
return ret ;
return ( unsigned char ) rec . data [ 0 ] ;
}
static int mpu401_prefix_cmd ( int dev , unsigned char status )
{
struct mpu_config * devc = & dev_conf [ dev ] ;
if ( devc - > uart_mode )
return 1 ;
if ( status < 0xf0 )
{
if ( mpu_cmd ( dev , 0xD0 , 0 ) < 0 )
return 0 ;
return 1 ;
}
switch ( status )
{
case 0xF0 :
if ( mpu_cmd ( dev , 0xDF , 0 ) < 0 )
return 0 ;
return 1 ;
default :
return 0 ;
}
}
static int mpu401_start_read ( int dev )
{
return 0 ;
}
static int mpu401_end_read ( int dev )
{
return 0 ;
}
static int mpu401_ioctl ( int dev , unsigned cmd , void __user * arg )
{
struct mpu_config * devc ;
mpu_command_rec rec ;
int val , ret ;
devc = & dev_conf [ dev ] ;
switch ( cmd )
{
case SNDCTL_MIDI_MPUMODE :
if ( ! ( devc - > capabilities & MPU_CAP_INTLG ) ) { /* No intelligent mode */
printk ( KERN_WARNING " mpu401: Intelligent mode not supported by the HW \n " ) ;
return - EINVAL ;
}
if ( get_user ( val , ( int __user * ) arg ) )
return - EFAULT ;
set_uart_mode ( dev , devc , ! val ) ;
return 0 ;
case SNDCTL_MIDI_MPUCMD :
if ( copy_from_user ( & rec , arg , sizeof ( rec ) ) )
return - EFAULT ;
if ( ( ret = mpu401_command ( dev , & rec ) ) < 0 )
return ret ;
if ( copy_to_user ( arg , & rec , sizeof ( rec ) ) )
return - EFAULT ;
return 0 ;
default :
return - EINVAL ;
}
}
static void mpu401_kick ( int dev )
{
}
static int mpu401_buffer_status ( int dev )
{
return 0 ; /*
* No data in buffers
*/
}
static int mpu_synth_ioctl ( int dev , unsigned int cmd , void __user * arg )
{
int midi_dev ;
struct mpu_config * devc ;
midi_dev = synth_devs [ dev ] - > midi_dev ;
if ( midi_dev < 0 | | midi_dev > num_midis | | midi_devs [ midi_dev ] = = NULL )
return - ENXIO ;
devc = & dev_conf [ midi_dev ] ;
switch ( cmd )
{
case SNDCTL_SYNTH_INFO :
if ( copy_to_user ( arg , & mpu_synth_info [ midi_dev ] ,
sizeof ( struct synth_info ) ) )
return - EFAULT ;
return 0 ;
case SNDCTL_SYNTH_MEMAVL :
return 0x7fffffff ;
default :
return - EINVAL ;
}
}
static int mpu_synth_open ( int dev , int mode )
{
int midi_dev , err ;
struct mpu_config * devc ;
struct coproc_operations * coprocessor ;
midi_dev = synth_devs [ dev ] - > midi_dev ;
if ( midi_dev < 0 | | midi_dev > num_midis | | midi_devs [ midi_dev ] = = NULL )
return - ENXIO ;
devc = & dev_conf [ midi_dev ] ;
/*
* Verify that the device is really running .
* Some devices ( such as Ensoniq SoundScape don ' t
* work before the on board processor ( OBP ) is initialized
* by downloading its microcode .
*/
if ( ! devc - > initialized )
{
if ( mpu401_status ( devc ) = = 0xff ) /* Bus float */
{
printk ( KERN_ERR " mpu401: Device not initialized properly \n " ) ;
return - EIO ;
}
reset_mpu401 ( devc ) ;
}
if ( devc - > opened )
return - EBUSY ;
devc - > mode = MODE_SYNTH ;
devc - > synthno = dev ;
devc - > inputintr = NULL ;
coprocessor = midi_devs [ midi_dev ] - > coproc ;
if ( coprocessor ) {
if ( ! try_module_get ( coprocessor - > owner ) )
return - ENODEV ;
if ( ( err = coprocessor - > open ( coprocessor - > devc , COPR_MIDI ) ) < 0 )
{
printk ( KERN_WARNING " mpu401: Can't access coprocessor device \n " ) ;
return err ;
}
}
devc - > opened = mode ;
reset_mpu401 ( devc ) ;
if ( mode & OPEN_READ )
{
mpu_cmd ( midi_dev , 0x8B , 0 ) ; /* Enable data in stop mode */
mpu_cmd ( midi_dev , 0x34 , 0 ) ; /* Return timing bytes in stop mode */
mpu_cmd ( midi_dev , 0x87 , 0 ) ; /* Enable pitch & controller */
}
return 0 ;
}
static void mpu_synth_close ( int dev )
{
int midi_dev ;
struct mpu_config * devc ;
struct coproc_operations * coprocessor ;
midi_dev = synth_devs [ dev ] - > midi_dev ;
devc = & dev_conf [ midi_dev ] ;
mpu_cmd ( midi_dev , 0x15 , 0 ) ; /* Stop recording, playback and MIDI */
mpu_cmd ( midi_dev , 0x8a , 0 ) ; /* Disable data in stopped mode */
devc - > inputintr = NULL ;
coprocessor = midi_devs [ midi_dev ] - > coproc ;
if ( coprocessor ) {
coprocessor - > close ( coprocessor - > devc , COPR_MIDI ) ;
module_put ( coprocessor - > owner ) ;
}
devc - > opened = 0 ;
devc - > mode = 0 ;
}
# define MIDI_SYNTH_NAME "MPU-401 UART Midi"
# define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
# include "midi_synth.h"
static struct synth_operations mpu401_synth_proto =
{
. owner = THIS_MODULE ,
. id = " MPU401 " ,
. info = NULL ,
. midi_dev = 0 ,
. synth_type = SYNTH_TYPE_MIDI ,
. synth_subtype = 0 ,
. open = mpu_synth_open ,
. close = mpu_synth_close ,
. ioctl = mpu_synth_ioctl ,
. kill_note = midi_synth_kill_note ,
. start_note = midi_synth_start_note ,
. set_instr = midi_synth_set_instr ,
. reset = midi_synth_reset ,
. hw_control = midi_synth_hw_control ,
. load_patch = midi_synth_load_patch ,
. aftertouch = midi_synth_aftertouch ,
. controller = midi_synth_controller ,
. panning = midi_synth_panning ,
. bender = midi_synth_bender ,
. setup_voice = midi_synth_setup_voice ,
. send_sysex = midi_synth_send_sysex
} ;
static struct synth_operations * mpu401_synth_operations [ MAX_MIDI_DEV ] ;
static struct midi_operations mpu401_midi_proto =
{
. owner = THIS_MODULE ,
. info = { " MPU-401 Midi " , 0 , MIDI_CAP_MPU401 , SNDCARD_MPU401 } ,
. in_info = { 0 } ,
. open = mpu401_open ,
. close = mpu401_close ,
. ioctl = mpu401_ioctl ,
. outputc = mpu401_out ,
. start_read = mpu401_start_read ,
. end_read = mpu401_end_read ,
. kick = mpu401_kick ,
. buffer_status = mpu401_buffer_status ,
. prefix_cmd = mpu401_prefix_cmd
} ;
static struct midi_operations mpu401_midi_operations [ MAX_MIDI_DEV ] ;
static void mpu401_chk_version ( int n , struct mpu_config * devc )
{
int tmp ;
unsigned long flags ;
devc - > version = devc - > revision = 0 ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( ( tmp = mpu_cmd ( n , 0xAC , 0 ) ) < 0 )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return ;
}
if ( ( tmp & 0xf0 ) > 0x20 ) /* Why it's larger than 2.x ??? */
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return ;
}
devc - > version = tmp ;
if ( ( tmp = mpu_cmd ( n , 0xAD , 0 ) ) < 0 )
{
devc - > version = 0 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return ;
}
devc - > revision = tmp ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
int attach_mpu401 ( struct address_info * hw_config , struct module * owner )
{
unsigned long flags ;
char revision_char ;
int m , ret ;
struct mpu_config * devc ;
hw_config - > slots [ 1 ] = - 1 ;
m = sound_alloc_mididev ( ) ;
if ( m = = - 1 )
{
printk ( KERN_WARNING " MPU-401: Too many midi devices detected \n " ) ;
ret = - ENOMEM ;
goto out_err ;
}
devc = & dev_conf [ m ] ;
devc - > base = hw_config - > io_base ;
devc - > osp = hw_config - > osp ;
devc - > irq = hw_config - > irq ;
devc - > opened = 0 ;
devc - > uart_mode = 0 ;
devc - > initialized = 0 ;
devc - > version = 0 ;
devc - > revision = 0 ;
devc - > capabilities = 0 ;
devc - > timer_flag = 0 ;
devc - > m_busy = 0 ;
devc - > m_state = ST_INIT ;
devc - > shared_irq = hw_config - > always_detect ;
devc - > irq = hw_config - > irq ;
spin_lock_init ( & devc - > lock ) ;
if ( devc - > irq < 0 )
{
devc - > irq * = - 1 ;
devc - > shared_irq = 1 ;
}
if ( ! hw_config - > always_detect )
{
/* Verify the hardware again */
if ( ! reset_mpu401 ( devc ) )
{
printk ( KERN_WARNING " mpu401: Device didn't respond \n " ) ;
ret = - ENODEV ;
goto out_mididev ;
}
if ( ! devc - > shared_irq )
{
if ( request_irq ( devc - > irq , mpuintr , 0 , " mpu401 " , ( void * ) m ) < 0 )
{
printk ( KERN_WARNING " mpu401: Failed to allocate IRQ%d \n " , devc - > irq ) ;
ret = - ENOMEM ;
goto out_mididev ;
}
}
spin_lock_irqsave ( & devc - > lock , flags ) ;
mpu401_chk_version ( m , devc ) ;
if ( devc - > version = = 0 )
mpu401_chk_version ( m , devc ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
if ( devc - > version ! = 0 )
if ( mpu_cmd ( m , 0xC5 , 0 ) > = 0 ) /* Set timebase OK */
if ( mpu_cmd ( m , 0xE0 , 120 ) > = 0 ) /* Set tempo OK */
devc - > capabilities | = MPU_CAP_INTLG ; /* Supports intelligent mode */
mpu401_synth_operations [ m ] = ( struct synth_operations * ) kmalloc ( sizeof ( struct synth_operations ) , GFP_KERNEL ) ;
if ( mpu401_synth_operations [ m ] = = NULL )
{
printk ( KERN_ERR " mpu401: Can't allocate memory \n " ) ;
ret = - ENOMEM ;
goto out_irq ;
}
if ( ! ( devc - > capabilities & MPU_CAP_INTLG ) ) /* No intelligent mode */
{
memcpy ( ( char * ) mpu401_synth_operations [ m ] ,
( char * ) & std_midi_synth ,
sizeof ( struct synth_operations ) ) ;
}
else
{
memcpy ( ( char * ) mpu401_synth_operations [ m ] ,
( char * ) & mpu401_synth_proto ,
sizeof ( struct synth_operations ) ) ;
}
if ( owner )
mpu401_synth_operations [ m ] - > owner = owner ;
memcpy ( ( char * ) & mpu401_midi_operations [ m ] ,
( char * ) & mpu401_midi_proto ,
sizeof ( struct midi_operations ) ) ;
mpu401_midi_operations [ m ] . converter = mpu401_synth_operations [ m ] ;
memcpy ( ( char * ) & mpu_synth_info [ m ] ,
( char * ) & mpu_synth_info_proto ,
sizeof ( struct synth_info ) ) ;
n_mpu_devs + + ;
if ( devc - > version = = 0x20 & & devc - > revision > = 0x07 ) /* MusicQuest interface */
{
int ports = ( devc - > revision & 0x08 ) ? 32 : 16 ;
devc - > capabilities | = MPU_CAP_SYNC | MPU_CAP_SMPTE |
MPU_CAP_CLS | MPU_CAP_2PORT ;
revision_char = ( devc - > revision = = 0x7f ) ? ' M ' : ' ' ;
sprintf ( mpu_synth_info [ m ] . name , " MQX-%d%c MIDI Interface #%d " ,
ports ,
revision_char ,
n_mpu_devs ) ;
}
else
{
revision_char = devc - > revision ? devc - > revision + ' @ ' : ' ' ;
if ( ( int ) devc - > revision > ( ' Z ' - ' @ ' ) )
revision_char = ' + ' ;
devc - > capabilities | = MPU_CAP_SYNC | MPU_CAP_FSK ;
if ( hw_config - > name )
sprintf ( mpu_synth_info [ m ] . name , " %s (MPU401) " , hw_config - > name ) ;
else
sprintf ( mpu_synth_info [ m ] . name ,
" MPU-401 %d.%d%c Midi interface #%d " ,
( int ) ( devc - > version & 0xf0 ) > > 4 ,
devc - > version & 0x0f ,
revision_char ,
n_mpu_devs ) ;
}
strcpy ( mpu401_midi_operations [ m ] . info . name ,
mpu_synth_info [ m ] . name ) ;
conf_printf ( mpu_synth_info [ m ] . name , hw_config ) ;
mpu401_synth_operations [ m ] - > midi_dev = devc - > devno = m ;
mpu401_synth_operations [ devc - > devno ] - > info = & mpu_synth_info [ devc - > devno ] ;
if ( devc - > capabilities & MPU_CAP_INTLG ) /* Intelligent mode */
hw_config - > slots [ 2 ] = mpu_timer_init ( m ) ;
midi_devs [ m ] = & mpu401_midi_operations [ devc - > devno ] ;
if ( owner )
midi_devs [ m ] - > owner = owner ;
hw_config - > slots [ 1 ] = m ;
sequencer_init ( ) ;
return 0 ;
out_irq :
free_irq ( devc - > irq , ( void * ) m ) ;
out_mididev :
sound_unload_mididev ( m ) ;
out_err :
release_region ( hw_config - > io_base , 2 ) ;
return ret ;
}
static int reset_mpu401 ( struct mpu_config * devc )
{
unsigned long flags ;
int ok , timeout , n ;
int timeout_limit ;
/*
* Send the RESET command . Try again if no success at the first time .
* ( If the device is in the UART mode , it will not ack the reset cmd ) .
*/
ok = 0 ;
timeout_limit = devc - > initialized ? 30000 : 100000 ;
devc - > initialized = 1 ;
for ( n = 0 ; n < 2 & & ! ok ; n + + )
{
for ( timeout = timeout_limit ; timeout > 0 & & ! ok ; timeout - - )
ok = output_ready ( devc ) ;
write_command ( devc , MPU_RESET ) ; /*
* Send MPU - 401 RESET Command
*/
/*
* Wait at least 25 msec . This method is not accurate so let ' s make the
* loop bit longer . Cannot sleep since this is called during boot .
*/
for ( timeout = timeout_limit * 2 ; timeout > 0 & & ! ok ; timeout - - )
{
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( input_avail ( devc ) )
if ( read_data ( devc ) = = MPU_ACK )
ok = 1 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
}
devc - > m_state = ST_INIT ;
devc - > m_ptr = 0 ;
devc - > m_left = 0 ;
devc - > last_status = 0 ;
devc - > uart_mode = 0 ;
return ok ;
}
static void set_uart_mode ( int dev , struct mpu_config * devc , int arg )
{
if ( ! arg & & ( devc - > capabilities & MPU_CAP_INTLG ) )
return ;
if ( ( devc - > uart_mode = = 0 ) = = ( arg = = 0 ) )
return ; /* Already set */
reset_mpu401 ( devc ) ; /* This exits the uart mode */
if ( arg )
{
if ( mpu_cmd ( dev , UART_MODE_ON , 0 ) < 0 )
{
printk ( KERN_ERR " mpu401: Can't enter UART mode \n " ) ;
devc - > uart_mode = 0 ;
return ;
}
}
devc - > uart_mode = arg ;
}
int probe_mpu401 ( struct address_info * hw_config , struct resource * ports )
{
int ok = 0 ;
struct mpu_config tmp_devc ;
tmp_devc . base = hw_config - > io_base ;
tmp_devc . irq = hw_config - > irq ;
tmp_devc . initialized = 0 ;
tmp_devc . opened = 0 ;
tmp_devc . osp = hw_config - > osp ;
if ( hw_config - > always_detect )
return 1 ;
if ( inb ( hw_config - > io_base + 1 ) = = 0xff )
{
DDB ( printk ( " MPU401: Port %x looks dead. \n " , hw_config - > io_base ) ) ;
return 0 ; /* Just bus float? */
}
ok = reset_mpu401 ( & tmp_devc ) ;
if ( ! ok )
{
DDB ( printk ( " MPU401: Reset failed on port %x \n " , hw_config - > io_base ) ) ;
}
return ok ;
}
void unload_mpu401 ( struct address_info * hw_config )
{
void * p ;
int n = hw_config - > slots [ 1 ] ;
if ( n ! = - 1 ) {
release_region ( hw_config - > io_base , 2 ) ;
if ( hw_config - > always_detect = = 0 & & hw_config - > irq > 0 )
free_irq ( hw_config - > irq , ( void * ) n ) ;
p = mpu401_synth_operations [ n ] ;
sound_unload_mididev ( n ) ;
sound_unload_timerdev ( hw_config - > slots [ 2 ] ) ;
2005-06-26 01:58:49 +04:00
kfree ( p ) ;
2005-04-17 02:20:36 +04:00
}
}
/*****************************************************
* Timer stuff
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static volatile int timer_initialized = 0 , timer_open = 0 , tmr_running = 0 ;
static volatile int curr_tempo , curr_timebase , hw_timebase ;
static int max_timebase = 8 ; /* 8*24=192 ppqn */
static volatile unsigned long next_event_time ;
static volatile unsigned long curr_ticks , curr_clocks ;
static unsigned long prev_event_time ;
static int metronome_mode ;
static unsigned long clocks2ticks ( unsigned long clocks )
{
/*
* The MPU - 401 supports just a limited set of possible timebase values .
* Since the applications require more choices , the driver has to
* program the HW to do its best and to convert between the HW and
* actual timebases .
*/
return ( ( clocks * curr_timebase ) + ( hw_timebase / 2 ) ) / hw_timebase ;
}
static void set_timebase ( int midi_dev , int val )
{
int hw_val ;
if ( val < 48 )
val = 48 ;
if ( val > 1000 )
val = 1000 ;
hw_val = val ;
hw_val = ( hw_val + 12 ) / 24 ;
if ( hw_val > max_timebase )
hw_val = max_timebase ;
if ( mpu_cmd ( midi_dev , 0xC0 | ( hw_val & 0x0f ) , 0 ) < 0 )
{
printk ( KERN_WARNING " mpu401: Can't set HW timebase to %d \n " , hw_val * 24 ) ;
return ;
}
hw_timebase = hw_val * 24 ;
curr_timebase = val ;
}
static void tmr_reset ( struct mpu_config * devc )
{
unsigned long flags ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
next_event_time = ( unsigned long ) - 1 ;
prev_event_time = 0 ;
curr_ticks = curr_clocks = 0 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
static void set_timer_mode ( int midi_dev )
{
if ( timer_mode & TMR_MODE_CLS )
mpu_cmd ( midi_dev , 0x3c , 0 ) ; /* Use CLS sync */
else if ( timer_mode & TMR_MODE_SMPTE )
mpu_cmd ( midi_dev , 0x3d , 0 ) ; /* Use SMPTE sync */
if ( timer_mode & TMR_INTERNAL )
{
mpu_cmd ( midi_dev , 0x80 , 0 ) ; /* Use MIDI sync */
}
else
{
if ( timer_mode & ( TMR_MODE_MIDI | TMR_MODE_CLS ) )
{
mpu_cmd ( midi_dev , 0x82 , 0 ) ; /* Use MIDI sync */
mpu_cmd ( midi_dev , 0x91 , 0 ) ; /* Enable ext MIDI ctrl */
}
else if ( timer_mode & TMR_MODE_FSK )
mpu_cmd ( midi_dev , 0x81 , 0 ) ; /* Use FSK sync */
}
}
static void stop_metronome ( int midi_dev )
{
mpu_cmd ( midi_dev , 0x84 , 0 ) ; /* Disable metronome */
}
static void setup_metronome ( int midi_dev )
{
int numerator , denominator ;
int clks_per_click , num_32nds_per_beat ;
int beats_per_measure ;
numerator = ( ( unsigned ) metronome_mode > > 24 ) & 0xff ;
denominator = ( ( unsigned ) metronome_mode > > 16 ) & 0xff ;
clks_per_click = ( ( unsigned ) metronome_mode > > 8 ) & 0xff ;
num_32nds_per_beat = ( unsigned ) metronome_mode & 0xff ;
beats_per_measure = ( numerator * 4 ) > > denominator ;
if ( ! metronome_mode )
mpu_cmd ( midi_dev , 0x84 , 0 ) ; /* Disable metronome */
else
{
mpu_cmd ( midi_dev , 0xE4 , clks_per_click ) ;
mpu_cmd ( midi_dev , 0xE6 , beats_per_measure ) ;
mpu_cmd ( midi_dev , 0x83 , 0 ) ; /* Enable metronome without accents */
}
}
static int mpu_start_timer ( int midi_dev )
{
struct mpu_config * devc = & dev_conf [ midi_dev ] ;
tmr_reset ( devc ) ;
set_timer_mode ( midi_dev ) ;
if ( tmr_running )
return TIMER_NOT_ARMED ; /* Already running */
if ( timer_mode & TMR_INTERNAL )
{
mpu_cmd ( midi_dev , 0x02 , 0 ) ; /* Send MIDI start */
tmr_running = 1 ;
return TIMER_NOT_ARMED ;
}
else
{
mpu_cmd ( midi_dev , 0x35 , 0 ) ; /* Enable mode messages to PC */
mpu_cmd ( midi_dev , 0x38 , 0 ) ; /* Enable sys common messages to PC */
mpu_cmd ( midi_dev , 0x39 , 0 ) ; /* Enable real time messages to PC */
mpu_cmd ( midi_dev , 0x97 , 0 ) ; /* Enable system exclusive messages to PC */
}
return TIMER_ARMED ;
}
static int mpu_timer_open ( int dev , int mode )
{
int midi_dev = sound_timer_devs [ dev ] - > devlink ;
struct mpu_config * devc = & dev_conf [ midi_dev ] ;
if ( timer_open )
return - EBUSY ;
tmr_reset ( devc ) ;
curr_tempo = 50 ;
mpu_cmd ( midi_dev , 0xE0 , 50 ) ;
curr_timebase = hw_timebase = 120 ;
set_timebase ( midi_dev , 120 ) ;
timer_open = 1 ;
metronome_mode = 0 ;
set_timer_mode ( midi_dev ) ;
mpu_cmd ( midi_dev , 0xe7 , 0x04 ) ; /* Send all clocks to host */
mpu_cmd ( midi_dev , 0x95 , 0 ) ; /* Enable clock to host */
return 0 ;
}
static void mpu_timer_close ( int dev )
{
int midi_dev = sound_timer_devs [ dev ] - > devlink ;
timer_open = tmr_running = 0 ;
mpu_cmd ( midi_dev , 0x15 , 0 ) ; /* Stop all */
mpu_cmd ( midi_dev , 0x94 , 0 ) ; /* Disable clock to host */
mpu_cmd ( midi_dev , 0x8c , 0 ) ; /* Disable measure end messages to host */
stop_metronome ( midi_dev ) ;
}
static int mpu_timer_event ( int dev , unsigned char * event )
{
unsigned char command = event [ 1 ] ;
unsigned long parm = * ( unsigned int * ) & event [ 4 ] ;
int midi_dev = sound_timer_devs [ dev ] - > devlink ;
switch ( command )
{
case TMR_WAIT_REL :
parm + = prev_event_time ;
case TMR_WAIT_ABS :
if ( parm > 0 )
{
long time ;
if ( parm < = curr_ticks ) /* It's the time */
return TIMER_NOT_ARMED ;
time = parm ;
next_event_time = prev_event_time = time ;
return TIMER_ARMED ;
}
break ;
case TMR_START :
if ( tmr_running )
break ;
return mpu_start_timer ( midi_dev ) ;
case TMR_STOP :
mpu_cmd ( midi_dev , 0x01 , 0 ) ; /* Send MIDI stop */
stop_metronome ( midi_dev ) ;
tmr_running = 0 ;
break ;
case TMR_CONTINUE :
if ( tmr_running )
break ;
mpu_cmd ( midi_dev , 0x03 , 0 ) ; /* Send MIDI continue */
setup_metronome ( midi_dev ) ;
tmr_running = 1 ;
break ;
case TMR_TEMPO :
if ( parm )
{
if ( parm < 8 )
parm = 8 ;
if ( parm > 250 )
parm = 250 ;
if ( mpu_cmd ( midi_dev , 0xE0 , parm ) < 0 )
printk ( KERN_WARNING " mpu401: Can't set tempo to %d \n " , ( int ) parm ) ;
curr_tempo = parm ;
}
break ;
case TMR_ECHO :
seq_copy_to_input ( event , 8 ) ;
break ;
case TMR_TIMESIG :
if ( metronome_mode ) /* Metronome enabled */
{
metronome_mode = parm ;
setup_metronome ( midi_dev ) ;
}
break ;
default : ;
}
return TIMER_NOT_ARMED ;
}
static unsigned long mpu_timer_get_time ( int dev )
{
if ( ! timer_open )
return 0 ;
return curr_ticks ;
}
static int mpu_timer_ioctl ( int dev , unsigned int command , void __user * arg )
{
int midi_dev = sound_timer_devs [ dev ] - > devlink ;
int __user * p = ( int __user * ) arg ;
switch ( command )
{
case SNDCTL_TMR_SOURCE :
{
int parm ;
if ( get_user ( parm , p ) )
return - EFAULT ;
parm & = timer_caps ;
if ( parm ! = 0 )
{
timer_mode = parm ;
if ( timer_mode & TMR_MODE_CLS )
mpu_cmd ( midi_dev , 0x3c , 0 ) ; /* Use CLS sync */
else if ( timer_mode & TMR_MODE_SMPTE )
mpu_cmd ( midi_dev , 0x3d , 0 ) ; /* Use SMPTE sync */
}
if ( put_user ( timer_mode , p ) )
return - EFAULT ;
return timer_mode ;
}
break ;
case SNDCTL_TMR_START :
mpu_start_timer ( midi_dev ) ;
return 0 ;
case SNDCTL_TMR_STOP :
tmr_running = 0 ;
mpu_cmd ( midi_dev , 0x01 , 0 ) ; /* Send MIDI stop */
stop_metronome ( midi_dev ) ;
return 0 ;
case SNDCTL_TMR_CONTINUE :
if ( tmr_running )
return 0 ;
tmr_running = 1 ;
mpu_cmd ( midi_dev , 0x03 , 0 ) ; /* Send MIDI continue */
return 0 ;
case SNDCTL_TMR_TIMEBASE :
{
int val ;
if ( get_user ( val , p ) )
return - EFAULT ;
if ( val )
set_timebase ( midi_dev , val ) ;
if ( put_user ( curr_timebase , p ) )
return - EFAULT ;
return curr_timebase ;
}
break ;
case SNDCTL_TMR_TEMPO :
{
int val ;
int ret ;
if ( get_user ( val , p ) )
return - EFAULT ;
if ( val )
{
if ( val < 8 )
val = 8 ;
if ( val > 250 )
val = 250 ;
if ( ( ret = mpu_cmd ( midi_dev , 0xE0 , val ) ) < 0 )
{
printk ( KERN_WARNING " mpu401: Can't set tempo to %d \n " , ( int ) val ) ;
return ret ;
}
curr_tempo = val ;
}
if ( put_user ( curr_tempo , p ) )
return - EFAULT ;
return curr_tempo ;
}
break ;
case SNDCTL_SEQ_CTRLRATE :
{
int val ;
if ( get_user ( val , p ) )
return - EFAULT ;
if ( val ! = 0 ) /* Can't change */
return - EINVAL ;
val = ( ( curr_tempo * curr_timebase ) + 30 ) / 60 ;
if ( put_user ( val , p ) )
return - EFAULT ;
return val ;
}
break ;
case SNDCTL_SEQ_GETTIME :
if ( put_user ( curr_ticks , p ) )
return - EFAULT ;
return curr_ticks ;
case SNDCTL_TMR_METRONOME :
if ( get_user ( metronome_mode , p ) )
return - EFAULT ;
setup_metronome ( midi_dev ) ;
return 0 ;
default : ;
}
return - EINVAL ;
}
static void mpu_timer_arm ( int dev , long time )
{
if ( time < 0 )
time = curr_ticks + 1 ;
else if ( time < = curr_ticks ) /* It's the time */
return ;
next_event_time = prev_event_time = time ;
return ;
}
static struct sound_timer_operations mpu_timer =
{
. owner = THIS_MODULE ,
. info = { " MPU-401 Timer " , 0 } ,
. priority = 10 , /* Priority */
. devlink = 0 , /* Local device link */
. open = mpu_timer_open ,
. close = mpu_timer_close ,
. event = mpu_timer_event ,
. get_time = mpu_timer_get_time ,
. ioctl = mpu_timer_ioctl ,
. arm_timer = mpu_timer_arm
} ;
static void mpu_timer_interrupt ( void )
{
if ( ! timer_open )
return ;
if ( ! tmr_running )
return ;
curr_clocks + + ;
curr_ticks = clocks2ticks ( curr_clocks ) ;
if ( curr_ticks > = next_event_time )
{
next_event_time = ( unsigned long ) - 1 ;
sequencer_timer ( 0 ) ;
}
}
static void timer_ext_event ( struct mpu_config * devc , int event , int parm )
{
int midi_dev = devc - > devno ;
if ( ! devc - > timer_flag )
return ;
switch ( event )
{
case TMR_CLOCK :
printk ( " <MIDI clk> " ) ;
break ;
case TMR_START :
printk ( " Ext MIDI start \n " ) ;
if ( ! tmr_running )
{
if ( timer_mode & TMR_EXTERNAL )
{
tmr_running = 1 ;
setup_metronome ( midi_dev ) ;
next_event_time = 0 ;
STORE ( SEQ_START_TIMER ( ) ) ;
}
}
break ;
case TMR_STOP :
printk ( " Ext MIDI stop \n " ) ;
if ( timer_mode & TMR_EXTERNAL )
{
tmr_running = 0 ;
stop_metronome ( midi_dev ) ;
STORE ( SEQ_STOP_TIMER ( ) ) ;
}
break ;
case TMR_CONTINUE :
printk ( " Ext MIDI continue \n " ) ;
if ( timer_mode & TMR_EXTERNAL )
{
tmr_running = 1 ;
setup_metronome ( midi_dev ) ;
STORE ( SEQ_CONTINUE_TIMER ( ) ) ;
}
break ;
case TMR_SPP :
printk ( " Songpos: %d \n " , parm ) ;
if ( timer_mode & TMR_EXTERNAL )
{
STORE ( SEQ_SONGPOS ( parm ) ) ;
}
break ;
}
}
static int mpu_timer_init ( int midi_dev )
{
struct mpu_config * devc ;
int n ;
devc = & dev_conf [ midi_dev ] ;
if ( timer_initialized )
return - 1 ; /* There is already a similar timer */
timer_initialized = 1 ;
mpu_timer . devlink = midi_dev ;
dev_conf [ midi_dev ] . timer_flag = 1 ;
n = sound_alloc_timerdev ( ) ;
if ( n = = - 1 )
n = 0 ;
sound_timer_devs [ n ] = & mpu_timer ;
if ( devc - > version < 0x20 ) /* Original MPU-401 */
timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI ;
else
{
/*
* The version number 2.0 is used ( at least ) by the
* MusicQuest cards and the Roland Super - MPU .
*
* MusicQuest has given a special meaning to the bits of the
* revision number . The Super - MPU returns 0.
*/
if ( devc - > revision )
timer_caps | = TMR_EXTERNAL | TMR_MODE_MIDI ;
if ( devc - > revision & 0x02 )
timer_caps | = TMR_MODE_CLS ;
if ( devc - > revision & 0x40 )
max_timebase = 10 ; /* Has the 216 and 240 ppqn modes */
}
timer_mode = ( TMR_INTERNAL | TMR_MODE_MIDI ) & timer_caps ;
return n ;
}
EXPORT_SYMBOL ( probe_mpu401 ) ;
EXPORT_SYMBOL ( attach_mpu401 ) ;
EXPORT_SYMBOL ( unload_mpu401 ) ;
EXPORT_SYMBOL ( intchk_mpu401 ) ;
EXPORT_SYMBOL ( mpuintr ) ;
static struct address_info cfg ;
static int io = - 1 ;
static int irq = - 1 ;
module_param ( irq , int , 0 ) ;
module_param ( io , int , 0 ) ;
static int __init init_mpu401 ( void )
{
int ret ;
/* Can be loaded either for module use or to provide functions
to others */
if ( io ! = - 1 & & irq ! = - 1 ) {
struct resource * ports ;
cfg . irq = irq ;
cfg . io_base = io ;
ports = request_region ( io , 2 , " mpu401 " ) ;
if ( ! ports )
return - EBUSY ;
if ( probe_mpu401 ( & cfg , ports ) = = 0 ) {
release_region ( io , 2 ) ;
return - ENODEV ;
}
if ( ( ret = attach_mpu401 ( & cfg , THIS_MODULE ) ) )
return ret ;
}
return 0 ;
}
static void __exit cleanup_mpu401 ( void )
{
if ( io ! = - 1 & & irq ! = - 1 ) {
/* Check for use by, for example, sscape driver */
unload_mpu401 ( & cfg ) ;
}
}
module_init ( init_mpu401 ) ;
module_exit ( cleanup_mpu401 ) ;
# ifndef MODULE
static int __init setup_mpu401 ( char * str )
{
/* io, irq */
int ints [ 3 ] ;
str = get_options ( str , ARRAY_SIZE ( ints ) , ints ) ;
io = ints [ 1 ] ;
irq = ints [ 2 ] ;
return 1 ;
}
__setup ( " mpu401= " , setup_mpu401 ) ;
# endif
MODULE_LICENSE ( " GPL " ) ;