summaryrefslogtreecommitdiff
path: root/sound/core/oss
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/oss')
-rw-r--r--sound/core/oss/Makefile3
-rw-r--r--sound/core/oss/io.c4
-rw-r--r--sound/core/oss/linear.c2
-rw-r--r--sound/core/oss/mixer_oss.c406
-rw-r--r--sound/core/oss/mulaw.c6
-rw-r--r--sound/core/oss/pcm_oss.c842
-rw-r--r--sound/core/oss/pcm_plugin.c191
-rw-r--r--sound/core/oss/pcm_plugin.h48
-rw-r--r--sound/core/oss/rate.c12
-rw-r--r--sound/core/oss/route.c2
10 files changed, 793 insertions, 723 deletions
diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile
index 10a79453245f..d5f48ae6ba96 100644
--- a/sound/core/oss/Makefile
+++ b/sound/core/oss/Makefile
@@ -1,9 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Makefile for ALSA
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
-snd-mixer-oss-objs := mixer_oss.o
+snd-mixer-oss-y := mixer_oss.o
snd-pcm-oss-y := pcm_oss.o
snd-pcm-oss-$(CONFIG_SND_PCM_OSS_PLUGINS) += pcm_plugin.o \
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
index 6faa1d719206..d870b2d93135 100644
--- a/sound/core/oss/io.c
+++ b/sound/core/oss/io.c
@@ -26,9 +26,9 @@
#include "pcm_plugin.h"
#define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
-#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1)
+#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count)
#define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
-#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1)
+#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count)
/*
* Basic io plugin
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index 2045697f449d..797d838a2f9e 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -107,6 +107,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
}
}
#endif
+ if (frames > dst_channels[0].frames)
+ frames = dst_channels[0].frames;
convert(plugin, src_channels, dst_channels, frames);
return frames;
}
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index e8a1d18774b2..e839a4bb93f8 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1,22 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OSS emulation layer for the mixer interface
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/init.h>
@@ -24,6 +9,7 @@
#include <linux/time.h>
#include <linux/string.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/control.h>
@@ -101,8 +87,8 @@ static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
struct mixer_info info;
memset(&info, 0, sizeof(info));
- strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
- strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
+ strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+ strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
info.modify_counter = card->mixer_oss_change_count;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -117,8 +103,8 @@ static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
_old_mixer_info info;
memset(&info, 0, sizeof(info));
- strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
- strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
+ strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+ strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return 0;
@@ -144,6 +130,7 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume || pslot->put_recsrc)
@@ -160,6 +147,7 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume && pslot->stereo)
@@ -175,6 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
result = mixer->mask_recsrc;
} else {
@@ -196,11 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
- int err;
unsigned int index;
- if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
- return err;
+ result = mixer->get_recsrc(fmixer, &index);
+ if (result < 0)
+ return result;
result = 1 << index;
} else {
struct snd_mixer_oss_slot *pslot;
@@ -215,7 +205,8 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
}
}
}
- return mixer->oss_recsrc = result;
+ mixer->oss_recsrc = result;
+ return result;
}
static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
@@ -228,6 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
if (mixer == NULL)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
@@ -264,6 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
if (mixer == NULL || slot > 30)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
left = pslot->volume[0];
right = pslot->volume[1];
@@ -292,6 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (mixer == NULL || slot > 30)
return -EIO;
+ guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
if (left > 100)
left = 100;
@@ -305,7 +299,8 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
return result;
pslot->volume[0] = left;
pslot->volume[1] = right;
- return (left & 0xff) | ((right & 0xff) << 8);
+ result = (left & 0xff) | ((right & 0xff) << 8);
+ return result;
}
static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
@@ -394,10 +389,16 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
fmixer.mixer = card->mixer_oss;
return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
}
+EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
#ifdef CONFIG_COMPAT
/* all compatible */
-#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl
+static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return snd_mixer_oss_ioctl1(file->private_data, cmd,
+ (unsigned long)compat_ptr(arg));
+}
#else
#define snd_mixer_oss_ioctl_compat NULL
#endif
@@ -411,7 +412,6 @@ static const struct file_operations snd_mixer_oss_f_ops =
.owner = THIS_MODULE,
.open = snd_mixer_oss_open,
.release = snd_mixer_oss_release,
- .llseek = no_llseek,
.unlocked_ioctl = snd_mixer_oss_ioctl,
.compat_ioctl = snd_mixer_oss_ioctl_compat,
};
@@ -426,7 +426,7 @@ static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long n
if (orange == 0)
return 0;
- return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
+ return DIV_ROUND_CLOSEST(nrange * (val - omin), orange) + nmin;
}
/* convert from alsa native to oss values (0-100) */
@@ -494,7 +494,7 @@ struct slot {
unsigned int channels;
unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
unsigned int capture_item;
- struct snd_mixer_oss_assign_table *assigned;
+ const struct snd_mixer_oss_assign_table *assigned;
unsigned int allocated: 1;
};
@@ -507,7 +507,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strlcpy(id.name, name, sizeof(id.name));
+ strscpy(id.name, name, sizeof(id.name));
id.index = index;
return snd_ctl_find_id(card, &id);
}
@@ -517,36 +517,31 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int *left, int *right)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, numid);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (kctl->get(kctl, uctl))
- goto __unalloc;
+ return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
- goto __unalloc;
+ return;
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
if (uinfo->count > 1)
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -555,26 +550,25 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
int *left, int *right,
int route)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, numid);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (kctl->get(kctl, uctl))
- goto __unalloc;
+ return;
if (!uctl->value.integer.value[0]) {
*left = 0;
if (uinfo->count == 1)
@@ -582,10 +576,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
}
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
*right = 0;
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
@@ -619,39 +609,35 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int left, int right)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, numid);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
- goto __unalloc;
+ return;
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
if (uinfo->count > 1)
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
- if ((res = kctl->put(kctl, uctl)) < 0)
- goto __unalloc;
+ res = kctl->put(kctl, uctl);
+ if (res < 0)
+ return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -660,25 +646,24 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
int left, int right,
int route)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
- if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
- up_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, numid);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (uinfo->count > 1) {
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
@@ -689,14 +674,11 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
} else {
uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
}
- if ((res = kctl->put(kctl, uctl)) < 0)
- goto __unalloc;
+ res = kctl->put(kctl, uctl);
+ if (res < 0)
+ return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
@@ -801,26 +783,24 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot;
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err, idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
- if (uinfo == NULL || uctl == NULL) {
- err = -ENOMEM;
- goto __free_only;
- }
- down_read(&card->controls_rwsem);
+ if (uinfo == NULL || uctl == NULL)
+ return -ENOMEM;
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- if (! kctl) {
- err = -ENOENT;
- goto __unlock;
- }
- if ((err = kctl->info(kctl, uinfo)) < 0)
- goto __unlock;
- if ((err = kctl->get(kctl, uctl)) < 0)
- goto __unlock;
+ if (!kctl)
+ return -ENOENT;
+ err = kctl->info(kctl, uinfo);
+ if (err < 0)
+ return err;
+ err = kctl->get(kctl, uctl);
+ if (err < 0)
+ return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@@ -835,13 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
}
}
- err = 0;
- __unlock:
- up_read(&card->controls_rwsem);
- __free_only:
- kfree(uctl);
- kfree(uinfo);
- return err;
+ return 0;
}
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
@@ -851,25 +825,22 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot = NULL;
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err;
unsigned int idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
- if (uinfo == NULL || uctl == NULL) {
- err = -ENOMEM;
- goto __free_only;
- }
- down_read(&card->controls_rwsem);
+ if (uinfo == NULL || uctl == NULL)
+ return -ENOMEM;
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- if (! kctl) {
- err = -ENOENT;
- goto __unlock;
- }
- if ((err = kctl->info(kctl, uinfo)) < 0)
- goto __unlock;
+ if (!kctl)
+ return -ENOENT;
+ err = kctl->info(kctl, uinfo);
+ if (err < 0)
+ return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@@ -883,20 +854,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
slot = NULL;
}
- if (! slot)
- goto __unlock;
+ if (!slot)
+ return 0;
for (idx = 0; idx < uinfo->count; idx++)
uctl->value.enumerated.item[idx] = slot->capture_item;
err = kctl->put(kctl, uctl);
if (err > 0)
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- err = 0;
- __unlock:
- up_read(&card->controls_rwsem);
- __free_only:
- kfree(uctl);
- kfree(uinfo);
- return err;
+ return 0;
}
struct snd_mixer_oss_assign_table {
@@ -907,33 +872,26 @@ struct snd_mixer_oss_assign_table {
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
{
- struct snd_ctl_elem_info *info;
+ struct snd_ctl_elem_info *info __free(kfree) = NULL;
struct snd_kcontrol *kcontrol;
struct snd_card *card = mixer->card;
int err;
- down_read(&card->controls_rwsem);
- kcontrol = snd_mixer_oss_test_id(mixer, name, index);
- if (kcontrol == NULL) {
- up_read(&card->controls_rwsem);
- return 0;
- }
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (! info) {
- up_read(&card->controls_rwsem);
- return -ENOMEM;
- }
- if ((err = kcontrol->info(kcontrol, info)) < 0) {
- up_read(&card->controls_rwsem);
- kfree(info);
- return err;
+ scoped_guard(rwsem_read, &card->controls_rwsem) {
+ kcontrol = snd_mixer_oss_test_id(mixer, name, index);
+ if (kcontrol == NULL)
+ return 0;
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ err = kcontrol->info(kcontrol, info);
+ if (err < 0)
+ return err;
+ slot->numid[item] = kcontrol->id.numid;
}
- slot->numid[item] = kcontrol->id.numid;
- up_read(&card->controls_rwsem);
if (info->count > slot->channels)
slot->channels = info->count;
slot->present |= 1 << item;
- kfree(info);
return 0;
}
@@ -961,7 +919,7 @@ static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
snd_mixer_oss_build_input! */
static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
- struct snd_mixer_oss_assign_table *ptr,
+ const struct snd_mixer_oss_assign_table *ptr,
struct slot *slot)
{
char str[64];
@@ -1025,13 +983,15 @@ static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
* ptr_allocated means the entry is dynamically allocated (change via proc file).
* when replace_old = 1, the old entry is replaced with the new one.
*/
-static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
+static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
+ const struct snd_mixer_oss_assign_table *ptr,
+ int ptr_allocated, int replace_old)
{
struct slot slot;
struct slot *pslot;
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *rslot;
- char str[64];
+ const char *str;
/* check if already assigned */
if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
@@ -1041,46 +1001,39 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
return 0;
- down_read(&mixer->card->controls_rwsem);
- if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
- struct snd_ctl_elem_info *uinfo;
+ guard(rwsem_read)(&mixer->card->controls_rwsem);
+ kctl = NULL;
+ if (!ptr->index)
+ kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
+ if (kctl) {
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
- if (! uinfo) {
- up_read(&mixer->card->controls_rwsem);
+ if (!uinfo)
return -ENOMEM;
- }
- if (kctl->info(kctl, uinfo)) {
- up_read(&mixer->card->controls_rwsem);
- kfree(uinfo);
+ if (kctl->info(kctl, uinfo))
return 0;
- }
- strcpy(str, ptr->name);
+ str = ptr->name;
if (!strcmp(str, "Master"))
- strcpy(str, "Mix");
- if (!strcmp(str, "Master Mono"))
- strcpy(str, "Mix Mono");
+ str = "Mix";
+ else if (!strcmp(str, "Master Mono"))
+ str = "Mix Mono";
slot.capture_item = 0;
if (!strcmp(uinfo->value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
} else {
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
uinfo->value.enumerated.item = slot.capture_item;
- if (kctl->info(kctl, uinfo)) {
- up_read(&mixer->card->controls_rwsem);
- kfree(uinfo);
+ if (kctl->info(kctl, uinfo))
return 0;
- }
if (!strcmp(uinfo->value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
break;
}
}
}
- kfree(uinfo);
}
- up_read(&mixer->card->controls_rwsem);
if (slot.present != 0) {
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
if (! pslot)
@@ -1111,11 +1064,11 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
return 0;
}
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_SND_PROC_FS
/*
*/
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
-static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
+static const char * const oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
MIXER_VOL(VOLUME),
MIXER_VOL(BASS),
MIXER_VOL(TREBLE),
@@ -1153,7 +1106,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
struct snd_mixer_oss *mixer = entry->private_data;
int i;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
struct slot *p;
@@ -1168,7 +1121,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
else
snd_iprintf(buffer, "\"\" 0\n");
}
- mutex_unlock(&mixer->reg_mutex);
}
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1177,7 +1129,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
struct snd_mixer_oss *mixer = entry->private_data;
char line[128], str[32], idxstr[16];
const char *cptr;
- int ch, idx;
+ unsigned int idx;
+ int ch;
struct snd_mixer_oss_assign_table *tbl;
struct slot *slot;
@@ -1187,47 +1140,44 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
break;
if (ch >= SNDRV_OSS_MAX_MIXERS) {
- snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
+ pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n",
+ str);
continue;
}
cptr = snd_info_get_str(str, cptr, sizeof(str));
if (! *str) {
/* remove the entry */
- mutex_lock(&mixer->reg_mutex);
- mixer_slot_clear(&mixer->slots[ch]);
- mutex_unlock(&mixer->reg_mutex);
+ scoped_guard(mutex, &mixer->reg_mutex)
+ mixer_slot_clear(&mixer->slots[ch]);
continue;
}
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
idx = simple_strtoul(idxstr, NULL, 10);
if (idx >= 0x4000) { /* too big */
- snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
+ pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
continue;
}
- mutex_lock(&mixer->reg_mutex);
- slot = (struct slot *)mixer->slots[ch].private_data;
- if (slot && slot->assigned &&
- slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
- /* not changed */
- goto __unlock;
- tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
- if (! tbl) {
- snd_printk(KERN_ERR "mixer_oss: no memory\n");
- goto __unlock;
- }
- tbl->oss_id = ch;
- tbl->name = kstrdup(str, GFP_KERNEL);
- if (! tbl->name) {
- kfree(tbl);
- goto __unlock;
- }
- tbl->index = idx;
- if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
- kfree(tbl->name);
- kfree(tbl);
+ scoped_guard(mutex, &mixer->reg_mutex) {
+ slot = (struct slot *)mixer->slots[ch].private_data;
+ if (slot && slot->assigned &&
+ slot->assigned->index == idx && !strcmp(slot->assigned->name, str))
+ /* not changed */
+ break;
+ tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ break;
+ tbl->oss_id = ch;
+ tbl->name = kstrdup(str, GFP_KERNEL);
+ if (!tbl->name) {
+ kfree(tbl);
+ break;
+ }
+ tbl->index = idx;
+ if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
+ kfree(tbl->name);
+ kfree(tbl);
+ }
}
- __unlock:
- mutex_unlock(&mixer->reg_mutex);
}
}
@@ -1240,7 +1190,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
if (! entry)
return;
entry->content = SNDRV_INFO_CONTENT_TEXT;
- entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+ entry->mode = S_IFREG | 0644;
entry->c.text.read = snd_mixer_oss_proc_read;
entry->c.text.write = snd_mixer_oss_proc_write;
entry->private_data = mixer;
@@ -1256,14 +1206,14 @@ static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
snd_info_free_entry(mixer->proc_entry);
mixer->proc_entry = NULL;
}
-#else /* !CONFIG_PROC_FS */
+#else /* !CONFIG_SND_PROC_FS */
#define snd_mixer_oss_proc_init(mix)
#define snd_mixer_oss_proc_done(mix)
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_SND_PROC_FS */
static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
{
- static struct snd_mixer_oss_assign_table table[] = {
+ static const struct snd_mixer_oss_assign_table table[] = {
{ SOUND_MIXER_VOLUME, "Master", 0 },
{ SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */
{ SOUND_MIXER_BASS, "Tone Control - Bass", 0 },
@@ -1343,29 +1293,29 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
struct snd_mixer_oss *mixer;
if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
- char name[128];
int idx, err;
mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
if (mixer == NULL)
return -ENOMEM;
mutex_init(&mixer->reg_mutex);
- sprintf(name, "mixer%i%i", card->number, 0);
- if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
- card, 0,
- &snd_mixer_oss_f_ops, card,
- name)) < 0) {
- snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
- card->number, 0);
+ err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
+ card, 0,
+ &snd_mixer_oss_f_ops, card);
+ if (err < 0) {
+ dev_err(card->dev,
+ "unable to register OSS mixer device %i:%i\n",
+ card->number, 0);
kfree(mixer);
return err;
}
mixer->oss_dev_alloc = 1;
mixer->card = card;
if (*card->mixername)
- strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
+ strscpy(mixer->name, card->mixername, sizeof(mixer->name));
else
- strlcpy(mixer->name, name, sizeof(mixer->name));
+ snprintf(mixer->name, sizeof(mixer->name),
+ "mixer%i", card->number);
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
card->number,
@@ -1397,28 +1347,34 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
static int __init alsa_mixer_oss_init(void)
{
+ struct snd_card *card;
int idx;
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- if (snd_cards[idx])
- snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
+ card = snd_card_ref(idx);
+ if (card) {
+ snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
+ snd_card_unref(card);
+ }
}
return 0;
}
static void __exit alsa_mixer_oss_exit(void)
{
+ struct snd_card *card;
int idx;
snd_mixer_oss_notify_callback = NULL;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- if (snd_cards[idx])
- snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
+ card = snd_card_ref(idx);
+ if (card) {
+ snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
+ snd_card_unref(card);
+ }
}
}
module_init(alsa_mixer_oss_init)
module_exit(alsa_mixer_oss_exit)
-
-EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 7915564bd394..fe27034f2846 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -269,6 +269,8 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
}
}
#endif
+ if (frames > dst_channels[0].frames)
+ frames = dst_channels[0].frames;
data = (struct mulaw_priv *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames);
return frames;
@@ -327,8 +329,8 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
snd_BUG();
return -EINVAL;
}
- if (snd_BUG_ON(!snd_pcm_format_linear(format->format)))
- return -ENXIO;
+ if (!snd_pcm_format_linear(format->format))
+ return -EINVAL;
err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
src_format, dst_format,
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 4c1cc51772e6..a82dd155e1d3 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1,22 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Digital Audio (PCM) abstract layer / OSS compatible
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#if 0
@@ -28,11 +13,13 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/string.h>
+#include <linux/compat.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/pcm.h>
@@ -65,18 +52,6 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
-static inline mm_segment_t snd_enter_user(void)
-{
- mm_segment_t fs = get_fs();
- set_fs(get_ds());
- return fs;
-}
-
-static inline void snd_leave_user(mm_segment_t fs)
-{
- set_fs(fs);
-}
-
/*
* helper functions to process hw_params
*/
@@ -172,7 +147,7 @@ snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
*
* Return the maximum value for field PAR.
*/
-static unsigned int
+static int
snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, int *dir)
{
@@ -196,7 +171,7 @@ static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
{
int changed;
changed = snd_mask_refine(hw_param_mask(params, var), val);
- if (changed) {
+ if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
@@ -243,7 +218,7 @@ static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
val, open);
else
return -EINVAL;
- if (changed) {
+ if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
@@ -304,7 +279,7 @@ static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
val, open);
else
return -EINVAL;
- if (changed) {
+ if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
@@ -402,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
snd_pcm_hw_param_t var, unsigned int best,
int *dir)
{
- struct snd_pcm_hw_params *save = NULL;
+ struct snd_pcm_hw_params *save __free(kfree) = NULL;
int v;
unsigned int saved_min;
int last = 0;
@@ -429,43 +404,34 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
saved_min = min;
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
if (min >= 0) {
- struct snd_pcm_hw_params *params1;
+ struct snd_pcm_hw_params *params1 __free(kfree) = NULL;
if (max < 0)
goto _end;
if ((unsigned int)min == saved_min && mindir == valdir)
goto _end;
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
- if (params1 == NULL) {
- kfree(save);
+ if (params1 == NULL)
return -ENOMEM;
- }
*params1 = *save;
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
- if (max < 0) {
- kfree(params1);
+ if (max < 0)
goto _end;
- }
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = *params1;
last = 1;
}
- kfree(params1);
} else {
*params = *save;
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
- if (max < 0) {
- kfree(save);
+ if (max < 0)
return max;
- }
last = 1;
}
_end:
- kfree(save);
if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
v = snd_pcm_hw_param_first(pcm, params, var, dir);
- snd_BUG_ON(v < 0);
return v;
}
@@ -510,7 +476,7 @@ static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
}
} else
return -EINVAL;
- if (changed) {
+ if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
@@ -550,7 +516,7 @@ static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
{
int changed;
changed = snd_interval_setinteger(hw_param_interval(params, var));
- if (changed) {
+ if (changed > 0) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
@@ -708,18 +674,26 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *oss_params,
struct snd_pcm_hw_params *slave_params)
{
- size_t s;
- size_t oss_buffer_size, oss_period_size, oss_periods;
- size_t min_period_size, max_period_size;
+ ssize_t s;
+ ssize_t oss_buffer_size;
+ ssize_t oss_period_size, oss_periods;
+ ssize_t min_period_size, max_period_size;
struct snd_pcm_runtime *runtime = substream->runtime;
size_t oss_frame_size;
oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
params_channels(oss_params) / 8;
+ oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ NULL);
+ if (oss_buffer_size <= 0)
+ return -EINVAL;
oss_buffer_size = snd_pcm_plug_client_size(substream,
- snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
- oss_buffer_size = 1 << ld2(oss_buffer_size);
+ oss_buffer_size * oss_frame_size);
+ if (oss_buffer_size <= 0)
+ return -EINVAL;
+ oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes;
@@ -754,17 +728,21 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
min_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
- min_period_size *= oss_frame_size;
- min_period_size = 1 << (ld2(min_period_size - 1) + 1);
- if (oss_period_size < min_period_size)
- oss_period_size = min_period_size;
+ if (min_period_size > 0) {
+ min_period_size *= oss_frame_size;
+ min_period_size = roundup_pow_of_two(min_period_size);
+ if (oss_period_size < min_period_size)
+ oss_period_size = min_period_size;
+ }
max_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
- max_period_size *= oss_frame_size;
- max_period_size = 1 << ld2(max_period_size);
- if (oss_period_size > max_period_size)
- oss_period_size = max_period_size;
+ if (max_period_size > 0) {
+ max_period_size *= oss_frame_size;
+ max_period_size = rounddown_pow_of_two(max_period_size);
+ if (oss_period_size > max_period_size)
+ oss_period_size = max_period_size;
+ }
oss_periods = oss_buffer_size / oss_period_size;
@@ -772,7 +750,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_periods = substream->oss.setup.periods;
s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
- if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
+ if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
s = runtime->oss.maxfrags;
if (oss_periods > s)
oss_periods = s;
@@ -788,6 +766,11 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
if (oss_period_size < 16)
return -EINVAL;
+
+ /* don't allocate too large period; 1MB period must be enough */
+ if (oss_period_size > 1024 * 1024)
+ return -ENOMEM;
+
runtime->oss.period_bytes = oss_period_size;
runtime->oss.period_frames = 1;
runtime->oss.periods = oss_periods;
@@ -797,15 +780,15 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
static int choose_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, unsigned int best_rate)
{
- struct snd_interval *it;
- struct snd_pcm_hw_params *save;
+ const struct snd_interval *it;
+ struct snd_pcm_hw_params *save __free(kfree) = NULL;
unsigned int rate, prev;
save = kmalloc(sizeof(*save), GFP_KERNEL);
if (save == NULL)
return -ENOMEM;
*save = *params;
- it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);
+ it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE);
/* try multiples of the best rate */
rate = best_rate;
@@ -817,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
ret = snd_pcm_hw_param_set(substream, params,
SNDRV_PCM_HW_PARAM_RATE,
rate, 0);
- if (ret == (int)rate) {
- kfree(save);
+ if (ret == (int)rate)
return rate;
- }
*params = *save;
}
prev = rate;
@@ -830,11 +811,39 @@ static int choose_rate(struct snd_pcm_substream *substream,
}
/* not found, use the nearest rate */
- kfree(save);
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
}
-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
+/* parameter locking: returns immediately if tried during streaming */
+static int lock_params(struct snd_pcm_runtime *runtime)
+{
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ if (atomic_read(&runtime->oss.rw_ref)) {
+ mutex_unlock(&runtime->oss.params_lock);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static void unlock_params(struct snd_pcm_runtime *runtime)
+{
+ mutex_unlock(&runtime->oss.params_lock);
+}
+
+static void snd_pcm_oss_release_buffers(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ kvfree(runtime->oss.buffer);
+ runtime->oss.buffer = NULL;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+ snd_pcm_oss_plugin_clear(substream);
+#endif
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hw_params *params, *sparams;
@@ -845,16 +854,15 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
int direct;
snd_pcm_format_t format, sformat;
int n;
- struct snd_mask sformat_mask;
+ const struct snd_mask *sformat_mask;
struct snd_mask mask;
- if (mutex_lock_interruptible(&runtime->oss.params_lock))
- return -EINTR;
- sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+ if (!runtime->oss.params)
+ return 0;
+ sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
if (!sw_params || !params || !sparams) {
- snd_printd("No memory\n");
err = -ENOMEM;
goto failure;
}
@@ -877,36 +885,40 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
}
err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
if (err < 0) {
- snd_printd("No usable accesses\n");
+ pcm_dbg(substream->pcm, "No usable accesses\n");
err = -EINVAL;
goto failure;
}
- choose_rate(substream, sparams, runtime->oss.rate);
- snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
+
+ err = choose_rate(substream, sparams, runtime->oss.rate);
+ if (err < 0)
+ goto failure;
+ err = snd_pcm_hw_param_near(substream, sparams,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ runtime->oss.channels, NULL);
+ if (err < 0)
+ goto failure;
format = snd_pcm_oss_format_from(runtime->oss.format);
- sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
+ sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
if (direct)
sformat = format;
else
- sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
+ sformat = snd_pcm_plug_slave_format(format, sformat_mask);
if ((__force int)sformat < 0 ||
- !snd_mask_test(&sformat_mask, (__force int)sformat)) {
- for (sformat = (__force snd_pcm_format_t)0;
- (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST;
- sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) {
- if (snd_mask_test(&sformat_mask, (__force int)sformat) &&
+ !snd_mask_test_format(sformat_mask, sformat)) {
+ pcm_for_each_format(sformat) {
+ if (snd_mask_test_format(sformat_mask, sformat) &&
snd_pcm_oss_format_to(sformat) >= 0)
- break;
- }
- if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) {
- snd_printd("Cannot find a format!!!\n");
- err = -EINVAL;
- goto failure;
+ goto format_found;
}
+ pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
+ err = -EINVAL;
+ goto failure;
}
+ format_found:
err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
if (err < 0)
goto failure;
@@ -934,23 +946,44 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
params_channels(params) / 8;
+ err = snd_pcm_oss_period_size(substream, params, sparams);
+ if (err < 0)
+ goto failure;
+
+ n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
+ err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
+ if (err < 0)
+ goto failure;
+
+ err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
+ runtime->oss.periods, NULL);
+ if (err < 0)
+ goto failure;
+
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams);
+ if (err < 0) {
+ pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
+ goto failure;
+ }
+
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_oss_plugin_clear(substream);
if (!direct) {
/* add necessary plugins */
- snd_pcm_oss_plugin_clear(substream);
- if ((err = snd_pcm_plug_format_plugins(substream,
- params,
- sparams)) < 0) {
- snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
- snd_pcm_oss_plugin_clear(substream);
+ err = snd_pcm_plug_format_plugins(substream, params, sparams);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plug_format_plugins failed: %i\n", err);
goto failure;
}
if (runtime->oss.plugin_first) {
struct snd_pcm_plugin *plugin;
- if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
- snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
- snd_pcm_oss_plugin_clear(substream);
+ err = snd_pcm_plugin_build_io(substream, sparams, &plugin);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plugin_build_io failed: %i\n", err);
goto failure;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -958,36 +991,12 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
} else {
err = snd_pcm_plugin_insert(plugin);
}
- if (err < 0) {
- snd_pcm_oss_plugin_clear(substream);
+ if (err < 0)
goto failure;
- }
}
}
#endif
- err = snd_pcm_oss_period_size(substream, params, sparams);
- if (err < 0)
- goto failure;
-
- n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
- err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
- if (err < 0)
- goto failure;
-
- err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
- runtime->oss.periods, NULL);
- if (err < 0)
- goto failure;
-
- snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
-
- if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
- snd_printd("HW_PARAMS failed: %i\n", err);
- goto failure;
- }
-
- memset(sw_params, 0, sizeof(*sw_params));
if (runtime->oss.trigger) {
sw_params->start_threshold = 1;
} else {
@@ -1015,8 +1024,9 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
sw_params->silence_size = frames;
}
- if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
- snd_printd("SW_PARAMS failed: %i\n", err);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params);
+ if (err < 0) {
+ pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
goto failure;
}
@@ -1033,10 +1043,9 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
goto failure;
}
#endif
- oss_period_size *= oss_frame_size;
-
- oss_buffer_size = oss_period_size * runtime->oss.periods;
- if (oss_buffer_size < 0) {
+ oss_period_size = array_size(oss_period_size, oss_frame_size);
+ oss_buffer_size = array_size(oss_period_size, runtime->oss.periods);
+ if (oss_buffer_size <= 0) {
err = -EINVAL;
goto failure;
}
@@ -1055,8 +1064,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
runtime->oss.channels = params_channels(params);
runtime->oss.rate = params_rate(params);
- vfree(runtime->oss.buffer);
- runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);
+ kvfree(runtime->oss.buffer);
+ runtime->oss.buffer = kvzalloc(runtime->oss.period_bytes, GFP_KERNEL);
if (!runtime->oss.buffer) {
err = -ENOMEM;
goto failure;
@@ -1065,16 +1074,34 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
runtime->oss.params = 0;
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
- if (runtime->dma_area)
- snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
+ snd_pcm_runtime_buffer_set_silence(runtime);
runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
err = 0;
failure:
+ if (err)
+ snd_pcm_oss_release_buffers(substream);
kfree(sw_params);
kfree(params);
kfree(sparams);
+ return err;
+}
+
+/* this one takes the lock by itself */
+static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
+ bool trylock)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ if (trylock) {
+ if (!(mutex_trylock(&runtime->oss.params_lock)))
+ return -EAGAIN;
+ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+
+ err = snd_pcm_oss_change_params_locked(substream);
mutex_unlock(&runtime->oss.params_lock);
return err;
}
@@ -1091,7 +1118,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
if (asubstream == NULL)
asubstream = substream;
if (substream->runtime->oss.params) {
- err = snd_pcm_oss_change_params(substream);
+ err = snd_pcm_oss_change_params(substream, false);
if (err < 0)
return err;
}
@@ -1103,6 +1130,10 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
return 0;
}
+/* call with params_lock held */
+/* NOTE: this always call PREPARE unconditionally no matter whether
+ * runtime->oss.prepare is set or not
+ */
static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
{
int err;
@@ -1110,7 +1141,8 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
if (err < 0) {
- snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
+ pcm_dbg(substream->pcm,
+ "snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
return err;
}
runtime->oss.prepare = 0;
@@ -1126,11 +1158,32 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime;
int err;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (runtime->oss.params) {
- err = snd_pcm_oss_change_params(substream);
+ err = snd_pcm_oss_change_params(substream, false);
+ if (err < 0)
+ return err;
+ }
+ if (runtime->oss.prepare) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_prepare(substream);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ int err;
+
+ runtime = substream->runtime;
+ if (runtime->oss.params) {
+ err = snd_pcm_oss_change_params_locked(substream);
if (err < 0)
return err;
}
@@ -1172,33 +1225,27 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
while (1) {
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
- runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+ if (runtime->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: write: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: write: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: write: recovering from %s\n",
+ runtime->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;
}
- if (in_kernel) {
- mm_segment_t fs;
- fs = snd_enter_user();
- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
- snd_leave_user(fs);
- } else {
- ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
- }
+ mutex_unlock(&runtime->oss.params_lock);
+ ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
+ frames, in_kernel);
+ mutex_lock(&runtime->oss.params_lock);
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
/* test, if we can't store new data, because the stream */
/* has not been started */
- if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
+ if (runtime->state == SNDRV_PCM_STATE_PREPARED)
return -EAGAIN;
}
return ret;
@@ -1210,20 +1257,18 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
snd_pcm_sframes_t delay;
int ret;
while (1) {
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
- runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+ if (runtime->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: read: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: read: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: read: recovering from %s\n",
+ runtime->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
break;
- } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
+ } else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;
@@ -1231,16 +1276,12 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
if (ret < 0)
break;
- if (in_kernel) {
- mm_segment_t fs;
- fs = snd_enter_user();
- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
- snd_leave_user(fs);
- } else {
- ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
- }
+ mutex_unlock(&runtime->oss.params_lock);
+ ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
+ frames, in_kernel);
+ mutex_lock(&runtime->oss.params_lock);
if (ret == -EPIPE) {
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+ if (runtime->state == SNDRV_PCM_STATE_DRAINING) {
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (ret < 0)
break;
@@ -1253,80 +1294,64 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
return ret;
}
-snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
while (1) {
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
- runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+ if (runtime->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: writev: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: writev: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: writev: recovering from %s\n",
+ runtime->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;
}
- if (in_kernel) {
- mm_segment_t fs;
- fs = snd_enter_user();
- ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
- snd_leave_user(fs);
- } else {
- ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
- }
+ ret = snd_pcm_kernel_writev(substream, bufs, frames);
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
/* test, if we can't store new data, because the stream */
/* has not been started */
- if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
+ if (runtime->state == SNDRV_PCM_STATE_PREPARED)
return -EAGAIN;
}
return ret;
}
-snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
+snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
while (1) {
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
- runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+ if (runtime->state == SNDRV_PCM_STATE_XRUN ||
+ runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: readv: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: readv: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: readv: recovering from %s\n",
+ runtime->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
break;
- } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
+ } else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
break;
}
- if (in_kernel) {
- mm_segment_t fs;
- fs = snd_enter_user();
- ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
- snd_leave_user(fs);
- } else {
- ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
- }
+ ret = snd_pcm_kernel_readv(substream, bufs, frames);
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
}
return ret;
}
+#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
{
@@ -1364,16 +1389,21 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
{
size_t xfer = 0;
- ssize_t tmp;
+ ssize_t tmp = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return -ENXIO;
- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
- return tmp;
- mutex_lock(&runtime->oss.params_lock);
+ atomic_inc(&runtime->oss.rw_ref);
while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = snd_pcm_oss_make_ready_locked(substream);
+ if (tmp < 0)
+ goto err;
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
@@ -1417,14 +1447,19 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
- break;
+ tmp = -EAGAIN;
}
- }
- mutex_unlock(&runtime->oss.params_lock);
- return xfer;
-
err:
- mutex_unlock(&runtime->oss.params_lock);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
+ if (signal_pending(current)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = 0;
+ }
+ atomic_dec(&runtime->oss.rw_ref);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
@@ -1464,16 +1499,21 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
{
size_t xfer = 0;
- ssize_t tmp;
+ ssize_t tmp = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return -ENXIO;
- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
- return tmp;
- mutex_lock(&runtime->oss.params_lock);
+ atomic_inc(&runtime->oss.rw_ref);
while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = snd_pcm_oss_make_ready_locked(substream);
+ if (tmp < 0)
+ goto err;
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
if (runtime->oss.buffer_used == 0) {
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
@@ -1504,12 +1544,17 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
bytes -= tmp;
xfer += tmp;
}
- }
- mutex_unlock(&runtime->oss.params_lock);
- return xfer;
-
err:
- mutex_unlock(&runtime->oss.params_lock);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (tmp < 0)
+ break;
+ if (signal_pending(current)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
+ tmp = 0;
+ }
+ atomic_dec(&runtime->oss.rw_ref);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
@@ -1525,10 +1570,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
continue;
runtime = substream->runtime;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
+ mutex_unlock(&runtime->oss.params_lock);
}
return 0;
}
@@ -1540,7 +1587,8 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
- if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ err = snd_pcm_oss_make_ready(substream);
+ if (err < 0)
return err;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
}
@@ -1555,13 +1603,13 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
ssize_t result = 0;
snd_pcm_state_t state;
long res;
- wait_queue_t wait;
+ wait_queue_entry_t wait;
runtime = substream->runtime;
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync1: size = %li\n", size);
+ pcm_dbg(substream->pcm, "sync1: size = %li\n", size);
#endif
while (1) {
result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@@ -1574,9 +1622,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break;
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
- snd_pcm_stream_lock_irq(substream);
- state = runtime->status->state;
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream)
+ state = runtime->state;
if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING);
break;
@@ -1587,7 +1634,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break;
}
if (res == 0) {
- snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
+ pcm_err(substream->pcm,
+ "OSS sync error - DMA timeout\n");
result = -EIO;
break;
}
@@ -1611,37 +1659,38 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
goto __direct;
- if ((err = snd_pcm_oss_make_ready(substream)) < 0)
- return err;
+ atomic_inc(&runtime->oss.rw_ref);
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ atomic_dec(&runtime->oss.rw_ref);
+ return -ERESTARTSYS;
+ }
+ err = snd_pcm_oss_make_ready_locked(substream);
+ if (err < 0)
+ goto unlock;
format = snd_pcm_oss_format_from(runtime->oss.format);
width = snd_pcm_format_physical_width(format);
- mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync: buffer_used\n");
+ pcm_dbg(substream->pcm, "sync: buffer_used\n");
#endif
size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
snd_pcm_format_set_silence(format,
runtime->oss.buffer + runtime->oss.buffer_used,
size);
err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
- if (err < 0) {
- mutex_unlock(&runtime->oss.params_lock);
- return err;
- }
+ if (err < 0)
+ goto unlock;
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync: period_ptr\n");
+ pcm_dbg(substream->pcm, "sync: period_ptr\n");
#endif
size = runtime->oss.period_bytes - runtime->oss.period_ptr;
snd_pcm_format_set_silence(format,
runtime->oss.buffer,
size * 8 / width);
err = snd_pcm_oss_sync1(substream, size);
- if (err < 0) {
- mutex_unlock(&runtime->oss.params_lock);
- return err;
- }
+ if (err < 0)
+ goto unlock;
}
/*
* The ALSA's period might be a bit large than OSS one.
@@ -1650,29 +1699,16 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
size = runtime->control->appl_ptr % runtime->period_size;
if (size > 0) {
size = runtime->period_size - size;
- if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
- size = (runtime->frame_bits * size) / 8;
- while (size > 0) {
- mm_segment_t fs;
- size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
- size -= size1;
- size1 *= 8;
- size1 /= runtime->sample_bits;
- snd_pcm_format_set_silence(runtime->format,
- runtime->oss.buffer,
- size1);
- size1 /= runtime->channels; /* frames */
- fs = snd_enter_user();
- snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1);
- snd_leave_user(fs);
- }
- } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
- void __user *buffers[runtime->channels];
- memset(buffers, 0, runtime->channels * sizeof(void *));
- snd_pcm_lib_writev(substream, buffers, size);
- }
+ if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
+ snd_pcm_lib_write(substream, NULL, size);
+ else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
+ snd_pcm_lib_writev(substream, NULL, size);
}
+unlock:
mutex_unlock(&runtime->oss.params_lock);
+ atomic_dec(&runtime->oss.rw_ref);
+ if (err < 0)
+ return err;
/*
* finish sync: drain the buffer
*/
@@ -1683,19 +1719,24 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
substream->f_flags = saved_f_flags;
if (err < 0)
return err;
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.prepare = 1;
+ mutex_unlock(&runtime->oss.params_lock);
}
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream != NULL) {
- if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ err = snd_pcm_oss_make_ready(substream);
+ if (err < 0)
return err;
runtime = substream->runtime;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (err < 0)
return err;
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.buffer_used = 0;
runtime->oss.prepare = 1;
+ mutex_unlock(&runtime->oss.params_lock);
}
return 0;
}
@@ -1707,6 +1748,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
struct snd_pcm_runtime *runtime;
+ int err;
+
if (substream == NULL)
continue;
runtime = substream->runtime;
@@ -1714,10 +1757,14 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
rate = 1000;
else if (rate > 192000)
rate = 192000;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.rate != rate) {
runtime->oss.params = 1;
runtime->oss.rate = rate;
}
+ unlock_params(runtime);
}
return snd_pcm_oss_get_rate(pcm_oss_file);
}
@@ -1727,7 +1774,8 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
- if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
+ err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
+ if (err < 0)
return err;
return substream->runtime->oss.rate;
}
@@ -1742,13 +1790,19 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
struct snd_pcm_runtime *runtime;
+ int err;
+
if (substream == NULL)
continue;
runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.channels != channels) {
runtime->oss.params = 1;
runtime->oss.channels = channels;
}
+ unlock_params(runtime);
}
return snd_pcm_oss_get_channels(pcm_oss_file);
}
@@ -1758,7 +1812,8 @@ static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
- if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
+ err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
+ if (err < 0)
return err;
return substream->runtime->oss.channels;
}
@@ -1768,7 +1823,8 @@ static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
- if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
+ err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
+ if (err < 0)
return err;
return substream->runtime->oss.period_bytes;
}
@@ -1778,12 +1834,13 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
int direct;
- struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
unsigned int formats = 0;
- struct snd_mask format_mask;
+ const struct snd_mask *format_mask;
int fmt;
- if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
+ err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
+ if (err < 0)
return err;
if (atomic_read(&substream->mmap_count))
direct = 1;
@@ -1802,23 +1859,24 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
return -ENOMEM;
_snd_pcm_hw_params_any(params);
err = snd_pcm_hw_refine(substream, params);
- format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- kfree(params);
if (err < 0)
return err;
+ format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
for (fmt = 0; fmt < 32; ++fmt) {
- if (snd_mask_test(&format_mask, fmt)) {
- int f = snd_pcm_oss_format_to(fmt);
+ if (snd_mask_test(format_mask, fmt)) {
+ int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt);
if (f >= 0)
formats |= f;
}
}
+
return formats;
}
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
{
int formats, idx;
+ int err;
if (format != AFMT_QUERY) {
formats = snd_pcm_oss_get_formats(pcm_oss_file);
@@ -1832,10 +1890,14 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for
if (substream == NULL)
continue;
runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.format != format) {
runtime->oss.params = 1;
runtime->oss.format = format;
}
+ unlock_params(runtime);
}
}
return snd_pcm_oss_get_format(pcm_oss_file);
@@ -1846,7 +1908,8 @@ static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
- if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
+ err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
+ if (err < 0)
return err;
return substream->runtime->oss.format;
}
@@ -1855,8 +1918,6 @@ static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int s
{
struct snd_pcm_runtime *runtime;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (subdivide == 0) {
subdivide = runtime->oss.subdivision;
@@ -1880,9 +1941,17 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
+
if (substream == NULL)
continue;
- if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
+ runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+ unlock_params(runtime);
+ if (err < 0)
return err;
}
return err;
@@ -1891,13 +1960,15 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int
static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val)
{
struct snd_pcm_runtime *runtime;
+ int fragshift;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (runtime->oss.subdivision || runtime->oss.fragshift)
return -EINVAL;
- runtime->oss.fragshift = val & 0xffff;
+ fragshift = val & 0xffff;
+ if (fragshift >= 25) /* should be large enough */
+ return -EINVAL;
+ runtime->oss.fragshift = fragshift;
runtime->oss.maxfrags = (val >> 16) & 0xffff;
if (runtime->oss.fragshift < 4) /* < 16 */
runtime->oss.fragshift = 4;
@@ -1913,9 +1984,17 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
+
if (substream == NULL)
continue;
- if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
+ runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+ unlock_params(runtime);
+ if (err < 0)
return err;
}
return err;
@@ -1923,9 +2002,8 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig
static int snd_pcm_oss_nonblock(struct file * file)
{
- spin_lock(&file->f_lock);
+ guard(spinlock)(&file->f_lock);
file->f_flags |= O_NONBLOCK;
- spin_unlock(&file->f_lock);
return 0;
}
@@ -1983,22 +2061,27 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
int err, cmd;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
+ pr_debug("pcm_oss: trigger = 0x%x\n", trigger);
#endif
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (psubstream) {
- if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
+ err = snd_pcm_oss_make_ready(psubstream);
+ if (err < 0)
return err;
}
if (csubstream) {
- if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
+ err = snd_pcm_oss_make_ready(csubstream);
+ if (err < 0)
return err;
}
if (psubstream) {
runtime = psubstream->runtime;
+ cmd = 0;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
if (trigger & PCM_ENABLE_OUTPUT) {
if (runtime->oss.trigger)
goto _skip1;
@@ -2016,13 +2099,19 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
- if (err < 0)
- return err;
- }
_skip1:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (cmd) {
+ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
if (csubstream) {
runtime = csubstream->runtime;
+ cmd = 0;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
if (trigger & PCM_ENABLE_INPUT) {
if (runtime->oss.trigger)
goto _skip2;
@@ -2037,11 +2126,14 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
- if (err < 0)
- return err;
- }
_skip2:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (cmd) {
+ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
@@ -2069,7 +2161,8 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
return -EINVAL;
- if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ err = snd_pcm_oss_make_ready(substream);
+ if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare)
@@ -2096,7 +2189,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
substream = pcm_oss_file->streams[stream];
if (substream == NULL)
return -EINVAL;
- if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ err = snd_pcm_oss_make_ready(substream);
+ if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare) {
@@ -2167,9 +2261,11 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
return -EINVAL;
runtime = substream->runtime;
- if (runtime->oss.params &&
- (err = snd_pcm_oss_change_params(substream)) < 0)
- return err;
+ if (runtime->oss.params) {
+ err = snd_pcm_oss_change_params(substream, false);
+ if (err < 0)
+ return err;
+ }
info.fragsize = runtime->oss.period_bytes;
info.fragstotal = runtime->periods;
@@ -2203,9 +2299,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
}
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
- "fragstotal = %i, fragsize = %i\n",
- info.bytes, info.fragments, info.fragstotal, info.fragsize);
+ pcm_dbg(substream->pcm,
+ "pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n",
+ info.bytes, info.fragments, info.fragstotal, info.fragsize);
#endif
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -2215,7 +2311,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
{
// it won't be probably implemented
- // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
+ // pr_debug("TODO: snd_pcm_oss_get_mapbuf\n");
return -EINVAL;
}
@@ -2235,7 +2331,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
{
struct snd_pcm_oss_setup *setup;
- mutex_lock(&pcm->streams[stream].oss.setup_mutex);
+ guard(mutex)(&pcm->streams[stream].oss.setup_mutex);
do {
for (setup = pcm->streams[stream].oss.setup_list; setup;
setup = setup->next) {
@@ -2246,18 +2342,11 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
out:
if (setup)
*rsetup = *setup;
- mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
}
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime;
- runtime = substream->runtime;
- vfree(runtime->oss.buffer);
- runtime->oss.buffer = NULL;
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
- snd_pcm_oss_plugin_clear(substream);
-#endif
+ snd_pcm_oss_release_buffers(substream);
substream->oss.oss = 0;
}
@@ -2293,6 +2382,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
runtime->oss.maxfrags = 0;
runtime->oss.subdivision = 0;
substream->pcm_release = snd_pcm_oss_release_substream;
+ atomic_set(&runtime->oss.rw_ref, 0);
}
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
@@ -2351,7 +2441,6 @@ static int snd_pcm_oss_open_file(struct file *file,
}
pcm_oss_file->streams[idx] = substream;
- substream->file = pcm_oss_file;
snd_pcm_oss_init_substream(substream, &setup[idx], minor);
}
@@ -2387,7 +2476,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
struct snd_pcm_oss_file *pcm_oss_file;
struct snd_pcm_oss_setup setup[2];
int nonblock;
- wait_queue_t wait;
+ wait_queue_entry_t wait;
err = nonseekable_open(inode, file);
if (err < 0)
@@ -2502,7 +2591,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
return put_user(SNDRV_OSS_VERSION, p);
if (cmd == OSS_ALSAEMULVER)
return put_user(1, p);
-#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
+#if IS_REACHABLE(CONFIG_SND_MIXER_OSS)
if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */
struct snd_pcm_substream *substream;
int idx;
@@ -2519,7 +2608,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (((cmd >> 8) & 0xff) != 'P')
return -EINVAL;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
+ pr_debug("pcm_oss: ioctl = 0x%x\n", cmd);
#endif
switch (cmd) {
case SNDCTL_DSP_RESET:
@@ -2529,7 +2618,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDCTL_DSP_SPEED:
if (get_user(res, p))
return -EFAULT;
- if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
+ res = snd_pcm_oss_set_rate(pcm_oss_file, res);
+ if (res < 0)
return res;
return put_user(res, p);
case SOUND_PCM_READ_RATE:
@@ -2541,7 +2631,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (get_user(res, p))
return -EFAULT;
res = res > 0 ? 2 : 1;
- if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
+ res = snd_pcm_oss_set_channels(pcm_oss_file, res);
+ if (res < 0)
return res;
return put_user(--res, p);
case SNDCTL_DSP_GETBLKSIZE:
@@ -2646,14 +2737,22 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDCTL_DSP_PROFILE:
return 0; /* silently ignore */
default:
- snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
+ pr_debug("pcm_oss: unknown command = 0x%x\n", cmd);
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
/* all compatible */
-#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl
+static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ /*
+ * Everything is compatbile except SNDCTL_DSP_MAPINBUF/SNDCTL_DSP_MAPOUTBUF,
+ * which are not implemented for the native case either
+ */
+ return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
#else
#define snd_pcm_oss_ioctl_compat NULL
#endif
@@ -2673,8 +2772,9 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
#else
{
ssize_t res = snd_pcm_oss_read1(substream, buf, count);
- printk(KERN_DEBUG "pcm_oss: read %li bytes "
- "(returned %li bytes)\n", (long)count, (long)res);
+ pcm_dbg(substream->pcm,
+ "pcm_oss: read %li bytes (returned %li bytes)\n",
+ (long)count, (long)res);
return res;
}
#endif
@@ -2693,7 +2793,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
+ pcm_dbg(substream->pcm, "pcm_oss: write %li bytes (wrote %li bytes)\n",
(long)count, (long)result);
#endif
return result;
@@ -2721,10 +2821,10 @@ static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
runtime->oss.period_frames;
}
-static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
+static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
{
struct snd_pcm_oss_file *pcm_oss_file;
- unsigned int mask;
+ __poll_t mask;
struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
pcm_oss_file = file->private_data;
@@ -2736,22 +2836,23 @@ static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
if (psubstream != NULL) {
struct snd_pcm_runtime *runtime = psubstream->runtime;
poll_wait(file, &runtime->sleep, wait);
- snd_pcm_stream_lock_irq(psubstream);
- if (runtime->status->state != SNDRV_PCM_STATE_DRAINING &&
- (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
- snd_pcm_oss_playback_ready(psubstream)))
- mask |= POLLOUT | POLLWRNORM;
- snd_pcm_stream_unlock_irq(psubstream);
+ scoped_guard(pcm_stream_lock_irq, psubstream) {
+ if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
+ (runtime->state != SNDRV_PCM_STATE_RUNNING ||
+ snd_pcm_oss_playback_ready(psubstream)))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+ }
}
if (csubstream != NULL) {
struct snd_pcm_runtime *runtime = csubstream->runtime;
snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait);
- snd_pcm_stream_lock_irq(csubstream);
- if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
- snd_pcm_oss_capture_ready(csubstream))
- mask |= POLLIN | POLLRDNORM;
- snd_pcm_stream_unlock_irq(csubstream);
+ scoped_guard(pcm_stream_lock_irq, csubstream) {
+ ostate = runtime->state;
+ if (ostate != SNDRV_PCM_STATE_RUNNING ||
+ snd_pcm_oss_capture_ready(csubstream))
+ mask |= EPOLLIN | EPOLLRDNORM;
+ }
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
@@ -2772,7 +2873,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
int err;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: mmap begin\n");
+ pr_debug("pcm_oss: mmap begin\n");
#endif
pcm_oss_file = file->private_data;
switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@@ -2780,7 +2881,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;
@@ -2792,7 +2893,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
}
/* set VM_READ access as well to fix memset() routines that do
reads before writes (to improve performance) */
- area->vm_flags |= VM_READ;
+ vm_flags_set(area, VM_READ);
if (substream == NULL)
return -ENXIO;
runtime = substream->runtime;
@@ -2804,7 +2905,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
return -EIO;
if (runtime->oss.params) {
- if ((err = snd_pcm_oss_change_params(substream)) < 0)
+ /* use mutex_trylock() for params_lock for avoiding a deadlock
+ * 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);
+ if (err < 0)
return err;
}
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
@@ -2822,7 +2928,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
runtime->silence_threshold = 0;
runtime->silence_size = 0;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
+ pr_debug("pcm_oss: mmap ok, bytes = 0x%x\n",
runtime->oss.mmap_bytes);
#endif
/* In mmap mode we never stop */
@@ -2841,7 +2947,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
{
struct snd_pcm_str *pstr = entry->private_data;
struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
- mutex_lock(&pstr->oss.setup_mutex);
+ guard(mutex)(&pstr->oss.setup_mutex);
while (setup) {
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
setup->task_name,
@@ -2855,7 +2961,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
setup->nosilence ? " no-silence" : "");
setup = setup->next;
}
- mutex_unlock(&pstr->oss.setup_mutex);
}
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@@ -2881,12 +2986,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
struct snd_pcm_oss_setup *setup, *setup1, template;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
- mutex_lock(&pstr->oss.setup_mutex);
+ guard(mutex)(&pstr->oss.setup_mutex);
memset(&template, 0, sizeof(template));
ptr = snd_info_get_str(task_name, line, sizeof(task_name));
if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
snd_pcm_oss_proc_free_setup_list(pstr);
- mutex_unlock(&pstr->oss.setup_mutex);
continue;
}
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -2926,7 +3030,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
if (! setup) {
buffer->error = -ENOMEM;
- mutex_unlock(&pstr->oss.setup_mutex);
return;
}
if (pstr->oss.setup_list == NULL)
@@ -2940,12 +3043,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
if (! template.task_name) {
kfree(setup);
buffer->error = -ENOMEM;
- mutex_unlock(&pstr->oss.setup_mutex);
return;
}
}
*setup = template;
- mutex_unlock(&pstr->oss.setup_mutex);
}
}
@@ -2957,9 +3058,10 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
struct snd_pcm_str *pstr = &pcm->streams[stream];
if (pstr->substream_count == 0)
continue;
- if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
+ entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root);
+ if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
- entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+ entry->mode = S_IFREG | 0644;
entry->c.text.read = snd_pcm_oss_proc_read;
entry->c.text.write = snd_pcm_oss_proc_write;
entry->private_data = pstr;
@@ -2983,8 +3085,12 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
}
}
#else /* !CONFIG_SND_VERBOSE_PROCFS */
-#define snd_pcm_oss_proc_init(pcm)
-#define snd_pcm_oss_proc_done(pcm)
+static inline void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
+{
+}
+static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
+{
+}
#endif /* CONFIG_SND_VERBOSE_PROCFS */
/*
@@ -2998,7 +3104,6 @@ static const struct file_operations snd_pcm_oss_f_reg =
.write = snd_pcm_oss_write,
.open = snd_pcm_oss_open,
.release = snd_pcm_oss_release,
- .llseek = no_llseek,
.poll = snd_pcm_oss_poll,
.unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat,
@@ -3007,12 +3112,10 @@ static const struct file_operations snd_pcm_oss_f_reg =
static void register_oss_dsp(struct snd_pcm *pcm, int index)
{
- char name[128];
- sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, index, &snd_pcm_oss_f_reg,
- pcm, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n",
+ pcm) < 0) {
+ pcm_err(pcm, "unable to register OSS PCM device %i:%i\n",
pcm->card->number, pcm->device);
}
}
@@ -3093,17 +3196,18 @@ static int __init alsa_pcm_oss_init(void)
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
- snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n",
+ pr_err("ALSA: pcm_oss: invalid dsp_map[%d] = %d\n",
i, dsp_map[i]);
dsp_map[i] = 0;
}
if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
- snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n",
+ pr_err("ALSA: pcm_oss: invalid adsp_map[%d] = %d\n",
i, adsp_map[i]);
adsp_map[i] = 1;
}
}
- if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
+ err = snd_pcm_notify(&snd_pcm_oss_notify, 0);
+ if (err < 0)
return err;
return 0;
}
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 727ac44d39f4..82e180c776ae 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -59,15 +59,19 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
} else {
format = &plugin->dst_format;
}
- if ((width = snd_pcm_format_physical_width(format->format)) < 0)
+ width = snd_pcm_format_physical_width(format->format);
+ if (width < 0)
return width;
- size = frames * format->channels * width;
+ size = array3_size(frames, format->channels, width);
+ /* check for too large period size once again */
+ if (size > 1024 * 1024)
+ return -ENOMEM;
if (snd_BUG_ON(size % 8))
return -ENXIO;
size /= 8;
if (plugin->buf_frames < frames) {
- vfree(plugin->buf);
- plugin->buf = vmalloc(size);
+ kvfree(plugin->buf);
+ plugin->buf = kvzalloc(size, GFP_KERNEL);
plugin->buf_frames = frames;
}
if (!plugin->buf) {
@@ -111,7 +115,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
while (plugin->next) {
if (plugin->dst_frames)
frames = plugin->dst_frames(plugin, frames);
- if (snd_BUG_ON(frames <= 0))
+ if ((snd_pcm_sframes_t)frames <= 0)
return -ENXIO;
plugin = plugin->next;
err = snd_pcm_plugin_alloc(plugin, frames);
@@ -123,7 +127,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
while (plugin->prev) {
if (plugin->src_frames)
frames = plugin->src_frames(plugin, frames);
- if (snd_BUG_ON(frames <= 0))
+ if ((snd_pcm_sframes_t)frames <= 0)
return -ENXIO;
plugin = plugin->prev;
err = snd_pcm_plugin_alloc(plugin, frames);
@@ -191,82 +195,87 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
if (plugin->private_free)
plugin->private_free(plugin);
kfree(plugin->buf_channels);
- vfree(plugin->buf);
+ kvfree(plugin->buf);
kfree(plugin);
return 0;
}
-snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
+static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
+ snd_pcm_sframes_t frames,
+ bool check_size)
{
- struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
- int stream;
+ struct snd_pcm_plugin *plugin, *plugin_next;
- if (snd_BUG_ON(!plug))
- return -ENXIO;
- if (drv_frames == 0)
- return 0;
- stream = snd_pcm_plug_stream(plug);
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_last(plug);
- while (plugin && drv_frames > 0) {
- plugin_prev = plugin->prev;
- if (plugin->src_frames)
- drv_frames = plugin->src_frames(plugin, drv_frames);
- plugin = plugin_prev;
+ plugin = snd_pcm_plug_first(plug);
+ while (plugin && frames > 0) {
+ plugin_next = plugin->next;
+ if (check_size && plugin->buf_frames &&
+ frames > plugin->buf_frames)
+ frames = plugin->buf_frames;
+ if (plugin->dst_frames) {
+ frames = plugin->dst_frames(plugin, frames);
+ if (frames < 0)
+ return frames;
}
- } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
- plugin = snd_pcm_plug_first(plug);
- while (plugin && drv_frames > 0) {
- plugin_next = plugin->next;
- if (plugin->dst_frames)
- drv_frames = plugin->dst_frames(plugin, drv_frames);
- plugin = plugin_next;
+ plugin = plugin_next;
+ }
+ return frames;
+}
+
+static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
+ snd_pcm_sframes_t frames,
+ bool check_size)
+{
+ struct snd_pcm_plugin *plugin, *plugin_prev;
+
+ plugin = snd_pcm_plug_last(plug);
+ while (plugin && frames > 0) {
+ plugin_prev = plugin->prev;
+ if (plugin->src_frames) {
+ frames = plugin->src_frames(plugin, frames);
+ if (frames < 0)
+ return frames;
}
- } else
+ if (check_size && plugin->buf_frames &&
+ frames > plugin->buf_frames)
+ frames = plugin->buf_frames;
+ plugin = plugin_prev;
+ }
+ return frames;
+}
+
+snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
+{
+ if (snd_BUG_ON(!plug))
+ return -ENXIO;
+ switch (snd_pcm_plug_stream(plug)) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ return calc_src_frames(plug, drv_frames, false);
+ case SNDRV_PCM_STREAM_CAPTURE:
+ return calc_dst_frames(plug, drv_frames, false);
+ default:
snd_BUG();
- return drv_frames;
+ return -EINVAL;
+ }
}
snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
{
- struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
- snd_pcm_sframes_t frames;
- int stream;
-
if (snd_BUG_ON(!plug))
return -ENXIO;
- if (clt_frames == 0)
- return 0;
- frames = clt_frames;
- stream = snd_pcm_plug_stream(plug);
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
- plugin_next = plugin->next;
- if (plugin->dst_frames) {
- frames = plugin->dst_frames(plugin, frames);
- if (frames < 0)
- return frames;
- }
- plugin = plugin_next;
- }
- } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
- plugin = snd_pcm_plug_last(plug);
- while (plugin) {
- plugin_prev = plugin->prev;
- if (plugin->src_frames) {
- frames = plugin->src_frames(plugin, frames);
- if (frames < 0)
- return frames;
- }
- plugin = plugin_prev;
- }
- } else
+ switch (snd_pcm_plug_stream(plug)) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ return calc_dst_frames(plug, clt_frames, false);
+ case SNDRV_PCM_STREAM_CAPTURE:
+ return calc_src_frames(plug, clt_frames, false);
+ default:
snd_BUG();
- return frames;
+ return -EINVAL;
+ }
}
-static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format)
+static int snd_pcm_plug_formats(const struct snd_mask *mask,
+ snd_pcm_format_t format)
{
struct snd_mask formats = *mask;
u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
@@ -280,14 +289,14 @@ static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format)
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
- if (formats.bits[0] & (u32)linfmts)
- formats.bits[0] |= (u32)linfmts;
- if (formats.bits[1] & (u32)(linfmts >> 32))
- formats.bits[1] |= (u32)(linfmts >> 32);
+ if (formats.bits[0] & lower_32_bits(linfmts))
+ formats.bits[0] |= lower_32_bits(linfmts);
+ if (formats.bits[1] & upper_32_bits(linfmts))
+ formats.bits[1] |= upper_32_bits(linfmts);
return snd_mask_test(&formats, (__force int)format);
}
-static snd_pcm_format_t preferred_formats[] = {
+static const snd_pcm_format_t preferred_formats[] = {
SNDRV_PCM_FORMAT_S16_LE,
SNDRV_PCM_FORMAT_S16_BE,
SNDRV_PCM_FORMAT_U16_LE,
@@ -309,7 +318,7 @@ static snd_pcm_format_t preferred_formats[] = {
};
snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
- struct snd_mask *format_mask)
+ const struct snd_mask *format_mask)
{
int i;
@@ -352,6 +361,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;
}
+ fallthrough;
default:
return (__force snd_pcm_format_t)-EINVAL;
}
@@ -566,7 +576,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
}
v = plugin->buf_channels;
*channels = v;
- if ((width = snd_pcm_format_physical_width(format->format)) < 0)
+ width = snd_pcm_format_physical_width(format->format);
+ if (width < 0)
return width;
nchannels = format->channels;
if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@@ -591,28 +602,38 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
snd_pcm_sframes_t frames = size;
plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
- if ((next = plugin->next) != NULL) {
+ while (plugin) {
+ if (frames <= 0)
+ return frames;
+ next = plugin->next;
+ if (next) {
snd_pcm_sframes_t frames1 = frames;
- if (plugin->dst_frames)
+ if (plugin->dst_frames) {
frames1 = plugin->dst_frames(plugin, frames);
- if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
- return err;
+ if (frames1 <= 0)
+ return frames1;
}
+ err = next->client_channels(next, frames1, &dst_channels);
+ if (err < 0)
+ return err;
if (err != frames1) {
frames = err;
- if (plugin->src_frames)
+ if (plugin->src_frames) {
frames = plugin->src_frames(plugin, frames1);
+ if (frames <= 0)
+ return frames;
+ }
}
} else
dst_channels = NULL;
pdprintf("write plugin: %s, %li\n", plugin->name, frames);
- if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
+ frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
+ if (frames < 0)
return frames;
src_channels = dst_channels;
plugin = next;
}
- return snd_pcm_plug_client_size(plug, frames);
+ return calc_src_frames(plug, frames, true);
}
snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size)
@@ -622,23 +643,25 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
snd_pcm_sframes_t frames = size;
int err;
- frames = snd_pcm_plug_slave_size(plug, frames);
+ frames = calc_src_frames(plug, frames, true);
if (frames < 0)
return frames;
src_channels = NULL;
plugin = snd_pcm_plug_first(plug);
while (plugin && frames > 0) {
- if ((next = plugin->next) != NULL) {
- if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
+ next = plugin->next;
+ if (next) {
+ err = plugin->client_channels(plugin, frames, &dst_channels);
+ if (err < 0)
return err;
- }
frames = err;
} else {
dst_channels = dst_channels_final;
}
pdprintf("read plugin: %s, %li\n", plugin->name, frames);
- if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
+ frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
+ if (frames < 0)
return frames;
plugin = next;
src_channels = dst_channels;
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index a5035c2369a6..7b76cf64157e 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -1,25 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __PCM_PLUGIN_H
#define __PCM_PLUGIN_H
/*
* Digital Audio (Plugin interface) abstract layer
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
@@ -79,7 +64,7 @@ struct snd_pcm_plugin {
char *buf;
snd_pcm_uframes_t buf_frames;
struct snd_pcm_plugin_channel *buf_channels;
- char extra_data[0];
+ char extra_data[];
};
int snd_pcm_plugin_build(struct snd_pcm_substream *handle,
@@ -89,7 +74,6 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *handle,
size_t extra,
struct snd_pcm_plugin **ret);
int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin);
-int snd_pcm_plugin_clear(struct snd_pcm_plugin **first);
int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames);
snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size);
snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size);
@@ -126,7 +110,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *slave_params);
snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
- struct snd_mask *format_mask);
+ const struct snd_mask *format_mask);
int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin);
@@ -154,30 +138,26 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
size_t dst_offset,
size_t samples, snd_pcm_format_t format);
-void *snd_pcm_plug_buf_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t size);
-void snd_pcm_plug_buf_unlock(struct snd_pcm_substream *plug, void *ptr);
+#else
+
+static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
+static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
+static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; }
+
+#endif
+
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream,
const char *ptr, snd_pcm_uframes_t size,
int in_kernel);
snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream,
char *ptr, snd_pcm_uframes_t size, int in_kernel);
snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream,
- void **bufs, snd_pcm_uframes_t frames,
- int in_kernel);
+ void **bufs, snd_pcm_uframes_t frames);
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream,
- void **bufs, snd_pcm_uframes_t frames,
- int in_kernel);
-
-#else
-
-static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
-static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
-static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; }
-
-#endif
+ void **bufs, snd_pcm_uframes_t frames);
#ifdef PLUGIN_DEBUG
-#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
+#define pdprintf(fmt, args...) pr_debug("plugin: " fmt, ##args)
#else
#define pdprintf(fmt, args...)
#endif
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 2fa9299a440d..b56eeda5e30e 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -47,7 +47,7 @@ struct rate_priv {
unsigned int pos;
rate_f func;
snd_pcm_sframes_t old_src_frames, old_dst_frames;
- struct rate_channel channels[0];
+ struct rate_channel channels[];
};
static void rate_init(struct snd_pcm_plugin *plugin)
@@ -193,7 +193,7 @@ static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_
if (plugin->src_format.rate < plugin->dst_format.rate) {
res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
} else {
- res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
+ res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
}
if (data->old_src_frames > 0) {
snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames;
@@ -224,7 +224,7 @@ static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_
return 0;
data = (struct rate_priv *)plugin->extra_data;
if (plugin->src_format.rate < plugin->dst_format.rate) {
- res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
+ res = DIV_ROUND_CLOSEST(frames << SHIFT, data->pitch);
} else {
res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
}
@@ -294,7 +294,7 @@ static int rate_action(struct snd_pcm_plugin *plugin,
default:
break;
}
- return 0; /* silenty ignore other actions */
+ return 0; /* silently ignore other actions */
}
int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
@@ -323,8 +323,8 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
err = snd_pcm_plugin_build(plug, "rate conversion",
src_format, dst_format,
- sizeof(struct rate_priv) +
- src_format->channels * sizeof(struct rate_channel),
+ struct_size(data, channels,
+ src_format->channels),
&plugin);
if (err < 0)
return err;
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index c8171f5783c8..72dea04197ef 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -57,6 +57,8 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
return -ENXIO;
if (frames == 0)
return 0;
+ if (frames > dst_channels[0].frames)
+ frames = dst_channels[0].frames;
nsrcs = plugin->src_format.channels;
ndsts = plugin->dst_format.channels;