@@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
213213 spin_lock_init (& card -> files_lock );
214214 INIT_LIST_HEAD (& card -> files_list );
215215 init_waitqueue_head (& card -> shutdown_sleep );
216+ atomic_set (& card -> refcount , 0 );
216217#ifdef CONFIG_PM
217218 mutex_init (& card -> power_lock );
218219 init_waitqueue_head (& card -> power_sleep );
@@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
446447 return 0 ;
447448}
448449
450+ /**
451+ * snd_card_unref - release the reference counter
452+ * @card: the card instance
453+ *
454+ * Decrements the reference counter. When it reaches to zero, wake up
455+ * the sleeper and call the destructor if needed.
456+ */
457+ void snd_card_unref (struct snd_card * card )
458+ {
459+ if (atomic_dec_and_test (& card -> refcount )) {
460+ wake_up (& card -> shutdown_sleep );
461+ if (card -> free_on_last_close )
462+ snd_card_do_free (card );
463+ }
464+ }
465+ EXPORT_SYMBOL (snd_card_unref );
466+
449467int snd_card_free_when_closed (struct snd_card * card )
450468{
451- int free_now = 0 ;
452- int ret = snd_card_disconnect (card );
453- if (ret )
454- return ret ;
469+ int ret ;
455470
456- spin_lock (& card -> files_lock );
457- if ( list_empty ( & card -> files_list ))
458- free_now = 1 ;
459- else
460- card -> free_on_last_close = 1 ;
461- spin_unlock ( & card -> files_lock );
471+ atomic_inc (& card -> refcount );
472+ ret = snd_card_disconnect ( card );
473+ if ( ret ) {
474+ atomic_dec ( & card -> refcount );
475+ return ret ;
476+ }
462477
463- if (free_now )
478+ card -> free_on_last_close = 1 ;
479+ if (atomic_dec_and_test (& card -> refcount ))
464480 snd_card_do_free (card );
465481 return 0 ;
466482}
@@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
474490 return ret ;
475491
476492 /* wait, until all devices are ready for the free operation */
477- wait_event (card -> shutdown_sleep , list_empty (& card -> files_list ));
493+ wait_event (card -> shutdown_sleep , ! atomic_read (& card -> refcount ));
478494 snd_card_do_free (card );
479495 return 0 ;
480496}
@@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
886902 return - ENODEV ;
887903 }
888904 list_add (& mfile -> list , & card -> files_list );
905+ atomic_inc (& card -> refcount );
889906 spin_unlock (& card -> files_lock );
890907 return 0 ;
891908}
@@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
908925int snd_card_file_remove (struct snd_card * card , struct file * file )
909926{
910927 struct snd_monitor_file * mfile , * found = NULL ;
911- int last_close = 0 ;
912928
913929 spin_lock (& card -> files_lock );
914930 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)
923939 break ;
924940 }
925941 }
926- if (list_empty (& card -> files_list ))
927- last_close = 1 ;
928942 spin_unlock (& card -> files_lock );
929- if (last_close ) {
930- wake_up (& card -> shutdown_sleep );
931- if (card -> free_on_last_close )
932- snd_card_do_free (card );
933- }
934943 if (!found ) {
935944 snd_printk (KERN_ERR "ALSA card file remove problem (%p)\n" , file );
936945 return - ENOENT ;
937946 }
938947 kfree (found );
948+ snd_card_unref (card );
939949 return 0 ;
940950}
941951
0 commit comments