diff options
| -rw-r--r-- | include/sound/control.h | 1 | ||||
| -rw-r--r-- | sound/core/control.c | 64 | 
2 files changed, 65 insertions, 0 deletions
| diff --git a/include/sound/control.h b/include/sound/control.h index e67db2869360..40423810985a 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_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);  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 a08ad57c49b6..5d98194bcad5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -366,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)  EXPORT_SYMBOL(snd_ctl_add);  /** + * snd_ctl_replace - replace the control instance of the card + * @card: the card instance + * @kcontrol: the control instance to replace + * @add_on_replace: add the control if not already added + * + * Replaces the given control.  If the given control does not exist + * and the add_on_replace 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 replaced. + */ +int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, +		    bool add_on_replace) +{ +	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_replace) +			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_replace); + +/**   * snd_ctl_remove - remove the control from the card and release it   * @card: the card instance   * @kcontrol: the control instance to remove |