Skip to content

Commit

Permalink
ALSA: add snd_ctl_add_slave_uncached()
Browse files Browse the repository at this point in the history
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: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Mar 9, 2009
1 parent fec6c6f commit f5b1db6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 19 deletions.
20 changes: 18 additions & 2 deletions include/sound/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
46 changes: 29 additions & 17 deletions sound/core/vmaster.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -367,5 +380,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,

return kctl;
}

EXPORT_SYMBOL(snd_ctl_make_virtual_master);

0 comments on commit f5b1db6

Please sign in to comment.