2005-04-17 02:20:36 +04:00
/*
2006-10-04 01:01:26 +04:00
* sound / oss / v_midi . c
2005-04-17 02:20:36 +04:00
*
* The low level driver for the Sound Blaster DS chips .
*
*
* 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 .
* ? ?
*
* Changes
* Alan Cox Modularisation , changed memory allocations
* Christoph Hellwig Adapted to module_init / module_exit
*
* Status
* Untested
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include "sound_config.h"
# include "v_midi.h"
static vmidi_devc * v_devc [ 2 ] = { NULL , NULL } ;
static int midi1 , midi2 ;
static void * midi_mem = NULL ;
/*
* The DSP channel can be used either for input or output . Variable
* ' sb_irq_mode ' will be set when the program calls read or write first time
* after open . Current version doesn ' t support mode changes without closing
* and reopening the device . Support for this feature may be implemented in a
* future version of this driver .
*/
static int v_midi_open ( int dev , int mode ,
void ( * input ) ( int dev , unsigned char data ) ,
void ( * output ) ( int dev )
)
{
vmidi_devc * devc = midi_devs [ dev ] - > devc ;
unsigned long flags ;
if ( devc = = NULL )
return - ( ENXIO ) ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( devc - > opened )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return - ( EBUSY ) ;
}
devc - > opened = 1 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > intr_active = 1 ;
if ( mode & OPEN_READ )
{
devc - > input_opened = 1 ;
devc - > midi_input_intr = input ;
}
return 0 ;
}
static void v_midi_close ( int dev )
{
vmidi_devc * devc = midi_devs [ dev ] - > devc ;
unsigned long flags ;
if ( devc = = NULL )
return ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
devc - > intr_active = 0 ;
devc - > input_opened = 0 ;
devc - > opened = 0 ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
static int v_midi_out ( int dev , unsigned char midi_byte )
{
vmidi_devc * devc = midi_devs [ dev ] - > devc ;
vmidi_devc * pdevc ;
if ( devc = = NULL )
return - ENXIO ;
pdevc = midi_devs [ devc - > pair_mididev ] - > devc ;
if ( pdevc - > input_opened > 0 ) {
if ( MIDIbuf_avail ( pdevc - > my_mididev ) > 500 )
return 0 ;
pdevc - > midi_input_intr ( pdevc - > my_mididev , midi_byte ) ;
}
return 1 ;
}
static inline int v_midi_start_read ( int dev )
{
return 0 ;
}
static int v_midi_end_read ( int dev )
{
vmidi_devc * devc = midi_devs [ dev ] - > devc ;
if ( devc = = NULL )
return - ENXIO ;
devc - > intr_active = 0 ;
return 0 ;
}
/* why -EPERM and not -EINVAL?? */
static inline int v_midi_ioctl ( int dev , unsigned cmd , void __user * arg )
{
return - EPERM ;
}
# define MIDI_SYNTH_NAME "Loopback MIDI"
# define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
# include "midi_synth.h"
static struct midi_operations v_midi_operations =
{
. owner = THIS_MODULE ,
. info = { " Loopback MIDI Port 1 " , 0 , 0 , SNDCARD_VMIDI } ,
. converter = & std_midi_synth ,
. in_info = { 0 } ,
. open = v_midi_open ,
. close = v_midi_close ,
. ioctl = v_midi_ioctl ,
. outputc = v_midi_out ,
. start_read = v_midi_start_read ,
. end_read = v_midi_end_read ,
} ;
static struct midi_operations v_midi_operations2 =
{
. owner = THIS_MODULE ,
. info = { " Loopback MIDI Port 2 " , 0 , 0 , SNDCARD_VMIDI } ,
. converter = & std_midi_synth ,
. in_info = { 0 } ,
. open = v_midi_open ,
. close = v_midi_close ,
. ioctl = v_midi_ioctl ,
. outputc = v_midi_out ,
. start_read = v_midi_start_read ,
. end_read = v_midi_end_read ,
} ;
/*
* We kmalloc just one of these - it makes life simpler and the code
* cleaner and the memory handling far more efficient
*/
struct vmidi_memory
{
/* Must be first */
struct midi_operations m_ops [ 2 ] ;
struct synth_operations s_ops [ 2 ] ;
struct vmidi_devc v_ops [ 2 ] ;
} ;
static void __init attach_v_midi ( struct address_info * hw_config )
{
struct vmidi_memory * m ;
/* printk("Attaching v_midi device.....\n"); */
midi1 = sound_alloc_mididev ( ) ;
if ( midi1 = = - 1 )
{
printk ( KERN_ERR " v_midi: Too many midi devices detected \n " ) ;
return ;
}
2006-12-13 11:35:56 +03:00
m = kmalloc ( sizeof ( struct vmidi_memory ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( m = = NULL )
{
printk ( KERN_WARNING " Loopback MIDI: Failed to allocate memory \n " ) ;
sound_unload_mididev ( midi1 ) ;
return ;
}
midi_mem = m ;
midi_devs [ midi1 ] = & m - > m_ops [ 0 ] ;
midi2 = sound_alloc_mididev ( ) ;
if ( midi2 = = - 1 )
{
printk ( KERN_ERR " v_midi: Too many midi devices detected \n " ) ;
kfree ( m ) ;
sound_unload_mididev ( midi1 ) ;
return ;
}
midi_devs [ midi2 ] = & m - > m_ops [ 1 ] ;
/* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */
/* for MIDI-1 */
v_devc [ 0 ] = & m - > v_ops [ 0 ] ;
memcpy ( ( char * ) midi_devs [ midi1 ] , ( char * ) & v_midi_operations ,
sizeof ( struct midi_operations ) ) ;
v_devc [ 0 ] - > my_mididev = midi1 ;
v_devc [ 0 ] - > pair_mididev = midi2 ;
v_devc [ 0 ] - > opened = v_devc [ 0 ] - > input_opened = 0 ;
v_devc [ 0 ] - > intr_active = 0 ;
v_devc [ 0 ] - > midi_input_intr = NULL ;
spin_lock_init ( & v_devc [ 0 ] - > lock ) ;
midi_devs [ midi1 ] - > devc = v_devc [ 0 ] ;
midi_devs [ midi1 ] - > converter = & m - > s_ops [ 0 ] ;
std_midi_synth . midi_dev = midi1 ;
memcpy ( ( char * ) midi_devs [ midi1 ] - > converter , ( char * ) & std_midi_synth ,
sizeof ( struct synth_operations ) ) ;
midi_devs [ midi1 ] - > converter - > id = " V_MIDI 1 " ;
/* for MIDI-2 */
v_devc [ 1 ] = & m - > v_ops [ 1 ] ;
memcpy ( ( char * ) midi_devs [ midi2 ] , ( char * ) & v_midi_operations2 ,
sizeof ( struct midi_operations ) ) ;
v_devc [ 1 ] - > my_mididev = midi2 ;
v_devc [ 1 ] - > pair_mididev = midi1 ;
v_devc [ 1 ] - > opened = v_devc [ 1 ] - > input_opened = 0 ;
v_devc [ 1 ] - > intr_active = 0 ;
v_devc [ 1 ] - > midi_input_intr = NULL ;
spin_lock_init ( & v_devc [ 1 ] - > lock ) ;
midi_devs [ midi2 ] - > devc = v_devc [ 1 ] ;
midi_devs [ midi2 ] - > converter = & m - > s_ops [ 1 ] ;
std_midi_synth . midi_dev = midi2 ;
memcpy ( ( char * ) midi_devs [ midi2 ] - > converter , ( char * ) & std_midi_synth ,
sizeof ( struct synth_operations ) ) ;
midi_devs [ midi2 ] - > converter - > id = " V_MIDI 2 " ;
sequencer_init ( ) ;
/* printk("Attached v_midi device\n"); */
}
static inline int __init probe_v_midi ( struct address_info * hw_config )
{
return ( 1 ) ; /* always OK */
}
static void __exit unload_v_midi ( struct address_info * hw_config )
{
sound_unload_mididev ( midi1 ) ;
sound_unload_mididev ( midi2 ) ;
kfree ( midi_mem ) ;
}
static struct address_info cfg ; /* dummy */
static int __init init_vmidi ( void )
{
printk ( " MIDI Loopback device driver \n " ) ;
if ( ! probe_v_midi ( & cfg ) )
return - ENODEV ;
attach_v_midi ( & cfg ) ;
return 0 ;
}
static void __exit cleanup_vmidi ( void )
{
unload_v_midi ( & cfg ) ;
}
module_init ( init_vmidi ) ;
module_exit ( cleanup_vmidi ) ;
MODULE_LICENSE ( " GPL " ) ;