Commit f5b1db63 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: add snd_ctl_add_slave_uncached()

Added snd_ctl_add_slave_uncached() function to add a slave element
with volatile controls.  The values of normal slave elements are
supposed to be cachable, i.e. they are changed only via the put
callbacks.  OTOH, when a slave element is volatile and its values may
be changed by other reason (e.g. hardware status change), the values
will get inconsistent.

The new function allows the slave elements with volatile changes.
When the slave is tied with this call, the native get callback is
issued at each time so that the values are always updated.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent fec6c6fe
...@@ -171,6 +171,22 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, ...@@ -171,6 +171,22 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
*/ */
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
const unsigned int *tlv); 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 */ #endif /* __SOUND_CONTROL_H */
...@@ -50,18 +50,38 @@ struct link_slave { ...@@ -50,18 +50,38 @@ struct link_slave {
struct link_master *master; struct link_master *master;
struct link_ctl_info info; struct link_ctl_info info;
int vals[2]; /* current values */ int vals[2]; /* current values */
unsigned int flags;
struct snd_kcontrol slave; /* the copy of original control entry */ 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 */ /* get the slave ctl info and save the initial values */
static int slave_init(struct link_slave *slave) static int slave_init(struct link_slave *slave)
{ {
struct snd_ctl_elem_info *uinfo; struct snd_ctl_elem_info *uinfo;
struct snd_ctl_elem_value *uctl; int err;
int err, ch;
if (slave->info.count) if (slave->info.count) {
return 0; /* already initialized */ /* already initialized */
if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
return slave_update(slave);
return 0;
}
uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
if (!uinfo) if (!uinfo)
...@@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave) ...@@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave)
slave->info.max_val = uinfo->value.integer.max; slave->info.max_val = uinfo->value.integer.max;
kfree(uinfo); kfree(uinfo);
uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); return slave_update(slave);
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;
} }
/* initialize master volume */ /* initialize master volume */
...@@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol) ...@@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol)
* - logarithmic volume control (dB level), no linear volume * - logarithmic volume control (dB level), no linear volume
* - master can only attenuate the volume, no gain * - 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_master *master_link = snd_kcontrol_chip(master);
struct link_slave *srec; struct link_slave *srec;
...@@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) ...@@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
srec->slave = *slave; srec->slave = *slave;
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
srec->master = master_link; srec->master = master_link;
srec->flags = flags;
/* override callbacks */ /* override callbacks */
slave->info = slave_info; slave->info = slave_info;
...@@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) ...@@ -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); list_add_tail(&srec->list, &master_link->slaves);
return 0; return 0;
} }
EXPORT_SYMBOL(_snd_ctl_add_slave);
EXPORT_SYMBOL(snd_ctl_add_slave);
/* /*
* ctl callbacks for master controls * ctl callbacks for master controls
...@@ -367,5 +380,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, ...@@ -367,5 +380,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
return kctl; return kctl;
} }
EXPORT_SYMBOL(snd_ctl_make_virtual_master); EXPORT_SYMBOL(snd_ctl_make_virtual_master);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment