--- zzzz-none-000/linux-3.10.107/sound/core/init.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/sound/core/init.c 2021-02-04 17:41:59.000000000 +0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,8 @@ static const struct file_operations snd_shutdown_f_ops; -static unsigned int snd_cards_lock; /* locked for registering/using */ +/* locked for registering/using */ +static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS); struct snd_card *snd_cards[SNDRV_CARDS]; EXPORT_SYMBOL(snd_cards); @@ -65,7 +67,7 @@ #ifdef MODULE const char *s1, *s2; - if (!module || !module->name || !slots[idx]) + if (!module || !*module->name || !slots[idx]) return 0; s1 = module->name; @@ -93,45 +95,95 @@ 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 -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static void snd_card_id_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { snd_iprintf(buffer, "%s\n", entry->card->id); } -static inline int init_info_for_card(struct snd_card *card) +static int init_info_for_card(struct snd_card *card) { - int err; struct snd_info_entry *entry; - if ((err = snd_info_card_register(card)) < 0) { - snd_printd("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"); - return err; + entry = snd_info_create_card_entry(card, "id", card->proc_root); + if (!entry) { + dev_dbg(card->dev, "unable to create card entry\n"); + return -ENOMEM; } entry->c.text.read = snd_card_id_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } card->proc_id = entry; - return 0; + + return snd_info_card_register(card); } -#else /* !CONFIG_PROC_FS */ +#else /* !CONFIG_SND_PROC_FS */ #define init_info_for_card(card) #endif +static int check_empty_slot(struct module *module, int slot) +{ + return !slots[slot] || !*slots[slot]; +} + +/* return an empty slot number (>= 0) found in the given bitmask @mask. + * @mask == -1 == 0xffffffff means: take any free slot up to 32 + * when no slot is available, return the original @mask as is. + */ +static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int), + struct module *module) +{ + int slot; + + for (slot = 0; slot < SNDRV_CARDS; slot++) { + if (slot < 32 && !(mask & (1U << slot))) + continue; + if (!test_bit(slot, snd_cards_lock)) { + if (check(module, slot)) + return slot; /* found */ + } + } + return mask; /* unchanged */ +} + +/* the default release callback set in snd_device_initialize() below; + * this is just NOP for now, as almost all jobs are already done in + * dev_free callback of snd_device chain instead. + */ +static void default_release(struct device *dev) +{ +} + /** - * snd_card_create - create and initialize a soundcard structure + * snd_device_initialize - Initialize struct device for sound devices + * @dev: device to initialize + * @card: card to assign, optional + */ +void snd_device_initialize(struct device *dev, struct snd_card *card) +{ + device_initialize(dev); + if (card) + dev->parent = &card->card_dev; + dev->class = sound_class; + dev->release = default_release; +} +EXPORT_SYMBOL_GPL(snd_device_initialize); + +static int snd_card_do_free(struct snd_card *card); +static const struct attribute_group card_dev_attr_group; + +static void release_card_device(struct device *dev) +{ + snd_card_do_free(dev_to_snd_card(dev)); +} + +/** + * 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 @@ -146,12 +198,12 @@ * * 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) { struct snd_card *card; - int err, idx2; + int err; if (snd_BUG_ON(!card_ret)) return -EINVAL; @@ -162,47 +214,35 @@ 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; mutex_lock(&snd_card_mutex); - if (idx < 0) { - for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) - /* idx == -1 == 0xffff means: take any free slot */ - if (~snd_cards_lock & idx & 1<= SNDRV_CARDS) 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; } - snd_cards_lock |= 1 << idx; /* lock it */ + 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); @@ -213,36 +253,43 @@ 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_groups; + card->dev_groups[0] = &card_dev_attr_group; + 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) @@ -250,7 +297,7 @@ int locked; mutex_lock(&snd_card_mutex); - locked = snd_cards_lock & (1 << card); + locked = test_bit(card, snd_cards_lock); mutex_unlock(&snd_card_mutex); return locked; } @@ -346,7 +393,6 @@ int snd_card_disconnect(struct snd_card *card) { struct snd_monitor_file *mfile; - int err; if (!card) return -EINVAL; @@ -362,7 +408,7 @@ /* phase 1: disable fops (user space) operations for ALSA API */ mutex_lock(&snd_card_mutex); snd_cards[card->number] = NULL; - snd_cards_lock &= ~(1 << card->number); + clear_bit(card->number, snd_cards_lock); mutex_unlock(&snd_card_mutex); /* phase 2: replace file->f_op with special dummy operations */ @@ -385,20 +431,18 @@ /* 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 /* 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); + snd_device_disconnect_all(card); 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); @@ -408,94 +452,72 @@ EXPORT_SYMBOL(snd_card_disconnect); -/** - * snd_card_free - frees given soundcard structure - * @card: soundcard structure - * - * This function releases the soundcard structure and the all assigned - * devices automatically. That is, you don't have to release the devices - * by yourself. - * - * Return: Zero. Frees all associated devices and frees the control - * interface associated to given soundcard. - */ 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 + * snd_card_free_when_closed - Disconnect the card, free it later eventually + * @card: soundcard structure * - * Decrements the reference counter. When it reaches to zero, wake up - * the sleeper and call the destructor if needed. + * Unlike snd_card_free(), this function doesn't try to release the card + * resource immediately, but tries to disconnect at first. When the card + * is still in use, the function returns before freeing the resources. + * The card resources will be freed when the refcount gets to zero. */ -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); +/** + * snd_card_free - frees given soundcard structure + * @card: soundcard structure + * + * This function releases the soundcard structure and the all assigned + * devices automatically. That is, you don't have to release the devices + * by yourself. + * + * This function waits until the all resources are properly released. + * + * Return: Zero. Frees all associated devices and frees the control + * interface associated to given soundcard. + */ 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 */ @@ -550,7 +572,6 @@ const char *nid) { int len, loops; - bool with_suffix; bool is_default = false; char *id; @@ -566,26 +587,23 @@ is_default = true; } - with_suffix = false; + len = strlen(id); for (loops = 0; loops < SNDRV_CARDS; loops++) { + char *spos; + char sfxstr[5]; /* "_012" */ + int sfxlen; + if (card_id_ok(card, id)) return; /* OK */ - len = strlen(id); - if (!with_suffix) { - /* add the "_X" suffix */ - char *spos = id + len; - if (len > sizeof(card->id) - 3) - spos = id + sizeof(card->id) - 3; - strcpy(spos, "_1"); - with_suffix = true; - } else { - /* modify the existing suffix */ - if (id[len - 1] != '9') - id[len - 1]++; - else - id[len - 1] = 'A'; - } + /* Add _XYZ suffix */ + sprintf(sfxstr, "_%X", loops + 1); + sfxlen = strlen(sfxstr); + if (len + sfxlen >= sizeof(card->id)) + spos = id + sizeof(card->id) - sfxlen - 1; + else + spos = id + len; + strcpy(spos, sfxstr); } /* fallback to the default id */ if (!is_default) { @@ -593,9 +611,9 @@ 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) - strcpy(card->id, card->proc_root->name); + strlcpy(card->id, card->proc_root->name, sizeof(card->id)); } /** @@ -621,15 +639,15 @@ 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; @@ -655,19 +673,50 @@ 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 const struct attribute_group card_dev_attr_group = { + .attrs = card_dev_attrs, +}; + +/** + * snd_card_add_dev_attr - Append a new sysfs attribute group to card + * @card: card instance + * @group: attribute group to append + */ +int snd_card_add_dev_attr(struct snd_card *card, + const struct attribute_group *group) +{ + int i; + + /* loop for (arraysize-1) here to keep NULL at the last entry */ + for (i = 0; i < ARRAY_SIZE(card->dev_groups) - 1; i++) { + if (!card->dev_groups[i]) { + card->dev_groups[i] = group; + return 0; + } + } + + dev_err(card->dev, "Too many groups assigned\n"); + return -ENOSPC; +}; +EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); /** * snd_card_register - register the soundcard @@ -687,12 +736,11 @@ 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) @@ -701,7 +749,7 @@ if (snd_cards[card->number]) { /* already registered */ mutex_unlock(&snd_card_mutex); - return 0; + return snd_info_card_register(card); /* register pending info */ } if (*card->id) { /* make a unique id name from the given string */ @@ -718,27 +766,16 @@ 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; } EXPORT_SYMBOL(snd_card_register); -#ifdef CONFIG_PROC_FS -static struct snd_info_entry *snd_card_info_entry; - +#ifdef CONFIG_SND_PROC_FS static void snd_card_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -764,7 +801,6 @@ } #ifdef CONFIG_SND_OSSEMUL - void snd_card_info_read_oss(struct snd_info_buffer *buffer) { int idx, count; @@ -786,7 +822,6 @@ #endif #ifdef MODULE -static struct snd_info_entry *snd_card_module_info_entry; static void snd_card_module_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -811,36 +846,21 @@ if (! entry) return -ENOMEM; entry->c.text.read = snd_card_info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - snd_card_info_entry = entry; + if (snd_info_register(entry) < 0) + return -ENOMEM; /* freed in error path */ #ifdef MODULE entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); - if (entry) { - entry->c.text.read = snd_card_module_info_read; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - else - snd_card_module_info_entry = entry; - } + if (!entry) + return -ENOMEM; + entry->c.text.read = snd_card_module_info_read; + if (snd_info_register(entry) < 0) + return -ENOMEM; /* freed in error path */ #endif return 0; } - -int __exit snd_card_info_done(void) -{ - snd_info_free_entry(snd_card_info_entry); -#ifdef MODULE - snd_info_free_entry(snd_card_module_info_entry); -#endif - return 0; -} - -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ /** * snd_component_add - add a component string @@ -903,7 +923,7 @@ 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; } @@ -942,11 +962,11 @@ } 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; }