2005-04-17 02:20:36 +04:00
/*
* sound / uart6850 . c
*
*
* 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 .
* Extended by Alan Cox for Red Hat Software . Now a loadable MIDI driver .
* 28 / 4 / 97 - ( C ) Copyright Alan Cox . Released under the GPL version 2.
*
* Alan Cox : Updated for new modular code . Removed snd_ * irq handling . Now
* uses native linux resources
* Christoph Hellwig : Adapted to module_init / module_exit
* Jeff Garzik : Made it work again , in theory
* FIXME : If the request_irq ( ) succeeds , the probe succeeds . Ug .
*
* Status : Testing required ( no shit - jgarzik )
*
*
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/spinlock.h>
/* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
* added 6850 support , used with COVOX SoundMaster II and custom cards .
*/
# include "sound_config.h"
static int uart6850_base = 0x330 ;
static int * uart6850_osp ;
# define DATAPORT (uart6850_base)
# define COMDPORT (uart6850_base+1)
# define STATPORT (uart6850_base+1)
static int uart6850_status ( void )
{
return inb ( STATPORT ) ;
}
# define input_avail() (uart6850_status()&INPUT_AVAIL)
# define output_ready() (uart6850_status()&OUTPUT_READY)
static void uart6850_cmd ( unsigned char cmd )
{
outb ( cmd , COMDPORT ) ;
}
static int uart6850_read ( void )
{
return inb ( DATAPORT ) ;
}
static void uart6850_write ( unsigned char byte )
{
outb ( byte , DATAPORT ) ;
}
# define OUTPUT_READY 0x02 /* Mask for data ready Bit */
# define INPUT_AVAIL 0x01 /* Mask for Data Send Ready Bit */
# define UART_RESET 0x95
# define UART_MODE_ON 0x03
static int uart6850_opened ;
static int uart6850_irq ;
static int uart6850_detected ;
static int my_dev ;
static DEFINE_SPINLOCK ( lock ) ;
static void ( * midi_input_intr ) ( int dev , unsigned char data ) ;
static void poll_uart6850 ( unsigned long dummy ) ;
2005-09-10 00:10:40 +04:00
static DEFINE_TIMER ( uart6850_timer , poll_uart6850 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
static void uart6850_input_loop ( void )
{
int count = 10 ;
while ( count )
{
/*
* Not timed out
*/
if ( input_avail ( ) )
{
unsigned char c = uart6850_read ( ) ;
count = 100 ;
if ( uart6850_opened & OPEN_READ )
midi_input_intr ( my_dev , c ) ;
}
else
{
while ( ! input_avail ( ) & & count )
count - - ;
}
}
}
static irqreturn_t m6850intr ( int irq , void * dev_id , struct pt_regs * dummy )
{
if ( input_avail ( ) )
uart6850_input_loop ( ) ;
return IRQ_HANDLED ;
}
/*
* It looks like there is no input interrupts in the UART mode . Let ' s try
* polling .
*/
static void poll_uart6850 ( unsigned long dummy )
{
unsigned long flags ;
if ( ! ( uart6850_opened & OPEN_READ ) )
return ; /* Device has been closed */
spin_lock_irqsave ( & lock , flags ) ;
if ( input_avail ( ) )
uart6850_input_loop ( ) ;
uart6850_timer . expires = 1 + jiffies ;
add_timer ( & uart6850_timer ) ;
/*
* Come back later
*/
spin_unlock_irqrestore ( & lock , flags ) ;
}
static int uart6850_open ( int dev , int mode ,
void ( * input ) ( int dev , unsigned char data ) ,
void ( * output ) ( int dev )
)
{
if ( uart6850_opened )
{
/* printk("Midi6850: Midi busy\n");*/
return - EBUSY ;
} ;
uart6850_cmd ( UART_RESET ) ;
uart6850_input_loop ( ) ;
midi_input_intr = input ;
uart6850_opened = mode ;
poll_uart6850 ( 0 ) ; /*
* Enable input polling
*/
return 0 ;
}
static void uart6850_close ( int dev )
{
uart6850_cmd ( UART_MODE_ON ) ;
del_timer ( & uart6850_timer ) ;
uart6850_opened = 0 ;
}
static int uart6850_out ( int dev , unsigned char midi_byte )
{
int timeout ;
unsigned long flags ;
/*
* Test for input since pending input seems to block the output .
*/
spin_lock_irqsave ( & lock , flags ) ;
if ( input_avail ( ) )
uart6850_input_loop ( ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
/*
* Sometimes it takes about 13000 loops before the output becomes ready
* ( After reset ) . Normally it takes just about 10 loops .
*/
for ( timeout = 30000 ; timeout > 0 & & ! output_ready ( ) ; timeout - - ) ; /*
* Wait
*/
if ( ! output_ready ( ) )
{
printk ( KERN_WARNING " Midi6850: Timeout \n " ) ;
return 0 ;
}
uart6850_write ( midi_byte ) ;
return 1 ;
}
static inline int uart6850_command ( int dev , unsigned char * midi_byte )
{
return 1 ;
}
static inline int uart6850_start_read ( int dev )
{
return 0 ;
}
static inline int uart6850_end_read ( int dev )
{
return 0 ;
}
static inline void uart6850_kick ( int dev )
{
}
static inline int uart6850_buffer_status ( int dev )
{
return 0 ; /*
* No data in buffers
*/
}
# define MIDI_SYNTH_NAME "6850 UART Midi"
# define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
# include "midi_synth.h"
static struct midi_operations uart6850_operations =
{
. owner = THIS_MODULE ,
. info = { " 6850 UART " , 0 , 0 , SNDCARD_UART6850 } ,
. converter = & std_midi_synth ,
. in_info = { 0 } ,
. open = uart6850_open ,
. close = uart6850_close ,
. outputc = uart6850_out ,
. start_read = uart6850_start_read ,
. end_read = uart6850_end_read ,
. kick = uart6850_kick ,
. command = uart6850_command ,
. buffer_status = uart6850_buffer_status
} ;
static void __init attach_uart6850 ( struct address_info * hw_config )
{
int ok , timeout ;
unsigned long flags ;
if ( ! uart6850_detected )
return ;
if ( ( my_dev = sound_alloc_mididev ( ) ) = = - 1 )
{
printk ( KERN_INFO " uart6850: Too many midi devices detected \n " ) ;
return ;
}
uart6850_base = hw_config - > io_base ;
uart6850_osp = hw_config - > osp ;
uart6850_irq = hw_config - > irq ;
spin_lock_irqsave ( & lock , flags ) ;
for ( timeout = 30000 ; timeout > 0 & & ! output_ready ( ) ; timeout - - ) ; /*
* Wait
*/
uart6850_cmd ( UART_MODE_ON ) ;
ok = 1 ;
spin_unlock_irqrestore ( & lock , flags ) ;
conf_printf ( " 6850 Midi Interface " , hw_config ) ;
std_midi_synth . midi_dev = my_dev ;
hw_config - > slots [ 4 ] = my_dev ;
midi_devs [ my_dev ] = & uart6850_operations ;
sequencer_init ( ) ;
}
static inline int reset_uart6850 ( void )
{
uart6850_read ( ) ;
return 1 ; /*
* OK
*/
}
static int __init probe_uart6850 ( struct address_info * hw_config )
{
int ok ;
uart6850_osp = hw_config - > osp ;
uart6850_base = hw_config - > io_base ;
uart6850_irq = hw_config - > irq ;
if ( request_irq ( uart6850_irq , m6850intr , 0 , " MIDI6850 " , NULL ) < 0 )
return 0 ;
ok = reset_uart6850 ( ) ;
uart6850_detected = ok ;
return ok ;
}
static void __exit unload_uart6850 ( struct address_info * hw_config )
{
free_irq ( hw_config - > irq , NULL ) ;
sound_unload_mididev ( hw_config - > slots [ 4 ] ) ;
}
static struct address_info cfg_mpu ;
static int __initdata io = - 1 ;
static int __initdata irq = - 1 ;
module_param ( io , int , 0 ) ;
module_param ( irq , int , 0 ) ;
static int __init init_uart6850 ( void )
{
cfg_mpu . io_base = io ;
cfg_mpu . irq = irq ;
if ( cfg_mpu . io_base = = - 1 | | cfg_mpu . irq = = - 1 ) {
printk ( KERN_INFO " uart6850: irq and io must be set. \n " ) ;
return - EINVAL ;
}
if ( probe_uart6850 ( & cfg_mpu ) )
return - ENODEV ;
attach_uart6850 ( & cfg_mpu ) ;
return 0 ;
}
static void __exit cleanup_uart6850 ( void )
{
unload_uart6850 ( & cfg_mpu ) ;
}
module_init ( init_uart6850 ) ;
module_exit ( cleanup_uart6850 ) ;
# ifndef MODULE
static int __init setup_uart6850 ( char * str )
{
/* io, irq */
int ints [ 3 ] ;
str = get_options ( str , ARRAY_SIZE ( ints ) , ints ) ;
io = ints [ 1 ] ;
irq = ints [ 2 ] ;
return 1 ;
}
__setup ( " uart6850= " , setup_uart6850 ) ;
# endif
MODULE_LICENSE ( " GPL " ) ;