Merge branch 'for-next' into for-linus

This commit is contained in:
Takashi Iwai
2020-08-03 08:10:08 +02:00
14363 changed files with 848627 additions and 315991 deletions

View File

@@ -203,7 +203,10 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
mutex_unlock(&snd_card_mutex);
card->dev = parent;
card->number = idx;
#ifdef MODULE
WARN_ON(!module);
card->module = module;
#endif
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);

View File

@@ -135,16 +135,17 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->dev.type = type;
dmab->dev.dev = device;
dmab->bytes = 0;
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = NULL;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
dmab->addr = 0;
break;
case SNDRV_DMA_TYPE_VMALLOC:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp, PAGE_KERNEL);
dmab->addr = 0;
dmab->area = __vmalloc(size, gfp);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
@@ -157,7 +158,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
*/
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
#endif /* CONFIG_GENERIC_ALLOCATOR */
/* fall through */
fallthrough;
case SNDRV_DMA_TYPE_DEV:
case SNDRV_DMA_TYPE_DEV_UC:
snd_malloc_dev_pages(dmab, size);
@@ -171,8 +172,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
#endif
default:
pr_err("snd-malloc: invalid device type %d\n", type);
dmab->area = NULL;
dmab->addr = 0;
return -ENXIO;
}
if (! dmab->area)

View File

@@ -2851,7 +2851,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream)
break;
/* Fall through */
fallthrough;
case VM_READ:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
break;
@@ -2876,7 +2876,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
if (runtime->oss.params) {
/* use mutex_trylock() for params_lock for avoiding a deadlock
* between mmap_sem and params_lock taken by
* between mmap_lock and params_lock taken by
* copy_from/to_user() in snd_pcm_oss_write/read()
*/
err = snd_pcm_oss_change_params(substream, true);

View File

@@ -357,7 +357,7 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
if (snd_mask_test(format_mask, (__force int)format1))
return format1;
}
/* fall through */
fallthrough;
default:
return (__force snd_pcm_format_t)-EINVAL;
}

View File

@@ -103,7 +103,7 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
/**
* snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status
* @hw_params: the hw_params instance for extracting rate and sample format
* @params: the hw_params instance for extracting rate and sample format
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*

View File

@@ -39,6 +39,7 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card)
return -ENOMEM;
err = snd_dma_alloc_pages(type, dev, size, dmab);
if (!err) {
mutex_lock(&card->memory_mutex);
@@ -460,7 +461,7 @@ int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
return 0; /* already large enough */
vfree(runtime->dma_area);
}
runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
runtime->dma_area = __vmalloc(size, gfp_flags);
if (!runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;

View File

@@ -1903,7 +1903,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
switch (substream->runtime->status->state) {
case SNDRV_PCM_STATE_PAUSED:
snd_pcm_pause(substream, false);
/* fallthru */
fallthrough;
case SNDRV_PCM_STATE_SUSPENDED:
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
break;
@@ -2811,7 +2811,7 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream)
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
return -EBADFD;
/* Fall through */
fallthrough;
case SNDRV_PCM_STATE_RUNNING:
return snd_pcm_update_hw_ptr(substream);
case SNDRV_PCM_STATE_PREPARED:
@@ -3109,7 +3109,8 @@ static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream,
result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
else
result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
__put_user(result, &_xferi->result);
if (put_user(result, &_xferi->result))
return -EFAULT;
return result < 0 ? result : 0;
}
@@ -3138,7 +3139,8 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
else
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
kfree(bufs);
__put_user(result, &_xfern->result);
if (put_user(result, &_xfern->result))
return -EFAULT;
return result < 0 ? result : 0;
}
@@ -3153,7 +3155,8 @@ static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream,
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_rewind(substream, frames);
__put_user(result, _frames);
if (put_user(result, _frames))
return -EFAULT;
return result < 0 ? result : 0;
}
@@ -3168,7 +3171,8 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_forward(substream, frames);
__put_user(result, _frames);
if (put_user(result, _frames))
return -EFAULT;
return result < 0 ? result : 0;
}
@@ -3709,7 +3713,6 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page &&
(substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV ||
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC))
@@ -3718,7 +3721,6 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
substream->runtime->dma_area,
substream->runtime->dma_addr,
substream->runtime->dma_bytes);
#endif /* CONFIG_X86 */
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
@@ -3812,7 +3814,7 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
case SNDRV_PCM_MMAP_OFFSET_STATUS_OLD:
if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT))
return -ENXIO;
/* fallthrough */
fallthrough;
case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW:
if (!pcm_status_mmap_allowed(pcm_file))
return -ENXIO;
@@ -3820,7 +3822,7 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
case SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD:
if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT))
return -ENXIO;
/* fallthrough */
fallthrough;
case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW:
if (!pcm_control_mmap_allowed(pcm_file))
return -ENXIO;

