diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-06-28 17:25:57 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-06-28 17:26:27 +0200 |
commit | b53215eddce7b69170c83282a8ebec95e6d7a59f (patch) | |
tree | 5a628b1437c2d7e2561a244f7abe79cc3ddd3f36 | |
parent | 6bace726387332b2d4d9dd563e8b0fc82dbce952 (diff) | |
download | hda-emu-b53215eddce7b69170c83282a8ebec95e6d7a59f.tar.gz |
Add snd_ctl_sync_vmaster()
Taken from the upstream change (commit 1ca2f2ec).
-rw-r--r-- | include/sound/control.h | 3 | ||||
-rw-r--r-- | snd-vmaster.c | 80 |
2 files changed, 58 insertions, 25 deletions
diff --git a/include/sound/control.h b/include/sound/control.h index 346ec79..47b92c5 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -160,7 +160,8 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master, int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl, void (*hook)(void *, int), void *private_data); -void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl); +void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only); +#define snd_ctl_sync_vmaster_hook(kctl) snd_ctl_sync_vmaster(kctl, true) /* * Helper functions for jack-detection controls diff --git a/snd-vmaster.c b/snd-vmaster.c index 8b984d5..5df8dc2 100644 --- a/snd-vmaster.c +++ b/snd-vmaster.c @@ -44,7 +44,7 @@ struct link_master { /* * link slave - this contains a slave control element * - * It fakes the control callbacks with additional attenuation by the + * It fakes the control callbacsk with additional attenuation by the * master control. A slave may have either one or two channels. */ @@ -213,7 +213,10 @@ static int slave_put(struct snd_kcontrol *kcontrol, } if (!changed) return 0; - return slave_put_val(slave, ucontrol); + err = slave_put_val(slave, ucontrol); + if (err < 0) + return err; + return 1; } static int slave_tlv_cmd(struct snd_kcontrol *kcontrol, @@ -307,20 +310,10 @@ static int master_get(struct snd_kcontrol *kcontrol, return 0; } -static int master_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int sync_slaves(struct link_master *master, int old_val, int new_val) { - struct link_master *master = snd_kcontrol_chip(kcontrol); struct link_slave *slave; struct snd_ctl_elem_value *uval; - int err, old_val; - - err = master_init(master); - if (err < 0) - return err; - old_val = master->val; - if (ucontrol->value.integer.value[0] == old_val) - return 0; uval = kmalloc(sizeof(*uval), GFP_KERNEL); if (!uval) @@ -329,11 +322,33 @@ static int master_put(struct snd_kcontrol *kcontrol, master->val = old_val; uval->id = slave->slave.id; slave_get_val(slave, uval); - master->val = ucontrol->value.integer.value[0]; + master->val = new_val; slave_put_val(slave, uval); } kfree(uval); - if (master->hook && !err) + return 0; +} + +static int master_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct link_master *master = snd_kcontrol_chip(kcontrol); + int err, new_val, old_val; + bool first_init; + + err = master_init(master); + if (err < 0) + return err; + first_init = err; + old_val = master->val; + new_val = ucontrol->value.integer.value[0]; + if (new_val == old_val) + return 0; + + err = sync_slaves(master, old_val, new_val); + if (err < 0) + return err; + if (master->hook && first_init) master->hook(master->hook_private_data, master->val); return 1; } @@ -343,7 +358,7 @@ static void master_free(struct snd_kcontrol *kcontrol) struct link_master *master = snd_kcontrol_chip(kcontrol); struct link_slave *slave, *n; - /* free all slave links and restore the original slave kctls */ + /* free all slave links and retore the original slave kctls */ list_for_each_entry_safe(slave, n, &master->slaves, list) { struct snd_kcontrol *sctl = slave->kctl; struct list_head olist = sctl->list; @@ -363,7 +378,6 @@ static void master_free(struct snd_kcontrol *kcontrol) * @tlv: optional TLV int array for dB information * * Creates a virtual master control with the given name string. - * Returns the created control element, or NULL for errors (ENOMEM). * * After creating a vmaster element, you can add the slave controls * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached(). @@ -372,6 +386,8 @@ static void master_free(struct snd_kcontrol *kcontrol) * for dB scale of the master control. It should be a single element * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB. + * + * Return: The created control element, or %NULL for errors (ENOMEM). */ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, const unsigned int *tlv) @@ -419,9 +435,12 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master); * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control * @kcontrol: vmaster kctl element * @hook: the hook function + * @private_data: the private_data pointer to be saved * * Adds the given hook to the vmaster control element so that it's called * at each time when the value is changed. + * + * Return: Zero. */ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, void (*hook)(void *private_data, int), @@ -435,20 +454,33 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook); /** - * snd_ctl_sync_vmaster_hook - Sync the vmaster hook + * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook * @kcontrol: vmaster kctl element + * @hook_only: sync only the hook * - * Call the hook function to synchronize with the current value of the given - * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't - * exist. + * Forcibly call the put callback of each slave and call the hook function + * to synchronize with the current value of the given vmaster element. + * NOP when NULL is passed to @kcontrol. */ -void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol) +void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only) { struct link_master *master; + bool first_init = false; + if (!kcontrol) return; master = snd_kcontrol_chip(kcontrol); - if (master->hook) + if (!hook_only) { + int err = master_init(master); + if (err < 0) + return; + first_init = err; + err = sync_slaves(master, master->val, master->val); + if (err < 0) + return; + } + + if (master->hook && !first_init) master->hook(master->hook_private_data, master->val); } -EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook); +EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); |