summaryrefslogtreecommitdiff
path: root/sound/core/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/init.c')
-rw-r--r--sound/core/init.c241
1 files changed, 117 insertions, 124 deletions
diff --git a/sound/core/init.c b/sound/core/init.c
index 22c0d217b860..114fb87de990 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
static int module_slot_match(struct module *module, int idx)
{
int match = 1;
-#ifdef MODULE
+#ifdef CONFIG_MODULES
const char *s1, *s2;
if (!module || !*module->name || !slots[idx])
@@ -77,7 +77,7 @@ static int module_slot_match(struct module *module, int idx)
if (!c1)
break;
}
-#endif /* MODULE */
+#endif /* CONFIG_MODULES */
return match;
}
@@ -284,39 +284,38 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
if (xid)
strscpy(card->id, xid, sizeof(card->id));
err = 0;
- mutex_lock(&snd_card_mutex);
- if (idx < 0) /* first check the matching module-name slot */
- idx = get_slot_from_bitmask(idx, module_slot_match, module);
- if (idx < 0) /* if not matched, assign an empty slot */
- idx = get_slot_from_bitmask(idx, check_empty_slot, module);
- if (idx < 0)
- err = -ENODEV;
- else if (idx < snd_ecards_limit) {
- if (test_bit(idx, snd_cards_lock))
- err = -EBUSY; /* invalid */
- } else if (idx >= SNDRV_CARDS)
- err = -ENODEV;
+ scoped_guard(mutex, &snd_card_mutex) {
+ if (idx < 0) /* first check the matching module-name slot */
+ idx = get_slot_from_bitmask(idx, module_slot_match, module);
+ if (idx < 0) /* if not matched, assign an empty slot */
+ idx = get_slot_from_bitmask(idx, check_empty_slot, module);
+ if (idx < 0)
+ err = -ENODEV;
+ else if (idx < snd_ecards_limit) {
+ if (test_bit(idx, snd_cards_lock))
+ err = -EBUSY; /* invalid */
+ } else if (idx >= SNDRV_CARDS)
+ err = -ENODEV;
+ if (!err) {
+ set_bit(idx, snd_cards_lock); /* lock it */
+ if (idx >= snd_ecards_limit)
+ snd_ecards_limit = idx + 1; /* increase the limit */
+ }
+ }
if (err < 0) {
- mutex_unlock(&snd_card_mutex);
dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
- idx, snd_ecards_limit - 1, err);
+ idx, snd_ecards_limit - 1, err);
if (!card->managed)
kfree(card); /* manually free here, as no destructor called */
return err;
}
- set_bit(idx, snd_cards_lock); /* lock it */
- if (idx >= snd_ecards_limit)
- snd_ecards_limit = idx + 1; /* increase the limit */
- mutex_unlock(&snd_card_mutex);
card->dev = parent;
card->number = idx;
-#ifdef MODULE
- WARN_ON(!module);
+ WARN_ON(IS_MODULE(CONFIG_SND) && !module);
card->module = module;
-#endif
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
- rwlock_init(&card->ctl_files_rwlock);
+ rwlock_init(&card->controls_rwlock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
@@ -386,11 +385,10 @@ struct snd_card *snd_card_ref(int idx)
{
struct snd_card *card;
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
get_device(&card->card_dev);
- mutex_unlock(&snd_card_mutex);
return card;
}
EXPORT_SYMBOL_GPL(snd_card_ref);
@@ -398,12 +396,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
{
- int locked;
-
- mutex_lock(&snd_card_mutex);
- locked = test_bit(card, snd_cards_lock);
- mutex_unlock(&snd_card_mutex);
- return locked;
+ guard(mutex)(&snd_card_mutex);
+ return test_bit(card, snd_cards_lock);
}
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
@@ -427,15 +421,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
{
struct snd_monitor_file *df = NULL, *_df;
- spin_lock(&shutdown_lock);
- list_for_each_entry(_df, &shutdown_files, shutdown_list) {
- if (_df->file == file) {
- df = _df;
- list_del_init(&df->shutdown_list);
- break;
+ scoped_guard(spinlock, &shutdown_lock) {
+ list_for_each_entry(_df, &shutdown_files, shutdown_list) {
+ if (_df->file == file) {
+ df = _df;
+ list_del_init(&df->shutdown_list);
+ break;
+ }
}
}
- spin_unlock(&shutdown_lock);
if (likely(df)) {
if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
@@ -501,27 +495,32 @@ void snd_card_disconnect(struct snd_card *card)
if (!card)
return;
- spin_lock(&card->files_lock);
- if (card->shutdown) {
- spin_unlock(&card->files_lock);
- return;
- }
- card->shutdown = 1;
+ scoped_guard(spinlock, &card->files_lock) {
+ if (card->shutdown)
+ return;
+ card->shutdown = 1;
- /* replace file->f_op with special dummy operations */
- list_for_each_entry(mfile, &card->files_list, list) {
- /* it's critical part, use endless loop */
- /* we have no room to fail */
- mfile->disconnected_f_op = mfile->file->f_op;
+ /* replace file->f_op with special dummy operations */
+ list_for_each_entry(mfile, &card->files_list, list) {
+ /* it's critical part, use endless loop */
+ /* we have no room to fail */
+ mfile->disconnected_f_op = mfile->file->f_op;
- spin_lock(&shutdown_lock);
- list_add(&mfile->shutdown_list, &shutdown_files);
- spin_unlock(&shutdown_lock);
+ scoped_guard(spinlock, &shutdown_lock)
+ list_add(&mfile->shutdown_list, &shutdown_files);
- mfile->file->f_op = &snd_shutdown_f_ops;
- fops_get(mfile->file->f_op);
+ mfile->file->f_op = &snd_shutdown_f_ops;
+ fops_get(mfile->file->f_op);
+ }
}
- spin_unlock(&card->files_lock);
+
+#ifdef CONFIG_PM
+ /* wake up sleepers here before other callbacks for avoiding potential
+ * deadlocks with other locks (e.g. in kctls);
+ * then this notifies the shutdown and sleepers would abort immediately
+ */
+ wake_up_all(&card->power_sleep);
+#endif
/* notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
@@ -538,21 +537,23 @@ void snd_card_disconnect(struct snd_card *card)
synchronize_irq(card->sync_irq);
snd_info_card_disconnect(card);
+#ifdef CONFIG_SND_DEBUG
+ debugfs_remove(card->debugfs_root);
+ card->debugfs_root = NULL;
+#endif
+
if (card->registered) {
device_del(&card->card_dev);
card->registered = false;
}
/* disable fops (user space) operations for ALSA API */
- mutex_lock(&snd_card_mutex);
- snd_cards[card->number] = NULL;
- clear_bit(card->number, snd_cards_lock);
- mutex_unlock(&snd_card_mutex);
+ scoped_guard(mutex, &snd_card_mutex) {
+ snd_cards[card->number] = NULL;
+ clear_bit(card->number, snd_cards_lock);
+ }
-#ifdef CONFIG_PM
- wake_up(&card->power_sleep);
snd_power_sync_ref(card);
-#endif
}
EXPORT_SYMBOL(snd_card_disconnect);
@@ -569,11 +570,10 @@ void snd_card_disconnect_sync(struct snd_card *card)
{
snd_card_disconnect(card);
- spin_lock_irq(&card->files_lock);
+ guard(spinlock_irq)(&card->files_lock);
wait_event_lock_irq(card->remove_sleep,
list_empty(&card->files_list),
card->files_lock);
- spin_unlock_irq(&card->files_lock);
}
EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
@@ -591,10 +591,6 @@ static int snd_card_do_free(struct snd_card *card)
dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
}
-#ifdef CONFIG_SND_DEBUG
- debugfs_remove(card->debugfs_root);
- card->debugfs_root = NULL;
-#endif
if (card->release_completion)
complete(card->release_completion);
if (!card->managed)
@@ -658,13 +654,19 @@ void snd_card_free(struct snd_card *card)
}
EXPORT_SYMBOL(snd_card_free);
+/* check, if the character is in the valid ASCII range */
+static inline bool safe_ascii_char(char c)
+{
+ return isascii(c) && isalnum(c);
+}
+
/* retrieve the last word of shortname or longname */
static const char *retrieve_id_from_card_name(const char *name)
{
const char *spos = name;
while (*name) {
- if (isspace(*name) && isalnum(name[1]))
+ if (isspace(*name) && safe_ascii_char(name[1]))
spos = name + 1;
name++;
}
@@ -691,12 +693,12 @@ static void copy_valid_id_string(struct snd_card *card, const char *src,
{
char *id = card->id;
- while (*nid && !isalnum(*nid))
+ while (*nid && !safe_ascii_char(*nid))
nid++;
if (isdigit(*nid))
*id++ = isalpha(*src) ? *src : 'D';
while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) {
- if (isalnum(*nid))
+ if (safe_ascii_char(*nid))
*id++ = *nid;
nid++;
}
@@ -767,9 +769,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
/* check if user specified own card->id */
if (card->id[0] != '\0')
return;
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
snd_card_set_id_no_lock(card, nid, nid);
- mutex_unlock(&snd_card_mutex);
}
EXPORT_SYMBOL(snd_card_set_id);
@@ -792,19 +793,16 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr,
for (idx = 0; idx < copy; idx++) {
c = buf[idx];
- if (!isalnum(c) && c != '_' && c != '-')
+ if (!safe_ascii_char(c) && c != '_' && c != '-')
return -EINVAL;
}
memcpy(buf1, buf, copy);
buf1[copy] = '\0';
- mutex_lock(&snd_card_mutex);
- if (!card_id_ok(NULL, buf1)) {
- mutex_unlock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
+ if (!card_id_ok(NULL, buf1))
return -EEXIST;
- }
strcpy(card->id, buf1);
snd_info_card_id_change(card);
- mutex_unlock(&snd_card_mutex);
return count;
}
@@ -897,26 +895,27 @@ int snd_card_register(struct snd_card *card)
err = snd_device_register_all(card);
if (err < 0)
return err;
- mutex_lock(&snd_card_mutex);
- if (snd_cards[card->number]) {
- /* already registered */
- mutex_unlock(&snd_card_mutex);
- return snd_info_card_register(card); /* register pending info */
- }
- if (*card->id) {
- /* make a unique id name from the given string */
- char tmpid[sizeof(card->id)];
- memcpy(tmpid, card->id, sizeof(card->id));
- snd_card_set_id_no_lock(card, tmpid, tmpid);
- } else {
- /* create an id from either shortname or longname */
- const char *src;
- src = *card->shortname ? card->shortname : card->longname;
- snd_card_set_id_no_lock(card, src,
- retrieve_id_from_card_name(src));
+ scoped_guard(mutex, &snd_card_mutex) {
+ if (snd_cards[card->number]) {
+ /* already registered */
+ return snd_info_card_register(card); /* register pending info */
+ }
+ if (*card->id) {
+ /* make a unique id name from the given string */
+ char tmpid[sizeof(card->id)];
+
+ memcpy(tmpid, card->id, sizeof(card->id));
+ snd_card_set_id_no_lock(card, tmpid, tmpid);
+ } else {
+ /* create an id from either shortname or longname */
+ const char *src;
+
+ src = *card->shortname ? card->shortname : card->longname;
+ snd_card_set_id_no_lock(card, src,
+ retrieve_id_from_card_name(src));
+ }
+ snd_cards[card->number] = card;
}
- snd_cards[card->number] = card;
- mutex_unlock(&snd_card_mutex);
err = snd_info_card_register(card);
if (err < 0)
return err;
@@ -937,7 +936,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
@@ -949,7 +948,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
snd_iprintf(buffer, " %s\n",
card->longname);
}
- mutex_unlock(&snd_card_mutex);
}
if (!count)
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -962,13 +960,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
- mutex_unlock(&snd_card_mutex);
}
if (!count) {
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -977,7 +974,7 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
#endif
-#ifdef MODULE
+#ifdef CONFIG_MODULES
static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -985,12 +982,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
- mutex_unlock(&snd_card_mutex);
}
}
#endif
@@ -1006,7 +1002,7 @@ int __init snd_card_info_init(void)
if (snd_info_register(entry) < 0)
return -ENOMEM; /* freed in error path */
-#ifdef MODULE
+#ifdef CONFIG_MODULES
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
if (!entry)
return -ENOMEM;
@@ -1072,15 +1068,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
mfile->file = file;
mfile->disconnected_f_op = NULL;
INIT_LIST_HEAD(&mfile->shutdown_list);
- spin_lock(&card->files_lock);
+ guard(spinlock)(&card->files_lock);
if (card->shutdown) {
- spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
list_add(&mfile->list, &card->files_list);
get_device(&card->card_dev);
- spin_unlock(&card->files_lock);
return 0;
}
EXPORT_SYMBOL(snd_card_file_add);
@@ -1102,22 +1096,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *found = NULL;
- spin_lock(&card->files_lock);
- list_for_each_entry(mfile, &card->files_list, list) {
- if (mfile->file == file) {
- list_del(&mfile->list);
- spin_lock(&shutdown_lock);
- list_del(&mfile->shutdown_list);
- spin_unlock(&shutdown_lock);
- if (mfile->disconnected_f_op)
- fops_put(mfile->disconnected_f_op);
- found = mfile;
- break;
+ scoped_guard(spinlock, &card->files_lock) {
+ list_for_each_entry(mfile, &card->files_list, list) {
+ if (mfile->file == file) {
+ list_del(&mfile->list);
+ scoped_guard(spinlock, &shutdown_lock)
+ list_del(&mfile->shutdown_list);
+ if (mfile->disconnected_f_op)
+ fops_put(mfile->disconnected_f_op);
+ found = mfile;
+ break;
+ }
}
+ if (list_empty(&card->files_list))
+ wake_up_all(&card->remove_sleep);
}
- if (list_empty(&card->files_list))
- wake_up_all(&card->remove_sleep);
- spin_unlock(&card->files_lock);
if (!found) {
dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;