View File

@@ -79,7 +79,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
case TMR_WAIT_REL:
parm += rec->cur_tick;
rec->realtime = 0;
/* fall through */
fallthrough;
case TMR_WAIT_ABS:
if (parm == 0) {
rec->realtime = 1;

View File

@@ -309,7 +309,7 @@ do_control(const struct snd_midi_op *ops, void *drv,
break;
case MIDI_CTL_MSB_DATA_ENTRY:
chan->control[MIDI_CTL_LSB_DATA_ENTRY] = 0;
/* fall through */
fallthrough;
case MIDI_CTL_LSB_DATA_ENTRY:
if (chan->param_type == SNDRV_MIDI_PARAM_TYPE_REGISTERED)
rpn(ops, drv, chan, chset);

View File

@@ -9,7 +9,6 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <asm/pgtable.h>
#include <sound/memalloc.h>
@@ -143,6 +142,9 @@ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
struct snd_sg_buf *sg = dmab->private_data;
unsigned int start, end, pg;
if (!sg)
return size;
start = ofs >> PAGE_SHIFT;
end = (ofs + size - 1) >> PAGE_SHIFT;
/* check page continuity */

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Virtual master and slave controls
* Virtual master and follower controls
*
* Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
*/
@@ -21,15 +21,15 @@ struct link_ctl_info {
};
/*
* link master - this contains a list of slave controls that are
* link master - this contains a list of follower controls that are
* identical types, i.e. info returns the same value type and value
* ranges, but may have different number of counts.
*
* The master control is so far only mono volume/switch for simplicity.
* The same value will be applied to all slaves.
* The same value will be applied to all followers.
*/
struct link_master {
struct list_head slaves;
struct list_head followers;
struct link_ctl_info info;
int val; /* the master value */
unsigned int tlv[4];
@@ -38,23 +38,23 @@ struct link_master {
};
/*
* link slave - this contains a slave control element
* link follower - this contains a follower control element
*
* It fakes the control callbacsk with additional attenuation by the
* master control. A slave may have either one or two channels.
* It fakes the control callbacks with additional attenuation by the
* master control. A follower may have either one or two channels.
*/
struct link_slave {
struct link_follower {
struct list_head list;
struct link_master *master;
struct link_ctl_info info;
int vals[2]; /* current values */
unsigned int flags;
struct snd_kcontrol *kctl; /* original kcontrol pointer */
struct snd_kcontrol slave; /* the copy of original control entry */
struct snd_kcontrol follower; /* the copy of original control entry */
};
static int slave_update(struct link_slave *slave)
static int follower_update(struct link_follower *follower)
{
struct snd_ctl_elem_value *uctl;
int err, ch;
@@ -62,68 +62,68 @@ static int slave_update(struct link_slave *slave)
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (!uctl)
return -ENOMEM;
uctl->id = slave->slave.id;
err = slave->slave.get(&slave->slave, uctl);
uctl->id = follower->follower.id;
err = follower->follower.get(&follower->follower, uctl);
if (err < 0)
goto error;
for (ch = 0; ch < slave->info.count; ch++)
slave->vals[ch] = uctl->value.integer.value[ch];
for (ch = 0; ch < follower->info.count; ch++)
follower->vals[ch] = uctl->value.integer.value[ch];
error:
kfree(uctl);
return err < 0 ? err : 0;
}
/* get the slave ctl info and save the initial values */
static int slave_init(struct link_slave *slave)
/* get the follower ctl info and save the initial values */
static int follower_init(struct link_follower *follower)
{
struct snd_ctl_elem_info *uinfo;
int err;
if (slave->info.count) {
if (follower->info.count) {
/* already initialized */
if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
return slave_update(slave);
if (follower->flags & SND_CTL_FOLLOWER_NEED_UPDATE)
return follower_update(follower);
return 0;
}
uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
if (!uinfo)
return -ENOMEM;
uinfo->id = slave->slave.id;
err = slave->slave.info(&slave->slave, uinfo);
uinfo->id = follower->follower.id;
err = follower->follower.info(&follower->follower, uinfo);
if (err < 0) {
kfree(uinfo);
return err;
}
slave->info.type = uinfo->type;
slave->info.count = uinfo->count;
if (slave->info.count > 2 ||
(slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
pr_err("ALSA: vmaster: invalid slave element\n");
follower->info.type = uinfo->type;
follower->info.count = uinfo->count;
if (follower->info.count > 2 ||
(follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
pr_err("ALSA: vmaster: invalid follower element\n");
kfree(uinfo);
return -EINVAL;
}
slave->info.min_val = uinfo->value.integer.min;
slave->info.max_val = uinfo->value.integer.max;
follower->info.min_val = uinfo->value.integer.min;
follower->info.max_val = uinfo->value.integer.max;
kfree(uinfo);
return slave_update(slave);
return follower_update(follower);
}
/* initialize master volume */
static int master_init(struct link_master *master)
{
struct link_slave *slave;
struct link_follower *follower;
if (master->info.count)
return 0; /* already initialized */
list_for_each_entry(slave, &master->slaves, list) {
int err = slave_init(slave);
list_for_each_entry(follower, &master->followers, list) {
int err = follower_init(follower);
if (err < 0)
return err;
master->info = slave->info;
master->info = follower->info;
master->info.count = 1; /* always mono */
/* set full volume as default (= no attenuation) */
master->val = master->info.max_val;
@@ -134,113 +134,113 @@ static int master_init(struct link_master *master)
return -ENOENT;
}
static int slave_get_val(struct link_slave *slave,
struct snd_ctl_elem_value *ucontrol)
static int follower_get_val(struct link_follower *follower,
struct snd_ctl_elem_value *ucontrol)
{
int err, ch;
err = slave_init(slave);
err = follower_init(follower);
if (err < 0)
return err;
for (ch = 0; ch < slave->info.count; ch++)
ucontrol->value.integer.value[ch] = slave->vals[ch];
for (ch = 0; ch < follower->info.count; ch++)
ucontrol->value.integer.value[ch] = follower->vals[ch];
return 0;
}
static int slave_put_val(struct link_slave *slave,
struct snd_ctl_elem_value *ucontrol)
static int follower_put_val(struct link_follower *follower,
struct snd_ctl_elem_value *ucontrol)
{
int err, ch, vol;
err = master_init(slave->master);
err = master_init(follower->master);
if (err < 0)
return err;
switch (slave->info.type) {
switch (follower->info.type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
for (ch = 0; ch < slave->info.count; ch++)
for (ch = 0; ch < follower->info.count; ch++)
ucontrol->value.integer.value[ch] &=
!!slave->master->val;
!!follower->master->val;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
for (ch = 0; ch < slave->info.count; ch++) {
for (ch = 0; ch < follower->info.count; ch++) {
/* max master volume is supposed to be 0 dB */
vol = ucontrol->value.integer.value[ch];
vol += slave->master->val - slave->master->info.max_val;
if (vol < slave->info.min_val)
vol = slave->info.min_val;
else if (vol > slave->info.max_val)
vol = slave->info.max_val;
vol += follower->master->val - follower->master->info.max_val;
if (vol < follower->info.min_val)
vol = follower->info.min_val;
else if (vol > follower->info.max_val)
vol = follower->info.max_val;
ucontrol->value.integer.value[ch] = vol;
}
break;
}
return slave->slave.put(&slave->slave, ucontrol);
return follower->follower.put(&follower->follower, ucontrol);
}
/*
* ctl callbacks for slaves
* ctl callbacks for followers
*/
static int slave_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
static int follower_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct link_slave *slave = snd_kcontrol_chip(kcontrol);
return slave->slave.info(&slave->slave, uinfo);
struct link_follower *follower = snd_kcontrol_chip(kcontrol);
return follower->follower.info(&follower->follower, uinfo);
}
static int slave_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int follower_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct link_slave *slave = snd_kcontrol_chip(kcontrol);
return slave_get_val(slave, ucontrol);
struct link_follower *follower = snd_kcontrol_chip(kcontrol);
return follower_get_val(follower, ucontrol);
}
static int slave_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int follower_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct link_slave *slave = snd_kcontrol_chip(kcontrol);
struct link_follower *follower = snd_kcontrol_chip(kcontrol);
int err, ch, changed = 0;
err = slave_init(slave);
err = follower_init(follower);
if (err < 0)
return err;
for (ch = 0; ch < slave->info.count; ch++) {
if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
for (ch = 0; ch < follower->info.count; ch++) {
if (follower->vals[ch] != ucontrol->value.integer.value[ch]) {
changed = 1;
slave->vals[ch] = ucontrol->value.integer.value[ch];
follower->vals[ch] = ucontrol->value.integer.value[ch];
}
}
if (!changed)
return 0;
err = slave_put_val(slave, ucontrol);
err = follower_put_val(follower, ucontrol);
if (err < 0)
return err;
return 1;
}
static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
int op_flag, unsigned int size,
unsigned int __user *tlv)
static int follower_tlv_cmd(struct snd_kcontrol *kcontrol,
int op_flag, unsigned int size,
unsigned int __user *tlv)
{
struct link_slave *slave = snd_kcontrol_chip(kcontrol);
struct link_follower *follower = snd_kcontrol_chip(kcontrol);
/* FIXME: this assumes that the max volume is 0 dB */
return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
return follower->follower.tlv.c(&follower->follower, op_flag, size, tlv);
}
static void slave_free(struct snd_kcontrol *kcontrol)
static void follower_free(struct snd_kcontrol *kcontrol)
{
struct link_slave *slave = snd_kcontrol_chip(kcontrol);
if (slave->slave.private_free)
slave->slave.private_free(&slave->slave);
if (slave->master)
list_del(&slave->list);
kfree(slave);
struct link_follower *follower = snd_kcontrol_chip(kcontrol);
if (follower->follower.private_free)
follower->follower.private_free(&follower->follower);
if (follower->master)
list_del(&follower->list);
kfree(follower);
}
/*
* Add a slave control to the group with the given master control
* Add a follower control to the group with the given master control
*
* All slaves must be the same type (returning the same information
* All followers must be the same type (returning the same information
* via info callback). The function doesn't check it, so it's your
* responsibility.
*
@@ -249,35 +249,36 @@ 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,
unsigned int flags)
int _snd_ctl_add_follower(struct snd_kcontrol *master,
struct snd_kcontrol *follower,
unsigned int flags)
{
struct link_master *master_link = snd_kcontrol_chip(master);
struct link_slave *srec;
struct link_follower *srec;
srec = kzalloc(struct_size(srec, slave.vd, slave->count),
srec = kzalloc(struct_size(srec, follower.vd, follower->count),
GFP_KERNEL);
if (!srec)
return -ENOMEM;
srec->kctl = slave;
srec->slave = *slave;
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
srec->kctl = follower;
srec->follower = *follower;
memcpy(srec->follower.vd, follower->vd, follower->count * sizeof(*follower->vd));
srec->master = master_link;
srec->flags = flags;
/* override callbacks */
slave->info = slave_info;
slave->get = slave_get;
slave->put = slave_put;
if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
slave->tlv.c = slave_tlv_cmd;
slave->private_data = srec;
slave->private_free = slave_free;
follower->info = follower_info;
follower->get = follower_get;
follower->put = follower_put;
if (follower->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
follower->tlv.c = follower_tlv_cmd;
follower->private_data = srec;
follower->private_free = follower_free;
list_add_tail(&srec->list, &master_link->slaves);
list_add_tail(&srec->list, &master_link->followers);
return 0;
}
EXPORT_SYMBOL(_snd_ctl_add_slave);
EXPORT_SYMBOL(_snd_ctl_add_follower);
/*
* ctl callbacks for master controls
@@ -309,20 +310,20 @@ static int master_get(struct snd_kcontrol *kcontrol,
return 0;
}
static int sync_slaves(struct link_master *master, int old_val, int new_val)
static int sync_followers(struct link_master *master, int old_val, int new_val)
{
struct link_slave *slave;
struct link_follower *follower;
struct snd_ctl_elem_value *uval;
uval = kmalloc(sizeof(*uval), GFP_KERNEL);
if (!uval)
return -ENOMEM;
list_for_each_entry(slave, &master->slaves, list) {
list_for_each_entry(follower, &master->followers, list) {
master->val = old_val;
uval->id = slave->slave.id;
slave_get_val(slave, uval);
uval->id = follower->follower.id;
follower_get_val(follower, uval);
master->val = new_val;
slave_put_val(slave, uval);
follower_put_val(follower, uval);
}
kfree(uval);
return 0;
@@ -344,7 +345,7 @@ static int master_put(struct snd_kcontrol *kcontrol,
if (new_val == old_val)
return 0;
err = sync_slaves(master, old_val, new_val);
err = sync_followers(master, old_val, new_val);
if (err < 0)
return err;
if (master->hook && !first_init)
@@ -355,17 +356,17 @@ static int master_put(struct snd_kcontrol *kcontrol,
static void master_free(struct snd_kcontrol *kcontrol)
{
struct link_master *master = snd_kcontrol_chip(kcontrol);
struct link_slave *slave, *n;
struct link_follower *follower, *n;
/* 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;
/* free all follower links and retore the original follower kctls */
list_for_each_entry_safe(follower, n, &master->followers, list) {
struct snd_kcontrol *sctl = follower->kctl;
struct list_head olist = sctl->list;
memcpy(sctl, &slave->slave, sizeof(*sctl));
memcpy(sctl->vd, slave->slave.vd,
memcpy(sctl, &follower->follower, sizeof(*sctl));
memcpy(sctl->vd, follower->follower.vd,
sctl->count * sizeof(*sctl->vd));
sctl->list = olist; /* keep the current linked-list */
kfree(slave);
kfree(follower);
}
kfree(master);
}
@@ -378,8 +379,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
*
* Creates a virtual master control with the given name string.
*
* After creating a vmaster element, you can add the slave controls
* via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
* After creating a vmaster element, you can add the follower controls
* via snd_ctl_add_follower() or snd_ctl_add_follower_uncached().
*
* The optional argument @tlv can be used to specify the TLV information
* for dB scale of the master control. It should be a single element
@@ -403,7 +404,7 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
master = kzalloc(sizeof(*master), GFP_KERNEL);
if (!master)
return NULL;
INIT_LIST_HEAD(&master->slaves);
INIT_LIST_HEAD(&master->followers);
kctl = snd_ctl_new1(&knew, master);
if (!kctl) {
@@ -455,11 +456,11 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
/**
* snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
* snd_ctl_sync_vmaster - Sync the vmaster followers and hook
* @kcontrol: vmaster kctl element
* @hook_only: sync only the hook
*
* Forcibly call the put callback of each slave and call the hook function
* Forcibly call the put callback of each follower and call the hook function
* to synchronize with the current value of the given vmaster element.
* NOP when NULL is passed to @kcontrol.
*/
@@ -476,7 +477,7 @@ void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
if (err < 0)
return;
first_init = err;
err = sync_slaves(master, master->val, master->val);
err = sync_followers(master, master->val, master->val);
if (err < 0)
return;
}
@@ -487,34 +488,34 @@ void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
/**
* snd_ctl_apply_vmaster_slaves - Apply function to each vmaster slave
* snd_ctl_apply_vmaster_followers - Apply function to each vmaster follower
* @kctl: vmaster kctl element
* @func: function to apply
* @arg: optional function argument
*
* Apply the function @func to each slave kctl of the given vmaster kctl.
* Apply the function @func to each follower kctl of the given vmaster kctl.
* Returns 0 if successful, or a negative error code.
*/
int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
int (*func)(struct snd_kcontrol *vslave,
struct snd_kcontrol *slave,
void *arg),
void *arg)
int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,
int (*func)(struct snd_kcontrol *vfollower,
struct snd_kcontrol *follower,
void *arg),
void *arg)
{
struct link_master *master;
struct link_slave *slave;
struct link_follower *follower;
int err;
master = snd_kcontrol_chip(kctl);
err = master_init(master);
if (err < 0)
return err;
list_for_each_entry(slave, &master->slaves, list) {
err = func(slave->kctl, &slave->slave, arg);
list_for_each_entry(follower, &master->followers, list) {
err = func(follower->kctl, &follower->follower, arg);
if (err < 0)
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_slaves);
EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_followers);