|
@@ -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_list));
|
|
|
+ wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
|
|
|
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;
|
|
|
}
|
|
|
|