summaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/Makefile1
-rw-r--r--sound/core/compress_offload.c3
-rw-r--r--sound/core/control.c388
-rw-r--r--sound/core/control_compat.c34
-rw-r--r--sound/core/device.c4
-rw-r--r--sound/core/init.c6
-rw-r--r--sound/core/oss/Makefile1
-rw-r--r--sound/core/pcm.c69
-rw-r--r--sound/core/pcm_compat.c6
-rw-r--r--sound/core/pcm_native.c303
-rw-r--r--sound/core/pcm_param_trace.h1
-rw-r--r--sound/core/pcm_trace.h1
-rw-r--r--sound/core/seq/Kconfig4
-rw-r--r--sound/core/seq/Makefile1
-rw-r--r--sound/core/seq/seq_clientmgr.c21
-rw-r--r--sound/core/seq/seq_lock.c4
-rw-r--r--sound/core/seq/seq_lock.h13
-rw-r--r--sound/core/seq/seq_ports.c7
-rw-r--r--sound/core/seq/seq_queue.c14
-rw-r--r--sound/core/seq/seq_queue.h2
-rw-r--r--sound/core/seq/seq_virmidi.c27
-rw-r--r--sound/core/seq_device.c3
-rw-r--r--sound/core/timer.c13
-rw-r--r--sound/core/timer_compat.c17
-rw-r--r--sound/core/vmaster.c31
25 files changed, 508 insertions, 466 deletions
diff --git a/sound/core/Makefile b/sound/core/Makefile
index e2066e2ef9f8..ee4a4a6b99ba 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Makefile for ALSA
# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index fec1dfdb14ad..4490a699030b 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -948,14 +948,13 @@ static const struct file_operations snd_compr_file_ops = {
static int snd_compress_dev_register(struct snd_device *device)
{
int ret = -EINVAL;
- char str[16];
struct snd_compr *compr;
if (snd_BUG_ON(!device || !device->device_data))
return -EBADFD;
compr = device->device_data;
- pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
+ pr_debug("reg device %s, direction %d\n", compr->name,
compr->direction);
/* register compressed device */
ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,
diff --git a/sound/core/control.c b/sound/core/control.c
index 3c6be1452e35..56b3e2d49c82 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -864,14 +864,14 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
- snd_power_lock(ctl->card);
result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
- if (result >= 0)
- result = snd_ctl_elem_info(ctl, &info);
- snd_power_unlock(ctl->card);
- if (result >= 0)
- if (copy_to_user(_info, &info, sizeof(info)))
- return -EFAULT;
+ if (result < 0)
+ return result;
+ result = snd_ctl_elem_info(ctl, &info);
+ if (result < 0)
+ return result;
+ if (copy_to_user(_info, &info, sizeof(info)))
+ return -EFAULT;
return result;
}
@@ -881,24 +881,18 @@ static int snd_ctl_elem_read(struct snd_card *card,
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
- int result;
- down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
- if (kctl == NULL) {
- result = -ENOENT;
- } else {
- index_offset = snd_ctl_get_ioff(kctl, &control->id);
- vd = &kctl->vd[index_offset];
- if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
- kctl->get != NULL) {
- snd_ctl_build_ioff(&control->id, kctl, index_offset);
- result = kctl->get(kctl, control);
- } else
- result = -EPERM;
- }
- up_read(&card->controls_rwsem);
- return result;
+ if (kctl == NULL)
+ return -ENOENT;
+
+ index_offset = snd_ctl_get_ioff(kctl, &control->id);
+ vd = &kctl->vd[index_offset];
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL)
+ return -EPERM;
+
+ snd_ctl_build_ioff(&control->id, kctl, index_offset);
+ return kctl->get(kctl, control);
}
static int snd_ctl_elem_read_user(struct snd_card *card,
@@ -911,14 +905,19 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
if (IS_ERR(control))
return PTR_ERR(control);
- snd_power_lock(card);
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
- if (result >= 0)
- result = snd_ctl_elem_read(card, control);
- snd_power_unlock(card);
- if (result >= 0)
- if (copy_to_user(_control, control, sizeof(*control)))
- result = -EFAULT;
+ if (result < 0)
+ goto error;
+
+ down_read(&card->controls_rwsem);
+ result = snd_ctl_elem_read(card, control);
+ up_read(&card->controls_rwsem);
+ if (result < 0)
+ goto error;
+
+ if (copy_to_user(_control, control, sizeof(*control)))
+ result = -EFAULT;
+ error:
kfree(control);
return result;
}
@@ -931,30 +930,28 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
unsigned int index_offset;
int result;
- down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
- if (kctl == NULL) {
- result = -ENOENT;
- } else {
- index_offset = snd_ctl_get_ioff(kctl, &control->id);
- vd = &kctl->vd[index_offset];
- if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
- kctl->put == NULL ||
- (file && vd->owner && vd->owner != file)) {
- result = -EPERM;
- } else {
- snd_ctl_build_ioff(&control->id, kctl, index_offset);
- result = kctl->put(kctl, control);
- }
- if (result > 0) {
- struct snd_ctl_elem_id id = control->id;
- up_read(&card->controls_rwsem);
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
- return 0;
- }
+ if (kctl == NULL)
+ return -ENOENT;
+
+ index_offset = snd_ctl_get_ioff(kctl, &control->id);
+ vd = &kctl->vd[index_offset];
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL ||
+ (file && vd->owner && vd->owner != file)) {
+ return -EPERM;
}
- up_read(&card->controls_rwsem);
- return result;
+
+ snd_ctl_build_ioff(&control->id, kctl, index_offset);
+ result = kctl->put(kctl, control);
+ if (result < 0)
+ return result;
+
+ if (result > 0) {
+ struct snd_ctl_elem_id id = control->id;
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
+ }
+
+ return 0;
}
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
@@ -969,14 +966,19 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
return PTR_ERR(control);
card = file->card;
- snd_power_lock(card);
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
- if (result >= 0)
- result = snd_ctl_elem_write(card, file, control);
- snd_power_unlock(card);
- if (result >= 0)
- if (copy_to_user(_control, control, sizeof(*control)))
- result = -EFAULT;
+ if (result < 0)
+ goto error;
+
+ down_write(&card->controls_rwsem);
+ result = snd_ctl_elem_write(card, file, control);
+ up_write(&card->controls_rwsem);
+ if (result < 0)
+ goto error;
+
+ if (copy_to_user(_control, control, sizeof(*control)))
+ result = -EFAULT;
+ error:
kfree(control);
return result;
}
@@ -1095,9 +1097,7 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
char *src = ue->elem_data +
snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
- mutex_lock(&ue->card->user_ctl_lock);
memcpy(&ucontrol->value, src, size);
- mutex_unlock(&ue->card->user_ctl_lock);
return 0;
}
@@ -1110,60 +1110,83 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
char *dst = ue->elem_data +
snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
- mutex_lock(&ue->card->user_ctl_lock);
change = memcmp(&ucontrol->value, dst, size) != 0;
if (change)
memcpy(dst, &ucontrol->value, size);
- mutex_unlock(&ue->card->user_ctl_lock);
return change;
}
-static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
- int op_flag,
- unsigned int size,
- unsigned int __user *tlv)
+static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
+ unsigned int size)
{
- struct user_element *ue = kcontrol->private_data;
- int change = 0;
- void *new_data;
+ struct user_element *ue = kctl->private_data;
+ unsigned int *container;
+ struct snd_ctl_elem_id id;
+ unsigned int mask = 0;
+ int i;
+ int change;
- if (op_flag == SNDRV_CTL_TLV_OP_WRITE) {
- if (size > 1024 * 128) /* sane value */
- return -EINVAL;
+ if (size > 1024 * 128) /* sane value */
+ return -EINVAL;
- new_data = memdup_user(tlv, size);
- if (IS_ERR(new_data))
- return PTR_ERR(new_data);
- mutex_lock(&ue->card->user_ctl_lock);
- change = ue->tlv_data_size != size;
- if (!change)
- change = memcmp(ue->tlv_data, new_data, size);
- kfree(ue->tlv_data);
- ue->tlv_data = new_data;
- ue->tlv_data_size = size;
- mutex_unlock(&ue->card->user_ctl_lock);
- } else {
- int ret = 0;
+ container = memdup_user(buf, size);
+ if (IS_ERR(container))
+ return PTR_ERR(container);
- mutex_lock(&ue->card->user_ctl_lock);
- if (!ue->tlv_data_size || !ue->tlv_data) {
- ret = -ENXIO;
- goto err_unlock;
- }
- if (size < ue->tlv_data_size) {
- ret = -ENOSPC;
- goto err_unlock;
- }
- if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
- ret = -EFAULT;
-err_unlock:
- mutex_unlock(&ue->card->user_ctl_lock);
- if (ret)
- return ret;
+ change = ue->tlv_data_size != size;
+ if (!change)
+ change = memcmp(ue->tlv_data, container, size) != 0;
+ if (!change) {
+ kfree(container);
+ return 0;
}
+
+ if (ue->tlv_data == NULL) {
+ /* Now TLV data is available. */
+ for (i = 0; i < kctl->count; ++i)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ mask = SNDRV_CTL_EVENT_MASK_INFO;
+ }
+
+ kfree(ue->tlv_data);
+ ue->tlv_data = container;
+ ue->tlv_data_size = size;
+
+ mask |= SNDRV_CTL_EVENT_MASK_TLV;
+ for (i = 0; i < kctl->count; ++i) {
+ snd_ctl_build_ioff(&id, kctl, i);
+ snd_ctl_notify(ue->card, mask, &id);
+ }
+
return change;
}
+static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
+ unsigned int size)
+{
+ struct user_element *ue = kctl->private_data;
+
+ if (ue->tlv_data_size == 0 || ue->tlv_data == NULL)
+ return -ENXIO;
+
+ if (size < ue->tlv_data_size)
+ return -ENOSPC;
+
+ if (copy_to_user(buf, ue->tlv_data, ue->tlv_data_size))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag,
+ unsigned int size, unsigned int __user *buf)
+{
+ if (op_flag == SNDRV_CTL_TLV_OP_WRITE)
+ return replace_user_tlv(kctl, buf, size);
+ else
+ return read_user_tlv(kctl, buf, size);
+}
+
static int snd_ctl_elem_init_enum_names(struct user_element *ue)
{
char *names, *p;
@@ -1267,8 +1290,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
- if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+ SNDRV_CTL_ELEM_ACCESS_TLV_WRITE);
+
+ /* In initial state, nothing is available as TLV container. */
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
@@ -1331,7 +1356,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
kctl->get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
kctl->put = snd_ctl_elem_user_put;
- if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
kctl->tlv.c = snd_ctl_elem_user_tlv;
/* This function manage to free the instance on failure. */
@@ -1405,71 +1430,107 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
return 0;
}
+static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
+ struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_id *id,
+ unsigned int __user *buf, unsigned int size)
+{
+ static const struct {
+ int op;
+ int perm;
+ } pairs[] = {
+ {SNDRV_CTL_TLV_OP_READ, SNDRV_CTL_ELEM_ACCESS_TLV_READ},
+ {SNDRV_CTL_TLV_OP_WRITE, SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
+ {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
+ };
+ struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
+ int i;
+
+ /* Check support of the request for this element. */
+ for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
+ if (op_flag == pairs[i].op && (vd->access & pairs[i].perm))
+ break;
+ }
+ if (i == ARRAY_SIZE(pairs))
+ return -ENXIO;
+
+ if (kctl->tlv.c == NULL)
+ return -ENXIO;
+
+ /* When locked, this is unavailable. */
+ if (vd->owner != NULL && vd->owner != file)
+ return -EPERM;
+
+ return kctl->tlv.c(kctl, op_flag, size, buf);
+}
+
+static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
+ unsigned int __user *buf, unsigned int size)
+{
+ struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
+ unsigned int len;
+
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ))
+ return -ENXIO;
+
+ if (kctl->tlv.p == NULL)
+ return -ENXIO;
+
+ len = sizeof(unsigned int) * 2 + kctl->tlv.p[1];
+ if (size < len)
+ return -ENOMEM;
+
+ if (copy_to_user(buf, kctl->tlv.p, len))
+ return -EFAULT;
+
+ return 0;
+}
+
static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
- struct snd_ctl_tlv __user *_tlv,
+ struct snd_ctl_tlv __user *buf,
int op_flag)
{
- struct snd_card *card = file->card;
- struct snd_ctl_tlv tlv;
+ struct snd_ctl_tlv header;
+ unsigned int *container;
+ unsigned int container_size;
struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_id id;
struct snd_kcontrol_volatile *vd;
- unsigned int len;
- int err = 0;
- if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
+ if (copy_from_user(&header, buf, sizeof(header)))
return -EFAULT;
- if (tlv.length < sizeof(unsigned int) * 2)
+
+ /* In design of control core, numerical ID starts at 1. */
+ if (header.numid == 0)
return -EINVAL;
- if (!tlv.numid)
+
+ /* At least, container should include type and length fields. */
+ if (header.length < sizeof(unsigned int) * 2)
return -EINVAL;
- down_read(&card->controls_rwsem);
- kctl = snd_ctl_find_numid(card, tlv.numid);
- if (kctl == NULL) {
- err = -ENOENT;
- goto __kctl_end;
- }
- if (kctl->tlv.p == NULL) {
- err = -ENXIO;
- goto __kctl_end;
- }
- vd = &kctl->vd[tlv.numid - kctl->id.numid];
- if ((op_flag == SNDRV_CTL_TLV_OP_READ &&
- (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
- (op_flag == SNDRV_CTL_TLV_OP_WRITE &&
- (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
- (op_flag == SNDRV_CTL_TLV_OP_CMD &&
- (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
- err = -ENXIO;
- goto __kctl_end;
- }
+ container_size = header.length;
+ container = buf->tlv;
+
+ kctl = snd_ctl_find_numid(file->card, header.numid);
+ if (kctl == NULL)
+ return -ENOENT;
+
+ /* Calculate index of the element in this set. */
+ id = kctl->id;
+ snd_ctl_build_ioff(&id, kctl, header.numid - id.numid);
+ vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+
if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- if (vd->owner != NULL && vd->owner != file) {
- err = -EPERM;
- goto __kctl_end;
- }
- err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
- if (err > 0) {
- struct snd_ctl_elem_id id = kctl->id;
- up_read(&card->controls_rwsem);
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
- return 0;
- }
+ return call_tlv_handler(file, op_flag, kctl, &id, container,
+ container_size);
} else {
- if (op_flag != SNDRV_CTL_TLV_OP_READ) {
- err = -ENXIO;
- goto __kctl_end;
+ if (op_flag == SNDRV_CTL_TLV_OP_READ) {
+ return read_tlv_buf(kctl, &id, container,
+ container_size);
}
- len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
- if (tlv.length < len) {
- err = -ENOMEM;
- goto __kctl_end;
- }
- if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
- err = -EFAULT;
}
- __kctl_end:
- up_read(&card->controls_rwsem);
- return err;
+
+ /* Not supported. */
+ return -ENXIO;
}
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1511,11 +1572,20 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip);
case SNDRV_CTL_IOCTL_TLV_READ:
- return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
+ down_read(&ctl->card->controls_rwsem);
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
+ up_read(&ctl->card->controls_rwsem);
+ return err;
case SNDRV_CTL_IOCTL_TLV_WRITE:
- return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
+ down_write(&ctl->card->controls_rwsem);
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
+ up_write(&ctl->card->controls_rwsem);
+ return err;
case SNDRV_CTL_IOCTL_TLV_COMMAND:
- return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
+ down_write(&ctl->card->controls_rwsem);
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
+ up_write(&ctl->card->controls_rwsem);
+ return err;
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 1fa70766ffab..a848836a5de0 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -111,12 +111,10 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
goto error;
- snd_power_lock(ctl->card);
err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
- if (err >= 0)
- err = snd_ctl_elem_info(ctl, data);
- snd_power_unlock(ctl->card);
-
+ if (err < 0)
+ goto error;
+ err = snd_ctl_elem_info(ctl, data);
if (err < 0)
goto error;
/* restore info to 32bit */
@@ -315,14 +313,13 @@ static int ctl_elem_read_user(struct snd_card *card,
if (err < 0)
goto error;
- snd_power_lock(card);
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
- if (err >= 0)
- err = snd_ctl_elem_read(card, data);
- snd_power_unlock(card);
- if (err >= 0)
- err = copy_ctl_value_to_user(userdata, valuep, data,
- type, count);
+ if (err < 0)
+ goto error;
+ err = snd_ctl_elem_read(card, data);
+ if (err < 0)
+ goto error;
+ err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
error:
kfree(data);
return err;
@@ -344,14 +341,13 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
if (err < 0)
goto error;
- snd_power_lock(card);
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
- if (err >= 0)
- err = snd_ctl_elem_write(card, file, data);
- snd_power_unlock(card);
- if (err >= 0)
- err = copy_ctl_value_to_user(userdata, valuep, data,
- type, count);
+ if (err < 0)
+ goto error;
+ err = snd_ctl_elem_write(card, file, data);
+ if (err < 0)
+ goto error;
+ err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
error:
kfree(data);
return err;
diff --git a/sound/core/device.c b/sound/core/device.c
index 8918838b1999..cb0e46f66cc9 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -128,7 +128,7 @@ void snd_device_disconnect(struct snd_card *card, void *device_data)
if (dev)
__snd_device_disconnect(dev);
else
- dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
+ dev_dbg(card->dev, "device disconnect %p (from %pS), not found\n",
device_data, __builtin_return_address(0));
}
EXPORT_SYMBOL_GPL(snd_device_disconnect);
@@ -152,7 +152,7 @@ void snd_device_free(struct snd_card *card, void *device_data)
if (dev)
__snd_device_free(dev);
else
- dev_dbg(card->dev, "device free %p (from %pF), not found\n",
+ dev_dbg(card->dev, "device free %p (from %pS), not found\n",
device_data, __builtin_return_address(0));
}
EXPORT_SYMBOL(snd_device_free);
diff --git a/sound/core/init.c b/sound/core/init.c
index b4365bcf28a7..32ebe2f6bc59 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -248,13 +248,11 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
- mutex_init(&card->user_ctl_lock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PM
- mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
@@ -979,8 +977,6 @@ EXPORT_SYMBOL(snd_card_file_remove);
* Waits until the power-state is changed.
*
* Return: Zero if successful, or a negative error code.
- *
- * Note: the power lock must be active before call.
*/
int snd_power_wait(struct snd_card *card, unsigned int power_state)
{
@@ -1000,9 +996,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
if (snd_power_get_state(card) == power_state)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
- snd_power_unlock(card);
schedule_timeout(30 * HZ);
- snd_power_lock(card);
}
remove_wait_queue(&card->power_sleep, &wait);
return result;
diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile
index 10a79453245f..ae25edcc3b42 100644
--- a/sound/core/oss/Makefile
+++ b/sound/core/oss/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Makefile for ALSA
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 89c7485519cb..7eadb7fd8074 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -523,7 +523,9 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
sprintf(name, "pcm%i%c", pcm->device,
pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
- if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL)
+ entry = snd_info_create_card_entry(pcm->card, name,
+ pcm->card->proc_root);
+ if (!entry)
return -ENOMEM;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
if (snd_info_register(entry) < 0) {
@@ -531,8 +533,8 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
return -ENOMEM;
}
pstr->proc_root = entry;
-
- if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root);
+ if (entry) {
snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -542,8 +544,9 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
pstr->proc_info_entry = entry;
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
- pstr->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
+ pstr->proc_root);
+ if (entry) {
entry->c.text.read = snd_pcm_xrun_debug_read;
entry->c.text.write = snd_pcm_xrun_debug_write;
entry->mode |= S_IWUSR;
@@ -580,7 +583,9 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
card = substream->pcm->card;
sprintf(name, "sub%i", substream->number);
- if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL)
+ entry = snd_info_create_card_entry(card, name,
+ substream->pstr->proc_root);
+ if (!entry)
return -ENOMEM;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
if (snd_info_register(entry) < 0) {
@@ -588,8 +593,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
return -ENOMEM;
}
substream->proc_root = entry;
-
- if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(card, "info", substream->proc_root);
+ if (entry) {
snd_info_set_text_ops(entry, substream,
snd_pcm_substream_proc_info_read);
if (snd_info_register(entry) < 0) {
@@ -598,8 +603,9 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
}
}
substream->proc_info_entry = entry;
-
- if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(card, "hw_params",
+ substream->proc_root);
+ if (entry) {
snd_info_set_text_ops(entry, substream,
snd_pcm_substream_proc_hw_params_read);
if (snd_info_register(entry) < 0) {
@@ -608,8 +614,9 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
}
}
substream->proc_hw_params_entry = entry;
-
- if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(card, "sw_params",
+ substream->proc_root);
+ if (entry) {
snd_info_set_text_ops(entry, substream,
snd_pcm_substream_proc_sw_params_read);
if (snd_info_register(entry) < 0) {
@@ -618,8 +625,9 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
}
}
substream->proc_sw_params_entry = entry;
-
- if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(card, "status",
+ substream->proc_root);
+ if (entry) {
snd_info_set_text_ops(entry, substream,
snd_pcm_substream_proc_status_read);
if (snd_info_register(entry) < 0) {
@@ -783,21 +791,27 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
INIT_LIST_HEAD(&pcm->list);
if (id)
strlcpy(pcm->id, id, sizeof(pcm->id));
- if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
- snd_pcm_free(pcm);
- return err;
- }
- if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
- snd_pcm_free(pcm);
- return err;
- }
- if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
- snd_pcm_free(pcm);
- return err;
- }
+
+ err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ playback_count);
+ if (err < 0)
+ goto free_pcm;
+
+ err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count);
+ if (err < 0)
+ goto free_pcm;
+
+ err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops);
+ if (err < 0)
+ goto free_pcm;
+
if (rpcm)
*rpcm = pcm;
return 0;
+
+free_pcm:
+ snd_pcm_free(pcm);
+ return err;
}
/**
@@ -1224,7 +1238,8 @@ static void snd_pcm_proc_init(void)
{
struct snd_info_entry *entry;
- if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
+ entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL);
+ if (entry) {
snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 10f537f4d735..b719d0bd833e 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -547,6 +547,7 @@ struct snd_pcm_mmap_status_x32 {
u32 pad2; /* alignment */
struct timespec tstamp;
s32 suspended_state;
+ s32 pad3;
struct timespec audio_tstamp;
} __packed;
@@ -689,10 +690,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
case SNDRV_PCM_IOCTL_XRUN:
case SNDRV_PCM_IOCTL_LINK:
case SNDRV_PCM_IOCTL_UNLINK:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
- else
- return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
+ return snd_pcm_common_ioctl(file, substream, cmd, argp);
case SNDRV_PCM_IOCTL_HW_REFINE32:
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
case SNDRV_PCM_IOCTL_HW_PARAMS32:
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 22995cb3bd44..2fec2feac387 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1830,7 +1830,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
up_read(&snd_pcm_link_rwsem);
- snd_power_unlock(card);
if (runtime->no_period_wakeup)
tout = MAX_SCHEDULE_TIMEOUT;
else {
@@ -1842,7 +1841,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
tout = msecs_to_jiffies(tout * 1000);
}
tout = schedule_timeout_interruptible(tout);
- snd_power_lock(card);
down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream);
remove_wait_queue(&to_check->sleep, &wait);
@@ -2763,12 +2761,106 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
runtime->tstamp_type = arg;
return 0;
}
-
+
+static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream,
+ struct snd_xferi __user *_xferi)
+{
+ struct snd_xferi xferi;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_sframes_t result;
+
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ if (put_user(0, &_xferi->result))
+ return -EFAULT;
+ if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
+ return -EFAULT;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ 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);
+ return result < 0 ? result : 0;
+}
+
+static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
+ struct snd_xfern __user *_xfern)
+{
+ struct snd_xfern xfern;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ void *bufs;
+ snd_pcm_sframes_t result;
+
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ if (runtime->channels > 128)
+ return -EINVAL;
+ if (put_user(0, &_xfern->result))
+ return -EFAULT;
+ if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
+ return -EFAULT;
+
+ bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
+ if (IS_ERR(bufs))
+ return PTR_ERR(bufs);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
+ else
+ result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
+ kfree(bufs);
+ __put_user(result, &_xfern->result);
+ return result < 0 ? result : 0;
+}
+
+static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t __user *_frames)
+{
+ snd_pcm_uframes_t frames;
+ snd_pcm_sframes_t result;
+
+ if (get_user(frames, _frames))
+ return -EFAULT;
+ if (put_user(0, _frames))
+ return -EFAULT;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ result = snd_pcm_playback_rewind(substream, frames);
+ else
+ result = snd_pcm_capture_rewind(substream, frames);
+ __put_user(result, _frames);
+ return result < 0 ? result : 0;
+}
+
+static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t __user *_frames)
+{
+ snd_pcm_uframes_t frames;
+ snd_pcm_sframes_t result;
+
+ if (get_user(frames, _frames))
+ return -EFAULT;
+ if (put_user(0, _frames))
+ return -EFAULT;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ result = snd_pcm_playback_forward(substream, frames);
+ else
+ result = snd_pcm_capture_forward(substream, frames);
+ __put_user(result, _frames);
+ return result < 0 ? result : 0;
+}
+
static int snd_pcm_common_ioctl(struct file *file,
struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
struct snd_pcm_file *pcm_file = file->private_data;
+ int res;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
+
+ res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
+ if (res < 0)
+ return res;
switch (cmd) {
case SNDRV_PCM_IOCTL_PVERSION:
@@ -2841,202 +2933,23 @@ static int snd_pcm_common_ioctl(struct file *file,
return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
substream,
(int)(unsigned long)arg);
- }
- pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
- return -ENOTTY;
-}
-
-static int snd_pcm_common_ioctl1(struct file *file,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg)
-{
- struct snd_card *card = substream->pcm->card;
- int res;
-
- snd_power_lock(card);
- res = snd_power_wait(card, SNDRV_CTL_POWER_D0);
- if (res >= 0)
- res = snd_pcm_common_ioctl(file, substream, cmd, arg);
- snd_power_unlock(card);
- return res;
-}
-
-static int snd_pcm_playback_ioctl1(struct file *file,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg)
-{
- if (PCM_RUNTIME_CHECK(substream))
- return -ENXIO;
- if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
- return -EINVAL;
- switch (cmd) {
case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
- {
- struct snd_xferi xferi;
- struct snd_xferi __user *_xferi = arg;
- struct snd_pcm_runtime *runtime = substream->runtime;
- snd_pcm_sframes_t result;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
- if (put_user(0, &_xferi->result))
- return -EFAULT;
- if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
- return -EFAULT;
- result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
- __put_user(result, &_xferi->result);
- return result < 0 ? result : 0;
- }
- case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
- {
- struct snd_xfern xfern;
- struct snd_xfern __user *_xfern = arg;
- struct snd_pcm_runtime *runtime = substream->runtime;
- void __user **bufs;
- snd_pcm_sframes_t result;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
- if (runtime->channels > 128)
- return -EINVAL;
- if (put_user(0, &_xfern->result))
- return -EFAULT;
- if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
- return -EFAULT;
-
- bufs = memdup_user(xfern.bufs,
- sizeof(void *) * runtime->channels);
- if (IS_ERR(bufs))
- return PTR_ERR(bufs);
- result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
- kfree(bufs);
- __put_user(result, &_xfern->result);
- return result < 0 ? result : 0;
- }
- case SNDRV_PCM_IOCTL_REWIND:
- {
- snd_pcm_uframes_t frames;
- snd_pcm_uframes_t __user *_frames = arg;
- snd_pcm_sframes_t result;
- if (get_user(frames, _frames))
- return -EFAULT;
- if (put_user(0, _frames))
- return -EFAULT;
- result = snd_pcm_playback_rewind(substream, frames);
- __put_user(result, _frames);
- return result < 0 ? result : 0;
- }
- case SNDRV_PCM_IOCTL_FORWARD:
- {
- snd_pcm_uframes_t frames;
- snd_pcm_uframes_t __user *_frames = arg;
- snd_pcm_sframes_t result;
- if (get_user(frames, _frames))
- return -EFAULT;
- if (put_user(0, _frames))
- return -EFAULT;
- result = snd_pcm_playback_forward(substream, frames);
- __put_user(result, _frames);
- return result < 0 ? result : 0;
- }
- }
- return snd_pcm_common_ioctl1(file, substream, cmd, arg);
-}
-
-static int snd_pcm_capture_ioctl1(struct file *file,
- struct snd_pcm_substream *substream,
- unsigned int cmd, void __user *arg)
-{
- if (PCM_RUNTIME_CHECK(substream))
- return -ENXIO;
- if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
- return -EINVAL;
- switch (cmd) {
case SNDRV_PCM_IOCTL_READI_FRAMES:
- {
- struct snd_xferi xferi;
- struct snd_xferi __user *_xferi = arg;
- struct snd_pcm_runtime *runtime = substream->runtime;
- snd_pcm_sframes_t result;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
- if (put_user(0, &_xferi->result))
- return -EFAULT;
- if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
- return -EFAULT;
- result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
- __put_user(result, &_xferi->result);
- return result < 0 ? result : 0;
- }
+ return snd_pcm_xferi_frames_ioctl(substream, arg);
+ case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
case SNDRV_PCM_IOCTL_READN_FRAMES:
- {
- struct snd_xfern xfern;
- struct snd_xfern __user *_xfern = arg;
- struct snd_pcm_runtime *runtime = substream->runtime;
- void *bufs;
- snd_pcm_sframes_t result;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
- if (runtime->channels > 128)
- return -EINVAL;
- if (put_user(0, &_xfern->result))
- return -EFAULT;
- if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
- return -EFAULT;
-
- bufs = memdup_user(xfern.bufs,
- sizeof(void *) * runtime->channels);
- if (IS_ERR(bufs))
- return PTR_ERR(bufs);
- result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
- kfree(bufs);
- __put_user(result, &_xfern->result);
- return result < 0 ? result : 0;
- }
+ return snd_pcm_xfern_frames_ioctl(substream, arg);
case SNDRV_PCM_IOCTL_REWIND:
- {
- snd_pcm_uframes_t frames;
- snd_pcm_uframes_t __user *_frames = arg;
- snd_pcm_sframes_t result;
- if (get_user(frames, _frames))
- return -EFAULT;
- if (put_user(0, _frames))
- return -EFAULT;
- result = snd_pcm_capture_rewind(substream, frames);
- __put_user(result, _frames);
- return result < 0 ? result : 0;
- }
+ return snd_pcm_rewind_ioctl(substream, arg);
case SNDRV_PCM_IOCTL_FORWARD:
- {
- snd_pcm_uframes_t frames;
- snd_pcm_uframes_t __user *_frames = arg;
- snd_pcm_sframes_t result;
- if (get_user(frames, _frames))
- return -EFAULT;
- if (put_user(0, _frames))
- return -EFAULT;
- result = snd_pcm_capture_forward(substream, frames);
- __put_user(result, _frames);
- return result < 0 ? result : 0;
- }
+ return snd_pcm_forward_ioctl(substream, arg);
}
- return snd_pcm_common_ioctl1(file, substream, cmd, arg);
-}
-
-static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct snd_pcm_file *pcm_file;
-
- pcm_file = file->private_data;
-
- if (((cmd >> 8) & 0xff) != 'A')
- return -ENOTTY;
-
- return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
- (void __user *)arg);
+ pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
+ return -ENOTTY;
}
-static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct snd_pcm_file *pcm_file;
@@ -3045,8 +2958,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
- (void __user *)arg);
+ return snd_pcm_common_ioctl(file, pcm_file->substream, cmd,
+ (void __user *)arg);
}
/**
@@ -3787,7 +3700,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_playback_poll,
- .unlocked_ioctl = snd_pcm_playback_ioctl,
+ .unlocked_ioctl = snd_pcm_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
@@ -3801,7 +3714,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_capture_poll,
- .unlocked_ioctl = snd_pcm_capture_ioctl,
+ .unlocked_ioctl = snd_pcm_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h
index 86c8d658a25c..08abba3133ab 100644
--- a/sound/core/pcm_param_trace.h
+++ b/sound/core/pcm_param_trace.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM snd_pcm
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
index 3ddec1b8ae46..f18da2050772 100644
--- a/sound/core/pcm_trace.h
+++ b/sound/core/pcm_trace.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM snd_pcm
#define TRACE_INCLUDE_FILE pcm_trace
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
index a536760a94c2..45c1336c6597 100644
--- a/sound/core/seq/Kconfig
+++ b/sound/core/seq/Kconfig
@@ -47,10 +47,10 @@ config SND_SEQ_HRTIMER_DEFAULT
timer.
config SND_SEQ_MIDI_EVENT
- def_tristate SND_RAWMIDI
+ tristate
config SND_SEQ_MIDI
- tristate
+ def_tristate SND_RAWMIDI
select SND_SEQ_MIDI_EVENT
config SND_SEQ_MIDI_EMUL
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 68fd367ac39c..3a2177a7e50c 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Makefile for ALSA
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 272c55fe17c8..d10c780dfd54 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -663,7 +663,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
if (atomic)
read_lock(&grp->list_lock);
else
- down_read(&grp->list_mutex);
+ down_read_nested(&grp->list_mutex, hop);
list_for_each_entry(subs, &grp->list_head, src_list) {
/* both ports ready? */
if (atomic_read(&subs->ref_count) != 2)
@@ -1259,6 +1259,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
struct snd_seq_port_info *info = arg;
struct snd_seq_client_port *port;
struct snd_seq_port_callback *callback;
+ int port_idx;
/* it is not allowed to create the port for an another client */
if (info->addr.client != client->number)
@@ -1269,7 +1270,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
return -ENOMEM;
if (client->type == USER_CLIENT && info->kernel) {
- snd_seq_delete_port(client, port->addr.port);
+ port_idx = port->addr.port;
+ snd_seq_port_unlock(port);
+ snd_seq_delete_port(client, port_idx);
return -EINVAL;
}
if (client->type == KERNEL_CLIENT) {
@@ -1290,6 +1293,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
snd_seq_set_port_info(port, info);
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
+ snd_seq_port_unlock(port);
return 0;
}
@@ -1502,16 +1506,11 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
{
struct snd_seq_queue_info *info = arg;
- int result;
struct snd_seq_queue *q;
- result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
- if (result < 0)
- return result;
-
- q = queueptr(result);
- if (q == NULL)
- return -EINVAL;
+ q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
info->queue = q->queue;
info->locked = q->locked;
@@ -1521,7 +1520,7 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
if (!info->name[0])
snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
strlcpy(q->name, info->name, sizeof(q->name));
- queuefree(q);
+ snd_use_lock_free(&q->use_lock);
return 0;
}
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index 0ff7926a5a69..cda64b489e42 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -23,8 +23,6 @@
#include <sound/core.h>
#include "seq_lock.h"
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
/* wait until all locks are released */
void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
{
@@ -41,5 +39,3 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
}
}
EXPORT_SYMBOL(snd_use_lock_sync_helper);
-
-#endif
diff --git a/sound/core/seq/seq_lock.h b/sound/core/seq/seq_lock.h
index 54044bc2c9ef..a973860ebcd0 100644
--- a/sound/core/seq/seq_lock.h
+++ b/sound/core/seq/seq_lock.h
@@ -1,10 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __SND_SEQ_LOCK_H
#define __SND_SEQ_LOCK_H
#include <linux/sched.h>
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
typedef atomic_t snd_use_lock_t;
/* initialize lock */
@@ -20,14 +19,4 @@ typedef atomic_t snd_use_lock_t;
void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line);
#define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__)
-#else /* SMP || CONFIG_SND_DEBUG */
-
-typedef spinlock_t snd_use_lock_t; /* dummy */
-#define snd_use_lock_init(lockp) /**/
-#define snd_use_lock_use(lockp) /**/
-#define snd_use_lock_free(lockp) /**/
-#define snd_use_lock_sync(lockp) /**/
-
-#endif /* SMP || CONFIG_SND_DEBUG */
-
#endif /* __SND_SEQ_LOCK_H */
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 0a7020c82bfc..d21ece9f8d73 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
}
-/* create a port, port number is returned (-1 on failure) */
+/* create a port, port number is returned (-1 on failure);
+ * the caller needs to unref the port via snd_seq_port_unlock() appropriately
+ */
struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
int port)
{
@@ -151,6 +153,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
snd_use_lock_init(&new_port->use_lock);
port_subs_info_init(&new_port->c_src);
port_subs_info_init(&new_port->c_dest);
+ snd_use_lock_use(&new_port->use_lock);
num = port >= 0 ? port : 0;
mutex_lock(&client->ports_mutex);
@@ -165,9 +168,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
list_add_tail(&new_port->list, &p->list);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
+ sprintf(new_port->name, "port-%d", num);
write_unlock_irqrestore(&client->ports_lock, flags);
mutex_unlock(&client->ports_mutex);
- sprintf(new_port->name, "port-%d", num);
return new_port;
}
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 450c5187eecb..79e0c5604ef8 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -184,22 +184,26 @@ void __exit snd_seq_queues_delete(void)
static void queue_use(struct snd_seq_queue *queue, int client, int use);
/* allocate a new queue -
- * return queue index value or negative value for error
+ * return pointer to new queue or ERR_PTR(-errno) for error
+ * The new queue's use_lock is set to 1. It is the caller's responsibility to
+ * call snd_use_lock_free(&q->use_lock).
*/
-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
{
struct snd_seq_queue *q;
q = queue_new(client, locked);
if (q == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
q->info_flags = info_flags;
queue_use(q, client, 1);
+ snd_use_lock_use(&q->use_lock);
if (queue_list_add(q) < 0) {
+ snd_use_lock_free(&q->use_lock);
queue_delete(q);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- return q->queue;
+ return q;
}
/* delete a queue - queue must be owned by the client */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 30c8111477f6..719093489a2c 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -71,7 +71,7 @@ void snd_seq_queues_delete(void);
/* create new queue (constructor) */
-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
/* delete queue (destructor) */
int snd_seq_queue_delete(int client, int queueid);
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 8d93a4021c78..f48a4cd24ffc 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -77,13 +77,17 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
* decode input event and put to read buffer of each opened file
*/
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
- struct snd_seq_event *ev)
+ struct snd_seq_event *ev,
+ bool atomic)
{
struct snd_virmidi *vmidi;
unsigned char msg[4];
int len;
- read_lock(&rdev->filelist_lock);
+ if (atomic)
+ read_lock(&rdev->filelist_lock);
+ else
+ down_read(&rdev->filelist_sem);
list_for_each_entry(vmidi, &rdev->filelist, list) {
if (!vmidi->trigger)
continue;
@@ -97,7 +101,10 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
snd_rawmidi_receive(vmidi->substream, msg, len);
}
}
- read_unlock(&rdev->filelist_lock);
+ if (atomic)
+ read_unlock(&rdev->filelist_lock);
+ else
+ up_read(&rdev->filelist_sem);
return 0;
}
@@ -115,7 +122,7 @@ int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev)
struct snd_virmidi_dev *rdev;
rdev = rmidi->private_data;
- return snd_virmidi_dev_receive_event(rdev, ev);
+ return snd_virmidi_dev_receive_event(rdev, ev, true);
}
#endif /* 0 */
@@ -130,7 +137,7 @@ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
rdev = private_data;
if (!(rdev->flags & SNDRV_VIRMIDI_USE))
return 0; /* ignored */
- return snd_virmidi_dev_receive_event(rdev, ev);
+ return snd_virmidi_dev_receive_event(rdev, ev, atomic);
}
/*
@@ -209,7 +216,6 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_rawmidi_runtime *runtime = substream->runtime;
struct snd_virmidi *vmidi;
- unsigned long flags;
vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
if (vmidi == NULL)
@@ -223,9 +229,11 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->client = rdev->client;
vmidi->port = rdev->port;
runtime->private_data = vmidi;
- write_lock_irqsave(&rdev->filelist_lock, flags);
+ down_write(&rdev->filelist_sem);
+ write_lock_irq(&rdev->filelist_lock);
list_add_tail(&vmidi->list, &rdev->filelist);
- write_unlock_irqrestore(&rdev->filelist_lock, flags);
+ write_unlock_irq(&rdev->filelist_lock);
+ up_write(&rdev->filelist_sem);
vmidi->rdev = rdev;
return 0;
}
@@ -264,9 +272,11 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_virmidi *vmidi = substream->runtime->private_data;
+ down_write(&rdev->filelist_sem);
write_lock_irq(&rdev->filelist_lock);
list_del(&vmidi->list);
write_unlock_irq(&rdev->filelist_lock);
+ up_write(&rdev->filelist_sem);
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -520,6 +530,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
rdev->rmidi = rmidi;
rdev->device = device;
rdev->client = -1;
+ init_rwsem(&rdev->filelist_sem);
rwlock_init(&rdev->filelist_lock);
INIT_LIST_HEAD(&rdev->filelist);
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c
index c4acf17e9f5e..e40a2cba5002 100644
--- a/sound/core/seq_device.c
+++ b/sound/core/seq_device.c
@@ -148,8 +148,10 @@ void snd_seq_device_load_drivers(void)
flush_work(&autoload_work);
}
EXPORT_SYMBOL(snd_seq_device_load_drivers);
+#define cancel_autoload_drivers() cancel_work_sync(&autoload_work)
#else
#define queue_autoload_drivers() /* NOP */
+#define cancel_autoload_drivers() /* NOP */
#endif
/*
@@ -159,6 +161,7 @@ static int snd_seq_device_dev_free(struct snd_device *device)
{
struct snd_seq_device *dev = device->device_data;
+ cancel_autoload_drivers();
put_device(&dev->dev);
return 0;
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index a9b9a277e00c..6cdd04a45962 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -393,7 +393,8 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
if (timeri == NULL)
return 0;
- if ((timer = timeri->timer) != NULL) {
+ timer = timeri->timer;
+ if (timer) {
if (timer->hw.c_resolution)
return timer->hw.c_resolution(timer);
return timer->hw.resolution;
@@ -2096,8 +2097,7 @@ static int __init alsa_timer_init(void)
err = snd_timer_register_system();
if (err < 0) {
pr_err("ALSA: unable to register system timer (%i)\n", err);
- put_device(&timer_dev);
- return err;
+ goto put_timer;
}
err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
@@ -2105,12 +2105,15 @@ static int __init alsa_timer_init(void)
if (err < 0) {
pr_err("ALSA: unable to register timer device (%i)\n", err);
snd_timer_free_all();
- put_device(&timer_dev);
- return err;
+ goto put_timer;
}
snd_timer_proc_init();
return 0;
+
+put_timer:
+ put_device(&timer_dev);
+ return err;
}
static void __exit alsa_timer_exit(void)
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 6a437eb66115..59127b6ef39e 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -133,7 +133,8 @@ enum {
#endif /* CONFIG_X86_X32 */
};
-static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
void __user *argp = compat_ptr(arg);
@@ -153,7 +154,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
case SNDRV_TIMER_IOCTL_PAUSE:
case SNDRV_TIMER_IOCTL_PAUSE_OLD:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
- return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+ return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_TIMER_IOCTL_GPARAMS32:
return snd_timer_user_gparams_compat(file, argp);
case SNDRV_TIMER_IOCTL_INFO32:
@@ -167,3 +168,15 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
}
return -ENOIOCTLCMD;
}
+
+static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct snd_timer_user *tu = file->private_data;
+ long ret;
+
+ mutex_lock(&tu->ioctl_lock);
+ ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
+ mutex_unlock(&tu->ioctl_lock);
+ return ret;
+}
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 6c58e6f73a01..e43af18d4383 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -484,3 +484,34 @@ void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
master->hook(master->hook_private_data, master->val);
}
EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
+
+/**
+ * snd_ctl_apply_vmaster_slaves - Apply function to each vmaster slave
+ * @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.
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
+ int (*func)(struct snd_kcontrol *, void *),
+ void *arg)
+{
+ struct link_master *master;
+ struct link_slave *slave;
+ 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->slave, arg);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_slaves);