diff --git a/include/sound/control.h b/include/sound/control.h index 4721b4bba053..4cf8f7aaa13f 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -171,6 +171,22 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, */ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, const unsigned int *tlv); -int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave); - +int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, + unsigned int flags); +/* optional flags for slave */ +#define SND_CTL_SLAVE_NEED_UPDATE (1 << 0) + +static inline int +snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) +{ + return _snd_ctl_add_slave(master, slave, 0); +} + +static inline int +snd_ctl_add_slave_uncached(struct snd_kcontrol *master, + struct snd_kcontrol *slave) +{ + return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); +} + #endif /* __SOUND_CONTROL_H */ diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 4cc57f902e2c..d51b198d06d9 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -50,18 +50,38 @@ struct link_slave { struct link_master *master; struct link_ctl_info info; int vals[2]; /* current values */ + unsigned int flags; struct snd_kcontrol slave; /* the copy of original control entry */ }; +static int slave_update(struct link_slave *slave) +{ + struct snd_ctl_elem_value *uctl; + int err, ch; + + uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return -ENOMEM; + uctl->id = slave->slave.id; + err = slave->slave.get(&slave->slave, uctl); + for (ch = 0; ch < slave->info.count; ch++) + slave->vals[ch] = uctl->value.integer.value[ch]; + kfree(uctl); + return 0; +} + /* get the slave ctl info and save the initial values */ static int slave_init(struct link_slave *slave) { struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; - int err, ch; + int err; - if (slave->info.count) - return 0; /* already initialized */ + if (slave->info.count) { + /* already initialized */ + if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE) + return slave_update(slave); + return 0; + } uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); if (!uinfo) @@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave) slave->info.max_val = uinfo->value.integer.max; kfree(uinfo); - uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); - if (!uctl) - return -ENOMEM; - uctl->id = slave->slave.id; - err = slave->slave.get(&slave->slave, uctl); - for (ch = 0; ch < slave->info.count; ch++) - slave->vals[ch] = uctl->value.integer.value[ch]; - kfree(uctl); - return 0; + return slave_update(slave); } /* initialize master volume */ @@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol) * - logarithmic volume control (dB level), no linear volume * - master can only attenuate the volume, no gain */ -int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) +int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, + unsigned int flags) { struct link_master *master_link = snd_kcontrol_chip(master); struct link_slave *srec; @@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) srec->slave = *slave; memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); srec->master = master_link; + srec->flags = flags; /* override callbacks */ slave->info = slave_info; @@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) list_add_tail(&srec->list, &master_link->slaves); return 0; } - -EXPORT_SYMBOL(snd_ctl_add_slave); +EXPORT_SYMBOL(_snd_ctl_add_slave); /* * ctl callbacks for master controls @@ -367,5 +380,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, return kctl; } - EXPORT_SYMBOL(snd_ctl_make_virtual_master);