[RFC PATCH v2 1/2] ALSA: core: add snd_device_init
From: Curtis Malainey cujomalainey@chromium.org
Begin allowing refactored modules to allocate their own device but use a common initialization procedure for their devices.
Signed-off-by: Curtis Malainey cujomalainey@chromium.org --- include/sound/core.h | 1 + sound/core/init.c | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/include/sound/core.h b/include/sound/core.h index dfef0c9d4b9f7..a4744e142c7e3 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -240,6 +240,7 @@ extern struct dentry *sound_debugfs_root; void snd_request_card(int card);
int snd_device_alloc(struct device **dev_p, struct snd_card *card); +void snd_device_init(struct device *dev, struct snd_card *card);
int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, diff --git a/sound/core/init.c b/sound/core/init.c index 22c0d217b8608..87b5368d20350 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -132,15 +132,28 @@ int snd_device_alloc(struct device **dev_p, struct snd_card *card) dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; + snd_device_init(dev, card); + *dev_p = dev; + return 0; +} +EXPORT_SYMBOL_GPL(snd_device_alloc); + +/** + * snd_device_init - Initialize struct device for sound devices + * @dev_p: pointer to store the allocated device + * @card: card to assign, optional + * + * For releasing the allocated device, call put_device(). + */ +void snd_device_init(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_alloc; - *dev_p = dev; - return 0; } -EXPORT_SYMBOL_GPL(snd_device_alloc); +EXPORT_SYMBOL_GPL(snd_device_init);
static int snd_card_init(struct snd_card *card, struct device *parent, int idx, const char *xid, struct module *module,
From: Curtis Malainey cujomalainey@chromium.org
Having two kobj in the same struct is broken at its core. This splits card_dev from ctl_dev so they can properly refcount and release on their own schedules without the workaround of having them being just a pointer.
Change-Id: Iecc91a116dfcb5a6364c7e6bdf993949e8542ca1 Signed-off-by: Curtis Malainey cujomalainey@chromium.org --- v2: - Fix leak rnd formatting eported by Takashi - Collapse snd_ctl_create into snd_control_new to ease memory handling reported by Takashi - Fix OSS errors reported by kbuild
include/sound/control.h | 1 + include/sound/core.h | 32 +- sound/core/control.c | 362 +++++++++++++---------- sound/core/control_compat.c | 8 +- sound/core/control_led.c | 18 +- sound/core/init.c | 14 +- sound/core/oss/mixer_oss.c | 52 ++-- sound/pci/hda/hda_codec.c | 3 +- sound/soc/intel/atom/sst-atom-controls.c | 8 +- sound/soc/soc-card.c | 2 +- sound/usb/media.c | 2 +- 11 files changed, 269 insertions(+), 233 deletions(-)
diff --git a/include/sound/control.h b/include/sound/control.h index 9a4f4f7138da8..32920f33eb47e 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -128,6 +128,7 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, struct snd_ctl_file * control, unsigned int cmd, unsigned long arg);
+int snd_control_new(struct snd_card * card); void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); void snd_ctl_notify_one(struct snd_card * card, unsigned int mask, struct snd_kcontrol * kctl, unsigned int ioff);
diff --git a/include/sound/core.h b/include/sound/core.h index a4744e142c7e3..263174eea4634 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -95,21 +95,7 @@ struct snd_card { void (*private_free) (struct snd_card *card); /* callback for freeing of private data */ struct list_head devices; /* devices */ - - struct device *ctl_dev; /* control device */ - unsigned int last_numid; /* last used numeric ID */ - struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ - rwlock_t ctl_files_rwlock; /* ctl_files list lock */ - int controls_count; /* count of all controls */ - size_t user_ctl_alloc_size; // current memory allocation by user controls. - struct list_head controls; /* all controls for this card */ - struct list_head ctl_files; /* active control files */ -#ifdef CONFIG_SND_CTL_FAST_LOOKUP - struct xarray ctl_numids; /* hash table for numids */ - struct xarray ctl_hash; /* hash table for ctl id matching */ - bool ctl_hash_collision; /* ctl_hash collision seen? */ -#endif - + struct snd_control *ctl; /* control devices */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct proc_dir_entry *proc_root_link; /* number link to real id */
@@ -147,6 +133,22 @@ struct snd_card { #endif };
+struct snd_control { + struct device dev; /* control device */ + struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ + rwlock_t files_rwlock; /* ctl_files list lock */ + int controls_count; /* count of all controls */ + size_t user_ctl_alloc_size; /* current memory allocation by user controls. */ + struct list_head controls; /* all controls for this card */ + struct list_head files; /* active control files */ + unsigned int last_numid; /* last used numeric ID */ +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + struct xarray numids; /* hash table for numids */ + struct xarray hash; /* hash table for ctl id matching */ + bool hash_collision; /* ctl_hash collision seen? */ +#endif +}; + #define dev_to_snd_card(p) container_of(p, struct snd_card, card_dev)
#ifdef CONFIG_PM diff --git a/sound/core/control.c b/sound/core/control.c index 59c8658966d4c..e09e9d65851b3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -41,12 +41,70 @@ static struct snd_ctl_layer_ops *snd_ctl_layer;
static int snd_ctl_remove_locked(struct snd_card *card, struct snd_kcontrol *kcontrol); +static int snd_ctl_dev_free(struct snd_device *device); +static int snd_ctl_dev_register(struct snd_device *device); +static int snd_ctl_dev_disconnect(struct snd_device *device); +static void release_control_device(struct device *dev); + +/** + * snd_control_new - Allocate and initialize snd_control + * @card: the card to be initialized + * + * This function creates and initializes snd_control + */ +int snd_control_new(struct snd_card *card) +{ + static const struct snd_device_ops ops = { + .dev_free = snd_ctl_dev_free, + .dev_register = snd_ctl_dev_register, + .dev_disconnect = snd_ctl_dev_disconnect, + }; + struct snd_control *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + int err; + + if (!ctl) + return -ENOMEM; + if (snd_BUG_ON(!card)) { + err = -EINVAL; + goto err_release; + } + if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS)) { + err = -ENXIO; + goto err_release; + } + + init_rwsem(&ctl->controls_rwsem); + rwlock_init(&ctl->files_rwlock); + INIT_LIST_HEAD(&ctl->controls); + INIT_LIST_HEAD(&ctl->files); +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_init(&ctl->numids); + xa_init(&ctl->hash); +#endif + card->ctl = ctl; + /* the control interface cannot be accessed from the user space until */ + /* snd_cards_bitmask and snd_cards are set with snd_card_register */ + + snd_device_init(&ctl->dev, card); + dev_set_name(&ctl->dev, "controlC%d", card->number); + ctl->dev.release = release_control_device; + + err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); + if (err < 0) + put_device(&ctl->dev); + + return err; +err_release: + kfree(ctl); + return err; +}
static int snd_ctl_open(struct inode *inode, struct file *file) { unsigned long flags; struct snd_card *card; - struct snd_ctl_file *ctl; + struct snd_control *ctl; + struct snd_ctl_file *ctlf; int i, err;
err = stream_open(inode, file); @@ -58,6 +116,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) err = -ENODEV; goto __error1; } + ctl = card->ctl; err = snd_card_file_add(card, file); if (err < 0) { err = -ENODEV; @@ -67,22 +126,22 @@ static int snd_ctl_open(struct inode *inode, struct file *file) err = -EFAULT; goto __error2; } - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (ctl == NULL) { + ctlf = kzalloc(sizeof(*ctlf), GFP_KERNEL); + if (ctlf == NULL) { err = -ENOMEM; goto __error; } - INIT_LIST_HEAD(&ctl->events); - init_waitqueue_head(&ctl->change_sleep); - spin_lock_init(&ctl->read_lock); - ctl->card = card; + INIT_LIST_HEAD(&ctlf->events); + init_waitqueue_head(&ctlf->change_sleep); + spin_lock_init(&ctlf->read_lock); + ctlf->card = card; for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++) - ctl->preferred_subdevice[i] = -1; - ctl->pid = get_pid(task_pid(current)); - file->private_data = ctl; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_add_tail(&ctl->list, &card->ctl_files); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); + ctlf->preferred_subdevice[i] = -1; + ctlf->pid = get_pid(task_pid(current)); + file->private_data = ctlf; + write_lock_irqsave(&ctl->files_rwlock, flags); + list_add_tail(&ctlf->list, &ctl->files); + write_unlock_irqrestore(&ctl->files_rwlock, flags); snd_card_unref(card); return 0;
@@ -113,27 +172,26 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) static int snd_ctl_release(struct inode *inode, struct file *file) { unsigned long flags; - struct snd_card *card; - struct snd_ctl_file *ctl; + struct snd_ctl_file *ctlf = file->private_data; + struct snd_card *card = ctlf->card; + struct snd_control *ctl = card->ctl; struct snd_kcontrol *control; unsigned int idx;
- ctl = file->private_data; file->private_data = NULL; - card = ctl->card; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_del(&ctl->list); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); - down_write(&card->controls_rwsem); - list_for_each_entry(control, &card->controls, list) + write_lock_irqsave(&ctl->files_rwlock, flags); + list_del(&ctlf->list); + write_unlock_irqrestore(&ctl->files_rwlock, flags); + down_write(&ctl->controls_rwsem); + list_for_each_entry(control, &ctl->controls, list) for (idx = 0; idx < control->count; idx++) - if (control->vd[idx].owner == ctl) + if (control->vd[idx].owner == ctlf) control->vd[idx].owner = NULL; - up_write(&card->controls_rwsem); - snd_fasync_free(ctl->fasync); - snd_ctl_empty_read_queue(ctl); - put_pid(ctl->pid); - kfree(ctl); + up_write(&ctl->controls_rwsem); + snd_fasync_free(ctlf->fasync); + snd_ctl_empty_read_queue(ctlf); + put_pid(ctlf->pid); + kfree(ctlf); module_put(card->module); snd_card_file_remove(card, file); return 0; @@ -160,11 +218,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, return; if (card->shutdown) return; - read_lock_irqsave(&card->ctl_files_rwlock, flags); + read_lock_irqsave(&card->ctl->files_rwlock, flags); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; #endif - list_for_each_entry(ctl, &card->ctl_files, list) { + list_for_each_entry(ctl, &card->ctl->files, list) { if (!ctl->subscribed) continue; spin_lock(&ctl->read_lock); @@ -187,7 +245,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, spin_unlock(&ctl->read_lock); snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN); } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags); } EXPORT_SYMBOL(snd_ctl_notify);
@@ -341,13 +399,13 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, struct snd_kcontrol *kctl;
/* Make sure that the ids assigned to the control do not wrap around */ - if (card->last_numid >= UINT_MAX - count) - card->last_numid = 0; + if (card->ctl->last_numid >= UINT_MAX - count) + card->ctl->last_numid = 0;
- list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.numid < card->last_numid + 1 + count && - kctl->id.numid + kctl->count > card->last_numid + 1) { - card->last_numid = kctl->id.numid + kctl->count - 1; + list_for_each_entry(kctl, &card->ctl->controls, list) { + if (kctl->id.numid < card->ctl->last_numid + 1 + count && + kctl->id.numid + kctl->count > card->ctl->last_numid + 1) { + card->ctl->last_numid = kctl->id.numid + kctl->count - 1; return true; } } @@ -406,18 +464,19 @@ static void add_hash_entries(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id = kcontrol->id; + struct snd_control *ctl = card->ctl; int i;
- xa_store_range(&card->ctl_numids, kcontrol->id.numid, + xa_store_range(&ctl->numids, kcontrol->id.numid, kcontrol->id.numid + kcontrol->count - 1, kcontrol, GFP_KERNEL);
for (i = 0; i < kcontrol->count; i++) { id.index = kcontrol->id.index + i; - if (xa_insert(&card->ctl_hash, get_ctl_id_hash(&id), + if (xa_insert(&ctl->hash, get_ctl_id_hash(&id), kcontrol, GFP_KERNEL)) { /* skip hash for this entry, noting we had collision */ - card->ctl_hash_collision = true; + ctl->hash_collision = true; dev_dbg(card->dev, "ctl_hash collision %d:%s:%d\n", id.iface, id.name, id.index); } @@ -429,17 +488,18 @@ static void remove_hash_entries(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id = kcontrol->id; + struct snd_control *ctl = card->ctl; struct snd_kcontrol *matched; unsigned long h; int i;
for (i = 0; i < kcontrol->count; i++) { - xa_erase(&card->ctl_numids, id.numid); + xa_erase(&ctl->numids, id.numid); h = get_ctl_id_hash(&id); - matched = xa_load(&card->ctl_hash, h); + matched = xa_load(&ctl->hash, h); if (matched && (matched == kcontrol || elem_id_matches(matched, &id))) - xa_erase(&card->ctl_hash, h); + xa_erase(&ctl->hash, h); id.index++; id.numid++; } @@ -469,7 +529,7 @@ static int __snd_ctl_add_replace(struct snd_card *card, struct snd_kcontrol *old; int err;
- lockdep_assert_held_write(&card->controls_rwsem); + lockdep_assert_held_write(&card->ctl->controls_rwsem);
id = kcontrol->id; if (id.index > UINT_MAX - kcontrol->count) @@ -496,10 +556,10 @@ static int __snd_ctl_add_replace(struct snd_card *card, if (snd_ctl_find_hole(card, kcontrol->count) < 0) return -ENOMEM;
- list_add_tail(&kcontrol->list, &card->controls); - card->controls_count += kcontrol->count; - kcontrol->id.numid = card->last_numid + 1; - card->last_numid += kcontrol->count; + list_add_tail(&kcontrol->list, &card->ctl->controls); + card->ctl->controls_count += kcontrol->count; + kcontrol->id.numid = card->ctl->last_numid + 1; + card->ctl->last_numid += kcontrol->count;
add_hash_entries(card, kcontrol);
@@ -520,9 +580,9 @@ static int snd_ctl_add_replace(struct snd_card *card, if (snd_BUG_ON(!card || !kcontrol->info)) goto error;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); err = __snd_ctl_add_replace(card, kcontrol, mode); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); if (err < 0) goto error; return 0; @@ -580,7 +640,7 @@ static int __snd_ctl_remove(struct snd_card *card, { unsigned int idx;
- lockdep_assert_held_write(&card->controls_rwsem); + lockdep_assert_held_write(&card->ctl->controls_rwsem);
if (snd_BUG_ON(!card || !kcontrol)) return -EINVAL; @@ -589,7 +649,7 @@ static int __snd_ctl_remove(struct snd_card *card, if (remove_hash) remove_hash_entries(card, kcontrol);
- card->controls_count -= kcontrol->count; + card->ctl->controls_count -= kcontrol->count; for (idx = 0; idx < kcontrol->count; idx++) snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); snd_ctl_free_one(kcontrol); @@ -618,9 +678,9 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { int ret;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); ret = snd_ctl_remove_locked(card, kcontrol); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL(snd_ctl_remove); @@ -640,14 +700,14 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) struct snd_kcontrol *kctl; int ret;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; } ret = snd_ctl_remove_locked(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL(snd_ctl_remove_id); @@ -669,7 +729,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, struct snd_kcontrol *kctl; int idx, ret;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; @@ -686,7 +746,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, } ret = snd_ctl_remove_locked(card, kctl); error: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; }
@@ -710,7 +770,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, unsigned int index_offset; int ret;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; @@ -729,13 +789,13 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; } snd_ctl_build_ioff(id, kctl, index_offset); - downgrade_write(&card->controls_rwsem); + downgrade_write(&card->ctl->controls_rwsem); snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, index_offset); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 1;
unlock: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL_GPL(snd_ctl_activate_id); @@ -764,10 +824,10 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, struct snd_kcontrol *kctl; int saved_numid;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, src_id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; } saved_numid = kctl->id.numid; @@ -775,7 +835,7 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, kctl->id = *dst_id; kctl->id.numid = saved_numid; add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return 0; } EXPORT_SYMBOL(snd_ctl_rename_id); @@ -793,7 +853,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id); void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name) { - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); remove_hash_entries(card, kctl);
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0) @@ -801,7 +861,7 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, name, kctl->id.name);
add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); } EXPORT_SYMBOL(snd_ctl_rename);
@@ -836,9 +896,9 @@ snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid) { if (snd_BUG_ON(!card || !numid)) return NULL; - lockdep_assert_held(&card->controls_rwsem); + lockdep_assert_held(&card->ctl->controls_rwsem); #ifdef CONFIG_SND_CTL_FAST_LOOKUP - return xa_load(&card->ctl_numids, numid); + return xa_load(&card->ctl->numids, numid); #else return snd_ctl_find_numid_slow(card, numid); #endif @@ -861,9 +921,9 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, { struct snd_kcontrol *kctl;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return kctl; } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -887,18 +947,18 @@ struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card,
if (snd_BUG_ON(!card || !id)) return NULL; - lockdep_assert_held(&card->controls_rwsem); + lockdep_assert_held(&card->ctl->controls_rwsem); if (id->numid != 0) return snd_ctl_find_numid_locked(card, id->numid); #ifdef CONFIG_SND_CTL_FAST_LOOKUP - kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id)); + kctl = xa_load(&card->ctl->hash, get_ctl_id_hash(id)); if (kctl && elem_id_matches(kctl, id)) return kctl; - if (!card->ctl_hash_collision) + if (!card->ctl->hash_collision) return NULL; /* we can rely on only hash table */ #endif /* no matching in hash table - try all as the last resort */ - list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) if (elem_id_matches(kctl, id)) return kctl;
@@ -922,9 +982,9 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, { struct snd_kcontrol *kctl;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return kctl; } EXPORT_SYMBOL(snd_ctl_find_id); @@ -965,11 +1025,11 @@ static int snd_ctl_elem_list(struct snd_card *card, offset = list->offset; space = list->space;
- down_read(&card->controls_rwsem); - list->count = card->controls_count; + down_read(&card->ctl->controls_rwsem); + list->count = card->ctl->controls_count; list->used = 0; if (space > 0) { - list_for_each_entry(kctl, &card->controls, list) { + list_for_each_entry(kctl, &card->ctl->controls, list) { if (offset >= kctl->count) { offset -= kctl->count; continue; @@ -989,7 +1049,7 @@ static int snd_ctl_elem_list(struct snd_card *card, } } out: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return err; }
@@ -1240,13 +1300,13 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, struct snd_kcontrol *kctl; int result;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &info->id); if (kctl == NULL) result = -ENOENT; else result = __snd_ctl_elem_info(card, kctl, info, ctl); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return result; }
@@ -1279,7 +1339,7 @@ static int snd_ctl_elem_read(struct snd_card *card, const u32 pattern = 0xdeadbeef; int ret;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { ret = -ENOENT; @@ -1323,7 +1383,7 @@ static int snd_ctl_elem_read(struct snd_card *card, goto unlock; } unlock: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return ret; }
@@ -1356,10 +1416,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, unsigned int index_offset; int result;
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; }
@@ -1367,7 +1427,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, vd = &kctl->vd[index_offset]; if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL || (file && vd->owner && vd->owner != file)) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -EPERM; }
@@ -1388,16 +1448,16 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, result = kctl->put(kctl, control); snd_power_unref(card); if (result < 0) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; }
if (result > 0) { - downgrade_write(&card->controls_rwsem); + downgrade_write(&card->ctl->controls_rwsem); snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, index_offset); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); } else { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); }
return 0; @@ -1437,7 +1497,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; @@ -1450,7 +1510,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, result = 0; } } - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; }
@@ -1465,7 +1525,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; @@ -1480,7 +1540,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, result = 0; } } - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; }
@@ -1497,7 +1557,7 @@ struct user_element { // check whether the addition (in bytes) of user ctl element may overflow the limit. static bool check_user_elem_overflow(struct snd_card *card, ssize_t add) { - return (ssize_t)card->user_ctl_alloc_size + add > max_user_ctl_alloc_size; + return (ssize_t)card->ctl->user_ctl_alloc_size + add > max_user_ctl_alloc_size; }
static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, @@ -1575,7 +1635,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, int i; int change;
- lockdep_assert_held_write(&ue->card->controls_rwsem); + lockdep_assert_held_write(&ue->card->ctl->controls_rwsem);
if (size > 1024 * 128) /* sane value */ return -EINVAL; @@ -1602,7 +1662,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; mask = SNDRV_CTL_EVENT_MASK_INFO; } else { - ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->card->ctl->user_ctl_alloc_size -= ue->tlv_data_size; ue->tlv_data_size = 0; kvfree(ue->tlv_data); } @@ -1610,7 +1670,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, ue->tlv_data = container; ue->tlv_data_size = size; // decremented at private_free. - ue->card->user_ctl_alloc_size += size; + ue->card->ctl->user_ctl_alloc_size += size;
mask |= SNDRV_CTL_EVENT_MASK_TLV; for (i = 0; i < kctl->count; ++i) @@ -1653,7 +1713,7 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) unsigned int i; const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
- lockdep_assert_held_write(&ue->card->controls_rwsem); + lockdep_assert_held_write(&ue->card->ctl->controls_rwsem);
buf_len = ue->info.value.enumerated.names_length; if (buf_len > 64 * 1024) @@ -1680,7 +1740,7 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) ue->priv_data = names; ue->info.value.enumerated.names_ptr = 0; // increment the allocation size; decremented again at private_free. - ue->card->user_ctl_alloc_size += ue->info.value.enumerated.names_length; + ue->card->ctl->user_ctl_alloc_size += ue->info.value.enumerated.names_length;
return 0; } @@ -1695,10 +1755,10 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) struct user_element *ue = kcontrol->private_data;
// decrement the allocation size. - ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); - ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->card->ctl->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); + ue->card->ctl->user_ctl_alloc_size -= ue->tlv_data_size; if (ue->priv_data) - ue->card->user_ctl_alloc_size -= ue->info.value.enumerated.names_length; + ue->card->ctl->user_ctl_alloc_size -= ue->info.value.enumerated.names_length;
kvfree(ue->tlv_data); kvfree(ue->priv_data); @@ -1763,7 +1823,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, private_size = value_sizes[info->type] * info->count; alloc_size = compute_user_elem_size(private_size, count);
- down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); if (check_user_elem_overflow(card, alloc_size)) { err = -ENOMEM; goto unlock; @@ -1789,7 +1849,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->private_free = snd_ctl_elem_user_free;
// increment the allocated size; decremented again at private_free. - card->user_ctl_alloc_size += alloc_size; + card->ctl->user_ctl_alloc_size += alloc_size;
/* Set private data for this userspace control. */ ue->card = card; @@ -1833,7 +1893,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * which locks the element. */ unlock: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return err; }
@@ -1959,7 +2019,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, struct snd_ctl_elem_id id; struct snd_kcontrol_volatile *vd;
- lockdep_assert_held(&file->card->controls_rwsem); + lockdep_assert_held(&file->card->ctl->controls_rwsem);
if (copy_from_user(&header, buf, sizeof(header))) return -EFAULT; @@ -2036,19 +2096,19 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, ip); case SNDRV_CTL_IOCTL_TLV_READ: - down_read(&ctl->card->controls_rwsem); + down_read(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); - up_read(&ctl->card->controls_rwsem); + up_read(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_TLV_WRITE: - down_write(&ctl->card->controls_rwsem); + down_write(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); - up_write(&ctl->card->controls_rwsem); + up_write(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_TLV_COMMAND: - down_write(&ctl->card->controls_rwsem); + down_write(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); - up_write(&ctl->card->controls_rwsem); + up_write(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; @@ -2258,15 +2318,15 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) int subdevice = -1; unsigned long flags;
- read_lock_irqsave(&card->ctl_files_rwlock, flags); - list_for_each_entry(kctl, &card->ctl_files, list) { + read_lock_irqsave(&card->ctl->files_rwlock, flags); + list_for_each_entry(kctl, &card->ctl->files, list) { if (kctl->pid == task_pid(current)) { subdevice = kctl->preferred_subdevice[type]; if (subdevice != -1) break; } } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags); return subdevice; } EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); @@ -2326,9 +2386,9 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops) for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { card = snd_card_ref(card_number); if (card) { - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); lops->lregister(card); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); snd_card_unref(card); } } @@ -2389,15 +2449,15 @@ static int snd_ctl_dev_register(struct snd_device *device) int err;
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, - &snd_ctl_f_ops, card, card->ctl_dev); + &snd_ctl_f_ops, card, &card->ctl->dev); if (err < 0) return err; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); down_read(&snd_ctl_layer_rwsem); for (lops = snd_ctl_layer; lops; lops = lops->next) lops->lregister(card); up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 0; }
@@ -2411,21 +2471,21 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) struct snd_ctl_layer_ops *lops; unsigned long flags;
- read_lock_irqsave(&card->ctl_files_rwlock, flags); - list_for_each_entry(ctl, &card->ctl_files, list) { + read_lock_irqsave(&card->ctl->files_rwlock, flags); + list_for_each_entry(ctl, &card->ctl->files, list) { wake_up(&ctl->change_sleep); snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags);
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); down_read(&snd_ctl_layer_rwsem); for (lops = snd_ctl_layer; lops; lops = lops->next) lops->ldisconnect(card); up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem);
- return snd_unregister_device(card->ctl_dev); + return snd_unregister_device(&card->ctl->dev); }
/* @@ -2436,48 +2496,26 @@ static int snd_ctl_dev_free(struct snd_device *device) struct snd_card *card = device->device_data; struct snd_kcontrol *control;
- down_write(&card->controls_rwsem); - while (!list_empty(&card->controls)) { - control = snd_kcontrol(card->controls.next); + down_write(&card->ctl->controls_rwsem); + while (!list_empty(&card->ctl->controls)) { + control = snd_kcontrol(card->ctl->controls.next); __snd_ctl_remove(card, control, false); }
#ifdef CONFIG_SND_CTL_FAST_LOOKUP - xa_destroy(&card->ctl_numids); - xa_destroy(&card->ctl_hash); + xa_destroy(&card->ctl->numids); + xa_destroy(&card->ctl->hash); #endif - up_write(&card->controls_rwsem); - put_device(card->ctl_dev); + up_write(&card->ctl->controls_rwsem); + put_device(&card->ctl->dev); return 0; }
-/* - * create control core: - * called from init.c - */ -int snd_ctl_create(struct snd_card *card) +static void release_control_device(struct device *dev) { - static const struct snd_device_ops ops = { - .dev_free = snd_ctl_dev_free, - .dev_register = snd_ctl_dev_register, - .dev_disconnect = snd_ctl_dev_disconnect, - }; - int err; + struct snd_control *ctl = container_of(dev, struct snd_control, dev);
- if (snd_BUG_ON(!card)) - return -ENXIO; - if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS)) - return -ENXIO; - - err = snd_device_alloc(&card->ctl_dev, card); - if (err < 0) - return err; - dev_set_name(card->ctl_dev, "controlC%d", card->number); - - err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); - if (err < 0) - put_device(card->ctl_dev); - return err; + kfree(ctl); }
/* diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 0e8b1bfb040e0..0e0b555f71537 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -172,15 +172,15 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, struct snd_ctl_elem_info *info; int err;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (! kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return -ENOENT; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return -ENOMEM; } info->id = *id; @@ -188,7 +188,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, if (!err) err = kctl->info(kctl, info); snd_power_unref(card); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); if (err >= 0) { err = info->type; *countp = info->count; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index a78eb48927c7b..6b53de7660438 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -243,6 +243,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, unsigned int group, bool set) { struct snd_card *card; + struct snd_control *ctl; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; unsigned int ioff, access, new_access; @@ -250,7 +251,8 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
card = snd_card_ref(card_number); if (card) { - down_write(&card->controls_rwsem); + ctl = card->ctl; + down_write(&ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl) { ioff = snd_ctl_get_ioff(kctl, id); @@ -271,7 +273,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, err = -ENOENT; } unlock: - up_write(&card->controls_rwsem); + up_write(&ctl->controls_rwsem); snd_card_unref(card); } else { err = -ENXIO; @@ -357,7 +359,7 @@ static void snd_ctl_led_register(struct snd_card *card) snd_ctl_led_card_valid[card->number] = true; mutex_unlock(&snd_ctl_led_mutex); /* the register callback is already called with held card->controls_rwsem */ - list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) for (ioff = 0; ioff < kctl->count; ioff++) snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff); snd_ctl_led_refresh(); @@ -617,12 +619,14 @@ static ssize_t list_show(struct device *dev, struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); struct snd_card *card; struct snd_ctl_led_ctl *lctl; + struct snd_control *ctl; size_t l = 0;
card = snd_card_ref(led_card->number); if (!card) return -ENXIO; - down_read(&card->controls_rwsem); + ctl = card->ctl; + down_read(&ctl->controls_rwsem); mutex_lock(&snd_ctl_led_mutex); if (snd_ctl_led_card_valid[led_card->number]) { list_for_each_entry(lctl, &led_card->led->controls, list) { @@ -635,7 +639,7 @@ static ssize_t list_show(struct device *dev, } } mutex_unlock(&snd_ctl_led_mutex); - up_read(&card->controls_rwsem); + up_read(&ctl->controls_rwsem); snd_card_unref(card); return l; } @@ -688,7 +692,7 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card) goto cerr; led->cards[card->number] = led_card; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - WARN(sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, link_name), + WARN(sysfs_create_link(&card->ctl->dev.kobj, &led_card->dev.kobj, link_name), "can't create symlink to controlC%i device\n", card->number); WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), "can't create symlink to card%i\n", card->number); @@ -714,7 +718,7 @@ static void snd_ctl_led_sysfs_remove(struct snd_card *card) if (!led_card) continue; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - sysfs_remove_link(&card->ctl_dev->kobj, link_name); + sysfs_remove_link(&card->ctl->dev.kobj, link_name); sysfs_remove_link(&led_card->dev.kobj, "card"); device_unregister(&led_card->dev); led->cards[card->number] = NULL; diff --git a/sound/core/init.c b/sound/core/init.c index 87b5368d20350..9cd2cb22de728 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -328,14 +328,6 @@ static int snd_card_init(struct snd_card *card, struct device *parent, card->module = module; #endif INIT_LIST_HEAD(&card->devices); - init_rwsem(&card->controls_rwsem); - rwlock_init(&card->ctl_files_rwlock); - INIT_LIST_HEAD(&card->controls); - INIT_LIST_HEAD(&card->ctl_files); -#ifdef CONFIG_SND_CTL_FAST_LOOKUP - xa_init(&card->ctl_numids); - xa_init(&card->ctl_hash); -#endif spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); mutex_init(&card->memory_mutex); @@ -360,11 +352,9 @@ static int snd_card_init(struct snd_card *card, struct device *parent, snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s", dev_driver_string(card->dev), dev_name(&card->card_dev));
- /* 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); + err = snd_control_new(card); if (err < 0) { - dev_err(parent, "unable to register control minors\n"); + dev_err(parent, "unable to create controls and register\n"); goto __error; } err = snd_info_card_create(card); diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index dae2da3808351..d9457f2e73550 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -539,10 +539,10 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -560,7 +560,7 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, if (uinfo->count > 1) *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); __unalloc: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); kfree(uctl); kfree(uinfo); } @@ -578,10 +578,10 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -600,7 +600,7 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) *right = 0; __unalloc: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); kfree(uctl); kfree(uinfo); } @@ -644,10 +644,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -668,7 +668,7 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); kfree(uctl); kfree(uinfo); } @@ -687,10 +687,10 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); if (!kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -715,7 +715,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); kfree(uctl); kfree(uinfo); } @@ -832,7 +832,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOMEM; goto __free_only; } - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); if (! kctl) { err = -ENOENT; @@ -860,7 +860,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned } err = 0; __unlock: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); __free_only: kfree(uctl); kfree(uinfo); @@ -885,7 +885,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOMEM; goto __free_only; } - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); if (! kctl) { err = -ENOENT; @@ -916,7 +916,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); err = 0; __unlock: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); __free_only: kfree(uctl); kfree(uinfo); @@ -936,25 +936,25 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl struct snd_card *card = mixer->card; int err;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kcontrol = snd_mixer_oss_test_id(mixer, name, index); if (kcontrol == NULL) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 0; } info = kmalloc(sizeof(*info), GFP_KERNEL); if (! info) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return -ENOMEM; } err = kcontrol->info(kcontrol, info); if (err < 0) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); kfree(info); return err; } slot->numid[item] = kcontrol->id.numid; - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); if (info->count > slot->channels) slot->channels = info->count; slot->present |= 1 << item; @@ -1068,7 +1068,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) return 0; - down_read(&mixer->card->controls_rwsem); + down_read(&mixer->card->ctl->controls_rwsem); kctl = NULL; if (!ptr->index) kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -1077,12 +1077,12 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); if (! uinfo) { - up_read(&mixer->card->controls_rwsem); + up_read(&mixer->card->ctl->controls_rwsem); return -ENOMEM; } if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); + up_read(&mixer->card->ctl->controls_rwsem); kfree(uinfo); return 0; } @@ -1098,7 +1098,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { uinfo->value.enumerated.item = slot.capture_item; if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); + up_read(&mixer->card->ctl->controls_rwsem); kfree(uinfo); return 0; } @@ -1110,7 +1110,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, } kfree(uinfo); } - up_read(&mixer->card->controls_rwsem); + up_read(&mixer->card->ctl->controls_rwsem); if (slot.present != 0) { pslot = kmalloc(sizeof(slot), GFP_KERNEL); if (! pslot) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 33af707a65ab1..7afc9a29ea9ec 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1784,13 +1784,14 @@ void snd_hda_ctls_clear(struct hda_codec *codec) int snd_hda_lock_devices(struct hda_bus *bus) { struct snd_card *card = bus->card; + struct snd_control *ctl = card->ctl; struct hda_codec *codec;
spin_lock(&card->files_lock); if (card->shutdown) goto err_unlock; card->shutdown = 1; - if (!list_empty(&card->ctl_files)) + if (!list_empty(&ctl->files)) goto err_clear;
list_for_each_codec(codec, bus) { diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 38116c7587174..8cd5681de9fbd 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1434,9 +1434,9 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, struct snd_card *card = component->card->snd_card; char *idx;
- down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem);
- list_for_each_entry(kctl, &card->controls, list) { + list_for_each_entry(kctl, &card->ctl->controls, list) { idx = strchr(kctl->id.name, ' '); if (idx == NULL) continue; @@ -1469,12 +1469,12 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, }
if (ret < 0) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return ret; } }
- up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 0; }
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index 285ab4c9c7168..1129eb33f78c9 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -35,7 +35,7 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, if (unlikely(!name)) return NULL;
- list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) return kctl; return NULL; diff --git a/sound/usb/media.c b/sound/usb/media.c index d48db6f3ae659..5298c2f49a164 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -163,7 +163,7 @@ void snd_media_stop_pipeline(struct snd_usb_substream *subs)
static int snd_media_mixer_init(struct snd_usb_audio *chip) { - struct device *ctl_dev = chip->card->ctl_dev; + struct device *ctl_dev = &chip->card->ctl->dev; struct media_intf_devnode *ctl_intf; struct usb_mixer_interface *mixer; struct media_device *mdev = chip->media_dev;
On Wed, Sep 13, 2023 at 01:07:44PM -0700, cujomalainey@chromium.org wrote:
From: Curtis Malainey cujomalainey@chromium.org
Having two kobj in the same struct is broken at its core. This splits card_dev from ctl_dev so they can properly refcount and release on their own schedules without the workaround of having them being just a pointer.
Acked-by: Mark Brown broonie@kernel.org
Change-Id: Iecc91a116dfcb5a6364c7e6bdf993949e8542ca1
Please don't put change IDs in upstream submissions (or put them after the --- so they get dropped on application like b4 does in cover letters, it might be good to look at improving the tooling around gerritt to support that since it seems like a pretty good comprimise which would reduce friction).
On Wed, 13 Sep 2023 22:07:42 +0200, cujomalainey@chromium.org wrote:
From: Curtis Malainey cujomalainey@chromium.org
Begin allowing refactored modules to allocate their own device but use a common initialization procedure for their devices.
Signed-off-by: Curtis Malainey cujomalainey@chromium.org
include/sound/core.h | 1 + sound/core/init.c | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/include/sound/core.h b/include/sound/core.h index dfef0c9d4b9f7..a4744e142c7e3 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -240,6 +240,7 @@ extern struct dentry *sound_debugfs_root; void snd_request_card(int card);
int snd_device_alloc(struct device **dev_p, struct snd_card *card); +void snd_device_init(struct device *dev, struct snd_card *card);
int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, diff --git a/sound/core/init.c b/sound/core/init.c index 22c0d217b8608..87b5368d20350 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -132,15 +132,28 @@ int snd_device_alloc(struct device **dev_p, struct snd_card *card) dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM;
- snd_device_init(dev, card);
- *dev_p = dev;
- return 0;
+} +EXPORT_SYMBOL_GPL(snd_device_alloc);
+/**
- snd_device_init - Initialize struct device for sound devices
- @dev_p: pointer to store the allocated device
- @card: card to assign, optional
- For releasing the allocated device, call put_device().
- */
+void snd_device_init(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_alloc;
I'd rather leave release unset here and mention in the function description to set release in each caller side. default_release_alloc() calls kfree(), and certainly it doesn't match with this call.
thanks,
Takashi
participants (3)
-
cujomalainey@chromium.org
-
Mark Brown
-
Takashi Iwai