2005-04-17 02:20:36 +04:00
/*
* Advanced Linux Sound Architecture
* Copyright ( c ) by Jaroslav Kysela < perex @ suse . cz >
*
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <sound/driver.h>
# ifdef CONFIG_SND_OSSEMUL
# if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
# error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
# endif
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/time.h>
# include <sound/core.h>
# include <sound/minors.h>
# include <sound/info.h>
# include <linux/sound.h>
2005-11-20 16:05:49 +03:00
# define SNDRV_OSS_MINORS 128
2005-04-17 02:20:36 +04:00
2005-11-20 16:05:49 +03:00
static struct snd_minor * snd_oss_minors [ SNDRV_OSS_MINORS ] ;
2005-04-17 02:20:36 +04:00
static DECLARE_MUTEX ( sound_oss_mutex ) ;
2005-11-20 16:06:59 +03:00
void * snd_lookup_oss_minor_data ( unsigned int minor , int type )
{
struct snd_minor * mreg ;
void * private_data ;
if ( minor > ARRAY_SIZE ( snd_oss_minors ) )
return NULL ;
down ( & sound_oss_mutex ) ;
mreg = snd_oss_minors [ minor ] ;
if ( mreg & & mreg - > type = = type )
private_data = mreg - > private_data ;
else
private_data = NULL ;
up ( & sound_oss_mutex ) ;
return private_data ;
}
2005-11-17 16:00:19 +03:00
static int snd_oss_kernel_minor ( int type , struct snd_card * card , int dev )
2005-04-17 02:20:36 +04:00
{
int minor ;
switch ( type ) {
case SNDRV_OSS_DEVICE_TYPE_MIXER :
snd_assert ( card ! = NULL & & dev < = 1 , return - EINVAL ) ;
minor = SNDRV_MINOR_OSS ( card - > number , ( dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER ) ) ;
break ;
case SNDRV_OSS_DEVICE_TYPE_SEQUENCER :
minor = SNDRV_MINOR_OSS_SEQUENCER ;
break ;
case SNDRV_OSS_DEVICE_TYPE_MUSIC :
minor = SNDRV_MINOR_OSS_MUSIC ;
break ;
case SNDRV_OSS_DEVICE_TYPE_PCM :
snd_assert ( card ! = NULL & & dev < = 1 , return - EINVAL ) ;
minor = SNDRV_MINOR_OSS ( card - > number , ( dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM ) ) ;
break ;
case SNDRV_OSS_DEVICE_TYPE_MIDI :
snd_assert ( card ! = NULL & & dev < = 1 , return - EINVAL ) ;
minor = SNDRV_MINOR_OSS ( card - > number , ( dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI ) ) ;
break ;
case SNDRV_OSS_DEVICE_TYPE_DMFM :
minor = SNDRV_MINOR_OSS ( card - > number , SNDRV_MINOR_OSS_DMFM ) ;
break ;
case SNDRV_OSS_DEVICE_TYPE_SNDSTAT :
minor = SNDRV_MINOR_OSS_SNDSTAT ;
break ;
default :
return - EINVAL ;
}
2005-11-20 16:05:49 +03:00
snd_assert ( minor > = 0 & & minor < SNDRV_OSS_MINORS , return - EINVAL ) ;
2005-04-17 02:20:36 +04:00
return minor ;
}
2005-11-17 16:00:19 +03:00
int snd_register_oss_device ( int type , struct snd_card * card , int dev ,
2005-11-20 16:06:59 +03:00
struct file_operations * f_ops , void * private_data ,
const char * name )
2005-04-17 02:20:36 +04:00
{
int minor = snd_oss_kernel_minor ( type , card , dev ) ;
int minor_unit ;
2005-11-17 16:00:19 +03:00
struct snd_minor * preg ;
2005-04-17 02:20:36 +04:00
int cidx = SNDRV_MINOR_OSS_CARD ( minor ) ;
int track2 = - 1 ;
int register1 = - 1 , register2 = - 1 ;
2005-08-30 10:58:37 +04:00
struct device * carddev = NULL ;
2005-04-17 02:20:36 +04:00
2005-11-20 16:09:05 +03:00
if ( card & & card - > number > = 8 )
return 0 ; /* ignore silently */
2005-04-17 02:20:36 +04:00
if ( minor < 0 )
return minor ;
2005-11-20 16:05:49 +03:00
preg = kmalloc ( sizeof ( struct snd_minor ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( preg = = NULL )
return - ENOMEM ;
2005-11-20 16:03:48 +03:00
preg - > type = type ;
2005-11-20 16:05:49 +03:00
preg - > card = card ? card - > number : - 1 ;
2005-04-17 02:20:36 +04:00
preg - > device = dev ;
2005-11-20 16:03:48 +03:00
preg - > f_ops = f_ops ;
2005-11-20 16:06:59 +03:00
preg - > private_data = private_data ;
2005-04-17 02:20:36 +04:00
down ( & sound_oss_mutex ) ;
2005-11-20 16:05:49 +03:00
snd_oss_minors [ minor ] = preg ;
2005-04-17 02:20:36 +04:00
minor_unit = SNDRV_MINOR_OSS_DEVICE ( minor ) ;
switch ( minor_unit ) {
case SNDRV_MINOR_OSS_PCM :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_AUDIO ) ;
break ;
case SNDRV_MINOR_OSS_MIDI :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_DMMIDI ) ;
break ;
case SNDRV_MINOR_OSS_MIDI1 :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_DMMIDI1 ) ;
break ;
}
2005-08-30 10:58:37 +04:00
if ( card )
carddev = card - > dev ;
2005-11-20 16:03:48 +03:00
register1 = register_sound_special_device ( f_ops , minor , carddev ) ;
2005-04-17 02:20:36 +04:00
if ( register1 ! = minor )
goto __end ;
if ( track2 > = 0 ) {
2005-11-20 16:03:48 +03:00
register2 = register_sound_special_device ( f_ops , track2 ,
carddev ) ;
2005-04-17 02:20:36 +04:00
if ( register2 ! = track2 )
goto __end ;
2005-11-20 16:06:59 +03:00
snd_oss_minors [ track2 ] = preg ;
2005-04-17 02:20:36 +04:00
}
up ( & sound_oss_mutex ) ;
return 0 ;
__end :
if ( register2 > = 0 )
unregister_sound_special ( register2 ) ;
if ( register1 > = 0 )
unregister_sound_special ( register1 ) ;
2005-11-20 16:05:49 +03:00
snd_oss_minors [ minor ] = NULL ;
2005-04-17 02:20:36 +04:00
up ( & sound_oss_mutex ) ;
kfree ( preg ) ;
return - EBUSY ;
}
2005-11-17 16:00:19 +03:00
int snd_unregister_oss_device ( int type , struct snd_card * card , int dev )
2005-04-17 02:20:36 +04:00
{
int minor = snd_oss_kernel_minor ( type , card , dev ) ;
int cidx = SNDRV_MINOR_OSS_CARD ( minor ) ;
int track2 = - 1 ;
2005-11-17 16:00:19 +03:00
struct snd_minor * mptr ;
2005-04-17 02:20:36 +04:00
2005-11-20 16:09:05 +03:00
if ( card & & card - > number > = 8 )
return 0 ;
2005-04-17 02:20:36 +04:00
if ( minor < 0 )
return minor ;
down ( & sound_oss_mutex ) ;
2005-11-20 16:05:49 +03:00
mptr = snd_oss_minors [ minor ] ;
2005-04-17 02:20:36 +04:00
if ( mptr = = NULL ) {
up ( & sound_oss_mutex ) ;
return - ENOENT ;
}
unregister_sound_special ( minor ) ;
switch ( SNDRV_MINOR_OSS_DEVICE ( minor ) ) {
case SNDRV_MINOR_OSS_PCM :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_AUDIO ) ;
break ;
case SNDRV_MINOR_OSS_MIDI :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_DMMIDI ) ;
break ;
case SNDRV_MINOR_OSS_MIDI1 :
track2 = SNDRV_MINOR_OSS ( cidx , SNDRV_MINOR_OSS_DMMIDI1 ) ;
break ;
}
2005-11-20 16:06:59 +03:00
if ( track2 > = 0 ) {
2005-04-17 02:20:36 +04:00
unregister_sound_special ( track2 ) ;
2005-11-20 16:06:59 +03:00
snd_oss_minors [ track2 ] = NULL ;
}
2005-11-20 16:05:49 +03:00
snd_oss_minors [ minor ] = NULL ;
2005-04-17 02:20:36 +04:00
up ( & sound_oss_mutex ) ;
kfree ( mptr ) ;
return 0 ;
}
/*
* INFO PART
*/
# ifdef CONFIG_PROC_FS
2005-11-17 16:00:19 +03:00
static struct snd_info_entry * snd_minor_info_oss_entry = NULL ;
2005-04-17 02:20:36 +04:00
2005-11-20 16:03:48 +03:00
static const char * snd_oss_device_type_name ( int type )
{
switch ( type ) {
case SNDRV_OSS_DEVICE_TYPE_MIXER :
return " mixer " ;
case SNDRV_OSS_DEVICE_TYPE_SEQUENCER :
case SNDRV_OSS_DEVICE_TYPE_MUSIC :
return " sequencer " ;
case SNDRV_OSS_DEVICE_TYPE_PCM :
return " digital audio " ;
case SNDRV_OSS_DEVICE_TYPE_MIDI :
return " raw midi " ;
case SNDRV_OSS_DEVICE_TYPE_DMFM :
return " hardware dependent " ;
default :
return " ? " ;
}
}
2005-11-17 16:00:19 +03:00
static void snd_minor_info_oss_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-17 02:20:36 +04:00
{
2005-11-20 16:05:49 +03:00
int minor ;
2005-11-17 16:00:19 +03:00
struct snd_minor * mptr ;
2005-04-17 02:20:36 +04:00
down ( & sound_oss_mutex ) ;
2005-11-20 16:05:49 +03:00
for ( minor = 0 ; minor < SNDRV_OSS_MINORS ; + + minor ) {
if ( ! ( mptr = snd_oss_minors [ minor ] ) )
continue ;
if ( mptr - > card > = 0 )
snd_iprintf ( buffer , " %3i: [%i-%2i]: %s \n " , minor ,
mptr - > card , mptr - > device ,
snd_oss_device_type_name ( mptr - > type ) ) ;
else
snd_iprintf ( buffer , " %3i: : %s \n " , minor ,
snd_oss_device_type_name ( mptr - > type ) ) ;
2005-04-17 02:20:36 +04:00
}
up ( & sound_oss_mutex ) ;
}
int __init snd_minor_info_oss_init ( void )
{
2005-11-17 16:00:19 +03:00
struct snd_info_entry * entry ;
2005-04-17 02:20:36 +04:00
entry = snd_info_create_module_entry ( THIS_MODULE , " devices " , snd_oss_root ) ;
if ( entry ) {
entry - > c . text . read_size = PAGE_SIZE ;
entry - > c . text . read = snd_minor_info_oss_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
snd_minor_info_oss_entry = entry ;
return 0 ;
}
int __exit snd_minor_info_oss_done ( void )
{
if ( snd_minor_info_oss_entry )
snd_info_unregister ( snd_minor_info_oss_entry ) ;
return 0 ;
}
2005-12-01 12:42:42 +03:00
# endif /* CONFIG_PROC_FS */
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_SND_OSSEMUL */