2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
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
*/
# 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 )
2014-01-29 15:13:43 +04:00
get_device ( & mreg - > card_ptr - > card_dev ) ;
2012-10-16 15:05:59 +04:00
} 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 ,
2014-02-04 16:51:45 +04:00
const struct file_operations * f_ops , void * private_data )
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 ;
}
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 ;
}
2022-10-11 10:01:47 +03:00
if ( track2 > = 0 )
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 ) ;
2022-10-11 10:01:47 +03:00
/* call unregister_sound_special() outside sound_oss_mutex;
* otherwise may deadlock , as it can trigger the release of a card
*/
unregister_sound_special ( minor ) ;
if ( track2 > = 0 )
unregister_sound_special ( track2 ) ;
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
*/
2015-05-27 14:45:45 +03:00
# ifdef CONFIG_SND_PROC_FS
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 ) {
2021-06-08 17:05:27 +03:00
mptr = snd_oss_minors [ minor ] ;
if ( ! mptr )
2005-11-20 16:05:49 +03:00
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 ) ;
2015-04-22 23:29:10 +03:00
if ( ! entry )
return - ENOMEM ;
entry - > c . text . read = snd_minor_info_oss_read ;
return snd_info_register ( entry ) ; /* freed in error path */
2005-04-17 02:20:36 +04:00
}
2015-05-27 14:45:45 +03:00
# endif /* CONFIG_SND_PROC_FS */