@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
spin_lock_init ( & card - > files_lock ) ;
INIT_LIST_HEAD ( & card - > files_list ) ;
init_waitqueue_head ( & card - > shutdown_sleep ) ;
atomic_set ( & card - > refcount , 0 ) ;
# ifdef CONFIG_PM
mutex_init ( & card - > power_lock ) ;
init_waitqueue_head ( & card - > power_sleep ) ;
@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
return 0 ;
}
/**
* snd_card_unref - release the reference counter
* @ card : the card instance
*
* Decrements the reference counter . When it reaches to zero , wake up
* the sleeper and call the destructor if needed .
*/
void snd_card_unref ( struct snd_card * card )
{
if ( atomic_dec_and_test ( & card - > refcount ) ) {
wake_up ( & card - > shutdown_sleep ) ;
if ( card - > free_on_last_close )
snd_card_do_free ( card ) ;
}
}
EXPORT_SYMBOL ( snd_card_unref ) ;
int snd_card_free_when_closed ( struct snd_card * card )
{
int free_now = 0 ;
int ret = snd_card_disconnect ( card ) ;
if ( ret )
return ret ;
int ret ;
spin_lock ( & card - > files_lock ) ;
if ( list_empty ( & card - > files_list ) )
free_now = 1 ;
else
card - > free_on_last_close = 1 ;
spin_unlock ( & card - > files_lock ) ;
atomic_inc ( & card - > refcount ) ;
ret = snd_card_disconnect ( card ) ;
if ( ret ) {
atomic_dec ( & card - > refcount ) ;
return ret ;
}
if ( free_now )
card - > free_on_last_close = 1 ;
if ( atomic_dec_and_test ( & card - > refcount ) )
snd_card_do_free ( card ) ;
return 0 ;
}
@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
return ret ;
/* wait, until all devices are ready for the free operation */
wait_event ( card - > shutdown_sleep , list_empty ( & card - > files_lis t) ) ;
wait_event ( card - > shutdown_sleep , ! atomic_read ( & card - > refcoun t) ) ;
snd_card_do_free ( card ) ;
return 0 ;
}
@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return - ENODEV ;
}
list_add ( & mfile - > list , & card - > files_list ) ;
atomic_inc ( & card - > refcount ) ;
spin_unlock ( & card - > files_lock ) ;
return 0 ;
}
@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
int snd_card_file_remove ( struct snd_card * card , struct file * file )
{
struct snd_monitor_file * mfile , * found = NULL ;
int last_close = 0 ;
spin_lock ( & card - > files_lock ) ;
list_for_each_entry ( mfile , & card - > files_list , list ) {
@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
break ;
}
}
if ( list_empty ( & card - > files_list ) )
last_close = 1 ;
spin_unlock ( & card - > files_lock ) ;
if ( last_close ) {
wake_up ( & card - > shutdown_sleep ) ;
if ( card - > free_on_last_close )
snd_card_do_free ( card ) ;
}
if ( ! found ) {
snd_printk ( KERN_ERR " ALSA card file remove problem (%p) \n " , file ) ;
return - ENOENT ;
}
kfree ( found ) ;
snd_card_unref ( card ) ;
return 0 ;
}