[alsa-devel] [PATCH 1/2 v3] ALSA: Add snd_ctl_update() to dynamically update a control
Add a function to dynamically update a given control. If the control does not already exist, a third parameter is used to determine whether to actually add that control. This is useful in cases where downloadable firmware at runtime can add or update existing controls. A separate patch needs to be made to allow ALSA Mixer to update the controls dynamically.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- Hi,
Any potentially locking related issues have been fixed now. Any comments on whether it would be advisable to use the same `numid' when I update an existing control?
Thanks, Dimitris
include/sound/control.h | 1 + sound/core/control.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 0 deletions(-)
diff --git a/include/sound/control.h b/include/sound/control.h index e67db28..2a2fd82 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -113,6 +113,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, v void snd_ctl_free_one(struct snd_kcontrol * kcontrol); int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol); int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol); +int snd_ctl_update(struct snd_card * card, struct snd_kcontrol * kcontrol, bool add_on_update); int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id); int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id); int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, diff --git a/sound/core/control.c b/sound/core/control.c index db51e4e..1d2b524 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -368,6 +368,71 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) EXPORT_SYMBOL(snd_ctl_add);
/** + * snd_ctl_update - update the control instance of the card + * @card: the card instance + * @kcontrol: the control instance to update + * @add_on_update: add the control if not already added + * + * Updates the given control. If the given control does not exist + * and the add_on_update flag is set, the control is added. If the + * control exists, it is destroyed first. + * + * Returns zero if successful, or a negative error code on failure. + * + * It frees automatically the control which cannot be added or updated. + */ +int snd_ctl_update(struct snd_card *card, struct snd_kcontrol *kcontrol, + bool add_on_update) +{ + struct snd_ctl_elem_id id; + unsigned int idx; + struct snd_kcontrol *old; + int ret; + + if (!kcontrol) + return -EINVAL; + if (snd_BUG_ON(!card || !kcontrol->info)) { + ret = -EINVAL; + goto error; + } + id = kcontrol->id; + down_write(&card->controls_rwsem); + old = snd_ctl_find_id(card, &id); + if (!old) { + if (add_on_update) + goto add; + up_write(&card->controls_rwsem); + ret = -EINVAL; + goto error; + } + ret = snd_ctl_remove(card, old); + if (ret < 0) { + up_write(&card->controls_rwsem); + goto error; + } +add: + if (snd_ctl_find_hole(card, kcontrol->count) < 0) { + up_write(&card->controls_rwsem); + ret = -ENOMEM; + goto error; + } + list_add_tail(&kcontrol->list, &card->controls); + card->controls_count += kcontrol->count; + kcontrol->id.numid = card->last_numid + 1; + card->last_numid += kcontrol->count; + up_write(&card->controls_rwsem); + for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + return 0; + +error: + snd_ctl_free_one(kcontrol); + return ret; +} + +EXPORT_SYMBOL(snd_ctl_update); + +/** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance * @kcontrol: the control instance to remove
This function can be used to update or add controls at runtime. It will always try to add a given control if it does not already exist.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index bfa4836..509c1ea 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -344,6 +344,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, const char *prefix); int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); +int snd_soc_update_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls); int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 17efacd..7ce2a07 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2420,6 +2420,39 @@ int snd_soc_add_controls(struct snd_soc_codec *codec, EXPORT_SYMBOL_GPL(snd_soc_add_controls);
/** + * snd_soc_update_controls - update an array of controls + * Convienience function to update a list of controls. + * + * @codec: codec to update controls of + * @controls: array of controls to update + * @num_controls: number of elements in the array + * + * Return 0 for success, else error. + */ +int snd_soc_update_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls) +{ + struct snd_card *card = codec->card->snd_card; + int err, i; + + for (i = 0; i < num_controls; i++) { + const struct snd_kcontrol_new *control = &controls[i]; + /* always add on update if not already added */ + err = snd_ctl_update(card, snd_soc_cnew(control, codec, + control->name, + codec->name_prefix), true); + if (err < 0) { + dev_err(codec->dev, "%s: Failed to update %s: %d\n", + codec->name, control->name, err); + return err; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_update_controls); + +/** * snd_soc_info_enum_double - enumerated double mixer info callback * @kcontrol: mixer control * @uinfo: control element information
Dimitris Papastamos wrote:
Any comments on whether it would be advisable to use the same `numid' when I update an existing control?
"Update" sounds like it would change some properties of the existing control. However, what this function does is to entirely replace the old control(s) with new one(s) (and this is also how the userspace notifications look), so I think assigning a new ID is appropriate here, if you call it snd_ctl_replace(). :)
Regards, Clemens
participants (2)
-
Clemens Ladisch
-
Dimitris Papastamos