summaryrefslogtreecommitdiffstats
path: root/sound/core/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/init.c')
-rw-r--r--sound/core/init.c186
1 files changed, 88 insertions, 98 deletions
diff --git a/sound/core/init.c b/sound/core/init.c
index 0d42fcda0de2..5ee83845c5de 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -28,6 +28,7 @@
#include <linux/time.h>
#include <linux/ctype.h>
#include <linux/pm.h>
+#include <linux/completion.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -94,7 +95,7 @@ static int module_slot_match(struct module *module, int idx)
return match;
}
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif
@@ -112,11 +113,11 @@ static inline int init_info_for_card(struct snd_card *card)
struct snd_info_entry *entry;
if ((err = snd_info_card_register(card)) < 0) {
- snd_printd("unable to create card info\n");
+ dev_dbg(card->dev, "unable to create card info\n");
return err;
}
if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
- snd_printd("unable to create card entry\n");
+ dev_dbg(card->dev, "unable to create card entry\n");
return err;
}
entry->c.text.read = snd_card_id_read;
@@ -156,8 +157,17 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
return mask; /* unchanged */
}
+static int snd_card_do_free(struct snd_card *card);
+static const struct attribute_group *card_dev_attr_groups[];
+
+static void release_card_device(struct device *dev)
+{
+ snd_card_do_free(dev_to_snd_card(dev));
+}
+
/**
- * snd_card_create - create and initialize a soundcard structure
+ * snd_card_new - create and initialize a soundcard structure
+ * @parent: the parent device object
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
@@ -172,7 +182,7 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
*
* Return: Zero if successful or a negative error code.
*/
-int snd_card_create(int idx, const char *xid,
+int snd_card_new(struct device *parent, int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
{
@@ -188,6 +198,8 @@ int snd_card_create(int idx, const char *xid,
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
if (!card)
return -ENOMEM;
+ if (extra_size > 0)
+ card->private_data = (char *)card + sizeof(struct snd_card);
if (xid)
strlcpy(card->id, xid, sizeof(card->id));
err = 0;
@@ -205,14 +217,16 @@ int snd_card_create(int idx, const char *xid,
err = -ENODEV;
if (err < 0) {
mutex_unlock(&snd_card_mutex);
- snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+ dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
idx, snd_ecards_limit - 1, err);
- goto __error;
+ kfree(card);
+ 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;
card->module = module;
INIT_LIST_HEAD(&card->devices);
@@ -222,36 +236,42 @@ int snd_card_create(int idx, const char *xid,
INIT_LIST_HEAD(&card->ctl_files);
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);
#endif
+
+ device_initialize(&card->card_dev);
+ card->card_dev.parent = parent;
+ card->card_dev.class = sound_class;
+ card->card_dev.release = release_card_device;
+ card->card_dev.groups = card_dev_attr_groups;
+ err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
+ if (err < 0)
+ goto __error;
+
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
if (err < 0) {
- snd_printk(KERN_ERR "unable to register control minors\n");
+ dev_err(parent, "unable to register control minors\n");
goto __error;
}
err = snd_info_card_create(card);
if (err < 0) {
- snd_printk(KERN_ERR "unable to create card info\n");
+ dev_err(parent, "unable to create card info\n");
goto __error_ctl;
}
- if (extra_size > 0)
- card->private_data = (char *)card + sizeof(struct snd_card);
*card_ret = card;
return 0;
__error_ctl:
- snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
+ snd_device_free_all(card);
__error:
- kfree(card);
+ put_device(&card->card_dev);
return err;
}
-EXPORT_SYMBOL(snd_card_create);
+EXPORT_SYMBOL(snd_card_new);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
@@ -394,7 +414,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 3: notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
#endif
@@ -402,12 +422,12 @@ int snd_card_disconnect(struct snd_card *card)
/* notify all devices that we are disconnected */
err = snd_device_disconnect_all(card);
if (err < 0)
- snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+ dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
snd_info_card_disconnect(card);
- if (card->card_dev) {
- device_unregister(card->card_dev);
- card->card_dev = NULL;
+ if (card->registered) {
+ device_del(&card->card_dev);
+ card->registered = false;
}
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
@@ -430,81 +450,48 @@ EXPORT_SYMBOL(snd_card_disconnect);
*/
static int snd_card_do_free(struct snd_card *card)
{
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
- if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (pre)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (normal)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (post)\n");
- /* Fatal, but this situation should never occur */
- }
+ snd_device_free_all(card);
if (card->private_free)
card->private_free(card);
snd_info_free_entry(card->proc_id);
if (snd_info_card_free(card) < 0) {
- snd_printk(KERN_WARNING "unable to free card info\n");
+ dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
}
+ if (card->release_completion)
+ complete(card->release_completion);
kfree(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 ret;
-
- atomic_inc(&card->refcount);
- ret = snd_card_disconnect(card);
- if (ret) {
- atomic_dec(&card->refcount);
+ int ret = snd_card_disconnect(card);
+ if (ret)
return ret;
- }
-
- card->free_on_last_close = 1;
- if (atomic_dec_and_test(&card->refcount))
- snd_card_do_free(card);
+ 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);
+ 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_event(card->shutdown_sleep, !atomic_read(&card->refcount));
- snd_card_do_free(card);
+ wait_for_completion(&released);
return 0;
}
-
EXPORT_SYMBOL(snd_card_free);
/* retrieve the last word of shortname or longname */
@@ -598,7 +585,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
goto again;
}
/* last resort... */
- snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
+ dev_err(card->dev, "unable to set card id (%s)\n", id);
if (card->proc_root->name)
strlcpy(card->id, card->proc_root->name, sizeof(card->id));
}
@@ -626,15 +613,15 @@ static ssize_t
card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_card *card = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)");
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
static ssize_t
card_id_store_attr(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
char buf1[sizeof(card->id)];
size_t copy = count > sizeof(card->id) - 1 ?
sizeof(card->id) - 1 : count;
@@ -660,19 +647,32 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct device_attribute card_id_attrs =
- __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
+static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
static ssize_t
card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_card *card = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1);
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
-static struct device_attribute card_number_attrs =
- __ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+
+static struct attribute *card_dev_attrs[] = {
+ &dev_attr_id.attr,
+ &dev_attr_number.attr,
+ NULL
+};
+
+static struct attribute_group card_dev_attr_group = {
+ .attrs = card_dev_attrs,
+};
+
+static const struct attribute_group *card_dev_attr_groups[] = {
+ &card_dev_attr_group,
+ NULL
+};
/**
* snd_card_register - register the soundcard
@@ -692,12 +692,11 @@ int snd_card_register(struct snd_card *card)
if (snd_BUG_ON(!card))
return -EINVAL;
- if (!card->card_dev) {
- card->card_dev = device_create(sound_class, card->dev,
- MKDEV(0, 0), card,
- "card%i", card->number);
- if (IS_ERR(card->card_dev))
- card->card_dev = NULL;
+ if (!card->registered) {
+ err = device_add(&card->card_dev);
+ if (err < 0)
+ return err;
+ card->registered = true;
}
if ((err = snd_device_register_all(card)) < 0)
@@ -723,19 +722,10 @@ int snd_card_register(struct snd_card *card)
snd_cards[card->number] = card;
mutex_unlock(&snd_card_mutex);
init_info_for_card(card);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
- if (card->card_dev) {
- err = device_create_file(card->card_dev, &card_id_attrs);
- if (err < 0)
- return err;
- err = device_create_file(card->card_dev, &card_number_attrs);
- if (err < 0)
- return err;
- }
-
return 0;
}
@@ -908,7 +898,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);
+ get_device(&card->card_dev);
spin_unlock(&card->files_lock);
return 0;
}
@@ -947,11 +937,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
}
spin_unlock(&card->files_lock);
if (!found) {
- snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
+ dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;
}
kfree(found);
- snd_card_unref(card);
+ put_device(&card->card_dev);
return 0;
}