2005-04-17 02:20:36 +04:00
/*
* Advanced Linux Sound Architecture
2007-10-15 11:50:19 +04:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-17 02:20:36 +04:00
*
*
* 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
*
*/
# 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>
2011-09-22 17:34:58 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/time.h>
# include <sound/core.h>
# include <sound/minors.h>
# include <sound/info.h>
# include <linux/sound.h>
2006-01-16 18:29:08 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
2012-05-08 19:25:56 +04:00
# define SNDRV_OSS_MINORS 256
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 ] ;
2006-01-16 18:29:08 +03:00
static DEFINE_MUTEX ( sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
2012-10-16 15:05:59 +04:00
/* NOTE: This function increments the refcount of the associated card like
* snd_lookup_minor_data ( ) ; the caller must call snd_card_unref ( ) appropriately
*/
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 ;
2006-03-13 16:14:10 +03:00
if ( minor > = ARRAY_SIZE ( snd_oss_minors ) )
2005-11-20 16:06:59 +03:00
return NULL ;
2006-01-16 18:29:08 +03:00
mutex_lock ( & sound_oss_mutex ) ;
2005-11-20 16:06:59 +03:00
mreg = snd_oss_minors [ minor ] ;
2012-10-16 15:05:59 +04:00
if ( mreg & & mreg - > type = = type ) {
2005-11-20 16:06:59 +03:00
private_data = mreg - > private_data ;
2012-11-08 17:36:18 +04:00
if ( private_data & & mreg - > card_ptr )
2012-10-16 15:05:59 +04:00
atomic_inc ( & mreg - > card_ptr - > refcount ) ;
} else
2005-11-20 16:06:59 +03:00
private_data = NULL ;
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-11-20 16:06:59 +03:00
return private_data ;
}
2006-04-28 17:13:39 +04:00
EXPORT_SYMBOL ( snd_lookup_oss_minor_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 :
2008-08-08 19:09:09 +04:00
if ( snd_BUG_ON ( ! card | | dev < 0 | | dev > 1 ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
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 :
2008-08-08 19:09:09 +04:00
if ( snd_BUG_ON ( ! card | | dev < 0 | | dev > 1 ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
minor = SNDRV_MINOR_OSS ( card - > number , ( dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM ) ) ;
break ;
case SNDRV_OSS_DEVICE_TYPE_MIDI :
2008-08-08 19:09:09 +04:00
if ( snd_BUG_ON ( ! card | | dev < 0 | | dev > 1 ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
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 ;
}
2010-01-18 16:16:24 +03:00
if ( minor < 0 | | minor > = SNDRV_OSS_MINORS )
2008-08-08 19:09:09 +04:00
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 ,
2006-03-28 13:56:41 +04:00
const struct file_operations * f_ops , void * private_data ,
2005-11-20 16:06:59 +03:00
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 ;
2007-01-26 14:40:31 +03:00
struct device * carddev = snd_card_get_device_link ( card ) ;
2005-04-17 02:20:36 +04:00
2012-05-08 19:25:56 +04:00
if ( card & & card - > number > = SNDRV_MINOR_OSS_DEVICES )
2005-11-20 16:09:05 +03:00
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 ;
2012-10-16 15:05:59 +04:00
preg - > card_ptr = card ;
2006-01-16 18:29:08 +03:00
mutex_lock ( & 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-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
}
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
kfree ( preg ) ;
return - EBUSY ;
}
2006-04-28 17:13:39 +04:00
EXPORT_SYMBOL ( snd_register_oss_device ) ;
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
2012-05-08 19:25:56 +04:00
if ( card & & card - > number > = SNDRV_MINOR_OSS_DEVICES )
2005-11-20 16:09:05 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( minor < 0 )
return minor ;
2006-01-16 18:29:08 +03:00
mutex_lock ( & 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 ) {
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
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 ;
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
kfree ( mptr ) ;
return 0 ;
}
2006-04-28 17:13:39 +04:00
EXPORT_SYMBOL ( snd_unregister_oss_device ) ;
2005-04-17 02:20:36 +04:00
/*
* INFO PART
*/
# ifdef CONFIG_PROC_FS
2006-05-17 19:14:51 +04:00
static struct snd_info_entry * snd_minor_info_oss_entry ;
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
2006-01-16 18:29:08 +03:00
mutex_lock ( & 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
}
2006-01-16 18:29:08 +03:00
mutex_unlock ( & sound_oss_mutex ) ;
2005-04-17 02:20:36 +04:00
}
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 = 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 )
{
2006-06-23 16:37:59 +04:00
snd_info_free_entry ( snd_minor_info_oss_entry ) ;
2005-04-17 02:20:36 +04:00
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 */