ALSA: Use standard device refcount for card accounting
Drop the own refcount but use the standard device refcounting via get_device() and put_device(). Introduce a new completion to snd_card instead of the wait queue for syncing the last release, which is used in snd_card_free(). Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
34356dbdb6
commit
f246406481
|
@ -42,6 +42,7 @@
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
struct pci_dev;
|
struct pci_dev;
|
||||||
struct module;
|
struct module;
|
||||||
|
struct completion;
|
||||||
|
|
||||||
/* device allocation stuff */
|
/* device allocation stuff */
|
||||||
|
|
||||||
|
@ -130,9 +131,7 @@ struct snd_card {
|
||||||
state */
|
state */
|
||||||
spinlock_t files_lock; /* lock the files for this card */
|
spinlock_t files_lock; /* lock the files for this card */
|
||||||
int shutdown; /* this card is going down */
|
int shutdown; /* this card is going down */
|
||||||
int free_on_last_close; /* free in context of file_release */
|
struct completion *release_completion;
|
||||||
wait_queue_head_t shutdown_sleep;
|
|
||||||
atomic_t refcount; /* refcount for disconnection */
|
|
||||||
struct device *dev; /* device assigned to this card */
|
struct device *dev; /* device assigned to this card */
|
||||||
struct device card_dev; /* cardX object for sysfs */
|
struct device card_dev; /* cardX object for sysfs */
|
||||||
bool registered; /* card_dev is registered? */
|
bool registered; /* card_dev is registered? */
|
||||||
|
@ -306,7 +305,7 @@ int snd_card_info_done(void);
|
||||||
int snd_component_add(struct snd_card *card, const char *component);
|
int snd_component_add(struct snd_card *card, const char *component);
|
||||||
int snd_card_file_add(struct snd_card *card, struct file *file);
|
int snd_card_file_add(struct snd_card *card, struct file *file);
|
||||||
int snd_card_file_remove(struct snd_card *card, struct file *file);
|
int snd_card_file_remove(struct snd_card *card, struct file *file);
|
||||||
void snd_card_unref(struct snd_card *card);
|
#define snd_card_unref(card) put_device(&(card)->card_dev)
|
||||||
|
|
||||||
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
|
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/control.h>
|
#include <sound/control.h>
|
||||||
|
@ -235,8 +236,6 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
|
||||||
INIT_LIST_HEAD(&card->ctl_files);
|
INIT_LIST_HEAD(&card->ctl_files);
|
||||||
spin_lock_init(&card->files_lock);
|
spin_lock_init(&card->files_lock);
|
||||||
INIT_LIST_HEAD(&card->files_list);
|
INIT_LIST_HEAD(&card->files_list);
|
||||||
init_waitqueue_head(&card->shutdown_sleep);
|
|
||||||
atomic_set(&card->refcount, 0);
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
mutex_init(&card->power_lock);
|
mutex_init(&card->power_lock);
|
||||||
init_waitqueue_head(&card->power_sleep);
|
init_waitqueue_head(&card->power_sleep);
|
||||||
|
@ -474,58 +473,36 @@ static int snd_card_do_free(struct snd_card *card)
|
||||||
snd_printk(KERN_WARNING "unable to free card info\n");
|
snd_printk(KERN_WARNING "unable to free card info\n");
|
||||||
/* Not fatal error */
|
/* Not fatal error */
|
||||||
}
|
}
|
||||||
|
if (card->release_completion)
|
||||||
|
complete(card->release_completion);
|
||||||
kfree(card);
|
kfree(card);
|
||||||
return 0;
|
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)
|
|
||||||
put_device(&card->card_dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(snd_card_unref);
|
|
||||||
|
|
||||||
int snd_card_free_when_closed(struct snd_card *card)
|
int snd_card_free_when_closed(struct snd_card *card)
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
atomic_inc(&card->refcount);
|
|
||||||
ret = snd_card_disconnect(card);
|
|
||||||
if (ret) {
|
|
||||||
atomic_dec(&card->refcount);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
card->free_on_last_close = 1;
|
|
||||||
if (atomic_dec_and_test(&card->refcount))
|
|
||||||
put_device(&card->card_dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_card_free_when_closed);
|
|
||||||
|
|
||||||
int snd_card_free(struct snd_card *card)
|
|
||||||
{
|
{
|
||||||
int ret = snd_card_disconnect(card);
|
int ret = snd_card_disconnect(card);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* wait, until all devices are ready for the free operation */
|
|
||||||
wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
|
|
||||||
put_device(&card->card_dev);
|
put_device(&card->card_dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(snd_card_free_when_closed);
|
||||||
|
|
||||||
|
int snd_card_free(struct snd_card *card)
|
||||||
|
{
|
||||||
|
struct completion released;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
init_completion(&released);
|
||||||
|
card->release_completion = &released;
|
||||||
|
ret = snd_card_free_when_closed(card);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/* wait, until all devices are ready for the free operation */
|
||||||
|
wait_for_completion(&released);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(snd_card_free);
|
EXPORT_SYMBOL(snd_card_free);
|
||||||
|
|
||||||
/* retrieve the last word of shortname or longname */
|
/* retrieve the last word of shortname or longname */
|
||||||
|
@ -932,7 +909,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
list_add(&mfile->list, &card->files_list);
|
list_add(&mfile->list, &card->files_list);
|
||||||
atomic_inc(&card->refcount);
|
get_device(&card->card_dev);
|
||||||
spin_unlock(&card->files_lock);
|
spin_unlock(&card->files_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -975,7 +952,7 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
kfree(found);
|
kfree(found);
|
||||||
snd_card_unref(card);
|
put_device(&card->card_dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
|
||||||
if (mreg && mreg->type == type) {
|
if (mreg && mreg->type == type) {
|
||||||
private_data = mreg->private_data;
|
private_data = mreg->private_data;
|
||||||
if (private_data && mreg->card_ptr)
|
if (private_data && mreg->card_ptr)
|
||||||
atomic_inc(&mreg->card_ptr->refcount);
|
get_device(&mreg->card_ptr->card_dev);
|
||||||
} else
|
} else
|
||||||
private_data = NULL;
|
private_data = NULL;
|
||||||
mutex_unlock(&sound_mutex);
|
mutex_unlock(&sound_mutex);
|
||||||
|
|
|
@ -55,7 +55,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
|
||||||
if (mreg && mreg->type == type) {
|
if (mreg && mreg->type == type) {
|
||||||
private_data = mreg->private_data;
|
private_data = mreg->private_data;
|
||||||
if (private_data && mreg->card_ptr)
|
if (private_data && mreg->card_ptr)
|
||||||
atomic_inc(&mreg->card_ptr->refcount);
|
get_device(&mreg->card_ptr->card_dev);
|
||||||
} else
|
} else
|
||||||
private_data = NULL;
|
private_data = NULL;
|
||||||
mutex_unlock(&sound_oss_mutex);
|
mutex_unlock(&sound_oss_mutex);
|
||||||
|
|
Loading…
Reference in a new issue