2005-04-16 15:20:36 -07:00
/*
* sound / wf_midi . c
*
* The low level driver for the WaveFront ICS2115 MIDI interface ( s )
* Note that there is also an MPU - 401 emulation ( actually , a UART - 401
* emulation ) on the CS4232 on the Tropez Plus . This code has nothing
* to do with that interface at all .
*
* The interface is essentially just a UART - 401 , but is has the
* interesting property of supporting what Turtle Beach called
* " Virtual MIDI " mode . In this mode , there are effectively * two *
* MIDI buses accessible via the interface , one that is routed
* solely to / from the external WaveFront synthesizer and the other
* corresponding to the pin / socket connector used to link external
* MIDI devices to the board .
*
* This driver fully supports this mode , allowing two distinct
* midi devices ( / dev / midiNN and / dev / midiNN + 1 ) to be used
* completely independently , giving 32 channels of MIDI routing ,
* 16 to the WaveFront synth and 16 to the external MIDI bus .
*
* Switching between the two is accomplished externally by the driver
* using the two otherwise unused MIDI bytes . See the code for more details .
*
* NOTE : VIRTUAL MIDI MODE IS ON BY DEFAULT ( see wavefront . c )
*
* The main reason to turn off Virtual MIDI mode is when you want to
* tightly couple the WaveFront synth with an external MIDI
* device . You won ' t be able to distinguish the source of any MIDI
* data except via SysEx ID , but thats probably OK , since for the most
* part , the WaveFront won ' t be sending any MIDI data at all .
*
* The main reason to turn on Virtual MIDI Mode is to provide two
* completely independent 16 - channel MIDI buses , one to the
* WaveFront and one to any external MIDI devices . Given the 32
* voice nature of the WaveFront , its pretty easy to find a use
* for all 16 channels driving just that synth .
*
*/
/*
* Copyright ( C ) by Paul Barton - Davis 1998
* Some portions of this file are derived from work that is :
*
* CopyriGht ( C ) by Hannu Savolainen 1993 - 1996
*
* USS / Lite 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 .
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include "sound_config.h"
# include <linux/wavefront.h>
# ifdef MODULE
struct wf_mpu_config {
int base ;
# define DATAPORT(d) (d)->base
# define COMDPORT(d) (d)->base+1
# define STATPORT(d) (d)->base+1
int irq ;
int opened ;
int devno ;
int synthno ;
int mode ;
# define MODE_MIDI 1
# define MODE_SYNTH 2
void ( * inputintr ) ( int dev , unsigned char data ) ;
char isvirtual ; /* do virtual I/O stuff */
} ;
static struct wf_mpu_config devs [ 2 ] ;
static struct wf_mpu_config * phys_dev = & devs [ 0 ] ;
static struct wf_mpu_config * virt_dev = & devs [ 1 ] ;
static void start_uart_mode ( void ) ;
static DEFINE_SPINLOCK ( lock ) ;
# define OUTPUT_READY 0x40
# define INPUT_AVAIL 0x80
# define MPU_ACK 0xFE
# define UART_MODE_ON 0x3F
static inline int wf_mpu_status ( void )
{
return inb ( STATPORT ( phys_dev ) ) ;
}
static inline int input_avail ( void )
{
return ! ( wf_mpu_status ( ) & INPUT_AVAIL ) ;
}
static inline int output_ready ( void )
{
return ! ( wf_mpu_status ( ) & OUTPUT_READY ) ;
}
static inline int read_data ( void )
{
return inb ( DATAPORT ( phys_dev ) ) ;
}
static inline void write_data ( unsigned char byte )
{
outb ( byte , DATAPORT ( phys_dev ) ) ;
}
/*
* States for the input scanner ( should be in dev_table . h )
*/
# define MST_SYSMSG 100 /* System message (sysx etc). */
# define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */
# define MST_SONGSEL 103 /* Song select */
# define MST_SONGPOS 104 /* Song position pointer */
# define MST_TIMED 105 /* Leading timing byte rcvd */
/* buffer space check for input scanner */
# define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
{ printk ( KERN_ERR " WF-MPU: Invalid buffer pointer %d/%d, s=%d \n " , \
mi - > m_ptr , mi - > m_left , mi - > m_state ) ; mi - > m_ptr - - ; }
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 */
} ;
static int
wf_mpu_input_scanner ( int devno , int synthdev , unsigned char midic )
{
struct midi_input_info * mi = & midi_devs [ devno ] - > in_info ;
switch ( mi - > m_state ) {
case MST_INIT :
switch ( midic ) {
case 0xf8 :
/* Timer overflow */
break ;
case 0xfc :
break ;
case 0xfd :
/* XXX do something useful with this. If there is
an external MIDI timer ( e . g . a hardware sequencer ,
a useful timer can be derived . . .
For now , no timer support .
*/
break ;
case 0xfe :
return MPU_ACK ;
break ;
case 0xf0 :
case 0xf1 :
case 0xf2 :
case 0xf3 :
case 0xf4 :
case 0xf5 :
case 0xf6 :
case 0xf7 :
break ;
case 0xf9 :
break ;
case 0xff :
mi - > m_state = MST_SYSMSG ;
break ;
default :
if ( midic < = 0xef ) {
mi - > m_state = MST_TIMED ;
}
else
printk ( KERN_ERR " <MPU: Unknown event %02x> " ,
midic ) ;
}
break ;
case MST_TIMED :
{
int msg = ( ( int ) ( midic & 0xf0 ) > > 4 ) ;
mi - > m_state = MST_DATA ;
if ( msg < 8 ) { /* Data byte */
msg = ( ( int ) ( mi - > m_prev_status & 0xf0 ) > > 4 ) ;
msg - = 8 ;
mi - > m_left = len_tab [ msg ] - 1 ;
mi - > m_ptr = 2 ;
mi - > m_buf [ 0 ] = mi - > m_prev_status ;
mi - > m_buf [ 1 ] = midic ;
if ( mi - > m_left < = 0 ) {
mi - > m_state = MST_INIT ;
do_midi_msg ( synthdev , mi - > m_buf , mi - > m_ptr ) ;
mi - > m_ptr = 0 ;
}
} else if ( msg = = 0xf ) { /* MPU MARK */
mi - > m_state = MST_INIT ;
switch ( midic ) {
case 0xf8 :
break ;
case 0xf9 :
break ;
case 0xfc :
break ;
default :
break ;
}
} else {
mi - > m_prev_status = midic ;
msg - = 8 ;
mi - > m_left = len_tab [ msg ] ;
mi - > m_ptr = 1 ;
mi - > m_buf [ 0 ] = midic ;
if ( mi - > m_left < = 0 ) {
mi - > m_state = MST_INIT ;
do_midi_msg ( synthdev , mi - > m_buf , mi - > m_ptr ) ;
mi - > m_ptr = 0 ;
}
}
}
break ;
case MST_SYSMSG :
switch ( midic ) {
case 0xf0 :
mi - > m_state = MST_SYSEX ;
break ;
case 0xf1 :
mi - > m_state = MST_MTC ;
break ;
case 0xf2 :
mi - > m_state = MST_SONGPOS ;
mi - > m_ptr = 0 ;
break ;
case 0xf3 :
mi - > m_state = MST_SONGSEL ;
break ;
case 0xf6 :
mi - > m_state = MST_INIT ;
/*
* Real time messages
*/
case 0xf8 :
/* midi clock */
mi - > m_state = MST_INIT ;
/* XXX need ext MIDI timer support */
break ;
case 0xfA :
mi - > m_state = MST_INIT ;
/* XXX need ext MIDI timer support */
break ;
case 0xFB :
mi - > m_state = MST_INIT ;
/* XXX need ext MIDI timer support */
break ;
case 0xFC :
mi - > m_state = MST_INIT ;
/* XXX need ext MIDI timer support */
break ;
case 0xFE :
/* active sensing */
mi - > m_state = MST_INIT ;
break ;
case 0xff :
mi - > m_state = MST_INIT ;
break ;
default :
printk ( KERN_ERR " unknown MIDI sysmsg %0x \n " , midic ) ;
mi - > m_state = MST_INIT ;
}
break ;
case MST_MTC :
mi - > m_state = MST_INIT ;
break ;
case MST_SYSEX :
if ( midic = = 0xf7 ) {
mi - > m_state = MST_INIT ;
} else {
/* XXX fix me */
}
break ;
case MST_SONGPOS :
BUFTEST ( mi ) ;
mi - > m_buf [ mi - > m_ptr + + ] = midic ;
if ( mi - > m_ptr = = 2 ) {
mi - > m_state = MST_INIT ;
mi - > m_ptr = 0 ;
/* XXX need ext MIDI timer support */
}
break ;
case MST_DATA :
BUFTEST ( mi ) ;
mi - > m_buf [ mi - > m_ptr + + ] = midic ;
if ( ( - - mi - > m_left ) < = 0 ) {
mi - > m_state = MST_INIT ;
do_midi_msg ( synthdev , mi - > m_buf , mi - > m_ptr ) ;
mi - > m_ptr = 0 ;
}
break ;
default :
printk ( KERN_ERR " Bad state %d " , mi - > m_state ) ;
mi - > m_state = MST_INIT ;
}
return 1 ;
}
static irqreturn_t
wf_mpuintr ( int irq , void * dev_id , struct pt_regs * dummy )
{
struct wf_mpu_config * physical_dev = dev_id ;
static struct wf_mpu_config * input_dev ;
struct midi_input_info * mi = & midi_devs [ physical_dev - > devno ] - > in_info ;
int n ;
if ( ! input_avail ( ) ) { /* not for us */
return IRQ_NONE ;
}
if ( mi - > m_busy )
return IRQ_HANDLED ;
spin_lock ( & lock ) ;
mi - > m_busy = 1 ;
if ( ! input_dev ) {
input_dev = physical_dev ;
}
n = 50 ; /* XXX why ? */
do {
unsigned char c = read_data ( ) ;
if ( phys_dev - > isvirtual ) {
if ( c = = WF_EXTERNAL_SWITCH ) {
input_dev = virt_dev ;
continue ;
} else if ( c = = WF_INTERNAL_SWITCH ) {
input_dev = phys_dev ;
continue ;
} /* else just leave it as it is */
} else {
input_dev = phys_dev ;
}
if ( input_dev - > mode = = MODE_SYNTH ) {
wf_mpu_input_scanner ( input_dev - > devno ,
input_dev - > synthno , c ) ;
} else if ( input_dev - > opened & OPEN_READ ) {
if ( input_dev - > inputintr ) {
input_dev - > inputintr ( input_dev - > devno , c ) ;
}
}
} while ( input_avail ( ) & & n - - > 0 ) ;
mi - > m_busy = 0 ;
spin_unlock ( & lock ) ;
return IRQ_HANDLED ;
}
static int
wf_mpu_open ( int dev , int mode ,
void ( * input ) ( int dev , unsigned char data ) ,
void ( * output ) ( int dev )
)
{
struct wf_mpu_config * devc ;
if ( dev < 0 | | dev > = num_midis | | midi_devs [ dev ] = = NULL )
return - ( ENXIO ) ;
if ( phys_dev - > devno = = dev ) {
devc = phys_dev ;
} else if ( phys_dev - > isvirtual & & virt_dev - > devno = = dev ) {
devc = virt_dev ;
} else {
printk ( KERN_ERR " WF-MPU: unknown device number %d \n " , dev ) ;
return - ( EINVAL ) ;
}
if ( devc - > opened ) {
return - ( EBUSY ) ;
}
devc - > mode = MODE_MIDI ;
devc - > opened = mode ;
devc - > synthno = 0 ;
devc - > inputintr = input ;
return 0 ;
}
static void
wf_mpu_close ( int dev )
{
struct wf_mpu_config * devc ;
if ( dev < 0 | | dev > = num_midis | | midi_devs [ dev ] = = NULL )
return ;
if ( phys_dev - > devno = = dev ) {
devc = phys_dev ;
} else if ( phys_dev - > isvirtual & & virt_dev - > devno = = dev ) {
devc = virt_dev ;
} else {
printk ( KERN_ERR " WF-MPU: unknown device number %d \n " , dev ) ;
return ;
}
devc - > mode = 0 ;
devc - > inputintr = NULL ;
devc - > opened = 0 ;
}
static int
wf_mpu_out ( int dev , unsigned char midi_byte )
{
int timeout ;
unsigned long flags ;
static int lastoutdev = - 1 ;
unsigned char switchch ;
if ( phys_dev - > isvirtual & & lastoutdev ! = dev ) {
if ( dev = = phys_dev - > devno ) {
switchch = WF_INTERNAL_SWITCH ;
} else if ( dev = = virt_dev - > devno ) {
switchch = WF_EXTERNAL_SWITCH ;
} else {
printk ( KERN_ERR " WF-MPU: bad device number %d " , dev ) ;
return ( 0 ) ;
}
/* XXX fix me */
for ( timeout = 30000 ; timeout > 0 & & ! output_ready ( ) ;
timeout - - ) ;
spin_lock_irqsave ( & lock , flags ) ;
if ( ! output_ready ( ) ) {
printk ( KERN_WARNING " WF-MPU: Send switch "
" byte timeout \n " ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
return 0 ;
}
write_data ( switchch ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
}
lastoutdev = dev ;
/*
* Sometimes it takes about 30000 loops before the output becomes ready
* ( After reset ) . Normally it takes just about 10 loops .
*/
/* XXX fix me */
for ( timeout = 30000 ; timeout > 0 & & ! output_ready ( ) ; timeout - - ) ;
spin_lock_irqsave ( & lock , flags ) ;
if ( ! output_ready ( ) ) {
spin_unlock_irqrestore ( & lock , flags ) ;
printk ( KERN_WARNING " WF-MPU: Send data timeout \n " ) ;
return 0 ;
}
write_data ( midi_byte ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
return 1 ;
}
static inline int wf_mpu_start_read ( int dev ) {
return 0 ;
}
static inline int wf_mpu_end_read ( int dev ) {
return 0 ;
}
static int wf_mpu_ioctl ( int dev , unsigned cmd , void __user * arg )
{
printk ( KERN_WARNING
" WF-MPU: Intelligent mode not supported by hardware. \n " ) ;
return - ( EINVAL ) ;
}
static int wf_mpu_buffer_status ( int dev )
{
return 0 ;
}
static struct synth_operations wf_mpu_synth_operations [ 2 ] ;
static struct midi_operations wf_mpu_midi_operations [ 2 ] ;
static struct midi_operations wf_mpu_midi_proto =
{
. owner = THIS_MODULE ,
. info = { " WF-MPU MIDI " , 0 , MIDI_CAP_MPU401 , SNDCARD_MPU401 } ,
. in_info = { 0 } , /* in_info */
. open = wf_mpu_open ,
. close = wf_mpu_close ,
. ioctl = wf_mpu_ioctl ,
. outputc = wf_mpu_out ,
. start_read = wf_mpu_start_read ,
. end_read = wf_mpu_end_read ,
. buffer_status = wf_mpu_buffer_status ,
} ;
static struct synth_info wf_mpu_synth_info_proto =
{ " WaveFront MPU-401 interface " , 0 ,
SYNTH_TYPE_MIDI , MIDI_TYPE_MPU401 , 0 , 128 , 0 , 128 , SYNTH_CAP_INPUT } ;
static struct synth_info wf_mpu_synth_info [ 2 ] ;
static int
wf_mpu_synth_ioctl ( int dev , unsigned int cmd , void __user * arg )
{
int midi_dev ;
int index ;
midi_dev = synth_devs [ dev ] - > midi_dev ;
if ( midi_dev < 0 | | midi_dev > num_midis | | midi_devs [ midi_dev ] = = NULL )
return - ( ENXIO ) ;
if ( midi_dev = = phys_dev - > devno ) {
index = 0 ;
} else if ( phys_dev - > isvirtual & & midi_dev = = virt_dev - > devno ) {
index = 1 ;
} else {
return - ( EINVAL ) ;
}
switch ( cmd ) {
case SNDCTL_SYNTH_INFO :
if ( copy_to_user ( arg ,
& wf_mpu_synth_info [ index ] ,
sizeof ( struct synth_info ) ) )
return - EFAULT ;
return 0 ;
case SNDCTL_SYNTH_MEMAVL :
return 0x7fffffff ;
default :
return - EINVAL ;
}
}
static int
wf_mpu_synth_open ( int dev , int mode )
{
int midi_dev ;
struct wf_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 ) ;
}
if ( phys_dev - > devno = = midi_dev ) {
devc = phys_dev ;
} else if ( phys_dev - > isvirtual & & virt_dev - > devno = = midi_dev ) {
devc = virt_dev ;
} else {
printk ( KERN_ERR " WF-MPU: unknown device number %d \n " , dev ) ;
return - ( EINVAL ) ;
}
if ( devc - > opened ) {
return - ( EBUSY ) ;
}
devc - > mode = MODE_SYNTH ;
devc - > synthno = dev ;
devc - > opened = mode ;
devc - > inputintr = NULL ;
return 0 ;
}
static void
wf_mpu_synth_close ( int dev )
{
int midi_dev ;
struct wf_mpu_config * devc ;
midi_dev = synth_devs [ dev ] - > midi_dev ;
if ( phys_dev - > devno = = midi_dev ) {
devc = phys_dev ;
} else if ( phys_dev - > isvirtual & & virt_dev - > devno = = midi_dev ) {
devc = virt_dev ;
} else {
printk ( KERN_ERR " WF-MPU: unknown device number %d \n " , dev ) ;
return ;
}
devc - > inputintr = NULL ;
devc - > opened = 0 ;
devc - > mode = 0 ;
}
# define _MIDI_SYNTH_C_
# define MIDI_SYNTH_NAME "WaveFront (MIDI)"
# define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
# include "midi_synth.h"
static struct synth_operations wf_mpu_synth_proto =
{
. owner = THIS_MODULE ,
. id = " WaveFront (ICS2115) " ,
. info = NULL , /* info field, filled in during configuration */
. midi_dev = 0 , /* MIDI dev XXX should this be -1 ? */
. synth_type = SYNTH_TYPE_MIDI ,
. synth_subtype = SAMPLE_TYPE_WAVEFRONT ,
. open = wf_mpu_synth_open ,
. close = wf_mpu_synth_close ,
. ioctl = wf_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 int
config_wf_mpu ( struct wf_mpu_config * dev )
{
int is_external ;
char * name ;
int index ;
if ( dev = = phys_dev ) {
name = " WaveFront internal MIDI " ;
is_external = 0 ;
index = 0 ;
memcpy ( ( char * ) & wf_mpu_synth_operations [ index ] ,
( char * ) & wf_mpu_synth_proto ,
sizeof ( struct synth_operations ) ) ;
} else {
name = " WaveFront external MIDI " ;
is_external = 1 ;
index = 1 ;
/* no synth operations for an external MIDI interface */
}
memcpy ( ( char * ) & wf_mpu_synth_info [ dev - > devno ] ,
( char * ) & wf_mpu_synth_info_proto ,
sizeof ( struct synth_info ) ) ;
strcpy ( wf_mpu_synth_info [ index ] . name , name ) ;
wf_mpu_synth_operations [ index ] . midi_dev = dev - > devno ;
wf_mpu_synth_operations [ index ] . info = & wf_mpu_synth_info [ index ] ;
memcpy ( ( char * ) & wf_mpu_midi_operations [ index ] ,
( char * ) & wf_mpu_midi_proto ,
sizeof ( struct midi_operations ) ) ;
if ( is_external ) {
wf_mpu_midi_operations [ index ] . converter = NULL ;
} else {
wf_mpu_midi_operations [ index ] . converter =
& wf_mpu_synth_operations [ index ] ;
}
strcpy ( wf_mpu_midi_operations [ index ] . info . name , name ) ;
midi_devs [ dev - > devno ] = & wf_mpu_midi_operations [ index ] ;
midi_devs [ dev - > devno ] - > in_info . m_busy = 0 ;
midi_devs [ dev - > devno ] - > in_info . m_state = MST_INIT ;
midi_devs [ dev - > devno ] - > in_info . m_ptr = 0 ;
midi_devs [ dev - > devno ] - > in_info . m_left = 0 ;
midi_devs [ dev - > devno ] - > in_info . m_prev_status = 0 ;
devs [ index ] . opened = 0 ;
devs [ index ] . mode = 0 ;
return ( 0 ) ;
}
int virtual_midi_enable ( void )
{
if ( ( virt_dev - > devno < 0 ) & &
( virt_dev - > devno = sound_alloc_mididev ( ) ) = = - 1 ) {
printk ( KERN_ERR
" WF-MPU: too many midi devices detected \n " ) ;
return - 1 ;
}
config_wf_mpu ( virt_dev ) ;
phys_dev - > isvirtual = 1 ;
return virt_dev - > devno ;
}
int
virtual_midi_disable ( void )
{
unsigned long flags ;
spin_lock_irqsave ( & lock , flags ) ;
wf_mpu_close ( virt_dev - > devno ) ;
/* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
phys_dev - > isvirtual = 0 ;
spin_unlock_irqrestore ( & lock , flags ) ;
return 0 ;
}
int __init detect_wf_mpu ( int irq , int io_base )
{
if ( ! request_region ( io_base , 2 , " wavefront midi " ) ) {
printk ( KERN_WARNING " WF-MPU: I/O port %x already in use. \n " ,
io_base ) ;
return - 1 ;
}
phys_dev - > base = io_base ;
phys_dev - > irq = irq ;
phys_dev - > devno = - 1 ;
virt_dev - > devno = - 1 ;
return 0 ;
}
int __init install_wf_mpu ( void )
{
if ( ( phys_dev - > devno = sound_alloc_mididev ( ) ) < 0 ) {
printk ( KERN_ERR " WF-MPU: Too many MIDI devices detected. \n " ) ;
release_region ( phys_dev - > base , 2 ) ;
return - 1 ;
}
phys_dev - > isvirtual = 0 ;
if ( config_wf_mpu ( phys_dev ) ) {
printk ( KERN_WARNING
" WF-MPU: configuration for MIDI device %d failed \n " ,
phys_dev - > devno ) ;
sound_unload_mididev ( phys_dev - > devno ) ;
}
/* OK, now we're configured to handle an interrupt ... */
2006-07-01 19:29:46 -07:00
if ( request_irq ( phys_dev - > irq , wf_mpuintr , IRQF_DISABLED | IRQF_SHARED ,
2005-04-16 15:20:36 -07:00
" wavefront midi " , phys_dev ) < 0 ) {
printk ( KERN_ERR " WF-MPU: Failed to allocate IRQ%d \n " ,
phys_dev - > irq ) ;
return - 1 ;
}
/* This being a WaveFront (ICS-2115) emulated MPU-401, we have
to switch it into UART ( dumb ) mode , because otherwise , it
won ' t do anything at all .
*/
start_uart_mode ( ) ;
return phys_dev - > devno ;
}
void
uninstall_wf_mpu ( void )
{
release_region ( phys_dev - > base , 2 ) ;
free_irq ( phys_dev - > irq , phys_dev ) ;
sound_unload_mididev ( phys_dev - > devno ) ;
if ( virt_dev - > devno > = 0 ) {
sound_unload_mididev ( virt_dev - > devno ) ;
}
}
static void
start_uart_mode ( void )
{
int ok , i ;
unsigned long flags ;
spin_lock_irqsave ( & lock , flags ) ;
/* XXX fix me */
for ( i = 0 ; i < 30000 & & ! output_ready ( ) ; i + + ) ;
outb ( UART_MODE_ON , COMDPORT ( phys_dev ) ) ;
for ( ok = 0 , i = 50000 ; i > 0 & & ! ok ; i - - ) {
if ( input_avail ( ) ) {
if ( read_data ( ) = = MPU_ACK ) {
ok = 1 ;
}
}
}
spin_unlock_irqrestore ( & lock , flags ) ;
}
# endif