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.
Signed-off-by: Curtis Malainey cujomalainey@chromium.org --- include/sound/control.h | 1 + include/sound/core.h | 33 +-- sound/core/control.c | 330 +++++++++++++---------- sound/core/control_compat.c | 8 +- sound/core/control_led.c | 18 +- sound/core/init.c | 14 +- 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 +- 10 files changed, 232 insertions(+), 187 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..93048a7a800f4 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,23 @@ 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..09066d05a8800 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -41,12 +41,49 @@ static struct snd_ctl_layer_ops *snd_ctl_layer;
static int snd_ctl_remove_locked(struct snd_card *card, struct snd_kcontrol *kcontrol); +/** + * 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) +{ + struct snd_control *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + int err; + + if (snd_BUG_ON(!card)) + return -EINVAL; + if (!ctl) + return -ENOMEM; + + 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 */ + err = snd_ctl_create(card); + if (err < 0) { + dev_err(card->dev, "unable to register control minors\n"); + kfree(ctl); + return err; + } + return 0; +} +EXPORT_SYMBOL(snd_control_new);
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 +95,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 +105,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 +151,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 +197,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 +224,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 +378,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 +443,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 +467,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 +508,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 +535,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 +559,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 +619,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 +628,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 +657,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 +679,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 +708,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 +725,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 +749,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 +768,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 +803,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 +814,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 +832,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 +840,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 +875,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 +900,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 +926,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 +961,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 +1004,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 +1028,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 +1279,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 +1318,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 +1362,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 +1395,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 +1406,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 +1427,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 +1476,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 +1489,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 +1504,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 +1519,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 +1536,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 +1614,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 +1641,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 +1649,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 +1692,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 +1719,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 +1734,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 +1802,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 +1828,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 +1872,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 +1998,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 +2075,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 +2297,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 +2365,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 +2428,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 +2450,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,21 +2475,28 @@ 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; }
+static void release_control_device(struct device *dev) +{ + struct snd_control *ctl = container_of(dev, struct snd_control, dev); + + kfree(ctl); +} + /* * create control core: * called from init.c @@ -2462,6 +2508,7 @@ int snd_ctl_create(struct snd_card *card) .dev_register = snd_ctl_dev_register, .dev_disconnect = snd_ctl_dev_disconnect, }; + struct snd_control *ctl = card->ctl; int err;
if (snd_BUG_ON(!card)) @@ -2469,14 +2516,13 @@ int snd_ctl_create(struct snd_card *card) 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); + 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(card->ctl_dev); + put_device(&ctl->dev); return err; }
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 37a8e4791f781..695b080603e93 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -331,14 +331,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); @@ -363,11 +355,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/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;