aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/init.c')
-rw-r--r--sound/core/init.c50
1 files changed, 30 insertions, 20 deletions
diff --git a/sound/core/init.c b/sound/core/init.c
index d8ec849af128..7b012d15c2cf 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
213 spin_lock_init(&card->files_lock); 213 spin_lock_init(&card->files_lock);
214 INIT_LIST_HEAD(&card->files_list); 214 INIT_LIST_HEAD(&card->files_list);
215 init_waitqueue_head(&card->shutdown_sleep); 215 init_waitqueue_head(&card->shutdown_sleep);
216 atomic_set(&card->refcount, 0);
216#ifdef CONFIG_PM 217#ifdef CONFIG_PM
217 mutex_init(&card->power_lock); 218 mutex_init(&card->power_lock);
218 init_waitqueue_head(&card->power_sleep); 219 init_waitqueue_head(&card->power_sleep);
@@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
446 return 0; 447 return 0;
447} 448}
448 449
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 */
457void 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}
465EXPORT_SYMBOL(snd_card_unref);
466
449int snd_card_free_when_closed(struct snd_card *card) 467int snd_card_free_when_closed(struct snd_card *card)
450{ 468{
451 int free_now = 0; 469 int ret;
452 int ret = snd_card_disconnect(card);
453 if (ret)
454 return ret;
455 470
456 spin_lock(&card->files_lock); 471 atomic_inc(&card->refcount);
457 if (list_empty(&card->files_list)) 472 ret = snd_card_disconnect(card);
458 free_now = 1; 473 if (ret) {
459 else 474 atomic_dec(&card->refcount);
460 card->free_on_last_close = 1; 475 return ret;
461 spin_unlock(&card->files_lock); 476 }
462 477
463 if (free_now) 478 card->free_on_last_close = 1;
479 if (atomic_dec_and_test(&card->refcount))
464 snd_card_do_free(card); 480 snd_card_do_free(card);
465 return 0; 481 return 0;
466} 482}
@@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
474 return ret; 490 return ret;
475 491
476 /* wait, until all devices are ready for the free operation */ 492 /* 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));
478 snd_card_do_free(card); 494 snd_card_do_free(card);
479 return 0; 495 return 0;
480} 496}
@@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
886 return -ENODEV; 902 return -ENODEV;
887 } 903 }
888 list_add(&mfile->list, &card->files_list); 904 list_add(&mfile->list, &card->files_list);
905 atomic_inc(&card->refcount);
889 spin_unlock(&card->files_lock); 906 spin_unlock(&card->files_lock);
890 return 0; 907 return 0;
891} 908}
@@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
908int snd_card_file_remove(struct snd_card *card, struct file *file) 925int snd_card_file_remove(struct snd_card *card, struct file *file)
909{ 926{
910 struct snd_monitor_file *mfile, *found = NULL; 927 struct snd_monitor_file *mfile, *found = NULL;
911 int last_close = 0;
912 928
913 spin_lock(&card->files_lock); 929 spin_lock(&card->files_lock);
914 list_for_each_entry(mfile, &card->files_list, list) { 930 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)
923 break; 939 break;
924 } 940 }
925 } 941 }
926 if (list_empty(&card->files_list))
927 last_close = 1;
928 spin_unlock(&card->files_lock); 942 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 }
934 if (!found) { 943 if (!found) {
935 snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); 944 snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
936 return -ENOENT; 945 return -ENOENT;
937 } 946 }
938 kfree(found); 947 kfree(found);
948 snd_card_unref(card);
939 return 0; 949 return 0;
940} 950}
941 951