aboutsummaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/Kconfig134
-rw-r--r--sound/core/Makefile32
-rw-r--r--sound/core/compress_offload.c998
-rw-r--r--sound/core/control.c1146
-rw-r--r--sound/core/control_compat.c140
-rw-r--r--sound/core/ctljack.c56
-rw-r--r--sound/core/device.c235
-rw-r--r--sound/core/hrtimer.c166
-rw-r--r--sound/core/hwdep.c378
-rw-r--r--sound/core/hwdep_compat.c15
-rw-r--r--sound/core/info.c661
-rw-r--r--sound/core/info_oss.c54
-rw-r--r--sound/core/init.c1092
-rw-r--r--sound/core/isadma.c24
-rw-r--r--sound/core/jack.c260
-rw-r--r--sound/core/memalloc.c562
-rw-r--r--sound/core/memory.c225
-rw-r--r--sound/core/misc.c147
-rw-r--r--sound/core/oss/Makefile7
-rw-r--r--sound/core/oss/copy.c47
-rw-r--r--sound/core/oss/io.c55
-rw-r--r--sound/core/oss/linear.c150
-rw-r--r--sound/core/oss/mixer_oss.c583
-rw-r--r--sound/core/oss/mulaw.c160
-rw-r--r--sound/core/oss/pcm_oss.c1620
-rw-r--r--sound/core/oss/pcm_plugin.c482
-rw-r--r--sound/core/oss/pcm_plugin.h309
-rw-r--r--sound/core/oss/plugin_ops.h536
-rw-r--r--sound/core/oss/rate.c206
-rw-r--r--sound/core/oss/route.c510
-rw-r--r--sound/core/pcm.c1012
-rw-r--r--sound/core/pcm_compat.c154
-rw-r--r--sound/core/pcm_dmaengine.c369
-rw-r--r--sound/core/pcm_lib.c2407
-rw-r--r--sound/core/pcm_memory.c246
-rw-r--r--sound/core/pcm_misc.c228
-rw-r--r--sound/core/pcm_native.c1929
-rw-r--r--sound/core/pcm_timer.c66
-rw-r--r--sound/core/rawmidi.c1094
-rw-r--r--sound/core/rawmidi_compat.c22
-rw-r--r--sound/core/rtctimer.c79
-rw-r--r--sound/core/seq/Kconfig16
-rw-r--r--sound/core/seq/Makefile31
-rw-r--r--sound/core/seq/instr/Makefile23
-rw-r--r--sound/core/seq/instr/ainstr_fm.c156
-rw-r--r--sound/core/seq/instr/ainstr_gf1.c360
-rw-r--r--sound/core/seq/instr/ainstr_iw.c624
-rw-r--r--sound/core/seq/instr/ainstr_simple.c216
-rw-r--r--sound/core/seq/oss/Makefile2
-rw-r--r--sound/core/seq/oss/seq_oss.c111
-rw-r--r--sound/core/seq/oss/seq_oss_device.h74
-rw-r--r--sound/core/seq/oss/seq_oss_event.c70
-rw-r--r--sound/core/seq/oss/seq_oss_event.h50
-rw-r--r--sound/core/seq/oss/seq_oss_init.c162
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c30
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c123
-rw-r--r--sound/core/seq/oss/seq_oss_midi.h27
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c39
-rw-r--r--sound/core/seq/oss/seq_oss_readq.h24
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c18
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c124
-rw-r--r--sound/core/seq/oss/seq_oss_synth.h32
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c42
-rw-r--r--sound/core/seq/oss/seq_oss_timer.h22
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c41
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.h18
-rw-r--r--sound/core/seq/seq.c40
-rw-r--r--sound/core/seq/seq_clientmgr.c689
-rw-r--r--sound/core/seq/seq_clientmgr.h45
-rw-r--r--sound/core/seq/seq_compat.c35
-rw-r--r--sound/core/seq/seq_device.c238
-rw-r--r--sound/core/seq/seq_dummy.c57
-rw-r--r--sound/core/seq/seq_fifo.c60
-rw-r--r--sound/core/seq/seq_fifo.h26
-rw-r--r--sound/core/seq/seq_info.c35
-rw-r--r--sound/core/seq/seq_info.h12
-rw-r--r--sound/core/seq/seq_instr.c653
-rw-r--r--sound/core/seq/seq_lock.c11
-rw-r--r--sound/core/seq/seq_memory.c113
-rw-r--r--sound/core/seq/seq_memory.h41
-rw-r--r--sound/core/seq/seq_midi.c200
-rw-r--r--sound/core/seq/seq_midi_emul.c107
-rw-r--r--sound/core/seq/seq_midi_event.c209
-rw-r--r--sound/core/seq/seq_ports.c229
-rw-r--r--sound/core/seq/seq_ports.h64
-rw-r--r--sound/core/seq/seq_prioq.c72
-rw-r--r--sound/core/seq/seq_prioq.h26
-rw-r--r--sound/core/seq/seq_queue.c123
-rw-r--r--sound/core/seq/seq_queue.h24
-rw-r--r--sound/core/seq/seq_system.c37
-rw-r--r--sound/core/seq/seq_system.h2
-rw-r--r--sound/core/seq/seq_timer.c165
-rw-r--r--sound/core/seq/seq_timer.h61
-rw-r--r--sound/core/seq/seq_virmidi.c142
-rw-r--r--sound/core/sgbuf.c104
-rw-r--r--sound/core/sound.c557
-rw-r--r--sound/core/sound_oss.c195
-rw-r--r--sound/core/timer.c980
-rw-r--r--sound/core/timer_compat.c31
-rw-r--r--sound/core/vmaster.c486
-rw-r--r--sound/core/wrappers.c50
101 files changed, 13750 insertions, 13200 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 48cf45cfd0b..313f22e9d92 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -1,24 +1,31 @@
# ALSA soundcard-configuration
config SND_TIMER
tristate
- depends on SND
config SND_PCM
tristate
select SND_TIMER
- depends on SND
+
+config SND_DMAENGINE_PCM
+ tristate
config SND_HWDEP
tristate
- depends on SND
config SND_RAWMIDI
tristate
- depends on SND
+
+config SND_COMPRESS_OFFLOAD
+ tristate
+
+# To be effective this also requires INPUT - users should say:
+# select SND_JACK if INPUT=y || INPUT=SND
+# to avoid having to force INPUT on.
+config SND_JACK
+ bool
config SND_SEQUENCER
tristate "Sequencer support"
- depends on SND
select SND_TIMER
help
Say Y or M to enable MIDI sequencer and router support. This
@@ -43,12 +50,11 @@ config SND_SEQ_DUMMY
will be called snd-seq-dummy.
config SND_OSSEMUL
+ select SOUND_OSS_CORE
bool
- depends on SND
config SND_MIXER_OSS
tristate "OSS Mixer API"
- depends on SND
select SND_OSSEMUL
help
To enable OSS mixer API emulation (/dev/mixer*), say Y here
@@ -61,7 +67,6 @@ config SND_MIXER_OSS
config SND_PCM_OSS
tristate "OSS PCM (digital audio) API"
- depends on SND
select SND_OSSEMUL
select SND_PCM
help
@@ -73,9 +78,18 @@ config SND_PCM_OSS
To compile this driver as a module, choose M here: the module
will be called snd-pcm-oss.
+config SND_PCM_OSS_PLUGINS
+ bool "OSS PCM (digital audio) API - Include plugin system"
+ depends on SND_PCM_OSS
+ default y
+ help
+ If you disable this option, the ALSA's OSS PCM API will not
+ support conversion of channels, formats and rates. It will
+ behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
+
config SND_SEQUENCER_OSS
bool "OSS Sequencer API"
- depends on SND && SND_SEQUENCER
+ depends on SND_SEQUENCER
select SND_OSSEMUL
help
Say Y here to enable OSS sequencer emulation (both
@@ -83,12 +97,33 @@ config SND_SEQUENCER_OSS
Many programs still use the OSS API, so say Y.
+ If you choose M in "Sequencer support" (SND_SEQUENCER),
+ this will be compiled as a module. The module will be called
+ snd-seq-oss.
+
+config SND_HRTIMER
+ tristate "HR-timer backend support"
+ depends on HIGH_RES_TIMERS
+ select SND_TIMER
+ help
+ Say Y here to enable HR-timer backend for ALSA timer. ALSA uses
+ the hrtimer as a precise timing source. The ALSA sequencer code
+ also can use this timing source.
+
To compile this driver as a module, choose M here: the module
- will be called snd-seq-oss.
+ will be called snd-hrtimer.
+
+config SND_SEQ_HRTIMER_DEFAULT
+ bool "Use HR-timer as default sequencer timer"
+ depends on SND_HRTIMER && SND_SEQUENCER
+ default y
+ help
+ Say Y here to use the HR-timer backend as the default sequencer
+ timer.
config SND_RTCTIMER
tristate "RTC Timer support"
- depends on SND && RTC
+ depends on RTC
select SND_TIMER
help
Say Y here to enable RTC timer support for ALSA. ALSA uses
@@ -99,9 +134,13 @@ config SND_RTCTIMER
To compile this driver as a module, choose M here: the module
will be called snd-rtctimer.
+ Note that this option is exclusive with the new RTC drivers
+ (CONFIG_RTC_CLASS) since this requires the old API.
+
config SND_SEQ_RTCTIMER_DEFAULT
bool "Use RTC as default sequencer timer"
depends on SND_RTCTIMER && SND_SEQUENCER
+ depends on !SND_SEQ_HRTIMER_DEFAULT
default y
help
Say Y here to use the RTC timer as the default sequencer
@@ -111,9 +150,43 @@ config SND_SEQ_RTCTIMER_DEFAULT
If in doubt, say Y.
+config SND_DYNAMIC_MINORS
+ bool "Dynamic device file minor numbers"
+ help
+ If you say Y here, the minor numbers of ALSA device files in
+ /dev/snd/ are allocated dynamically. This allows you to have
+ more than 8 sound cards, but requires a dynamic device file
+ system like udev.
+
+ If you are unsure about this, say N here.
+
+config SND_MAX_CARDS
+ int "Max number of sound cards"
+ range 4 256
+ default 32
+ depends on SND_DYNAMIC_MINORS
+ help
+ Specify the max number of sound cards that can be assigned
+ on a single machine.
+
+config SND_SUPPORT_OLD_API
+ bool "Support old ALSA API"
+ default y
+ help
+ Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
+ or older).
+
+config SND_VERBOSE_PROCFS
+ bool "Verbose procfs contents"
+ depends on PROC_FS
+ default y
+ help
+ Say Y here to include code for verbose procfs contents (provides
+ useful information to developers when a problem occurs). On the
+ other side, it makes the ALSA subsystem larger.
+
config SND_VERBOSE_PRINTK
bool "Verbose printk"
- depends on SND
help
Say Y here to enable verbose log messages. These messages
will help to identify source file and position containing
@@ -123,23 +196,36 @@ config SND_VERBOSE_PRINTK
config SND_DEBUG
bool "Debug"
- depends on SND
help
Say Y here to enable ALSA debug code.
-config SND_DEBUG_MEMORY
- bool "Debug memory"
+config SND_DEBUG_VERBOSE
+ bool "More verbose debug"
depends on SND_DEBUG
help
- Say Y here to enable debugging of memory allocations.
-
-config SND_DEBUG_DETECT
- bool "Debug detection"
- depends on SND_DEBUG
+ Say Y here to enable extra-verbose debugging messages.
+
+ Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages.
+ So, say Y only if you are ready to be annoyed.
+
+config SND_PCM_XRUN_DEBUG
+ bool "Enable PCM ring buffer overrun/underrun debugging"
+ default n
+ depends on SND_DEBUG && SND_VERBOSE_PROCFS
help
- Say Y here to enable extra-verbose log messages printed when
- detecting devices.
+ Say Y to enable the PCM ring buffer overrun/underrun debugging.
+ It is usually not required, but if you have trouble with
+ sound clicking when system is loaded, it may help to determine
+ the process or driver which causes the scheduling gaps.
-config SND_GENERIC_DRIVER
+config SND_VMASTER
bool
- depends on SND
+
+config SND_KCTL_JACK
+ bool
+
+config SND_DMA_SGBUF
+ def_bool y
+ depends on X86
+
+source "sound/core/seq/Kconfig"
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 969d75528bd..394a38909f6 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -1,33 +1,39 @@
#
# Makefile for ALSA
-# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-objs := sound.o init.o memory.o info.o control.o misc.o \
- device.o wrappers.o
-ifeq ($(CONFIG_ISA_DMA_API),y)
-snd-objs += isadma.o
-endif
-ifeq ($(CONFIG_SND_OSSEMUL),y)
-snd-objs += sound_oss.o info_oss.o
-endif
+snd-y := sound.o init.o memory.o info.o control.o misc.o device.o
+snd-$(CONFIG_ISA_DMA_API) += isadma.o
+snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
+snd-$(CONFIG_SND_VMASTER) += vmaster.o
+snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o
+snd-$(CONFIG_SND_JACK) += jack.o
-snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
- pcm_memory.o
+snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
+ pcm_memory.o memalloc.o
+snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
-snd-page-alloc-objs := memalloc.o sgbuf.o
+snd-pcm-dmaengine-objs := pcm_dmaengine.o
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
+snd-hrtimer-objs := hrtimer.o
snd-rtctimer-objs := rtctimer.o
snd-hwdep-objs := hwdep.o
+snd-compress-objs := compress_offload.o
+
obj-$(CONFIG_SND) += snd.o
obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_TIMER) += snd-timer.o
+obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
-obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_PCM) += snd-pcm.o
+obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
obj-$(CONFIG_SND_OSSEMUL) += oss/
obj-$(CONFIG_SND_SEQUENCER) += seq/
+
+obj-$(CONFIG_SND_COMPRESS_OFFLOAD) += snd-compress.o
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
new file mode 100644
index 00000000000..7403f348ed1
--- /dev/null
+++ b/sound/core/compress_offload.c
@@ -0,0 +1,998 @@
+/*
+ * compress_core.c - compress offload core
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@linux.intel.com>
+ * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/math64.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+/* TODO:
+ * - add substream support for multiple devices in case of
+ * SND_DYNAMIC_MINORS is not used
+ * - Multiple node representation
+ * driver should be able to register multiple nodes
+ */
+
+static DEFINE_MUTEX(device_mutex);
+
+struct snd_compr_file {
+ unsigned long caps;
+ struct snd_compr_stream stream;
+};
+
+/*
+ * a note on stream states used:
+ * we use follwing states in the compressed core
+ * SNDRV_PCM_STATE_OPEN: When stream has been opened.
+ * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
+ * calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
+ * state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
+ * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
+ * decoding/encoding and rendering/capturing data.
+ * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
+ * by calling SNDRV_COMPRESS_DRAIN.
+ * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
+ * SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
+ * SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
+ */
+static int snd_compr_open(struct inode *inode, struct file *f)
+{
+ struct snd_compr *compr;
+ struct snd_compr_file *data;
+ struct snd_compr_runtime *runtime;
+ enum snd_compr_direction dirn;
+ int maj = imajor(inode);
+ int ret;
+
+ if ((f->f_flags & O_ACCMODE) == O_WRONLY)
+ dirn = SND_COMPRESS_PLAYBACK;
+ else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
+ dirn = SND_COMPRESS_CAPTURE;
+ else
+ return -EINVAL;
+
+ if (maj == snd_major)
+ compr = snd_lookup_minor_data(iminor(inode),
+ SNDRV_DEVICE_TYPE_COMPRESS);
+ else
+ return -EBADFD;
+
+ if (compr == NULL) {
+ pr_err("no device data!!!\n");
+ return -ENODEV;
+ }
+
+ if (dirn != compr->direction) {
+ pr_err("this device doesn't support this direction\n");
+ snd_card_unref(compr->card);
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ snd_card_unref(compr->card);
+ return -ENOMEM;
+ }
+ data->stream.ops = compr->ops;
+ data->stream.direction = dirn;
+ data->stream.private_data = compr->private_data;
+ data->stream.device = compr;
+ runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+ if (!runtime) {
+ kfree(data);
+ snd_card_unref(compr->card);
+ return -ENOMEM;
+ }
+ runtime->state = SNDRV_PCM_STATE_OPEN;
+ init_waitqueue_head(&runtime->sleep);
+ data->stream.runtime = runtime;
+ f->private_data = (void *)data;
+ mutex_lock(&compr->lock);
+ ret = compr->ops->open(&data->stream);
+ mutex_unlock(&compr->lock);
+ if (ret) {
+ kfree(runtime);
+ kfree(data);
+ }
+ snd_card_unref(compr->card);
+ return ret;
+}
+
+static int snd_compr_free(struct inode *inode, struct file *f)
+{
+ struct snd_compr_file *data = f->private_data;
+ struct snd_compr_runtime *runtime = data->stream.runtime;
+
+ switch (runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_PAUSED:
+ data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
+ break;
+ default:
+ break;
+ }
+
+ data->stream.ops->free(&data->stream);
+ kfree(data->stream.runtime->buffer);
+ kfree(data->stream.runtime);
+ kfree(data);
+ return 0;
+}
+
+static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ if (!stream->ops->pointer)
+ return -ENOTSUPP;
+ stream->ops->pointer(stream, tstamp);
+ pr_debug("dsp consumed till %d total %d bytes\n",
+ tstamp->byte_offset, tstamp->copied_total);
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ stream->runtime->total_bytes_transferred = tstamp->copied_total;
+ else
+ stream->runtime->total_bytes_available = tstamp->copied_total;
+ return 0;
+}
+
+static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
+ struct snd_compr_avail *avail)
+{
+ memset(avail, 0, sizeof(*avail));
+ snd_compr_update_tstamp(stream, &avail->tstamp);
+ /* Still need to return avail even if tstamp can't be filled in */
+
+ if (stream->runtime->total_bytes_available == 0 &&
+ stream->runtime->state == SNDRV_PCM_STATE_SETUP &&
+ stream->direction == SND_COMPRESS_PLAYBACK) {
+ pr_debug("detected init and someone forgot to do a write\n");
+ return stream->runtime->buffer_size;
+ }
+ pr_debug("app wrote %lld, DSP consumed %lld\n",
+ stream->runtime->total_bytes_available,
+ stream->runtime->total_bytes_transferred);
+ if (stream->runtime->total_bytes_available ==
+ stream->runtime->total_bytes_transferred) {
+ if (stream->direction == SND_COMPRESS_PLAYBACK) {
+ pr_debug("both pointers are same, returning full avail\n");
+ return stream->runtime->buffer_size;
+ } else {
+ pr_debug("both pointers are same, returning no avail\n");
+ return 0;
+ }
+ }
+
+ avail->avail = stream->runtime->total_bytes_available -
+ stream->runtime->total_bytes_transferred;
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ avail->avail = stream->runtime->buffer_size - avail->avail;
+
+ pr_debug("ret avail as %lld\n", avail->avail);
+ return avail->avail;
+}
+
+static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
+{
+ struct snd_compr_avail avail;
+
+ return snd_compr_calc_avail(stream, &avail);
+}
+
+static int
+snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_avail ioctl_avail;
+ size_t avail;
+
+ avail = snd_compr_calc_avail(stream, &ioctl_avail);
+ ioctl_avail.avail = avail;
+
+ if (copy_to_user((__u64 __user *)arg,
+ &ioctl_avail, sizeof(ioctl_avail)))
+ return -EFAULT;
+ return 0;
+}
+
+static int snd_compr_write_data(struct snd_compr_stream *stream,
+ const char __user *buf, size_t count)
+{
+ void *dstn;
+ size_t copy;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ /* 64-bit Modulus */
+ u64 app_pointer = div64_u64(runtime->total_bytes_available,
+ runtime->buffer_size);
+ app_pointer = runtime->total_bytes_available -
+ (app_pointer * runtime->buffer_size);
+
+ dstn = runtime->buffer + app_pointer;
+ pr_debug("copying %ld at %lld\n",
+ (unsigned long)count, app_pointer);
+ if (count < runtime->buffer_size - app_pointer) {
+ if (copy_from_user(dstn, buf, count))
+ return -EFAULT;
+ } else {
+ copy = runtime->buffer_size - app_pointer;
+ if (copy_from_user(dstn, buf, copy))
+ return -EFAULT;
+ if (copy_from_user(runtime->buffer, buf + copy, count - copy))
+ return -EFAULT;
+ }
+ /* if DSP cares, let it know data has been written */
+ if (stream->ops->ack)
+ stream->ops->ack(stream, count);
+ return count;
+}
+
+static ssize_t snd_compr_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct snd_compr_file *data = f->private_data;
+ struct snd_compr_stream *stream;
+ size_t avail;
+ int retval;
+
+ if (snd_BUG_ON(!data))
+ return -EFAULT;
+
+ stream = &data->stream;
+ mutex_lock(&stream->device->lock);
+ /* write is allowed when stream is running or has been steup */
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
+ stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
+ mutex_unlock(&stream->device->lock);
+ return -EBADFD;
+ }
+
+ avail = snd_compr_get_avail(stream);
+ pr_debug("avail returned %ld\n", (unsigned long)avail);
+ /* calculate how much we can write to buffer */
+ if (avail > count)
+ avail = count;
+
+ if (stream->ops->copy) {
+ char __user* cbuf = (char __user*)buf;
+ retval = stream->ops->copy(stream, cbuf, avail);
+ } else {
+ retval = snd_compr_write_data(stream, buf, avail);
+ }
+ if (retval > 0)
+ stream->runtime->total_bytes_available += retval;
+
+ /* while initiating the stream, write should be called before START
+ * call, so in setup move state */
+ if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
+ stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+ pr_debug("stream prepared, Houston we are good to go\n");
+ }
+
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+
+static ssize_t snd_compr_read(struct file *f, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct snd_compr_file *data = f->private_data;
+ struct snd_compr_stream *stream;
+ size_t avail;
+ int retval;
+
+ if (snd_BUG_ON(!data))
+ return -EFAULT;
+
+ stream = &data->stream;
+ mutex_lock(&stream->device->lock);
+
+ /* read is allowed when stream is running, paused, draining and setup
+ * (yes setup is state which we transition to after stop, so if user
+ * wants to read data after stop we allow that)
+ */
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_XRUN:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ case SNDRV_PCM_STATE_DISCONNECTED:
+ retval = -EBADFD;
+ goto out;
+ }
+
+ avail = snd_compr_get_avail(stream);
+ pr_debug("avail returned %ld\n", (unsigned long)avail);
+ /* calculate how much we can read from buffer */
+ if (avail > count)
+ avail = count;
+
+ if (stream->ops->copy) {
+ retval = stream->ops->copy(stream, buf, avail);
+ } else {
+ retval = -ENXIO;
+ goto out;
+ }
+ if (retval > 0)
+ stream->runtime->total_bytes_transferred += retval;
+
+out:
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
+{
+ return -ENXIO;
+}
+
+static inline int snd_compr_get_poll(struct snd_compr_stream *stream)
+{
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ return POLLOUT | POLLWRNORM;
+ else
+ return POLLIN | POLLRDNORM;
+}
+
+static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
+{
+ struct snd_compr_file *data = f->private_data;
+ struct snd_compr_stream *stream;
+ size_t avail;
+ int retval = 0;
+
+ if (snd_BUG_ON(!data))
+ return -EFAULT;
+ stream = &data->stream;
+ if (snd_BUG_ON(!stream))
+ return -EFAULT;
+
+ mutex_lock(&stream->device->lock);
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ retval = -EBADFD;
+ goto out;
+ }
+ poll_wait(f, &stream->runtime->sleep, wait);
+
+ avail = snd_compr_get_avail(stream);
+ pr_debug("avail is %ld\n", (unsigned long)avail);
+ /* check if we have at least one fragment to fill */
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_DRAINING:
+ /* stream has been woken up after drain is complete
+ * draining done so set stream state to stopped
+ */
+ retval = snd_compr_get_poll(stream);
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ break;
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_PAUSED:
+ if (avail >= stream->runtime->fragment_size)
+ retval = snd_compr_get_poll(stream);
+ break;
+ default:
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ retval = POLLOUT | POLLWRNORM | POLLERR;
+ else
+ retval = POLLIN | POLLRDNORM | POLLERR;
+ break;
+ }
+out:
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+static int
+snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+ int retval;
+ struct snd_compr_caps caps;
+
+ if (!stream->ops->get_caps)
+ return -ENXIO;
+
+ memset(&caps, 0, sizeof(caps));
+ retval = stream->ops->get_caps(stream, &caps);
+ if (retval)
+ goto out;
+ if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
+ retval = -EFAULT;
+out:
+ return retval;
+}
+
+static int
+snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+ int retval;
+ struct snd_compr_codec_caps *caps;
+
+ if (!stream->ops->get_codec_caps)
+ return -ENXIO;
+
+ caps = kzalloc(sizeof(*caps), GFP_KERNEL);
+ if (!caps)
+ return -ENOMEM;
+
+ retval = stream->ops->get_codec_caps(stream, caps);
+ if (retval)
+ goto out;
+ if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
+ retval = -EFAULT;
+
+out:
+ kfree(caps);
+ return retval;
+}
+
+/* revisit this with snd_pcm_preallocate_xxx */
+static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ unsigned int buffer_size;
+ void *buffer;
+
+ buffer_size = params->buffer.fragment_size * params->buffer.fragments;
+ if (stream->ops->copy) {
+ buffer = NULL;
+ /* if copy is defined the driver will be required to copy
+ * the data from core
+ */
+ } else {
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ }
+ stream->runtime->fragment_size = params->buffer.fragment_size;
+ stream->runtime->fragments = params->buffer.fragments;
+ stream->runtime->buffer = buffer;
+ stream->runtime->buffer_size = buffer_size;
+ return 0;
+}
+
+static int snd_compress_check_input(struct snd_compr_params *params)
+{
+ /* first let's check the buffer parameter's */
+ if (params->buffer.fragment_size == 0 ||
+ params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+ return -EINVAL;
+
+ /* now codec parameters */
+ if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
+ return -EINVAL;
+
+ if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_params *params;
+ int retval;
+
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ /*
+ * we should allow parameter change only when stream has been
+ * opened not in other cases
+ */
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ if (copy_from_user(params, (void __user *)arg, sizeof(*params))) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ retval = snd_compress_check_input(params);
+ if (retval)
+ goto out;
+
+ retval = snd_compr_allocate_buffer(stream, params);
+ if (retval) {
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ retval = stream->ops->set_params(stream, params);
+ if (retval)
+ goto out;
+
+ stream->metadata_set = false;
+ stream->next_track = false;
+
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ else
+ stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+ } else {
+ return -EPERM;
+ }
+out:
+ kfree(params);
+ return retval;
+}
+
+static int
+snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_codec *params;
+ int retval;
+
+ if (!stream->ops->get_params)
+ return -EBADFD;
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ retval = stream->ops->get_params(stream, params);
+ if (retval)
+ goto out;
+ if (copy_to_user((char __user *)arg, params, sizeof(*params)))
+ retval = -EFAULT;
+
+out:
+ kfree(params);
+ return retval;
+}
+
+static int
+snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_metadata metadata;
+ int retval;
+
+ if (!stream->ops->get_metadata)
+ return -ENXIO;
+
+ if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
+ return -EFAULT;
+
+ retval = stream->ops->get_metadata(stream, &metadata);
+ if (retval != 0)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int
+snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_metadata metadata;
+ int retval;
+
+ if (!stream->ops->set_metadata)
+ return -ENXIO;
+ /*
+ * we should allow parameter change only when stream has been
+ * opened not in other cases
+ */
+ if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
+ return -EFAULT;
+
+ retval = stream->ops->set_metadata(stream, &metadata);
+ stream->metadata_set = true;
+
+ return retval;
+}
+
+static inline int
+snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_tstamp tstamp = {0};
+ int ret;
+
+ ret = snd_compr_update_tstamp(stream, &tstamp);
+ if (ret == 0)
+ ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
+ &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
+ return ret;
+}
+
+static int snd_compr_pause(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ return retval;
+}
+
+static int snd_compr_resume(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ return retval;
+}
+
+static int snd_compr_start(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ return retval;
+}
+
+static int snd_compr_stop(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+ stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
+ if (!retval) {
+ snd_compr_drain_notify(stream);
+ stream->runtime->total_bytes_available = 0;
+ stream->runtime->total_bytes_transferred = 0;
+ }
+ return retval;
+}
+
+static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
+{
+ int ret;
+
+ /*
+ * We are called with lock held. So drop the lock while we wait for
+ * drain complete notfication from the driver
+ *
+ * It is expected that driver will notify the drain completion and then
+ * stream will be moved to SETUP state, even if draining resulted in an
+ * error. We can trigger next track after this.
+ */
+ stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+ mutex_unlock(&stream->device->lock);
+
+ /* we wait for drain to complete here, drain can return when
+ * interruption occurred, wait returned error or success.
+ * For the first two cases we don't do anything different here and
+ * return after waking up
+ */
+
+ ret = wait_event_interruptible(stream->runtime->sleep,
+ (stream->runtime->state != SNDRV_PCM_STATE_DRAINING));
+ if (ret == -ERESTARTSYS)
+ pr_debug("wait aborted by a signal");
+ else if (ret)
+ pr_debug("wait for drain failed with %d\n", ret);
+
+
+ wake_up(&stream->runtime->sleep);
+ mutex_lock(&stream->device->lock);
+
+ return ret;
+}
+
+static int snd_compr_drain(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+ stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+
+ retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
+ if (retval) {
+ pr_debug("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval);
+ wake_up(&stream->runtime->sleep);
+ return retval;
+ }
+
+ return snd_compress_wait_for_drain(stream);
+}
+
+static int snd_compr_next_track(struct snd_compr_stream *stream)
+{
+ int retval;
+
+ /* only a running stream can transition to next track */
+ if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+ return -EPERM;
+
+ /* you can signal next track isf this is intended to be a gapless stream
+ * and current track metadata is set
+ */
+ if (stream->metadata_set == false)
+ return -EPERM;
+
+ retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
+ if (retval != 0)
+ return retval;
+ stream->metadata_set = false;
+ stream->next_track = true;
+ return 0;
+}
+
+static int snd_compr_partial_drain(struct snd_compr_stream *stream)
+{
+ int retval;
+ if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+ stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ /* stream can be drained only when next track has been signalled */
+ if (stream->next_track == false)
+ return -EPERM;
+
+ retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
+ if (retval) {
+ pr_debug("Partial drain returned failure\n");
+ wake_up(&stream->runtime->sleep);
+ return retval;
+ }
+
+ stream->next_track = false;
+ return snd_compress_wait_for_drain(stream);
+}
+
+static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ struct snd_compr_file *data = f->private_data;
+ struct snd_compr_stream *stream;
+ int retval = -ENOTTY;
+
+ if (snd_BUG_ON(!data))
+ return -EFAULT;
+ stream = &data->stream;
+ if (snd_BUG_ON(!stream))
+ return -EFAULT;
+ mutex_lock(&stream->device->lock);
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
+ retval = put_user(SNDRV_COMPRESS_VERSION,
+ (int __user *)arg) ? -EFAULT : 0;
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
+ retval = snd_compr_get_caps(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
+ retval = snd_compr_get_codec_caps(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
+ retval = snd_compr_set_params(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
+ retval = snd_compr_get_params(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
+ retval = snd_compr_set_metadata(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
+ retval = snd_compr_get_metadata(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
+ retval = snd_compr_tstamp(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_AVAIL):
+ retval = snd_compr_ioctl_avail(stream, arg);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_PAUSE):
+ retval = snd_compr_pause(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_RESUME):
+ retval = snd_compr_resume(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_START):
+ retval = snd_compr_start(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_STOP):
+ retval = snd_compr_stop(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_DRAIN):
+ retval = snd_compr_drain(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
+ retval = snd_compr_partial_drain(stream);
+ break;
+ case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
+ retval = snd_compr_next_track(stream);
+ break;
+
+ }
+ mutex_unlock(&stream->device->lock);
+ return retval;
+}
+
+static const struct file_operations snd_compr_file_ops = {
+ .owner = THIS_MODULE,
+ .open = snd_compr_open,
+ .release = snd_compr_free,
+ .write = snd_compr_write,
+ .read = snd_compr_read,
+ .unlocked_ioctl = snd_compr_ioctl,
+ .mmap = snd_compr_mmap,
+ .poll = snd_compr_poll,
+};
+
+static int snd_compress_dev_register(struct snd_device *device)
+{
+ int ret = -EINVAL;
+ char str[16];
+ struct snd_compr *compr;
+
+ if (snd_BUG_ON(!device || !device->device_data))
+ return -EBADFD;
+ compr = device->device_data;
+
+ sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
+ pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
+ compr->direction);
+ /* register compressed device */
+ ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+ compr->device, &snd_compr_file_ops, compr, str);
+ if (ret < 0) {
+ pr_err("snd_register_device failed\n %d", ret);
+ return ret;
+ }
+ return ret;
+
+}
+
+static int snd_compress_dev_disconnect(struct snd_device *device)
+{
+ struct snd_compr *compr;
+
+ compr = device->device_data;
+ snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+ compr->device);
+ return 0;
+}
+
+/*
+ * snd_compress_new: create new compress device
+ * @card: sound card pointer
+ * @device: device number
+ * @dirn: device direction, should be of type enum snd_compr_direction
+ * @compr: compress device pointer
+ */
+int snd_compress_new(struct snd_card *card, int device,
+ int dirn, struct snd_compr *compr)
+{
+ static struct snd_device_ops ops = {
+ .dev_free = NULL,
+ .dev_register = snd_compress_dev_register,
+ .dev_disconnect = snd_compress_dev_disconnect,
+ };
+
+ compr->card = card;
+ compr->device = device;
+ compr->direction = dirn;
+ return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+}
+EXPORT_SYMBOL_GPL(snd_compress_new);
+
+static int snd_compress_add_device(struct snd_compr *device)
+{
+ int ret;
+
+ if (!device->card)
+ return -EINVAL;
+
+ /* register the card */
+ ret = snd_card_register(device->card);
+ if (ret)
+ goto out;
+ return 0;
+
+out:
+ pr_err("failed with %d\n", ret);
+ return ret;
+
+}
+
+static int snd_compress_remove_device(struct snd_compr *device)
+{
+ return snd_card_free(device->card);
+}
+
+/**
+ * snd_compress_register - register compressed device
+ *
+ * @device: compressed device to register
+ */
+int snd_compress_register(struct snd_compr *device)
+{
+ int retval;
+
+ if (device->name == NULL || device->dev == NULL || device->ops == NULL)
+ return -EINVAL;
+
+ pr_debug("Registering compressed device %s\n", device->name);
+ if (snd_BUG_ON(!device->ops->open))
+ return -EINVAL;
+ if (snd_BUG_ON(!device->ops->free))
+ return -EINVAL;
+ if (snd_BUG_ON(!device->ops->set_params))
+ return -EINVAL;
+ if (snd_BUG_ON(!device->ops->trigger))
+ return -EINVAL;
+
+ mutex_init(&device->lock);
+
+ /* register a compressed card */
+ mutex_lock(&device_mutex);
+ retval = snd_compress_add_device(device);
+ mutex_unlock(&device_mutex);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(snd_compress_register);
+
+int snd_compress_deregister(struct snd_compr *device)
+{
+ pr_debug("Removing compressed device %s\n", device->name);
+ mutex_lock(&device_mutex);
+ snd_compress_remove_device(device);
+ mutex_unlock(&device_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_compress_deregister);
+
+static int __init snd_compress_init(void)
+{
+ return 0;
+}
+
+static void __exit snd_compress_exit(void)
+{
+}
+
+module_init(snd_compress_init);
+module_exit(snd_compress_exit);
+
+MODULE_DESCRIPTION("ALSA Compressed offload framework");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/core/control.c b/sound/core/control.c
index 736edf358e0..f0b0e14497a 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1,6 +1,6 @@
/*
* Routines for driver control interface
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/threads.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
@@ -33,13 +32,12 @@
/* max number of user-defined controls */
#define MAX_USER_CONTROLS 32
+#define MAX_CONTROL_COUNT 1028
-typedef struct _snd_kctl_ioctl {
+struct snd_kctl_ioctl {
struct list_head list; /* list of all ioctls */
snd_kctl_ioctl_func_t fioctl;
-} snd_kctl_ioctl_t;
-
-#define snd_kctl_ioctl(n) list_entry(n, snd_kctl_ioctl_t, list)
+};
static DECLARE_RWSEM(snd_ioctl_rwsem);
static LIST_HEAD(snd_control_ioctls);
@@ -49,13 +47,16 @@ static LIST_HEAD(snd_control_compat_ioctls);
static int snd_ctl_open(struct inode *inode, struct file *file)
{
- int cardnum = SNDRV_MINOR_CARD(iminor(inode));
unsigned long flags;
- snd_card_t *card;
- snd_ctl_file_t *ctl;
+ struct snd_card *card;
+ struct snd_ctl_file *ctl;
int err;
- card = snd_cards[cardnum];
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+
+ card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
if (!card) {
err = -ENODEV;
goto __error1;
@@ -78,11 +79,14 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ctl->change_sleep);
spin_lock_init(&ctl->read_lock);
ctl->card = card;
- ctl->pid = current->pid;
+ ctl->prefer_pcm_subdevice = -1;
+ ctl->prefer_rawmidi_subdevice = -1;
+ ctl->pid = get_pid(task_pid(current));
file->private_data = ctl;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
list_add_tail(&ctl->list, &card->ctl_files);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+ snd_card_unref(card);
return 0;
__error:
@@ -90,73 +94,71 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
__error2:
snd_card_file_remove(card, file);
__error1:
+ if (card)
+ snd_card_unref(card);
return err;
}
-static void snd_ctl_empty_read_queue(snd_ctl_file_t * ctl)
+static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
{
- snd_kctl_event_t *cread;
+ unsigned long flags;
+ struct snd_kctl_event *cread;
- spin_lock(&ctl->read_lock);
+ spin_lock_irqsave(&ctl->read_lock, flags);
while (!list_empty(&ctl->events)) {
cread = snd_kctl_event(ctl->events.next);
list_del(&cread->list);
kfree(cread);
}
- spin_unlock(&ctl->read_lock);
+ spin_unlock_irqrestore(&ctl->read_lock, flags);
}
static int snd_ctl_release(struct inode *inode, struct file *file)
{
unsigned long flags;
- struct list_head *list;
- snd_card_t *card;
- snd_ctl_file_t *ctl;
- snd_kcontrol_t *control;
+ struct snd_card *card;
+ struct snd_ctl_file *ctl;
+ struct snd_kcontrol *control;
unsigned int idx;
ctl = file->private_data;
- fasync_helper(-1, file, 0, &ctl->fasync);
file->private_data = NULL;
card = ctl->card;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
list_del(&ctl->list);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_write(&card->controls_rwsem);
- list_for_each(list, &card->controls) {
- control = snd_kcontrol(list);
+ list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
if (control->vd[idx].owner == ctl)
control->vd[idx].owner = NULL;
- }
up_write(&card->controls_rwsem);
snd_ctl_empty_read_queue(ctl);
+ put_pid(ctl->pid);
kfree(ctl);
module_put(card->module);
snd_card_file_remove(card, file);
return 0;
}
-void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id)
+void snd_ctl_notify(struct snd_card *card, unsigned int mask,
+ struct snd_ctl_elem_id *id)
{
unsigned long flags;
- struct list_head *flist;
- snd_ctl_file_t *ctl;
- snd_kctl_event_t *ev;
+ struct snd_ctl_file *ctl;
+ struct snd_kctl_event *ev;
- snd_runtime_check(card != NULL && id != NULL, return);
+ if (snd_BUG_ON(!card || !id))
+ return;
read_lock(&card->ctl_files_rwlock);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++;
#endif
- list_for_each(flist, &card->ctl_files) {
- struct list_head *elist;
- ctl = snd_ctl_file(flist);
+ list_for_each_entry(ctl, &card->ctl_files, list) {
if (!ctl->subscribed)
continue;
spin_lock_irqsave(&ctl->read_lock, flags);
- list_for_each(elist, &ctl->events) {
- ev = snd_kctl_event(elist);
+ list_for_each_entry(ev, &ctl->events, list) {
if (ev->id.numid == id->numid) {
ev->mask |= mask;
goto _found;
@@ -168,7 +170,7 @@ void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id)
ev->mask = mask;
list_add_tail(&ev->list, &ctl->events);
} else {
- snd_printk(KERN_ERR "No memory available to allocate event\n");
+ dev_err(card->dev, "No memory available to allocate event\n");
}
_found:
wake_up(&ctl->change_sleep);
@@ -178,26 +180,35 @@ void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id)
read_unlock(&card->ctl_files_rwlock);
}
+EXPORT_SYMBOL(snd_ctl_notify);
+
/**
* snd_ctl_new - create a control instance from the template
* @control: the control template
* @access: the default control access
*
- * Allocates a new snd_kcontrol_t instance and copies the given template
+ * Allocates a new struct snd_kcontrol instance and copies the given template
* to the new instance. It does not copy volatile data (access).
*
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
*/
-snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access)
+static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
+ unsigned int access)
{
- snd_kcontrol_t *kctl;
+ struct snd_kcontrol *kctl;
unsigned int idx;
- snd_runtime_check(control != NULL, return NULL);
- snd_runtime_check(control->count > 0, return NULL);
- kctl = kzalloc(sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL);
- if (kctl == NULL)
+ if (snd_BUG_ON(!control || !control->count))
+ return NULL;
+
+ if (control->count > MAX_CONTROL_COUNT)
return NULL;
+
+ kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
+ if (kctl == NULL) {
+ pr_err("ALSA: Cannot allocate control instance\n");
+ return NULL;
+ }
*kctl = *control;
for (idx = 0; idx < kctl->count; idx++)
kctl->vd[idx].access = access;
@@ -209,38 +220,50 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access)
* @ncontrol: the initialization record
* @private_data: the private data to set
*
- * Allocates a new snd_kcontrol_t instance and initialize from the given
+ * Allocates a new struct snd_kcontrol instance and initialize from the given
* template. When the access field of ncontrol is 0, it's assumed as
* READWRITE access. When the count field is 0, it's assumes as one.
*
- * Returns the pointer of the newly generated instance, or NULL on failure.
+ * Return: The pointer of the newly generated instance, or %NULL on failure.
*/
-snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_data)
+struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
+ void *private_data)
{
- snd_kcontrol_t kctl;
+ struct snd_kcontrol kctl;
unsigned int access;
- snd_runtime_check(ncontrol != NULL, return NULL);
- snd_assert(ncontrol->info != NULL, return NULL);
+ if (snd_BUG_ON(!ncontrol || !ncontrol->info))
+ return NULL;
memset(&kctl, 0, sizeof(kctl));
kctl.id.iface = ncontrol->iface;
kctl.id.device = ncontrol->device;
kctl.id.subdevice = ncontrol->subdevice;
- if (ncontrol->name)
+ if (ncontrol->name) {
strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
+ if (strcmp(ncontrol->name, kctl.id.name) != 0)
+ pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
+ ncontrol->name, kctl.id.name);
+ }
kctl.id.index = ncontrol->index;
kctl.count = ncontrol->count ? ncontrol->count : 1;
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
- (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|
- SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
+ (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE|
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
kctl.info = ncontrol->info;
kctl.get = ncontrol->get;
kctl.put = ncontrol->put;
+ kctl.tlv.p = ncontrol->tlv.p;
kctl.private_value = ncontrol->private_value;
kctl.private_data = private_data;
return snd_ctl_new(&kctl, access);
}
+EXPORT_SYMBOL(snd_ctl_new1);
+
/**
* snd_ctl_free_one - release the control instance
* @kcontrol: the control instance
@@ -249,7 +272,7 @@ snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_
* or snd_ctl_new1().
* Don't call this after the control was added to the card.
*/
-void snd_ctl_free_one(snd_kcontrol_t * kcontrol)
+void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
{
if (kcontrol) {
if (kcontrol->private_free)
@@ -258,35 +281,37 @@ void snd_ctl_free_one(snd_kcontrol_t * kcontrol)
}
}
-static unsigned int snd_ctl_hole_check(snd_card_t * card,
- unsigned int count)
+EXPORT_SYMBOL(snd_ctl_free_one);
+
+static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
+ unsigned int count)
{
- struct list_head *list;
- snd_kcontrol_t *kctl;
-
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
- if ((kctl->id.numid <= card->last_numid &&
- kctl->id.numid + kctl->count > card->last_numid) ||
- (kctl->id.numid <= card->last_numid + count - 1 &&
- kctl->id.numid + kctl->count > card->last_numid + count - 1))
- return card->last_numid = kctl->id.numid + kctl->count - 1;
+ struct snd_kcontrol *kctl;
+
+ /* Make sure that the ids assigned to the control do not wrap around */
+ if (card->last_numid >= UINT_MAX - count)
+ card->last_numid = 0;
+
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (kctl->id.numid < card->last_numid + 1 + count &&
+ kctl->id.numid + kctl->count > card->last_numid + 1) {
+ card->last_numid = kctl->id.numid + kctl->count - 1;
+ return true;
+ }
}
- return card->last_numid;
+ return false;
}
-static int snd_ctl_find_hole(snd_card_t * card, unsigned int count)
+static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
{
- unsigned int last_numid, iter = 100000;
+ unsigned int iter = 100000;
- last_numid = card->last_numid;
- while (last_numid != snd_ctl_hole_check(card, count)) {
+ while (snd_ctl_remove_numid_conflict(card, count)) {
if (--iter == 0) {
/* this situation is very unlikely */
- snd_printk(KERN_ERR "unable to allocate new control numid\n");
+ dev_err(card->dev, "unable to allocate new control numid\n");
return -ENOMEM;
}
- last_numid = card->last_numid;
}
return 0;
}
@@ -300,44 +325,125 @@ static int snd_ctl_find_hole(snd_card_t * card, unsigned int count)
* snd_ctl_new1() to the given card. Assigns also an unique
* numid used for fast search.
*
- * Returns zero if successful, or a negative error code on failure.
- *
* It frees automatically the control which cannot be added.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ *
*/
-int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol)
+int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
- snd_ctl_elem_id_t id;
+ struct snd_ctl_elem_id id;
unsigned int idx;
+ unsigned int count;
+ int err = -EINVAL;
- snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);
- snd_assert(kcontrol->info != NULL, return -EINVAL);
+ if (! kcontrol)
+ return err;
+ if (snd_BUG_ON(!card || !kcontrol->info))
+ goto error;
id = kcontrol->id;
+ if (id.index > UINT_MAX - kcontrol->count)
+ goto error;
+
down_write(&card->controls_rwsem);
if (snd_ctl_find_id(card, &id)) {
up_write(&card->controls_rwsem);
- snd_ctl_free_one(kcontrol);
- snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
+ dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n",
id.iface,
id.device,
id.subdevice,
id.name,
id.index);
- return -EBUSY;
+ err = -EBUSY;
+ goto error;
}
if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
up_write(&card->controls_rwsem);
- snd_ctl_free_one(kcontrol);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto error;
}
list_add_tail(&kcontrol->list, &card->controls);
card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
+ count = kcontrol->count;
up_write(&card->controls_rwsem);
- for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+ for (idx = 0; idx < count; idx++, id.index++, id.numid++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+ return 0;
+
+ error:
+ snd_ctl_free_one(kcontrol);
+ return err;
+}
+
+EXPORT_SYMBOL(snd_ctl_add);
+
+/**
+ * snd_ctl_replace - replace the control instance of the card
+ * @card: the card instance
+ * @kcontrol: the control instance to replace
+ * @add_on_replace: add the control if not already added
+ *
+ * Replaces the given control. If the given control does not exist
+ * and the add_on_replace flag is set, the control is added. If the
+ * control exists, it is destroyed first.
+ *
+ * It frees automatically the control which cannot be added or replaced.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
+ bool add_on_replace)
+{
+ struct snd_ctl_elem_id id;
+ unsigned int count;
+ unsigned int idx;
+ struct snd_kcontrol *old;
+ int ret;
+
+ if (!kcontrol)
+ return -EINVAL;
+ if (snd_BUG_ON(!card || !kcontrol->info)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ id = kcontrol->id;
+ down_write(&card->controls_rwsem);
+ old = snd_ctl_find_id(card, &id);
+ if (!old) {
+ if (add_on_replace)
+ goto add;
+ up_write(&card->controls_rwsem);
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = snd_ctl_remove(card, old);
+ if (ret < 0) {
+ up_write(&card->controls_rwsem);
+ goto error;
+ }
+add:
+ if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+ up_write(&card->controls_rwsem);
+ ret = -ENOMEM;
+ goto error;
+ }
+ list_add_tail(&kcontrol->list, &card->controls);
+ card->controls_count += kcontrol->count;
+ kcontrol->id.numid = card->last_numid + 1;
+ card->last_numid += kcontrol->count;
+ count = kcontrol->count;
+ up_write(&card->controls_rwsem);
+ for (idx = 0; idx < count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
return 0;
+
+error:
+ snd_ctl_free_one(kcontrol);
+ return ret;
}
+EXPORT_SYMBOL(snd_ctl_replace);
/**
* snd_ctl_remove - remove the control from the card and release it
@@ -347,15 +453,16 @@ int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol)
* Removes the control from the card and then releases the instance.
* You don't need to call snd_ctl_free_one(). You must be in
* the write lock - down_write(&card->controls_rwsem).
- *
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
*/
-int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol)
+int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
- snd_ctl_elem_id_t id;
+ struct snd_ctl_elem_id id;
unsigned int idx;
- snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);
+ if (snd_BUG_ON(!card || !kcontrol))
+ return -EINVAL;
list_del(&kcontrol->list);
card->controls_count -= kcontrol->count;
id = kcontrol->id;
@@ -365,6 +472,8 @@ int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol)
return 0;
}
+EXPORT_SYMBOL(snd_ctl_remove);
+
/**
* snd_ctl_remove_id - remove the control of the given id and release it
* @card: the card instance
@@ -372,12 +481,12 @@ int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol)
*
* Finds the control instance with the given id, removes it from the
* card list and releases it.
- *
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
*/
-int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id)
+int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
{
- snd_kcontrol_t *kctl;
+ struct snd_kcontrol *kctl;
int ret;
down_write(&card->controls_rwsem);
@@ -391,39 +500,96 @@ int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id)
return ret;
}
+EXPORT_SYMBOL(snd_ctl_remove_id);
+
/**
- * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it
+ * snd_ctl_remove_user_ctl - remove and release the unlocked user control
* @file: active control handle
* @id: the control id to remove
*
* Finds the control instance with the given id, removes it from the
* card list and releases it.
- *
- * Returns 0 if successful, or a negative error code on failure.
+ *
+ * Return: 0 if successful, or a negative error code on failure.
*/
-static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *id)
+static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
+ struct snd_ctl_elem_id *id)
{
- snd_card_t *card = file->card;
- snd_kcontrol_t *kctl;
+ struct snd_card *card = file->card;
+ struct snd_kcontrol *kctl;
int idx, ret;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, id);
if (kctl == NULL) {
- up_write(&card->controls_rwsem);
- return -ENOENT;
+ ret = -ENOENT;
+ goto error;
+ }
+ if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
+ ret = -EINVAL;
+ goto error;
}
for (idx = 0; idx < kctl->count; idx++)
if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
- up_write(&card->controls_rwsem);
- return -EBUSY;
+ ret = -EBUSY;
+ goto error;
}
ret = snd_ctl_remove(card, kctl);
+ if (ret < 0)
+ goto error;
+ card->user_ctl_count--;
+error:
up_write(&card->controls_rwsem);
return ret;
}
/**
+ * snd_ctl_activate_id - activate/inactivate the control of the given id
+ * @card: the card instance
+ * @id: the control id to activate/inactivate
+ * @active: non-zero to activate
+ *
+ * Finds the control instance with the given id, and activate or
+ * inactivate the control together with notification, if changed.
+ *
+ * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
+ */
+int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
+ int active)
+{
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int index_offset;
+ int ret;
+
+ down_write(&card->controls_rwsem);
+ kctl = snd_ctl_find_id(card, id);
+ if (kctl == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+ index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
+ vd = &kctl->vd[index_offset];
+ ret = 0;
+ if (active) {
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+ goto unlock;
+ vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ } else {
+ if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
+ goto unlock;
+ vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ }
+ ret = 1;
+ unlock:
+ up_write(&card->controls_rwsem);
+ if (ret > 0)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
+
+/**
* snd_ctl_rename_id - replace the id of a control on the card
* @card: the card instance
* @src_id: the old id
@@ -432,11 +598,12 @@ static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *
* Finds the control with the old id from the card, and replaces the
* id with the new one.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_ctl_rename_id(snd_card_t * card, snd_ctl_elem_id_t *src_id, snd_ctl_elem_id_t *dst_id)
+int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
+ struct snd_ctl_elem_id *dst_id)
{
- snd_kcontrol_t *kctl;
+ struct snd_kcontrol *kctl;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, src_id);
@@ -451,6 +618,8 @@ int snd_ctl_rename_id(snd_card_t * card, snd_ctl_elem_id_t *src_id, snd_ctl_elem
return 0;
}
+EXPORT_SYMBOL(snd_ctl_rename_id);
+
/**
* snd_ctl_find_numid - find the control instance with the given number-id
* @card: the card instance
@@ -458,25 +627,27 @@ int snd_ctl_rename_id(snd_card_t * card, snd_ctl_elem_id_t *src_id, snd_ctl_elem
*
* Finds the control instance with the given number-id from the card.
*
- * Returns the pointer of the instance if found, or NULL if not.
- *
* The caller must down card->controls_rwsem before calling this function
* (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
*/
-snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid)
+struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
{
- struct list_head *list;
- snd_kcontrol_t *kctl;
+ struct snd_kcontrol *kctl;
- snd_runtime_check(card != NULL && numid != 0, return NULL);
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
+ if (snd_BUG_ON(!card || !numid))
+ return NULL;
+ list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl;
}
return NULL;
}
+EXPORT_SYMBOL(snd_ctl_find_numid);
+
/**
* snd_ctl_find_id - find the control instance with the given id
* @card: the card instance
@@ -484,21 +655,22 @@ snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid)
*
* Finds the control instance with the given id from the card.
*
- * Returns the pointer of the instance if found, or NULL if not.
- *
* The caller must down card->controls_rwsem before calling this function
* (if the race condition can happen).
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ *
*/
-snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id)
+struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
+ struct snd_ctl_elem_id *id)
{
- struct list_head *list;
- snd_kcontrol_t *kctl;
+ struct snd_kcontrol *kctl;
- snd_runtime_check(card != NULL && id != NULL, return NULL);
+ if (snd_BUG_ON(!card || !id))
+ return NULL;
if (id->numid != 0)
return snd_ctl_find_numid(card, id->numid);
- list_for_each(list, &card->controls) {
- kctl = snd_kcontrol(list);
+ list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.iface != id->iface)
continue;
if (kctl->id.device != id->device)
@@ -516,10 +688,12 @@ snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id)
return NULL;
}
-static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
+EXPORT_SYMBOL(snd_ctl_find_id);
+
+static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
unsigned int cmd, void __user *arg)
{
- snd_ctl_card_info_t *info;
+ struct snd_ctl_card_info *info;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
@@ -533,7 +707,7 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
strlcpy(info->components, card->components, sizeof(info->components));
up_read(&snd_ioctl_rwsem);
- if (copy_to_user(arg, info, sizeof(snd_ctl_card_info_t))) {
+ if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
kfree(info);
return -EFAULT;
}
@@ -541,25 +715,25 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
return 0;
}
-static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list)
+static int snd_ctl_elem_list(struct snd_card *card,
+ struct snd_ctl_elem_list __user *_list)
{
struct list_head *plist;
- snd_ctl_elem_list_t list;
- snd_kcontrol_t *kctl;
- snd_ctl_elem_id_t *dst, *id;
- unsigned int offset, space, first, jidx;
+ struct snd_ctl_elem_list list;
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_id *dst, *id;
+ unsigned int offset, space, jidx;
if (copy_from_user(&list, _list, sizeof(list)))
return -EFAULT;
offset = list.offset;
space = list.space;
- first = 0;
/* try limit maximum space */
if (space > 16384)
return -ENOMEM;
if (space > 0) {
/* allocate temporary buffer for atomic operation */
- dst = vmalloc(space * sizeof(snd_ctl_elem_id_t));
+ dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
if (dst == NULL)
return -ENOMEM;
down_read(&card->controls_rwsem);
@@ -588,7 +762,9 @@ static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list
offset = 0;
}
up_read(&card->controls_rwsem);
- if (list.used > 0 && copy_to_user(list.pids, dst, list.used * sizeof(snd_ctl_elem_id_t))) {
+ if (list.used > 0 &&
+ copy_to_user(list.pids, dst,
+ list.used * sizeof(struct snd_ctl_elem_id))) {
vfree(dst);
return -EFAULT;
}
@@ -603,11 +779,12 @@ static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list
return 0;
}
-static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
+static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
+ struct snd_ctl_elem_info *info)
{
- snd_card_t *card = ctl->card;
- snd_kcontrol_t *kctl;
- snd_kcontrol_volatile_t *vd;
+ struct snd_card *card = ctl->card;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
int result;
@@ -622,7 +799,7 @@ static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
#endif
result = kctl->info(kctl, info);
if (result >= 0) {
- snd_assert(info->access == 0, );
+ snd_BUG_ON(info->access);
index_offset = snd_ctl_get_ioff(kctl, &info->id);
vd = &kctl->vd[index_offset];
snd_ctl_build_ioff(&info->id, kctl, index_offset);
@@ -631,7 +808,7 @@ static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
if (vd->owner == ctl)
info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
- info->owner = vd->owner_pid;
+ info->owner = pid_vnr(vd->owner->pid);
} else {
info->owner = -1;
}
@@ -640,26 +817,32 @@ static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
return result;
}
-static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
+static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
+ struct snd_ctl_elem_info __user *_info)
{
- snd_ctl_elem_info_t info;
+ struct snd_ctl_elem_info info;
int result;
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
- result = snd_ctl_elem_info(ctl, &info);
+ snd_power_lock(ctl->card);
+ result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
+ if (result >= 0)
+ result = snd_ctl_elem_info(ctl, &info);
+ snd_power_unlock(ctl->card);
if (result >= 0)
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return result;
}
-int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control)
+static int snd_ctl_elem_read(struct snd_card *card,
+ struct snd_ctl_elem_value *control)
{
- snd_kcontrol_t *kctl;
- snd_kcontrol_volatile_t *vd;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
- int result, indirect;
+ int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
@@ -668,35 +851,32 @@ int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control)
} else {
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
- indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
- if (control->indirect != indirect) {
- result = -EACCES;
- } else {
- if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
- snd_ctl_build_ioff(&control->id, kctl, index_offset);
- result = kctl->get(kctl, control);
- } else {
- result = -EPERM;
- }
- }
+ if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
+ kctl->get != NULL) {
+ snd_ctl_build_ioff(&control->id, kctl, index_offset);
+ result = kctl->get(kctl, control);
+ } else
+ result = -EPERM;
}
up_read(&card->controls_rwsem);
return result;
}
-static int snd_ctl_elem_read_user(snd_card_t *card, snd_ctl_elem_value_t __user *_control)
+static int snd_ctl_elem_read_user(struct snd_card *card,
+ struct snd_ctl_elem_value __user *_control)
{
- snd_ctl_elem_value_t *control;
+ struct snd_ctl_elem_value *control;
int result;
-
- control = kmalloc(sizeof(*control), GFP_KERNEL);
- if (control == NULL)
- return -ENOMEM;
- if (copy_from_user(control, _control, sizeof(*control))) {
- kfree(control);
- return -EFAULT;
- }
- result = snd_ctl_elem_read(card, control);
+
+ control = memdup_user(_control, sizeof(*control));
+ if (IS_ERR(control))
+ return PTR_ERR(control);
+
+ snd_power_lock(card);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+ if (result >= 0)
+ result = snd_ctl_elem_read(card, control);
+ snd_power_unlock(card);
if (result >= 0)
if (copy_to_user(_control, control, sizeof(*control)))
result = -EFAULT;
@@ -704,12 +884,13 @@ static int snd_ctl_elem_read_user(snd_card_t *card, snd_ctl_elem_value_t __user
return result;
}
-int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control)
+static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+ struct snd_ctl_elem_value *control)
{
- snd_kcontrol_t *kctl;
- snd_kcontrol_volatile_t *vd;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
- int result, indirect;
+ int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
@@ -718,42 +899,42 @@ int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_valu
} else {
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
- indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
- if (control->indirect != indirect) {
- result = -EACCES;
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
+ kctl->put == NULL ||
+ (file && vd->owner && vd->owner != file)) {
+ result = -EPERM;
} else {
- if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
- kctl->put == NULL ||
- (file && vd->owner != NULL && vd->owner != file)) {
- result = -EPERM;
- } else {
- snd_ctl_build_ioff(&control->id, kctl, index_offset);
- result = kctl->put(kctl, control);
- }
- if (result > 0) {
- up_read(&card->controls_rwsem);
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id);
- return 0;
- }
+ snd_ctl_build_ioff(&control->id, kctl, index_offset);
+ result = kctl->put(kctl, control);
+ }
+ if (result > 0) {
+ struct snd_ctl_elem_id id = control->id;
+ up_read(&card->controls_rwsem);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
+ return 0;
}
}
up_read(&card->controls_rwsem);
return result;
}
-static int snd_ctl_elem_write_user(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control)
+static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
+ struct snd_ctl_elem_value __user *_control)
{
- snd_ctl_elem_value_t *control;
+ struct snd_ctl_elem_value *control;
+ struct snd_card *card;
int result;
- control = kmalloc(sizeof(*control), GFP_KERNEL);
- if (control == NULL)
- return -ENOMEM;
- if (copy_from_user(control, _control, sizeof(*control))) {
- kfree(control);
- return -EFAULT;
- }
- result = snd_ctl_elem_write(file->card, file, control);
+ control = memdup_user(_control, sizeof(*control));
+ if (IS_ERR(control))
+ return PTR_ERR(control);
+
+ card = file->card;
+ snd_power_lock(card);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+ if (result >= 0)
+ result = snd_ctl_elem_write(card, file, control);
+ snd_power_unlock(card);
if (result >= 0)
if (copy_to_user(_control, control, sizeof(*control)))
result = -EFAULT;
@@ -761,12 +942,13 @@ static int snd_ctl_elem_write_user(snd_ctl_file_t *file, snd_ctl_elem_value_t __
return result;
}
-static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
+static int snd_ctl_elem_lock(struct snd_ctl_file *file,
+ struct snd_ctl_elem_id __user *_id)
{
- snd_card_t *card = file->card;
- snd_ctl_elem_id_t id;
- snd_kcontrol_t *kctl;
- snd_kcontrol_volatile_t *vd;
+ struct snd_card *card = file->card;
+ struct snd_ctl_elem_id id;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
@@ -781,7 +963,6 @@ static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id
result = -EBUSY;
else {
vd->owner = file;
- vd->owner_pid = current->pid;
result = 0;
}
}
@@ -789,12 +970,13 @@ static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id
return result;
}
-static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
+static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
+ struct snd_ctl_elem_id __user *_id)
{
- snd_card_t *card = file->card;
- snd_ctl_elem_id_t id;
- snd_kcontrol_t *kctl;
- snd_kcontrol_volatile_t *vd;
+ struct snd_card *card = file->card;
+ struct snd_ctl_elem_id id;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
int result;
if (copy_from_user(&id, _id, sizeof(id)))
@@ -811,7 +993,6 @@ static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_
result = -EPERM;
else {
vd->owner = NULL;
- vd->owner_pid = 0;
result = 0;
}
}
@@ -820,14 +1001,17 @@ static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_
}
struct user_element {
- snd_ctl_elem_info_t info;
+ struct snd_ctl_elem_info info;
+ struct snd_card *card;
void *elem_data; /* element data */
unsigned long elem_data_size; /* size of element data in bytes */
+ void *tlv_data; /* TLV data */
+ unsigned long tlv_data_size; /* TLV data size */
void *priv_data; /* private data (like strings for enumerated type) */
- unsigned long priv_data_size; /* size of private data in bytes */
};
-static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
struct user_element *ue = kcontrol->private_data;
@@ -835,76 +1019,187 @@ static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t
return 0;
}
-static int snd_ctl_elem_user_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
struct user_element *ue = kcontrol->private_data;
+ const char *names;
+ unsigned int item;
+
+ item = uinfo->value.enumerated.item;
+
+ *uinfo = ue->info;
+
+ item = min(item, uinfo->value.enumerated.items - 1);
+ uinfo->value.enumerated.item = item;
+ names = ue->priv_data;
+ for (; item > 0; --item)
+ names += strlen(names) + 1;
+ strcpy(uinfo->value.enumerated.name, names);
+
+ return 0;
+}
+
+static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct user_element *ue = kcontrol->private_data;
+
+ mutex_lock(&ue->card->user_ctl_lock);
memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
+ mutex_unlock(&ue->card->user_ctl_lock);
return 0;
}
-static int snd_ctl_elem_user_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
int change;
struct user_element *ue = kcontrol->private_data;
-
+
+ mutex_lock(&ue->card->user_ctl_lock);
change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
if (change)
memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
+ mutex_unlock(&ue->card->user_ctl_lock);
return change;
}
-static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol)
+static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
+ int op_flag,
+ unsigned int size,
+ unsigned int __user *tlv)
{
- kfree(kcontrol->private_data);
+ struct user_element *ue = kcontrol->private_data;
+ int change = 0;
+ void *new_data;
+
+ if (op_flag > 0) {
+ if (size > 1024 * 128) /* sane value */
+ return -EINVAL;
+
+ new_data = memdup_user(tlv, size);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
+ mutex_lock(&ue->card->user_ctl_lock);
+ change = ue->tlv_data_size != size;
+ if (!change)
+ change = memcmp(ue->tlv_data, new_data, size);
+ kfree(ue->tlv_data);
+ ue->tlv_data = new_data;
+ ue->tlv_data_size = size;
+ mutex_unlock(&ue->card->user_ctl_lock);
+ } else {
+ int ret = 0;
+
+ mutex_lock(&ue->card->user_ctl_lock);
+ if (!ue->tlv_data_size || !ue->tlv_data) {
+ ret = -ENXIO;
+ goto err_unlock;
+ }
+ if (size < ue->tlv_data_size) {
+ ret = -ENOSPC;
+ goto err_unlock;
+ }
+ if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
+ ret = -EFAULT;
+err_unlock:
+ mutex_unlock(&ue->card->user_ctl_lock);
+ if (ret)
+ return ret;
+ }
+ return change;
}
-static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace)
+static int snd_ctl_elem_init_enum_names(struct user_element *ue)
{
- snd_card_t *card = file->card;
- snd_kcontrol_t kctl, *_kctl;
+ char *names, *p;
+ size_t buf_len, name_len;
+ unsigned int i;
+ const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
+
+ if (ue->info.value.enumerated.names_length > 64 * 1024)
+ return -EINVAL;
+
+ names = memdup_user((const void __user *)user_ptrval,
+ ue->info.value.enumerated.names_length);
+ if (IS_ERR(names))
+ return PTR_ERR(names);
+
+ /* check that there are enough valid names */
+ buf_len = ue->info.value.enumerated.names_length;
+ p = names;
+ for (i = 0; i < ue->info.value.enumerated.items; ++i) {
+ name_len = strnlen(p, buf_len);
+ if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
+ kfree(names);
+ return -EINVAL;
+ }
+ p += name_len + 1;
+ buf_len -= name_len + 1;
+ }
+
+ ue->priv_data = names;
+ ue->info.value.enumerated.names_ptr = 0;
+
+ return 0;
+}
+
+static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
+{
+ struct user_element *ue = kcontrol->private_data;
+
+ kfree(ue->tlv_data);
+ kfree(ue->priv_data);
+ kfree(ue);
+}
+
+static int snd_ctl_elem_add(struct snd_ctl_file *file,
+ struct snd_ctl_elem_info *info, int replace)
+{
+ struct snd_card *card = file->card;
+ struct snd_kcontrol kctl, *_kctl;
unsigned int access;
long private_size;
struct user_element *ue;
int idx, err;
-
- if (card->user_ctl_count >= MAX_USER_CONTROLS)
- return -ENOMEM;
- if (info->count > 1024)
+
+ if (info->count < 1)
return -EINVAL;
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
- (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
+ (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
info->id.numid = 0;
memset(&kctl, 0, sizeof(kctl));
- down_write(&card->controls_rwsem);
- _kctl = snd_ctl_find_id(card, &info->id);
- err = 0;
- if (_kctl) {
- if (replace)
- err = snd_ctl_remove(card, _kctl);
- else
- err = -EBUSY;
- } else {
- if (replace)
- err = -ENOENT;
+
+ if (replace) {
+ err = snd_ctl_remove_user_ctl(file, &info->id);
+ if (err)
+ return err;
}
- up_write(&card->controls_rwsem);
- if (err < 0)
- return err;
+
+ if (card->user_ctl_count >= MAX_USER_CONTROLS)
+ return -ENOMEM;
+
memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
- kctl.info = snd_ctl_elem_user_info;
+ if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
+ kctl.info = snd_ctl_elem_user_enum_info;
+ else
+ kctl.info = snd_ctl_elem_user_info;
if (access & SNDRV_CTL_ELEM_ACCESS_READ)
kctl.get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
kctl.put = snd_ctl_elem_user_put;
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
+ kctl.tlv.c = snd_ctl_elem_user_tlv;
+ access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+ }
switch (info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
- private_size = sizeof(char);
- if (info->count > 128)
- return -EINVAL;
- break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
private_size = sizeof(long);
if (info->count > 128)
@@ -915,13 +1210,18 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int
if (info->count > 64)
return -EINVAL;
break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ private_size = sizeof(unsigned int);
+ if (info->count > 128 || info->value.enumerated.items == 0)
+ return -EINVAL;
+ break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
private_size = sizeof(unsigned char);
if (info->count > 512)
return -EINVAL;
break;
case SNDRV_CTL_ELEM_TYPE_IEC958:
- private_size = sizeof(struct sndrv_aes_iec958);
+ private_size = sizeof(struct snd_aes_iec958);
if (info->count != 1)
return -EINVAL;
break;
@@ -932,23 +1232,31 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
if (ue == NULL)
return -ENOMEM;
+ ue->card = card;
ue->info = *info;
+ ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue);
ue->elem_data_size = private_size;
+ if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ err = snd_ctl_elem_init_enum_names(ue);
+ if (err < 0) {
+ kfree(ue);
+ return err;
+ }
+ }
kctl.private_free = snd_ctl_elem_user_free;
_kctl = snd_ctl_new(&kctl, access);
if (_kctl == NULL) {
- kfree(_kctl->private_data);
+ kfree(ue->priv_data);
+ kfree(ue);
return -ENOMEM;
}
_kctl->private_data = ue;
for (idx = 0; idx < _kctl->count; idx++)
_kctl->vd[idx].owner = file;
err = snd_ctl_add(card, _kctl);
- if (err < 0) {
- snd_ctl_free_one(_kctl);
+ if (err < 0)
return err;
- }
down_write(&card->controls_rwsem);
card->user_ctl_count++;
@@ -957,32 +1265,26 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int
return 0;
}
-static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
+static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
+ struct snd_ctl_elem_info __user *_info, int replace)
{
- snd_ctl_elem_info_t info;
+ struct snd_ctl_elem_info info;
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
return snd_ctl_elem_add(file, &info, replace);
}
-static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
+static int snd_ctl_elem_remove(struct snd_ctl_file *file,
+ struct snd_ctl_elem_id __user *_id)
{
- snd_ctl_elem_id_t id;
- int err;
+ struct snd_ctl_elem_id id;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
- err = snd_ctl_remove_unlocked_id(file, &id);
- if (! err) {
- snd_card_t *card = file->card;
- down_write(&card->controls_rwsem);
- card->user_ctl_count--;
- up_write(&card->controls_rwsem);
- }
- return err;
+ return snd_ctl_remove_user_ctl(file, &id);
}
-static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr)
+static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
{
int subscribe;
if (get_user(subscribe, ptr))
@@ -1003,60 +1305,92 @@ static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr)
return 0;
}
-#ifdef CONFIG_PM
-/*
- * change the power state
- */
-static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state)
+static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
+ struct snd_ctl_tlv __user *_tlv,
+ int op_flag)
{
- switch (power_state) {
- case SNDRV_CTL_POWER_D0:
- if (card->power_state != power_state) {
- card->pm_resume(card);
- snd_power_change_state(card, power_state);
+ struct snd_card *card = file->card;
+ struct snd_ctl_tlv tlv;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int len;
+ int err = 0;
+
+ if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
+ return -EFAULT;
+ if (tlv.length < sizeof(unsigned int) * 2)
+ return -EINVAL;
+ down_read(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, tlv.numid);
+ if (kctl == NULL) {
+ err = -ENOENT;
+ goto __kctl_end;
+ }
+ if (kctl->tlv.p == NULL) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ vd = &kctl->vd[tlv.numid - kctl->id.numid];
+ if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
+ (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
+ (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ if (vd->owner != NULL && vd->owner != file) {
+ err = -EPERM;
+ goto __kctl_end;
}
- break;
- case SNDRV_CTL_POWER_D3hot:
- if (card->power_state != power_state) {
- card->pm_suspend(card, PMSG_SUSPEND);
- snd_power_change_state(card, power_state);
+ err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
+ if (err > 0) {
+ struct snd_ctl_elem_id id = kctl->id;
+ up_read(&card->controls_rwsem);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
+ return 0;
}
- break;
- case SNDRV_CTL_POWER_D1:
- case SNDRV_CTL_POWER_D2:
- case SNDRV_CTL_POWER_D3cold:
- /* not supported yet */
- default:
- return -EINVAL;
+ } else {
+ if (op_flag) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
+ if (tlv.length < len) {
+ err = -ENOMEM;
+ goto __kctl_end;
+ }
+ if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
+ err = -EFAULT;
}
- return 0;
+ __kctl_end:
+ up_read(&card->controls_rwsem);
+ return err;
}
-#endif
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_ctl_file_t *ctl;
- snd_card_t *card;
- struct list_head *list;
- snd_kctl_ioctl_t *p;
+ struct snd_ctl_file *ctl;
+ struct snd_card *card;
+ struct snd_kctl_ioctl *p;
void __user *argp = (void __user *)arg;
int __user *ip = argp;
int err;
ctl = file->private_data;
card = ctl->card;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
case SNDRV_CTL_IOCTL_CARD_INFO:
return snd_ctl_card_info(card, ctl, cmd, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST:
- return snd_ctl_elem_list(ctl->card, argp);
+ return snd_ctl_elem_list(card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO:
return snd_ctl_elem_info_user(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_READ:
- return snd_ctl_elem_read_user(ctl->card, argp);
+ return snd_ctl_elem_read_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_WRITE:
return snd_ctl_elem_write_user(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_LOCK:
@@ -1071,20 +1405,14 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
return snd_ctl_elem_remove(ctl, argp);
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip);
+ case SNDRV_CTL_IOCTL_TLV_READ:
+ return snd_ctl_tlv_ioctl(ctl, argp, 0);
+ case SNDRV_CTL_IOCTL_TLV_WRITE:
+ return snd_ctl_tlv_ioctl(ctl, argp, 1);
+ case SNDRV_CTL_IOCTL_TLV_COMMAND:
+ return snd_ctl_tlv_ioctl(ctl, argp, -1);
case SNDRV_CTL_IOCTL_POWER:
- if (get_user(err, ip))
- return -EFAULT;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-#ifdef CONFIG_PM
- if (card->pm_suspend && card->pm_resume) {
- snd_power_lock(card);
- err = snd_ctl_set_power_state(card, err);
- snd_power_unlock(card);
- } else
-#endif
- err = -ENOPROTOOPT;
- return err;
+ return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
return put_user(card->power_state, ip) ? -EFAULT : 0;
@@ -1093,8 +1421,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
#endif
}
down_read(&snd_ioctl_rwsem);
- list_for_each(list, &snd_control_ioctls) {
- p = list_entry(list, snd_kctl_ioctl_t, list);
+ list_for_each_entry(p, &snd_control_ioctls, list) {
err = p->fioctl(card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
up_read(&snd_ioctl_rwsem);
@@ -1102,26 +1429,28 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
}
}
up_read(&snd_ioctl_rwsem);
- snd_printdd("unknown ioctl = 0x%x\n", cmd);
+ dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
-static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
+static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
+ size_t count, loff_t * offset)
{
- snd_ctl_file_t *ctl;
+ struct snd_ctl_file *ctl;
int err = 0;
ssize_t result = 0;
ctl = file->private_data;
- snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!ctl || !ctl->card))
+ return -ENXIO;
if (!ctl->subscribed)
return -EBADFD;
- if (count < sizeof(snd_ctl_event_t))
+ if (count < sizeof(struct snd_ctl_event))
return -EINVAL;
spin_lock_irq(&ctl->read_lock);
- while (count >= sizeof(snd_ctl_event_t)) {
- snd_ctl_event_t ev;
- snd_kctl_event_t *kev;
+ while (count >= sizeof(struct snd_ctl_event)) {
+ struct snd_ctl_event ev;
+ struct snd_kctl_event *kev;
while (list_empty(&ctl->events)) {
wait_queue_t wait;
if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
@@ -1134,8 +1463,10 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count
spin_unlock_irq(&ctl->read_lock);
schedule();
remove_wait_queue(&ctl->change_sleep, &wait);
+ if (ctl->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
- return result > 0 ? result : -ERESTARTSYS;
+ return -ERESTARTSYS;
spin_lock_irq(&ctl->read_lock);
}
kev = snd_kctl_event(ctl->events.next);
@@ -1145,14 +1476,14 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count
list_del(&kev->list);
spin_unlock_irq(&ctl->read_lock);
kfree(kev);
- if (copy_to_user(buffer, &ev, sizeof(snd_ctl_event_t))) {
+ if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) {
err = -EFAULT;
goto __end;
}
spin_lock_irq(&ctl->read_lock);
- buffer += sizeof(snd_ctl_event_t);
- count -= sizeof(snd_ctl_event_t);
- result += sizeof(snd_ctl_event_t);
+ buffer += sizeof(struct snd_ctl_event);
+ count -= sizeof(struct snd_ctl_event);
+ result += sizeof(struct snd_ctl_event);
}
__end_lock:
spin_unlock_irq(&ctl->read_lock);
@@ -1163,7 +1494,7 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count
static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
- snd_ctl_file_t *ctl;
+ struct snd_ctl_file *ctl;
ctl = file->private_data;
if (!ctl->subscribed)
@@ -1183,9 +1514,9 @@ static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
*/
static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
{
- snd_kctl_ioctl_t *pn;
+ struct snd_kctl_ioctl *pn;
- pn = kzalloc(sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
+ pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL);
if (pn == NULL)
return -ENOMEM;
pn->fioctl = fcn;
@@ -1200,25 +1531,29 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_register_ioctl);
+
#ifdef CONFIG_COMPAT
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
}
+
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
#endif
/*
* de-register the device-specific control-ioctls.
*/
-static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
+static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
+ struct list_head *lists)
{
- struct list_head *list;
- snd_kctl_ioctl_t *p;
+ struct snd_kctl_ioctl *p;
- snd_runtime_check(fcn != NULL, return -EINVAL);
+ if (snd_BUG_ON(!fcn))
+ return -EINVAL;
down_write(&snd_ioctl_rwsem);
- list_for_each(list, lists) {
- p = list_entry(list, snd_kctl_ioctl_t, list);
+ list_for_each_entry(p, lists, list) {
if (p->fioctl == fcn) {
list_del(&p->list);
up_write(&snd_ioctl_rwsem);
@@ -1236,23 +1571,23 @@ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+
#ifdef CONFIG_COMPAT
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
}
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
#endif
static int snd_ctl_fasync(int fd, struct file * file, int on)
{
- snd_ctl_file_t *ctl;
- int err;
+ struct snd_ctl_file *ctl;
+
ctl = file->private_data;
- err = fasync_helper(fd, file, on, &ctl->fasync);
- if (err < 0)
- return err;
- return 0;
+ return fasync_helper(fd, file, on, &ctl->fasync);
}
/*
@@ -1268,39 +1603,36 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
* INIT PART
*/
-static struct file_operations snd_ctl_f_ops =
+static const struct file_operations snd_ctl_f_ops =
{
.owner = THIS_MODULE,
.read = snd_ctl_read,
.open = snd_ctl_open,
.release = snd_ctl_release,
+ .llseek = no_llseek,
.poll = snd_ctl_poll,
.unlocked_ioctl = snd_ctl_ioctl,
.compat_ioctl = snd_ctl_ioctl_compat,
.fasync = snd_ctl_fasync,
};
-static snd_minor_t snd_ctl_reg =
-{
- .comment = "ctl",
- .f_ops = &snd_ctl_f_ops,
-};
-
/*
* registration of the control device
*/
-static int snd_ctl_dev_register(snd_device_t *device)
+static int snd_ctl_dev_register(struct snd_device *device)
{
- snd_card_t *card = device->device_data;
+ struct snd_card *card = device->device_data;
int err, cardnum;
char name[16];
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
cardnum = card->number;
- snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+ if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+ return -ENXIO;
sprintf(name, "controlC%i", cardnum);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL,
- card, 0, &snd_ctl_reg, name)) < 0)
+ if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
+ &snd_ctl_f_ops, card, name)) < 0)
return err;
return 0;
}
@@ -1308,29 +1640,38 @@ static int snd_ctl_dev_register(snd_device_t *device)
/*
* disconnection of the control device
*/
-static int snd_ctl_dev_disconnect(snd_device_t *device)
+static int snd_ctl_dev_disconnect(struct snd_device *device)
{
- snd_card_t *card = device->device_data;
- struct list_head *flist;
- snd_ctl_file_t *ctl;
+ struct snd_card *card = device->device_data;
+ struct snd_ctl_file *ctl;
+ int err, cardnum;
- down_read(&card->controls_rwsem);
- list_for_each(flist, &card->ctl_files) {
- ctl = snd_ctl_file(flist);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ cardnum = card->number;
+ if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
+ return -ENXIO;
+
+ read_lock(&card->ctl_files_rwlock);
+ list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep);
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
}
- up_read(&card->controls_rwsem);
+ read_unlock(&card->ctl_files_rwlock);
+
+ if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
+ card, -1)) < 0)
+ return err;
return 0;
}
/*
* free all controls
*/
-static int snd_ctl_dev_free(snd_device_t *device)
+static int snd_ctl_dev_free(struct snd_device *device)
{
- snd_card_t *card = device->device_data;
- snd_kcontrol_t *control;
+ struct snd_card *card = device->device_data;
+ struct snd_kcontrol *control;
down_write(&card->controls_rwsem);
while (!list_empty(&card->controls)) {
@@ -1342,34 +1683,73 @@ static int snd_ctl_dev_free(snd_device_t *device)
}
/*
- * de-registration of the control device
- */
-static int snd_ctl_dev_unregister(snd_device_t *device)
-{
- snd_card_t *card = device->device_data;
- int err, cardnum;
-
- snd_assert(card != NULL, return -ENXIO);
- cardnum = card->number;
- snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
- if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, 0)) < 0)
- return err;
- return snd_ctl_dev_free(device);
-}
-
-/*
* create control core:
* called from init.c
*/
-int snd_ctl_create(snd_card_t *card)
+int snd_ctl_create(struct snd_card *card)
{
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect,
- .dev_unregister = snd_ctl_dev_unregister
};
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
}
+
+/*
+ * Frequently used control callbacks/helpers
+ */
+int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
+
+int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
+
+/**
+ * snd_ctl_enum_info - fills the info structure for an enumerated control
+ * @info: the structure to be filled
+ * @channels: the number of the control's channels; often one
+ * @items: the number of control values; also the size of @names
+ * @names: an array containing the names of all control values
+ *
+ * Sets all required fields in @info to their appropriate values.
+ * If the control's accessibility is not the default (readable and writable),
+ * the caller has to fill @info->access.
+ *
+ * Return: Zero.
+ */
+int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
+ unsigned int items, const char *const names[])
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = channels;
+ info->value.enumerated.items = items;
+ if (info->value.enumerated.item >= items)
+ info->value.enumerated.item = items - 1;
+ strlcpy(info->value.enumerated.name,
+ names[info->value.enumerated.item],
+ sizeof(info->value.enumerated.name));
+ return 0;
+}
+EXPORT_SYMBOL(snd_ctl_enum_info);
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 207c7de5129..b9c0910fb8c 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -21,8 +21,9 @@
/* this file included from control.c */
#include <linux/compat.h>
+#include <linux/slab.h>
-struct sndrv_ctl_elem_list32 {
+struct snd_ctl_elem_list32 {
u32 offset;
u32 space;
u32 used;
@@ -31,9 +32,10 @@ struct sndrv_ctl_elem_list32 {
unsigned char reserved[50];
} /* don't set packed attribute here */;
-static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32)
+static int snd_ctl_elem_list_compat(struct snd_card *card,
+ struct snd_ctl_elem_list32 __user *data32)
{
- struct sndrv_ctl_elem_list __user *data;
+ struct snd_ctl_elem_list __user *data;
compat_caddr_t ptr;
int err;
@@ -60,8 +62,8 @@ static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list
* it uses union, so the things are not easy..
*/
-struct sndrv_ctl_elem_info32 {
- struct sndrv_ctl_elem_id id; // the size of struct is same
+struct snd_ctl_elem_info32 {
+ struct snd_ctl_elem_id id; // the size of struct is same
s32 type;
u32 access;
u32 count;
@@ -81,15 +83,18 @@ struct sndrv_ctl_elem_info32 {
u32 items;
u32 item;
char name[64];
+ u64 names_ptr;
+ u32 names_length;
} enumerated;
unsigned char reserved[128];
} value;
unsigned char reserved[64];
} __attribute__((packed));
-static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32)
+static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
+ struct snd_ctl_elem_info32 __user *data32)
{
- struct sndrv_ctl_elem_info *data;
+ struct snd_ctl_elem_info *data;
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -105,7 +110,13 @@ static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_i
*/
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
goto error;
- err = snd_ctl_elem_info(ctl, data);
+
+ snd_power_lock(ctl->card);
+ err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
+ if (err >= 0)
+ err = snd_ctl_elem_info(ctl, data);
+ snd_power_unlock(ctl->card);
+
if (err < 0)
goto error;
/* restore info to 32bit */
@@ -146,8 +157,8 @@ static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_i
}
/* read / write */
-struct sndrv_ctl_elem_value32 {
- struct sndrv_ctl_elem_id id;
+struct snd_ctl_elem_value32 {
+ struct snd_ctl_elem_id id;
unsigned int indirect; /* bit-field causes misalignment */
union {
s32 integer[128];
@@ -161,10 +172,11 @@ struct sndrv_ctl_elem_value32 {
/* get the value type and count of the control */
-static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp)
+static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
+ int *countp)
{
- snd_kcontrol_t *kctl;
- snd_ctl_elem_info_t info;
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_info *info;
int err;
down_read(&card->controls_rwsem);
@@ -173,13 +185,19 @@ static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp)
up_read(&card->controls_rwsem);
return -ENXIO;
}
- info.id = *id;
- err = kctl->info(kctl, &info);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ up_read(&card->controls_rwsem);
+ return -ENOMEM;
+ }
+ info->id = *id;
+ err = kctl->info(kctl, info);
up_read(&card->controls_rwsem);
if (err >= 0) {
- err = info.type;
- *countp = info.count;
+ err = info->type;
+ *countp = info->count;
}
+ kfree(info);
return err;
}
@@ -193,18 +211,19 @@ static int get_elem_size(int type, int count)
case SNDRV_CTL_ELEM_TYPE_BYTES:
return 512;
case SNDRV_CTL_ELEM_TYPE_IEC958:
- return sizeof(struct sndrv_aes_iec958);
+ return sizeof(struct snd_aes_iec958);
default:
return -1;
}
}
-static int copy_ctl_value_from_user(snd_card_t *card,
- struct sndrv_ctl_elem_value *data,
- struct sndrv_ctl_elem_value32 __user *data32,
+static int copy_ctl_value_from_user(struct snd_card *card,
+ struct snd_ctl_elem_value *data,
+ struct snd_ctl_elem_value32 __user *data32,
int *typep, int *countp)
{
- int i, type, count, size;
+ int i, type, size;
+ int uninitialized_var(count);
unsigned int indirect;
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
@@ -228,7 +247,7 @@ static int copy_ctl_value_from_user(snd_card_t *card,
} else {
size = get_elem_size(type, count);
if (size < 0) {
- printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
+ dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
}
if (copy_from_user(data->value.bytes.data,
@@ -242,8 +261,8 @@ static int copy_ctl_value_from_user(snd_card_t *card,
}
/* restore the value to 32bit */
-static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32,
- struct sndrv_ctl_elem_value *data,
+static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32,
+ struct snd_ctl_elem_value *data,
int type, int count)
{
int i, size;
@@ -265,10 +284,10 @@ static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32,
return 0;
}
-static int snd_ctl_elem_read_user_compat(snd_card_t *card,
- struct sndrv_ctl_elem_value32 __user *data32)
+static int snd_ctl_elem_read_user_compat(struct snd_card *card,
+ struct snd_ctl_elem_value32 __user *data32)
{
- struct sndrv_ctl_elem_value *data;
+ struct snd_ctl_elem_value *data;
int err, type, count;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -277,40 +296,51 @@ static int snd_ctl_elem_read_user_compat(snd_card_t *card,
if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
goto error;
- if ((err = snd_ctl_elem_read(card, data)) < 0)
- goto error;
- err = copy_ctl_value_to_user(data32, data, type, count);
+
+ snd_power_lock(card);
+ err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+ if (err >= 0)
+ err = snd_ctl_elem_read(card, data);
+ snd_power_unlock(card);
+ if (err >= 0)
+ err = copy_ctl_value_to_user(data32, data, type, count);
error:
kfree(data);
return err;
}
-static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file,
- struct sndrv_ctl_elem_value32 __user *data32)
+static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
+ struct snd_ctl_elem_value32 __user *data32)
{
- struct sndrv_ctl_elem_value *data;
+ struct snd_ctl_elem_value *data;
+ struct snd_card *card = file->card;
int err, type, count;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
- if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0)
- goto error;
- if ((err = snd_ctl_elem_write(file->card, file, data)) < 0)
+ if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
goto error;
- err = copy_ctl_value_to_user(data32, data, type, count);
+
+ snd_power_lock(card);
+ err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+ if (err >= 0)
+ err = snd_ctl_elem_write(card, file, data);
+ snd_power_unlock(card);
+ if (err >= 0)
+ err = copy_ctl_value_to_user(data32, data, type, count);
error:
kfree(data);
return err;
}
/* add or replace a user control */
-static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
- struct sndrv_ctl_elem_info32 __user *data32,
+static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
+ struct snd_ctl_elem_info32 __user *data32,
int replace)
{
- struct sndrv_ctl_elem_info *data;
+ struct snd_ctl_elem_info *data;
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -344,6 +374,8 @@ static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
&data32->value.enumerated,
sizeof(data->value.enumerated)))
goto error;
+ data->value.enumerated.names_ptr =
+ (uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break;
default:
break;
@@ -355,23 +387,24 @@ static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
}
enum {
- SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
- SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
- SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
- SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
- SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32),
- SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32),
+ SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
+ SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32),
+ SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32),
+ SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
+ SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
+ SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
};
static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_ctl_file_t *ctl;
- struct list_head *list;
+ struct snd_ctl_file *ctl;
+ struct snd_kctl_ioctl *p;
void __user *argp = compat_ptr(arg);
int err;
ctl = file->private_data;
- snd_assert(ctl && ctl->card, return -ENXIO);
+ if (snd_BUG_ON(!ctl || !ctl->card))
+ return -ENXIO;
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
@@ -381,6 +414,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
case SNDRV_CTL_IOCTL_POWER_STATE:
case SNDRV_CTL_IOCTL_ELEM_LOCK:
case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
+ case SNDRV_CTL_IOCTL_ELEM_REMOVE:
+ case SNDRV_CTL_IOCTL_TLV_READ:
+ case SNDRV_CTL_IOCTL_TLV_WRITE:
+ case SNDRV_CTL_IOCTL_TLV_COMMAND:
return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_CTL_IOCTL_ELEM_LIST32:
return snd_ctl_elem_list_compat(ctl->card, argp);
@@ -397,8 +434,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
}
down_read(&snd_ioctl_rwsem);
- list_for_each(list, &snd_control_compat_ioctls) {
- snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list);
+ list_for_each_entry(p, &snd_control_compat_ioctls, list) {
if (p->fioctl) {
err = p->fioctl(ctl->card, ctl, cmd, arg);
if (err != -ENOIOCTLCMD) {
diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c
new file mode 100644
index 00000000000..e4b38fbe51d
--- /dev/null
+++ b/sound/core/ctljack.c
@@ -0,0 +1,56 @@
+/*
+ * Helper functions for jack-detection kcontrols
+ *
+ * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#define jack_detect_kctl_info snd_ctl_boolean_mono_info
+
+static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = kcontrol->private_value;
+ return 0;
+}
+
+static struct snd_kcontrol_new jack_detect_kctl = {
+ /* name is filled later */
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = jack_detect_kctl_info,
+ .get = jack_detect_kctl_get,
+};
+
+struct snd_kcontrol *
+snd_kctl_jack_new(const char *name, int idx, void *private_data)
+{
+ struct snd_kcontrol *kctl;
+ kctl = snd_ctl_new1(&jack_detect_kctl, private_data);
+ if (!kctl)
+ return NULL;
+ snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name);
+ kctl->id.index = idx;
+ kctl->private_value = 0;
+ return kctl;
+}
+EXPORT_SYMBOL_GPL(snd_kctl_jack_new);
+
+void snd_kctl_jack_report(struct snd_card *card,
+ struct snd_kcontrol *kctl, bool status)
+{
+ if (kctl->private_value == status)
+ return;
+ kctl->private_value = status;
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+}
+EXPORT_SYMBOL_GPL(snd_kctl_jack_report);
diff --git a/sound/core/device.c b/sound/core/device.c
index 1f509f56e60..41bec3075ae 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -1,6 +1,6 @@
/*
* Device management routines
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/export.h>
#include <linux/errno.h>
#include <sound/core.h>
@@ -39,103 +39,110 @@
* The data pointer plays a role as the identifier, too, so the
* pointer address must be unique and unchanged.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_device_new(snd_card_t *card, snd_device_type_t type,
- void *device_data, snd_device_ops_t *ops)
+int snd_device_new(struct snd_card *card, enum snd_device_type type,
+ void *device_data, struct snd_device_ops *ops)
{
- snd_device_t *dev;
+ struct snd_device *dev;
+ struct list_head *p;
- snd_assert(card != NULL, return -ENXIO);
- snd_assert(device_data != NULL, return -ENXIO);
- snd_assert(ops != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card || !device_data || !ops))
+ return -ENXIO;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL)
+ if (dev == NULL) {
+ dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&dev->list);
dev->card = card;
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data;
dev->ops = ops;
- list_add(&dev->list, &card->devices); /* add to the head of list */
+
+ /* insert the entry in an incrementally sorted list */
+ list_for_each_prev(p, &card->devices) {
+ struct snd_device *pdev = list_entry(p, struct snd_device, list);
+ if ((unsigned int)pdev->type <= (unsigned int)type)
+ break;
+ }
+
+ list_add(&dev->list, p);
+ return 0;
+}
+EXPORT_SYMBOL(snd_device_new);
+
+static int __snd_device_disconnect(struct snd_device *dev)
+{
+ if (dev->state == SNDRV_DEV_REGISTERED) {
+ if (dev->ops->dev_disconnect &&
+ dev->ops->dev_disconnect(dev))
+ dev_err(dev->card->dev, "device disconnect failure\n");
+ dev->state = SNDRV_DEV_DISCONNECTED;
+ }
return 0;
}
+static void __snd_device_free(struct snd_device *dev)
+{
+ /* unlink */
+ list_del(&dev->list);
+
+ __snd_device_disconnect(dev);
+ if (dev->ops->dev_free) {
+ if (dev->ops->dev_free(dev))
+ dev_err(dev->card->dev, "device free failure\n");
+ }
+ kfree(dev);
+}
+
+static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
+{
+ struct snd_device *dev;
+
+ list_for_each_entry(dev, &card->devices, list)
+ if (dev->device_data == device_data)
+ return dev;
+
+ return NULL;
+}
+
/**
* snd_device_free - release the device from the card
* @card: the card instance
* @device_data: the data pointer to release
*
* Removes the device from the list on the card and invokes the
- * callback, dev_unregister or dev_free, corresponding to the state.
+ * callbacks, dev_disconnect and dev_free, corresponding to the state.
* Then release the device.
- *
- * Returns zero if successful, or a negative error code on failure or if the
- * device not found.
*/
-int snd_device_free(snd_card_t *card, void *device_data)
+void snd_device_free(struct snd_card *card, void *device_data)
{
- struct list_head *list;
- snd_device_t *dev;
+ struct snd_device *dev;
- snd_assert(card != NULL, return -ENXIO);
- snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->device_data != device_data)
- continue;
- /* unlink */
- list_del(&dev->list);
- if ((dev->state == SNDRV_DEV_REGISTERED || dev->state == SNDRV_DEV_DISCONNECTED) &&
- dev->ops->dev_unregister) {
- if (dev->ops->dev_unregister(dev))
- snd_printk(KERN_ERR "device unregister failure\n");
- } else {
- if (dev->ops->dev_free) {
- if (dev->ops->dev_free(dev))
- snd_printk(KERN_ERR "device free failure\n");
- }
- }
- kfree(dev);
- return 0;
- }
- snd_printd("device free %p (from %p), not found\n", device_data, __builtin_return_address(0));
- return -ENXIO;
+ if (snd_BUG_ON(!card || !device_data))
+ return;
+ dev = look_for_dev(card, device_data);
+ if (dev)
+ __snd_device_free(dev);
+ else
+ dev_dbg(card->dev, "device free %p (from %pF), not found\n",
+ device_data, __builtin_return_address(0));
}
+EXPORT_SYMBOL(snd_device_free);
-/**
- * snd_device_disconnect - disconnect the device
- * @card: the card instance
- * @device_data: the data pointer to disconnect
- *
- * Turns the device into the disconnection state, invoking
- * dev_disconnect callback, if the device was already registered.
- *
- * Usually called from snd_card_disconnect().
- *
- * Returns zero if successful, or a negative error code on failure or if the
- * device not found.
- */
-int snd_device_disconnect(snd_card_t *card, void *device_data)
+static int __snd_device_register(struct snd_device *dev)
{
- struct list_head *list;
- snd_device_t *dev;
-
- snd_assert(card != NULL, return -ENXIO);
- snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->device_data != device_data)
- continue;
- if (dev->state == SNDRV_DEV_REGISTERED && dev->ops->dev_disconnect) {
- if (dev->ops->dev_disconnect(dev))
- snd_printk(KERN_ERR "device disconnect failure\n");
- dev->state = SNDRV_DEV_DISCONNECTED;
+ if (dev->state == SNDRV_DEV_BUILD) {
+ if (dev->ops->dev_register) {
+ int err = dev->ops->dev_register(dev);
+ if (err < 0)
+ return err;
}
- return 0;
+ dev->state = SNDRV_DEV_REGISTERED;
}
- snd_printd("device disconnect %p (from %p), not found\n", device_data, __builtin_return_address(0));
- return -ENXIO;
+ return 0;
}
/**
@@ -148,51 +155,38 @@ int snd_device_disconnect(snd_card_t *card, void *device_data)
* but it can be called later if any new devices are created after
* invocation of snd_card_register().
*
- * Returns zero if successful, or a negative error code on failure or if the
+ * Return: Zero if successful, or a negative error code on failure or if the
* device not found.
*/
-int snd_device_register(snd_card_t *card, void *device_data)
+int snd_device_register(struct snd_card *card, void *device_data)
{
- struct list_head *list;
- snd_device_t *dev;
- int err;
+ struct snd_device *dev;
- snd_assert(card != NULL, return -ENXIO);
- snd_assert(device_data != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->device_data != device_data)
- continue;
- if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
- if ((err = dev->ops->dev_register(dev)) < 0)
- return err;
- dev->state = SNDRV_DEV_REGISTERED;
- return 0;
- }
- return -EBUSY;
- }
+ if (snd_BUG_ON(!card || !device_data))
+ return -ENXIO;
+ dev = look_for_dev(card, device_data);
+ if (dev)
+ return __snd_device_register(dev);
snd_BUG();
return -ENXIO;
}
+EXPORT_SYMBOL(snd_device_register);
/*
* register all the devices on the card.
* called from init.c
*/
-int snd_device_register_all(snd_card_t *card)
+int snd_device_register_all(struct snd_card *card)
{
- struct list_head *list;
- snd_device_t *dev;
+ struct snd_device *dev;
int err;
- snd_assert(card != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
- if ((err = dev->ops->dev_register(dev)) < 0)
- return err;
- dev->state = SNDRV_DEV_REGISTERED;
- }
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ list_for_each_entry(dev, &card->devices, list) {
+ err = __snd_device_register(dev);
+ if (err < 0)
+ return err;
}
return 0;
}
@@ -201,16 +195,15 @@ int snd_device_register_all(snd_card_t *card)
* disconnect all the devices on the card.
* called from init.c
*/
-int snd_device_disconnect_all(snd_card_t *card)
+int snd_device_disconnect_all(struct snd_card *card)
{
- snd_device_t *dev;
- struct list_head *list;
+ struct snd_device *dev;
int err = 0;
- snd_assert(card != NULL, return -ENXIO);
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (snd_device_disconnect(card, dev->device_data) < 0)
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ list_for_each_entry_reverse(dev, &card->devices, list) {
+ if (__snd_device_disconnect(dev) < 0)
err = -ENXIO;
}
return err;
@@ -220,24 +213,12 @@ int snd_device_disconnect_all(snd_card_t *card)
* release all the devices on the card.
* called from init.c
*/
-int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd)
+void snd_device_free_all(struct snd_card *card)
{
- snd_device_t *dev;
- struct list_head *list;
- int err;
- unsigned int range_low, range_high;
-
- snd_assert(card != NULL, return -ENXIO);
- range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
- range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
- __again:
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->type >= range_low && dev->type <= range_high) {
- if ((err = snd_device_free(card, dev->device_data)) < 0)
- return err;
- goto __again;
- }
- }
- return 0;
+ struct snd_device *dev, *next;
+
+ if (snd_BUG_ON(!card))
+ return;
+ list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
+ __snd_device_free(dev);
}
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
new file mode 100644
index 00000000000..886be7da989
--- /dev/null
+++ b/sound/core/hrtimer.c
@@ -0,0 +1,166 @@
+/*
+ * ALSA timer back-end using hrtimer
+ * Copyright (C) 2008 Takashi Iwai
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/hrtimer.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ALSA hrtimer backend");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
+
+#define NANO_SEC 1000000000UL /* 10^9 in sec */
+static unsigned int resolution;
+
+struct snd_hrtimer {
+ struct snd_timer *timer;
+ struct hrtimer hrt;
+ atomic_t running;
+};
+
+static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
+ struct snd_timer *t = stime->timer;
+ unsigned long oruns;
+
+ if (!atomic_read(&stime->running))
+ return HRTIMER_NORESTART;
+
+ oruns = hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
+ snd_timer_interrupt(stime->timer, t->sticks * oruns);
+
+ if (!atomic_read(&stime->running))
+ return HRTIMER_NORESTART;
+ return HRTIMER_RESTART;
+}
+
+static int snd_hrtimer_open(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime;
+
+ stime = kmalloc(sizeof(*stime), GFP_KERNEL);
+ if (!stime)
+ return -ENOMEM;
+ hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ stime->timer = t;
+ stime->hrt.function = snd_hrtimer_callback;
+ atomic_set(&stime->running, 0);
+ t->private_data = stime;
+ return 0;
+}
+
+static int snd_hrtimer_close(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+
+ if (stime) {
+ hrtimer_cancel(&stime->hrt);
+ kfree(stime);
+ t->private_data = NULL;
+ }
+ return 0;
+}
+
+static int snd_hrtimer_start(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+
+ atomic_set(&stime->running, 0);
+ hrtimer_cancel(&stime->hrt);
+ hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
+ HRTIMER_MODE_REL);
+ atomic_set(&stime->running, 1);
+ return 0;
+}
+
+static int snd_hrtimer_stop(struct snd_timer *t)
+{
+ struct snd_hrtimer *stime = t->private_data;
+ atomic_set(&stime->running, 0);
+ return 0;
+}
+
+static struct snd_timer_hardware hrtimer_hw = {
+ .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
+ .open = snd_hrtimer_open,
+ .close = snd_hrtimer_close,
+ .start = snd_hrtimer_start,
+ .stop = snd_hrtimer_stop,
+};
+
+/*
+ * entry functions
+ */
+
+static struct snd_timer *mytimer;
+
+static int __init snd_hrtimer_init(void)
+{
+ struct snd_timer *timer;
+ struct timespec tp;
+ int err;
+
+ hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+ if (tp.tv_sec > 0 || !tp.tv_nsec) {
+ pr_err("snd-hrtimer: Invalid resolution %u.%09u",
+ (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
+ return -EINVAL;
+ }
+ resolution = tp.tv_nsec;
+
+ /* Create a new timer and set up the fields */
+ err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
+ &timer);
+ if (err < 0)
+ return err;
+
+ timer->module = THIS_MODULE;
+ strcpy(timer->name, "HR timer");
+ timer->hw = hrtimer_hw;
+ timer->hw.resolution = resolution;
+ timer->hw.ticks = NANO_SEC / resolution;
+
+ err = snd_timer_global_register(timer);
+ if (err < 0) {
+ snd_timer_global_free(timer);
+ return err;
+ }
+ mytimer = timer; /* remember this */
+
+ return 0;
+}
+
+static void __exit snd_hrtimer_exit(void)
+{
+ if (mytimer) {
+ snd_timer_global_free(mytimer);
+ mytimer = NULL;
+ }
+}
+
+module_init(snd_hrtimer_init);
+module_exit(snd_hrtimer_exit);
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 9383f1294fb..69459e5f712 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -1,6 +1,6 @@
/*
* Hardware dependent layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,54 +19,62 @@
*
*/
-#include <sound/driver.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/hwdep.h>
#include <sound/info.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Hardware dependent layer");
MODULE_LICENSE("GPL");
-static snd_hwdep_t *snd_hwdep_devices[SNDRV_CARDS * SNDRV_MINOR_HWDEPS];
+static LIST_HEAD(snd_hwdep_devices);
+static DEFINE_MUTEX(register_mutex);
-static DECLARE_MUTEX(register_mutex);
+static int snd_hwdep_free(struct snd_hwdep *hwdep);
+static int snd_hwdep_dev_free(struct snd_device *device);
+static int snd_hwdep_dev_register(struct snd_device *device);
+static int snd_hwdep_dev_disconnect(struct snd_device *device);
-static int snd_hwdep_free(snd_hwdep_t *hwdep);
-static int snd_hwdep_dev_free(snd_device_t *device);
-static int snd_hwdep_dev_register(snd_device_t *device);
-static int snd_hwdep_dev_unregister(snd_device_t *device);
-/*
+static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
+{
+ struct snd_hwdep *hwdep;
- */
+ list_for_each_entry(hwdep, &snd_hwdep_devices, list)
+ if (hwdep->card == card && hwdep->device == device)
+ return hwdep;
+ return NULL;
+}
static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
if (hw->ops.llseek)
return hw->ops.llseek(hw, file, offset, orig);
return -ENXIO;
}
-static ssize_t snd_hwdep_read(struct file * file, char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_hwdep_read(struct file * file, char __user *buf,
+ size_t count, loff_t *offset)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
if (hw->ops.read)
return hw->ops.read(hw, buf, count, offset);
return -ENXIO;
}
-static ssize_t snd_hwdep_write(struct file * file, const char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_hwdep_write(struct file * file, const char __user *buf,
+ size_t count, loff_t *offset)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
if (hw->ops.write)
return hw->ops.write(hw, buf, count, offset);
return -ENXIO;
@@ -75,50 +83,40 @@ static ssize_t snd_hwdep_write(struct file * file, const char __user *buf, size_
static int snd_hwdep_open(struct inode *inode, struct file * file)
{
int major = imajor(inode);
- int cardnum;
- int device;
- snd_hwdep_t *hw;
+ struct snd_hwdep *hw;
int err;
wait_queue_t wait;
- switch (major) {
- case CONFIG_SND_MAJOR:
- cardnum = SNDRV_MINOR_CARD(iminor(inode));
- device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_HWDEP;
- break;
+ if (major == snd_major) {
+ hw = snd_lookup_minor_data(iminor(inode),
+ SNDRV_DEVICE_TYPE_HWDEP);
#ifdef CONFIG_SND_OSSEMUL
- case SOUND_MAJOR:
- cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
- device = 0;
- break;
+ } else if (major == SOUND_MAJOR) {
+ hw = snd_lookup_oss_minor_data(iminor(inode),
+ SNDRV_OSS_DEVICE_TYPE_DMFM);
#endif
- default:
+ } else
return -ENXIO;
- }
- cardnum %= SNDRV_CARDS;
- device %= SNDRV_MINOR_HWDEPS;
- hw = snd_hwdep_devices[(cardnum * SNDRV_MINOR_HWDEPS) + device];
if (hw == NULL)
return -ENODEV;
- if (!hw->ops.open)
- return -ENXIO;
-#ifdef CONFIG_SND_OSSEMUL
- if (major == SOUND_MAJOR && hw->oss_type < 0)
- return -ENXIO;
-#endif
-
- if (!try_module_get(hw->card->module))
+ if (!try_module_get(hw->card->module)) {
+ snd_card_unref(hw->card);
return -EFAULT;
+ }
init_waitqueue_entry(&wait, current);
add_wait_queue(&hw->open_wait, &wait);
- down(&hw->open_mutex);
+ mutex_lock(&hw->open_mutex);
while (1) {
if (hw->exclusive && hw->used > 0) {
err = -EBUSY;
break;
}
+ if (!hw->ops.open) {
+ err = 0;
+ break;
+ }
err = hw->ops.open(hw, file);
if (err >= 0)
break;
@@ -130,9 +128,13 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
} else
break;
set_current_state(TASK_INTERRUPTIBLE);
- up(&hw->open_mutex);
+ mutex_unlock(&hw->open_mutex);
schedule();
- down(&hw->open_mutex);
+ mutex_lock(&hw->open_mutex);
+ if (hw->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -149,40 +151,44 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
hw->ops.release(hw, file);
}
}
- up(&hw->open_mutex);
+ mutex_unlock(&hw->open_mutex);
if (err < 0)
module_put(hw->card->module);
+ snd_card_unref(hw->card);
return err;
}
static int snd_hwdep_release(struct inode *inode, struct file * file)
{
- int err = -ENXIO;
- snd_hwdep_t *hw = file->private_data;
- down(&hw->open_mutex);
- if (hw->ops.release) {
+ int err = 0;
+ struct snd_hwdep *hw = file->private_data;
+ struct module *mod = hw->card->module;
+
+ mutex_lock(&hw->open_mutex);
+ if (hw->ops.release)
err = hw->ops.release(hw, file);
- wake_up(&hw->open_wait);
- }
if (hw->used > 0)
hw->used--;
+ mutex_unlock(&hw->open_mutex);
+ wake_up(&hw->open_wait);
+
snd_card_file_remove(hw->card, file);
- up(&hw->open_mutex);
- module_put(hw->card->module);
+ module_put(mod);
return err;
}
static unsigned int snd_hwdep_poll(struct file * file, poll_table * wait)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
if (hw->ops.poll)
return hw->ops.poll(hw, file, wait);
return 0;
}
-static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t __user *_info)
+static int snd_hwdep_info(struct snd_hwdep *hw,
+ struct snd_hwdep_info __user *_info)
{
- snd_hwdep_info_t info;
+ struct snd_hwdep_info info;
memset(&info, 0, sizeof(info));
info.card = hw->card->number;
@@ -194,9 +200,10 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t __user *_info)
return 0;
}
-static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t __user *_info)
+static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
+ struct snd_hwdep_dsp_status __user *_info)
{
- snd_hwdep_dsp_status_t info;
+ struct snd_hwdep_dsp_status info;
int err;
if (! hw->ops.dsp_status)
@@ -210,9 +217,10 @@ static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t __user *
return 0;
}
-static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_info)
+static int snd_hwdep_dsp_load(struct snd_hwdep *hw,
+ struct snd_hwdep_dsp_image __user *_info)
{
- snd_hwdep_dsp_image_t info;
+ struct snd_hwdep_dsp_image info;
int err;
if (! hw->ops.dsp_load)
@@ -232,9 +240,10 @@ static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_in
return 0;
}
-static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
+static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
+ unsigned long arg)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
void __user *argp = (void __user *)arg;
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
@@ -253,18 +262,16 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long
static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
if (hw->ops.mmap)
return hw->ops.mmap(hw, file, vma);
return -ENXIO;
}
-static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
+static int snd_hwdep_control_ioctl(struct snd_card *card,
+ struct snd_ctl_file * control,
unsigned int cmd, unsigned long arg)
{
- unsigned int tmp;
-
- tmp = card->number * SNDRV_MINOR_HWDEPS;
switch (cmd) {
case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE:
{
@@ -272,32 +279,43 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
if (get_user(device, (int __user *)arg))
return -EFAULT;
- device = device < 0 ? 0 : device + 1;
+ mutex_lock(&register_mutex);
+
+ if (device < 0)
+ device = 0;
+ else if (device < SNDRV_MINOR_HWDEPS)
+ device++;
+ else
+ device = SNDRV_MINOR_HWDEPS;
+
while (device < SNDRV_MINOR_HWDEPS) {
- if (snd_hwdep_devices[tmp + device])
+ if (snd_hwdep_search(card, device))
break;
device++;
}
if (device >= SNDRV_MINOR_HWDEPS)
device = -1;
+ mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
}
case SNDRV_CTL_IOCTL_HWDEP_INFO:
{
- snd_hwdep_info_t __user *info = (snd_hwdep_info_t __user *)arg;
- int device;
- snd_hwdep_t *hwdep;
+ struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
+ int device, err;
+ struct snd_hwdep *hwdep;
if (get_user(device, &info->device))
return -EFAULT;
- if (device < 0 || device >= SNDRV_MINOR_HWDEPS)
- return -ENXIO;
- hwdep = snd_hwdep_devices[tmp + device];
- if (hwdep == NULL)
- return -ENXIO;
- return snd_hwdep_info(hwdep, info);
+ mutex_lock(&register_mutex);
+ hwdep = snd_hwdep_search(card, device);
+ if (hwdep)
+ err = snd_hwdep_info(hwdep, info);
+ else
+ err = -ENXIO;
+ mutex_unlock(&register_mutex);
+ return err;
}
}
return -ENOIOCTLCMD;
@@ -313,7 +331,7 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
*/
-static struct file_operations snd_hwdep_f_ops =
+static const struct file_operations snd_hwdep_f_ops =
{
.owner = THIS_MODULE,
.llseek = snd_hwdep_llseek,
@@ -327,12 +345,6 @@ static struct file_operations snd_hwdep_f_ops =
.mmap = snd_hwdep_mmap,
};
-static snd_minor_t snd_hwdep_reg =
-{
- .comment = "hardware dependent",
- .f_ops = &snd_hwdep_f_ops,
-};
-
/**
* snd_hwdep_new - create a new hwdep instance
* @card: the card instance
@@ -344,29 +356,32 @@ static snd_minor_t snd_hwdep_reg =
* The callbacks (hwdep->ops) must be set on the returned instance
* after this call manually by the caller.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep)
+int snd_hwdep_new(struct snd_card *card, char *id, int device,
+ struct snd_hwdep **rhwdep)
{
- snd_hwdep_t *hwdep;
+ struct snd_hwdep *hwdep;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_hwdep_dev_free,
.dev_register = snd_hwdep_dev_register,
- .dev_unregister = snd_hwdep_dev_unregister
+ .dev_disconnect = snd_hwdep_dev_disconnect,
};
- snd_assert(rhwdep != NULL, return -EINVAL);
- *rhwdep = NULL;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ if (rhwdep)
+ *rhwdep = NULL;
hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
- if (hwdep == NULL)
+ if (hwdep == NULL) {
+ dev_err(card->dev, "hwdep: cannot allocate\n");
return -ENOMEM;
+ }
hwdep->card = card;
hwdep->device = device;
- if (id) {
+ if (id)
strlcpy(hwdep->id, id, sizeof(hwdep->id));
- }
#ifdef CONFIG_SND_OSSEMUL
hwdep->oss_type = -1;
#endif
@@ -375,127 +390,144 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep
return err;
}
init_waitqueue_head(&hwdep->open_wait);
- init_MUTEX(&hwdep->open_mutex);
- *rhwdep = hwdep;
+ mutex_init(&hwdep->open_mutex);
+ if (rhwdep)
+ *rhwdep = hwdep;
return 0;
}
+EXPORT_SYMBOL(snd_hwdep_new);
-static int snd_hwdep_free(snd_hwdep_t *hwdep)
+static int snd_hwdep_free(struct snd_hwdep *hwdep)
{
- snd_assert(hwdep != NULL, return -ENXIO);
+ if (!hwdep)
+ return 0;
if (hwdep->private_free)
hwdep->private_free(hwdep);
kfree(hwdep);
return 0;
}
-static int snd_hwdep_dev_free(snd_device_t *device)
+static int snd_hwdep_dev_free(struct snd_device *device)
{
- snd_hwdep_t *hwdep = device->device_data;
+ struct snd_hwdep *hwdep = device->device_data;
return snd_hwdep_free(hwdep);
}
-static int snd_hwdep_dev_register(snd_device_t *device)
+static int snd_hwdep_dev_register(struct snd_device *device)
{
- snd_hwdep_t *hwdep = device->device_data;
- int idx, err;
+ struct snd_hwdep *hwdep = device->device_data;
+ struct snd_card *card = hwdep->card;
+ struct device *dev;
+ int err;
char name[32];
- down(&register_mutex);
- idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device;
- if (snd_hwdep_devices[idx]) {
- up(&register_mutex);
+ mutex_lock(&register_mutex);
+ if (snd_hwdep_search(card, hwdep->device)) {
+ mutex_unlock(&register_mutex);
return -EBUSY;
}
- snd_hwdep_devices[idx] = hwdep;
+ list_add_tail(&hwdep->list, &snd_hwdep_devices);
sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
- hwdep->card, hwdep->device,
- &snd_hwdep_reg, name)) < 0) {
- snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
- hwdep->card->number, hwdep->device);
- snd_hwdep_devices[idx] = NULL;
- up(&register_mutex);
+ dev = hwdep->dev;
+ if (!dev)
+ dev = snd_card_get_device_link(hwdep->card);
+ err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
+ hwdep->card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep, name, dev);
+ if (err < 0) {
+ dev_err(dev,
+ "unable to register hardware dependent device %i:%i\n",
+ card->number, hwdep->device);
+ list_del(&hwdep->list);
+ mutex_unlock(&register_mutex);
return err;
}
+
+ if (hwdep->groups) {
+ struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
+ hwdep->card, hwdep->device);
+ if (d) {
+ if (hwdep->private_data)
+ dev_set_drvdata(d, hwdep->private_data);
+ err = sysfs_create_groups(&d->kobj, hwdep->groups);
+ if (err < 0)
+ dev_warn(dev,
+ "hwdep %d:%d: cannot create sysfs groups\n",
+ card->number, hwdep->device);
+ put_device(d);
+ }
+ }
+
#ifdef CONFIG_SND_OSSEMUL
hwdep->ossreg = 0;
if (hwdep->oss_type >= 0) {
if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
- snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n");
+ dev_warn(dev,
+ "only hwdep device 0 can be registered as OSS direct FM device!\n");
} else {
if (snd_register_oss_device(hwdep->oss_type,
- hwdep->card, hwdep->device,
- &snd_hwdep_reg, hwdep->oss_dev) < 0) {
- snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n",
- hwdep->card->number, hwdep->device);
+ card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep) < 0) {
+ dev_err(dev,
+ "unable to register OSS compatibility device %i:%i\n",
+ card->number, hwdep->device);
} else
hwdep->ossreg = 1;
}
}
#endif
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
-static int snd_hwdep_dev_unregister(snd_device_t *device)
+static int snd_hwdep_dev_disconnect(struct snd_device *device)
{
- snd_hwdep_t *hwdep = device->device_data;
- int idx;
-
- snd_assert(hwdep != NULL, return -ENXIO);
- down(&register_mutex);
- idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device;
- if (snd_hwdep_devices[idx] != hwdep) {
- up(&register_mutex);
+ struct snd_hwdep *hwdep = device->device_data;
+
+ if (snd_BUG_ON(!hwdep))
+ return -ENXIO;
+ mutex_lock(&register_mutex);
+ if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
+ mutex_unlock(&register_mutex);
return -EINVAL;
}
+ mutex_lock(&hwdep->open_mutex);
+ wake_up(&hwdep->open_wait);
#ifdef CONFIG_SND_OSSEMUL
if (hwdep->ossreg)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
- snd_hwdep_devices[idx] = NULL;
- up(&register_mutex);
- return snd_hwdep_free(hwdep);
+ list_del_init(&hwdep->list);
+ mutex_unlock(&hwdep->open_mutex);
+ mutex_unlock(&register_mutex);
+ return 0;
}
+#ifdef CONFIG_PROC_FS
/*
* Info interface
*/
-static void snd_hwdep_proc_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_hwdep_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- int idx;
- snd_hwdep_t *hwdep;
-
- down(&register_mutex);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_MINOR_HWDEPS; idx++) {
- hwdep = snd_hwdep_devices[idx];
- if (hwdep == NULL)
- continue;
+ struct snd_hwdep *hwdep;
+
+ mutex_lock(&register_mutex);
+ list_for_each_entry(hwdep, &snd_hwdep_devices, list)
snd_iprintf(buffer, "%02i-%02i: %s\n",
- idx / SNDRV_MINOR_HWDEPS,
- idx % SNDRV_MINOR_HWDEPS,
- hwdep->name);
- }
- up(&register_mutex);
+ hwdep->card->number, hwdep->device, hwdep->name);
+ mutex_unlock(&register_mutex);
}
-/*
- * ENTRY functions
- */
-
-static snd_info_entry_t *snd_hwdep_proc_entry = NULL;
+static struct snd_info_entry *snd_hwdep_proc_entry;
-static int __init alsa_hwdep_init(void)
+static void __init snd_hwdep_proc_init(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
- memset(snd_hwdep_devices, 0, sizeof(snd_hwdep_devices));
if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
- entry->c.text.read_size = 512;
entry->c.text.read = snd_hwdep_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -503,6 +535,25 @@ static int __init alsa_hwdep_init(void)
}
}
snd_hwdep_proc_entry = entry;
+}
+
+static void __exit snd_hwdep_proc_done(void)
+{
+ snd_info_free_entry(snd_hwdep_proc_entry);
+}
+#else /* !CONFIG_PROC_FS */
+#define snd_hwdep_proc_init()
+#define snd_hwdep_proc_done()
+#endif /* CONFIG_PROC_FS */
+
+
+/*
+ * ENTRY functions
+ */
+
+static int __init alsa_hwdep_init(void)
+{
+ snd_hwdep_proc_init();
snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
return 0;
@@ -512,13 +563,8 @@ static void __exit alsa_hwdep_exit(void)
{
snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
- if (snd_hwdep_proc_entry) {
- snd_info_unregister(snd_hwdep_proc_entry);
- snd_hwdep_proc_entry = NULL;
- }
+ snd_hwdep_proc_done();
}
module_init(alsa_hwdep_init)
module_exit(alsa_hwdep_exit)
-
-EXPORT_SYMBOL(snd_hwdep_new);
diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
index 6866f423d4b..3827c0ceec8 100644
--- a/sound/core/hwdep_compat.c
+++ b/sound/core/hwdep_compat.c
@@ -22,7 +22,7 @@
#include <linux/compat.h>
-struct sndrv_hwdep_dsp_image32 {
+struct snd_hwdep_dsp_image32 {
u32 index;
unsigned char name[64];
u32 image; /* pointer */
@@ -30,10 +30,10 @@ struct sndrv_hwdep_dsp_image32 {
u32 driver_data;
} /* don't set packed attribute here */;
-static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
- struct sndrv_hwdep_dsp_image32 __user *src)
+static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw,
+ struct snd_hwdep_dsp_image32 __user *src)
{
- struct sndrv_hwdep_dsp_image *dst;
+ struct snd_hwdep_dsp_image __user *dst;
compat_caddr_t ptr;
u32 val;
@@ -56,12 +56,13 @@ static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
}
enum {
- SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
+ SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct snd_hwdep_dsp_image32)
};
-static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
+static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd,
+ unsigned long arg)
{
- snd_hwdep_t *hw = file->private_data;
+ struct snd_hwdep *hw = file->private_data;
void __user *argp = compat_ptr(arg);
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
diff --git a/sound/core/info.c b/sound/core/info.c
index 37024d68a26..051d55b0552 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -1,6 +1,6 @@
/*
* Information interface for ALSA driver
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,24 +19,26 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
+#include <linux/utsname.h>
#include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
#include <stdarg.h>
/*
*
*/
+#ifdef CONFIG_PROC_FS
+
int snd_info_check_reserved_words(const char *str)
{
static char *reserved[] =
@@ -66,20 +68,35 @@ int snd_info_check_reserved_words(const char *str)
return 1;
}
-#ifdef CONFIG_PROC_FS
+static DEFINE_MUTEX(info_mutex);
-static DECLARE_MUTEX(info_mutex);
-
-typedef struct _snd_info_private_data {
- snd_info_buffer_t *rbuffer;
- snd_info_buffer_t *wbuffer;
- snd_info_entry_t *entry;
+struct snd_info_private_data {
+ struct snd_info_buffer *rbuffer;
+ struct snd_info_buffer *wbuffer;
+ struct snd_info_entry *entry;
void *file_private_data;
-} snd_info_private_data_t;
+};
static int snd_info_version_init(void);
static int snd_info_version_done(void);
+static void snd_info_disconnect(struct snd_info_entry *entry);
+
+/* resize the proc r/w buffer */
+static int resize_info_buffer(struct snd_info_buffer *buffer,
+ unsigned int nsize)
+{
+ char *nbuf;
+
+ nsize = PAGE_ALIGN(nsize);
+ nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL | __GFP_ZERO);
+ if (! nbuf)
+ return -ENOMEM;
+
+ buffer->buffer = nbuf;
+ buffer->len = nsize;
+ return 0;
+}
/**
* snd_iprintf - printf on the procfs buffer
@@ -88,102 +105,111 @@ static int snd_info_version_done(void);
*
* Outputs the string on the procfs buffer just like printf().
*
- * Returns the size of output string.
+ * Return: The size of output string, or a negative error code.
*/
-int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...)
+int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
{
va_list args;
int len, res;
+ int err = 0;
+ might_sleep();
if (buffer->stop || buffer->error)
return 0;
len = buffer->len - buffer->size;
va_start(args, fmt);
- res = vsnprintf(buffer->curr, len, fmt, args);
- va_end(args);
- if (res >= len) {
- buffer->stop = 1;
- return 0;
+ for (;;) {
+ va_list ap;
+ va_copy(ap, args);
+ res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);
+ va_end(ap);
+ if (res < len)
+ break;
+ err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
+ if (err < 0)
+ break;
+ len = buffer->len - buffer->size;
}
+ va_end(args);
+
+ if (err < 0)
+ return err;
buffer->curr += res;
buffer->size += res;
return res;
}
+EXPORT_SYMBOL(snd_iprintf);
+
/*
*/
-static struct proc_dir_entry *snd_proc_root = NULL;
-snd_info_entry_t *snd_seq_root = NULL;
+static struct proc_dir_entry *snd_proc_root;
+struct snd_info_entry *snd_seq_root;
+EXPORT_SYMBOL(snd_seq_root);
+
#ifdef CONFIG_SND_OSSEMUL
-snd_info_entry_t *snd_oss_root = NULL;
+struct snd_info_entry *snd_oss_root;
#endif
-static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
-{
- de->owner = THIS_MODULE;
-}
-
-static void snd_remove_proc_entry(struct proc_dir_entry *parent,
- struct proc_dir_entry *de)
-{
- if (de)
- remove_proc_entry(de->name, parent);
-}
-
static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{
- snd_info_private_data_t *data;
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
- loff_t ret;
+ loff_t ret = -EINVAL, size;
data = file->private_data;
entry = data->entry;
- lock_kernel();
- switch (entry->content) {
- case SNDRV_INFO_CONTENT_TEXT:
- switch (orig) {
- case 0: /* SEEK_SET */
- file->f_pos = offset;
- ret = file->f_pos;
- goto out;
- case 1: /* SEEK_CUR */
- file->f_pos += offset;
- ret = file->f_pos;
- goto out;
- case 2: /* SEEK_END */
- default:
- ret = -EINVAL;
- goto out;
- }
+ mutex_lock(&entry->access);
+ if (entry->content == SNDRV_INFO_CONTENT_DATA &&
+ entry->c.ops->llseek) {
+ offset = entry->c.ops->llseek(entry,
+ data->file_private_data,
+ file, offset, orig);
+ goto out;
+ }
+ if (entry->content == SNDRV_INFO_CONTENT_DATA)
+ size = entry->size;
+ else
+ size = 0;
+ switch (orig) {
+ case SEEK_SET:
break;
- case SNDRV_INFO_CONTENT_DATA:
- if (entry->c.ops->llseek) {
- ret = entry->c.ops->llseek(entry,
- data->file_private_data,
- file, offset, orig);
+ case SEEK_CUR:
+ offset += file->f_pos;
+ break;
+ case SEEK_END:
+ if (!size)
goto out;
- }
+ offset += size;
break;
+ default:
+ goto out;
}
- ret = -ENXIO;
-out:
- unlock_kernel();
+ if (offset < 0)
+ goto out;
+ if (size && offset > size)
+ offset = size;
+ file->f_pos = offset;
+ ret = offset;
+ out:
+ mutex_unlock(&entry->access);
return ret;
}
static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
size_t count, loff_t * offset)
{
- snd_info_private_data_t *data;
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
- snd_info_buffer_t *buf;
+ struct snd_info_buffer *buf;
size_t size = 0;
loff_t pos;
data = file->private_data;
- snd_assert(data != NULL, return -ENXIO);
+ if (snd_BUG_ON(!data))
+ return -ENXIO;
pos = *offset;
if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
return -EIO;
@@ -203,10 +229,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
return -EFAULT;
break;
case SNDRV_INFO_CONTENT_DATA:
- if (entry->c.ops->read)
+ if (pos >= entry->size)
+ return 0;
+ if (entry->c.ops->read) {
+ size = entry->size - pos;
+ size = min(count, size);
size = entry->c.ops->read(entry,
data->file_private_data,
- file, buffer, count, pos);
+ file, buffer, size, pos);
+ }
break;
}
if ((ssize_t) size > 0)
@@ -217,14 +248,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
size_t count, loff_t * offset)
{
- snd_info_private_data_t *data;
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
- snd_info_buffer_t *buf;
- size_t size = 0;
+ struct snd_info_buffer *buf;
+ ssize_t size = 0;
loff_t pos;
data = file->private_data;
- snd_assert(data != NULL, return -ENXIO);
+ if (snd_BUG_ON(!data))
+ return -ENXIO;
entry = data->entry;
pos = *offset;
if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
@@ -236,20 +268,29 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
buf = data->wbuffer;
if (buf == NULL)
return -EIO;
- if (pos >= buf->len)
- return -ENOMEM;
- size = buf->len - pos;
- size = min(count, size);
- if (copy_from_user(buf->buffer + pos, buffer, size))
+ mutex_lock(&entry->access);
+ if (pos + count >= buf->len) {
+ if (resize_info_buffer(buf, pos + count)) {
+ mutex_unlock(&entry->access);
+ return -ENOMEM;
+ }
+ }
+ if (copy_from_user(buf->buffer + pos, buffer, count)) {
+ mutex_unlock(&entry->access);
return -EFAULT;
- if ((long)buf->size < pos + size)
- buf->size = pos + size;
+ }
+ buf->size = pos + count;
+ mutex_unlock(&entry->access);
+ size = count;
break;
case SNDRV_INFO_CONTENT_DATA:
- if (entry->c.ops->write)
+ if (entry->c.ops->write && count > 0) {
+ size_t maxsize = entry->size - pos;
+ count = min(count, maxsize);
size = entry->c.ops->write(entry,
data->file_private_data,
file, buffer, count, pos);
+ }
break;
}
if ((ssize_t) size > 0)
@@ -259,17 +300,15 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
static int snd_info_entry_open(struct inode *inode, struct file *file)
{
- snd_info_entry_t *entry;
- snd_info_private_data_t *data;
- snd_info_buffer_t *buffer;
- struct proc_dir_entry *p;
+ struct snd_info_entry *entry;
+ struct snd_info_private_data *data;
+ struct snd_info_buffer *buffer;
int mode, err;
- down(&info_mutex);
- p = PDE(inode);
- entry = p == NULL ? NULL : (snd_info_entry_t *)p->data;
- if (entry == NULL || entry->disconnected) {
- up(&info_mutex);
+ mutex_lock(&info_mutex);
+ entry = PDE_DATA(inode);
+ if (entry == NULL || ! entry->p) {
+ mutex_unlock(&info_mutex);
return -ENODEV;
}
if (!try_module_get(entry->module)) {
@@ -278,18 +317,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
}
mode = file->f_flags & O_ACCMODE;
if (mode == O_RDONLY || mode == O_RDWR) {
- if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
- !entry->c.text.read_size) ||
- (entry->content == SNDRV_INFO_CONTENT_DATA &&
+ if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
entry->c.ops->read == NULL)) {
err = -ENODEV;
goto __error;
}
}
if (mode == O_WRONLY || mode == O_RDWR) {
- if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
- !entry->c.text.write_size) ||
- (entry->content == SNDRV_INFO_CONTENT_DATA &&
+ if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
entry->c.ops->write == NULL)) {
err = -ENODEV;
goto __error;
@@ -305,49 +340,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
case SNDRV_INFO_CONTENT_TEXT:
if (mode == O_RDONLY || mode == O_RDWR) {
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (buffer == NULL) {
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->len = (entry->c.text.read_size +
- (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
- buffer->buffer = vmalloc(buffer->len);
- if (buffer->buffer == NULL) {
- kfree(buffer);
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->curr = buffer->buffer;
+ if (buffer == NULL)
+ goto __nomem;
data->rbuffer = buffer;
+ buffer->len = PAGE_SIZE;
+ buffer->buffer = kzalloc(buffer->len, GFP_KERNEL);
+ if (buffer->buffer == NULL)
+ goto __nomem;
}
if (mode == O_WRONLY || mode == O_RDWR) {
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (buffer == NULL) {
- if (mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
- kfree(data->rbuffer);
- }
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->len = (entry->c.text.write_size +
- (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
- buffer->buffer = vmalloc(buffer->len);
- if (buffer->buffer == NULL) {
- if (mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
- kfree(data->rbuffer);
- }
- kfree(buffer);
- kfree(data);
- err = -ENOMEM;
- goto __error;
- }
- buffer->curr = buffer->buffer;
+ if (buffer == NULL)
+ goto __nomem;
data->wbuffer = buffer;
+ buffer->len = PAGE_SIZE;
+ buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+ if (buffer->buffer == NULL)
+ goto __nomem;
}
break;
case SNDRV_INFO_CONTENT_DATA: /* data */
@@ -361,28 +370,39 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
break;
}
file->private_data = data;
- up(&info_mutex);
+ mutex_unlock(&info_mutex);
if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
(mode == O_RDONLY || mode == O_RDWR)) {
if (entry->c.text.read) {
- down(&entry->access);
+ mutex_lock(&entry->access);
entry->c.text.read(entry, data->rbuffer);
- up(&entry->access);
+ mutex_unlock(&entry->access);
}
}
return 0;
+ __nomem:
+ if (data->rbuffer) {
+ kfree(data->rbuffer->buffer);
+ kfree(data->rbuffer);
+ }
+ if (data->wbuffer) {
+ kfree(data->wbuffer->buffer);
+ kfree(data->wbuffer);
+ }
+ kfree(data);
+ err = -ENOMEM;
__error:
module_put(entry->module);
__error1:
- up(&info_mutex);
+ mutex_unlock(&info_mutex);
return err;
}
static int snd_info_entry_release(struct inode *inode, struct file *file)
{
- snd_info_entry_t *entry;
- snd_info_private_data_t *data;
+ struct snd_info_entry *entry;
+ struct snd_info_private_data *data;
int mode;
mode = file->f_flags & O_ACCMODE;
@@ -390,20 +410,25 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
entry = data->entry;
switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT:
- if (mode == O_RDONLY || mode == O_RDWR) {
- vfree(data->rbuffer->buffer);
+ if (data->rbuffer) {
+ kfree(data->rbuffer->buffer);
kfree(data->rbuffer);
}
- if (mode == O_WRONLY || mode == O_RDWR) {
+ if (data->wbuffer) {
if (entry->c.text.write) {
entry->c.text.write(entry, data->wbuffer);
if (data->wbuffer->error) {
- snd_printk(KERN_WARNING "data write error to %s (%i)\n",
- entry->name,
- data->wbuffer->error);
+ if (entry->card)
+ dev_warn(entry->card->dev, "info: data write error to %s (%i)\n",
+ entry->name,
+ data->wbuffer->error);
+ else
+ pr_warn("ALSA: info: data write error to %s (%i)\n",
+ entry->name,
+ data->wbuffer->error);
}
}
- vfree(data->wbuffer->buffer);
+ kfree(data->wbuffer->buffer);
kfree(data->wbuffer);
}
break;
@@ -420,7 +445,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait)
{
- snd_info_private_data_t *data;
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
unsigned int mask;
@@ -444,10 +469,10 @@ static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait)
return mask;
}
-static inline int _snd_info_entry_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- snd_info_private_data_t *data;
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
data = file->private_data;
@@ -465,21 +490,10 @@ static inline int _snd_info_entry_ioctl(struct inode *inode, struct file *file,
return -ENOTTY;
}
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_info_entry_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int err;
- unlock_kernel();
- err = _snd_info_entry_ioctl(inode, file, cmd, arg);
- lock_kernel();
- return err;
-}
-
static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
- snd_info_private_data_t *data;
+ struct inode *inode = file_inode(file);
+ struct snd_info_private_data *data;
struct snd_info_entry *entry;
data = file->private_data;
@@ -497,51 +511,30 @@ static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
return -ENXIO;
}
-static struct file_operations snd_info_entry_operations =
+static const struct file_operations snd_info_entry_operations =
{
- .owner = THIS_MODULE,
- .llseek = snd_info_entry_llseek,
- .read = snd_info_entry_read,
- .write = snd_info_entry_write,
- .poll = snd_info_entry_poll,
- .ioctl = snd_info_entry_ioctl,
- .mmap = snd_info_entry_mmap,
- .open = snd_info_entry_open,
- .release = snd_info_entry_release,
+ .owner = THIS_MODULE,
+ .llseek = snd_info_entry_llseek,
+ .read = snd_info_entry_read,
+ .write = snd_info_entry_write,
+ .poll = snd_info_entry_poll,
+ .unlocked_ioctl = snd_info_entry_ioctl,
+ .mmap = snd_info_entry_mmap,
+ .open = snd_info_entry_open,
+ .release = snd_info_entry_release,
};
-/**
- * snd_create_proc_entry - create a procfs entry
- * @name: the name of the proc file
- * @mode: the file permission bits, S_Ixxx
- * @parent: the parent proc-directory entry
- *
- * Creates a new proc file entry with the given name and permission
- * on the given directory.
- *
- * Returns the pointer of new instance or NULL on failure.
- */
-static struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode,
- struct proc_dir_entry *parent)
-{
- struct proc_dir_entry *p;
- p = create_proc_entry(name, mode, parent);
- if (p)
- snd_info_entry_prepare(p);
- return p;
-}
-
int __init snd_info_init(void)
{
struct proc_dir_entry *p;
- p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, &proc_root);
+ p = proc_mkdir("asound", NULL);
if (p == NULL)
return -ENOMEM;
snd_proc_root = p;
#ifdef CONFIG_SND_OSSEMUL
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
return -ENOMEM;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
@@ -552,9 +545,9 @@ int __init snd_info_init(void)
snd_oss_root = entry;
}
#endif
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
return -ENOMEM;
entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
@@ -566,7 +559,6 @@ int __init snd_info_init(void)
}
#endif
snd_info_version_init();
- snd_memory_info_init();
snd_minor_info_init();
snd_minor_info_oss_init();
snd_card_info_init();
@@ -578,18 +570,15 @@ int __exit snd_info_done(void)
snd_card_info_done();
snd_minor_info_oss_done();
snd_minor_info_done();
- snd_memory_info_done();
snd_info_version_done();
if (snd_proc_root) {
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
- if (snd_seq_root)
- snd_info_unregister(snd_seq_root);
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ snd_info_free_entry(snd_seq_root);
#endif
#ifdef CONFIG_SND_OSSEMUL
- if (snd_oss_root)
- snd_info_unregister(snd_oss_root);
+ snd_info_free_entry(snd_oss_root);
#endif
- snd_remove_proc_entry(&proc_root, snd_proc_root);
+ proc_remove(snd_proc_root);
}
return 0;
}
@@ -603,12 +592,13 @@ int __exit snd_info_done(void)
* create a card proc file
* called from init.c
*/
-int snd_info_card_create(snd_card_t * card)
+int snd_info_card_create(struct snd_card *card)
{
char str[8];
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
sprintf(str, "card%i", card->number);
if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
@@ -626,11 +616,12 @@ int snd_info_card_create(snd_card_t * card)
* register the card proc file
* called from init.c
*/
-int snd_info_card_register(snd_card_t * card)
+int snd_info_card_register(struct snd_card *card)
{
struct proc_dir_entry *p;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
if (!strcmp(card->id, card->proc_root->name))
return 0;
@@ -643,20 +634,48 @@ int snd_info_card_register(snd_card_t * card)
}
/*
- * de-register the card proc file
- * called from init.c
+ * called on card->id change
*/
-int snd_info_card_free(snd_card_t * card)
+void snd_info_card_id_change(struct snd_card *card)
{
- snd_assert(card != NULL, return -ENXIO);
+ mutex_lock(&info_mutex);
if (card->proc_root_link) {
- snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
+ proc_remove(card->proc_root_link);
card->proc_root_link = NULL;
}
- if (card->proc_root) {
- snd_info_unregister(card->proc_root);
- card->proc_root = NULL;
- }
+ if (strcmp(card->id, card->proc_root->name))
+ card->proc_root_link = proc_symlink(card->id,
+ snd_proc_root,
+ card->proc_root->name);
+ mutex_unlock(&info_mutex);
+}
+
+/*
+ * de-register the card proc file
+ * called from init.c
+ */
+void snd_info_card_disconnect(struct snd_card *card)
+{
+ if (!card)
+ return;
+ mutex_lock(&info_mutex);
+ proc_remove(card->proc_root_link);
+ card->proc_root_link = NULL;
+ if (card->proc_root)
+ snd_info_disconnect(card->proc_root);
+ mutex_unlock(&info_mutex);
+}
+
+/*
+ * release the card proc file resources
+ * called from init.c
+ */
+int snd_info_card_free(struct snd_card *card)
+{
+ if (!card)
+ return 0;
+ snd_info_free_entry(card->proc_root);
+ card->proc_root = NULL;
return 0;
}
@@ -669,38 +688,33 @@ int snd_info_card_free(snd_card_t * card)
*
* Reads one line from the buffer and stores the string.
*
- * Returns zero if successful, or 1 if error or EOF.
+ * Return: Zero if successful, or 1 if error or EOF.
*/
-int snd_info_get_line(snd_info_buffer_t * buffer, char *line, int len)
+int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
{
int c = -1;
+ if (snd_BUG_ON(!buffer || !buffer->buffer))
+ return 1;
if (len <= 0 || buffer->stop || buffer->error)
return 1;
- while (--len > 0) {
- c = *buffer->curr++;
- if (c == '\n') {
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
- buffer->stop = 1;
- }
- break;
- }
- *line++ = c;
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+ while (!buffer->stop) {
+ c = buffer->buffer[buffer->curr++];
+ if (buffer->curr >= buffer->size)
buffer->stop = 1;
+ if (c == '\n')
break;
- }
- }
- while (c != '\n' && !buffer->stop) {
- c = *buffer->curr++;
- if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
- buffer->stop = 1;
+ if (len) {
+ len--;
+ *line++ = c;
}
}
*line = '\0';
return 0;
}
+EXPORT_SYMBOL(snd_info_get_line);
+
/**
* snd_info_get_str - parse a string token
* @dest: the buffer to store the string token
@@ -710,10 +724,10 @@ int snd_info_get_line(snd_info_buffer_t * buffer, char *line, int len)
* Parses the original string and copy a token to the given
* string buffer.
*
- * Returns the updated pointer of the original string so that
+ * Return: The updated pointer of the original string so that
* it can be used for the next call.
*/
-char *snd_info_get_str(char *dest, char *src, int len)
+const char *snd_info_get_str(char *dest, const char *src, int len)
{
int c;
@@ -737,6 +751,8 @@ char *snd_info_get_str(char *dest, char *src, int len)
return src;
}
+EXPORT_SYMBOL(snd_info_get_str);
+
/**
* snd_info_create_entry - create an info entry
* @name: the proc file name
@@ -747,11 +763,11 @@ char *snd_info_get_str(char *dest, char *src, int len)
* Usually called from other functions such as
* snd_info_create_card_entry().
*
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
*/
-static snd_info_entry_t *snd_info_create_entry(const char *name)
+static struct snd_info_entry *snd_info_create_entry(const char *name)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL)
return NULL;
@@ -762,7 +778,9 @@ static snd_info_entry_t *snd_info_create_entry(const char *name)
}
entry->mode = S_IFREG | S_IRUGO;
entry->content = SNDRV_INFO_CONTENT_TEXT;
- init_MUTEX(&entry->access);
+ mutex_init(&entry->access);
+ INIT_LIST_HEAD(&entry->children);
+ INIT_LIST_HEAD(&entry->list);
return entry;
}
@@ -774,13 +792,13 @@ static snd_info_entry_t *snd_info_create_entry(const char *name)
*
* Creates a new info entry and assigns it to the given module.
*
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
*/
-snd_info_entry_t *snd_info_create_module_entry(struct module * module,
+struct snd_info_entry *snd_info_create_module_entry(struct module * module,
const char *name,
- snd_info_entry_t *parent)
+ struct snd_info_entry *parent)
{
- snd_info_entry_t *entry = snd_info_create_entry(name);
+ struct snd_info_entry *entry = snd_info_create_entry(name);
if (entry) {
entry->module = module;
entry->parent = parent;
@@ -788,6 +806,8 @@ snd_info_entry_t *snd_info_create_module_entry(struct module * module,
return entry;
}
+EXPORT_SYMBOL(snd_info_create_module_entry);
+
/**
* snd_info_create_card_entry - create an info entry for the given card
* @card: the card instance
@@ -796,13 +816,13 @@ snd_info_entry_t *snd_info_create_module_entry(struct module * module,
*
* Creates a new info entry and assigns it to the given card.
*
- * Returns the pointer of the new instance, or NULL on failure.
+ * Return: The pointer of the new instance, or %NULL on failure.
*/
-snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card,
+struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
const char *name,
- snd_info_entry_t * parent)
+ struct snd_info_entry * parent)
{
- snd_info_entry_t *entry = snd_info_create_entry(name);
+ struct snd_info_entry *entry = snd_info_create_entry(name);
if (entry) {
entry->module = card->module;
entry->card = card;
@@ -811,30 +831,37 @@ snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card,
return entry;
}
-static int snd_info_dev_free_entry(snd_device_t *device)
-{
- snd_info_entry_t *entry = device->device_data;
- snd_info_free_entry(entry);
- return 0;
-}
+EXPORT_SYMBOL(snd_info_create_card_entry);
-static int snd_info_dev_register_entry(snd_device_t *device)
+static void snd_info_disconnect(struct snd_info_entry *entry)
{
- snd_info_entry_t *entry = device->device_data;
- return snd_info_register(entry);
+ struct list_head *p, *n;
+ struct proc_dir_entry *root;
+
+ list_for_each_safe(p, n, &entry->children) {
+ snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
+ }
+
+ if (! entry->p)
+ return;
+ list_del_init(&entry->list);
+ root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
+ snd_BUG_ON(!root);
+ proc_remove(entry->p);
+ entry->p = NULL;
}
-static int snd_info_dev_disconnect_entry(snd_device_t *device)
+static int snd_info_dev_free_entry(struct snd_device *device)
{
- snd_info_entry_t *entry = device->device_data;
- entry->disconnected = 1;
+ struct snd_info_entry *entry = device->device_data;
+ snd_info_free_entry(entry);
return 0;
}
-static int snd_info_dev_unregister_entry(snd_device_t *device)
+static int snd_info_dev_register_entry(struct snd_device *device)
{
- snd_info_entry_t *entry = device->device_data;
- return snd_info_unregister(entry);
+ struct snd_info_entry *entry = device->device_data;
+ return snd_info_register(entry);
}
/**
@@ -855,18 +882,17 @@ static int snd_info_dev_unregister_entry(snd_device_t *device)
* For releasing this entry, use snd_device_free() instead of
* snd_info_free_entry().
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_card_proc_new(snd_card_t *card, const char *name,
- snd_info_entry_t **entryp)
+int snd_card_proc_new(struct snd_card *card, const char *name,
+ struct snd_info_entry **entryp)
{
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_info_dev_free_entry,
.dev_register = snd_info_dev_register_entry,
- .dev_disconnect = snd_info_dev_disconnect_entry,
- .dev_unregister = snd_info_dev_unregister_entry
+ /* disconnect is done via snd_info_card_disconnect() */
};
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
int err;
entry = snd_info_create_card_entry(card, name, card->proc_root);
@@ -881,97 +907,91 @@ int snd_card_proc_new(snd_card_t *card, const char *name,
return 0;
}
+EXPORT_SYMBOL(snd_card_proc_new);
+
/**
* snd_info_free_entry - release the info entry
* @entry: the info entry
*
* Releases the info entry. Don't call this after registered.
*/
-void snd_info_free_entry(snd_info_entry_t * entry)
+void snd_info_free_entry(struct snd_info_entry * entry)
{
if (entry == NULL)
return;
+ if (entry->p) {
+ mutex_lock(&info_mutex);
+ snd_info_disconnect(entry);
+ mutex_unlock(&info_mutex);
+ }
kfree(entry->name);
if (entry->private_free)
entry->private_free(entry);
kfree(entry);
}
+EXPORT_SYMBOL(snd_info_free_entry);
+
/**
* snd_info_register - register the info entry
* @entry: the info entry
*
* Registers the proc info entry.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_info_register(snd_info_entry_t * entry)
+int snd_info_register(struct snd_info_entry * entry)
{
struct proc_dir_entry *root, *p = NULL;
- snd_assert(entry != NULL, return -ENXIO);
+ if (snd_BUG_ON(!entry))
+ return -ENXIO;
root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
- down(&info_mutex);
- p = snd_create_proc_entry(entry->name, entry->mode, root);
- if (!p) {
- up(&info_mutex);
- return -ENOMEM;
+ mutex_lock(&info_mutex);
+ if (S_ISDIR(entry->mode)) {
+ p = proc_mkdir_mode(entry->name, entry->mode, root);
+ if (!p) {
+ mutex_unlock(&info_mutex);
+ return -ENOMEM;
+ }
+ } else {
+ p = proc_create_data(entry->name, entry->mode, root,
+ &snd_info_entry_operations, entry);
+ if (!p) {
+ mutex_unlock(&info_mutex);
+ return -ENOMEM;
+ }
+ proc_set_size(p, entry->size);
}
- p->owner = entry->module;
- if (!S_ISDIR(entry->mode))
- p->proc_fops = &snd_info_entry_operations;
- p->size = entry->size;
- p->data = entry;
entry->p = p;
- up(&info_mutex);
+ if (entry->parent)
+ list_add_tail(&entry->list, &entry->parent->children);
+ mutex_unlock(&info_mutex);
return 0;
}
-/**
- * snd_info_unregister - de-register the info entry
- * @entry: the info entry
- *
- * De-registers the info entry and releases the instance.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_info_unregister(snd_info_entry_t * entry)
-{
- struct proc_dir_entry *root;
-
- snd_assert(entry != NULL, return -ENXIO);
- snd_assert(entry->p != NULL, return -ENXIO);
- root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
- snd_assert(root, return -ENXIO);
- down(&info_mutex);
- snd_remove_proc_entry(root, entry->p);
- up(&info_mutex);
- snd_info_free_entry(entry);
- return 0;
-}
+EXPORT_SYMBOL(snd_info_register);
/*
*/
-static snd_info_entry_t *snd_info_version_entry = NULL;
+static struct snd_info_entry *snd_info_version_entry;
-static void snd_info_version_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
snd_iprintf(buffer,
- "Advanced Linux Sound Architecture Driver Version "
- CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
- );
+ "Advanced Linux Sound Architecture Driver Version k%s.\n",
+ init_utsname()->release);
}
static int __init snd_info_version_init(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
if (entry == NULL)
return -ENOMEM;
- entry->c.text.read_size = 256;
entry->c.text.read = snd_info_version_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -983,8 +1003,7 @@ static int __init snd_info_version_init(void)
static int __exit snd_info_version_done(void)
{
- if (snd_info_version_entry)
- snd_info_unregister(snd_info_version_entry);
+ snd_info_free_entry(snd_info_version_entry);
return 0;
}
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index 12107968d40..83c29dbff9c 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -1,6 +1,6 @@
/*
* Information interface for ALSA driver
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,15 +19,15 @@
*
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/string.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
#include <linux/utsname.h>
+#include <linux/mutex.h>
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
@@ -35,17 +35,19 @@
* OSS compatible part
*/
-static DECLARE_MUTEX(strings);
+static DEFINE_MUTEX(strings);
static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT];
-static snd_info_entry_t *snd_sndstat_proc_entry;
+static struct snd_info_entry *snd_sndstat_proc_entry;
int snd_oss_info_register(int dev, int num, char *string)
{
char *x;
- snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
- snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
- down(&strings);
+ if (snd_BUG_ON(dev < 0 || dev >= SNDRV_OSS_INFO_DEV_COUNT))
+ return -ENXIO;
+ if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
+ return -ENXIO;
+ mutex_lock(&strings);
if (string == NULL) {
if ((x = snd_sndstat_strings[num][dev]) != NULL) {
kfree(x);
@@ -54,24 +56,24 @@ int snd_oss_info_register(int dev, int num, char *string)
} else {
x = kstrdup(string, GFP_KERNEL);
if (x == NULL) {
- up(&strings);
+ mutex_unlock(&strings);
return -ENOMEM;
}
}
snd_sndstat_strings[num][dev] = x;
- up(&strings);
+ mutex_unlock(&strings);
return 0;
}
-extern void snd_card_info_read_oss(snd_info_buffer_t * buffer);
+EXPORT_SYMBOL(snd_oss_info_register);
-static int snd_sndstat_show_strings(snd_info_buffer_t * buf, char *id, int dev)
+static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev)
{
int idx, ok = -1;
char *str;
snd_iprintf(buf, "\n%s:", id);
- down(&strings);
+ mutex_lock(&strings);
for (idx = 0; idx < SNDRV_CARDS; idx++) {
str = snd_sndstat_strings[idx][dev];
if (str) {
@@ -82,21 +84,22 @@ static int snd_sndstat_show_strings(snd_info_buffer_t * buf, char *id, int dev)
snd_iprintf(buf, "%i: %s\n", idx, str);
}
}
- up(&strings);
+ mutex_unlock(&strings);
if (ok < 0)
snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
return ok;
}
-static void snd_sndstat_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static void snd_sndstat_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
+ snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n");
snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
- system_utsname.sysname,
- system_utsname.nodename,
- system_utsname.release,
- system_utsname.version,
- system_utsname.machine);
+ init_utsname()->sysname,
+ init_utsname()->nodename,
+ init_utsname()->release,
+ init_utsname()->version,
+ init_utsname()->machine);
snd_iprintf(buffer, "Config options: 0\n");
snd_iprintf(buffer, "\nInstalled drivers: \n");
snd_iprintf(buffer, "Type 10: ALSA emulation\n");
@@ -111,11 +114,10 @@ static void snd_sndstat_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * b
int snd_info_minor_register(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
- entry->c.text.read_size = 2048;
entry->c.text.read = snd_sndstat_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -128,10 +130,8 @@ int snd_info_minor_register(void)
int snd_info_minor_unregister(void)
{
- if (snd_sndstat_proc_entry) {
- snd_info_unregister(snd_sndstat_proc_entry);
- snd_sndstat_proc_entry = NULL;
- }
+ snd_info_free_entry(snd_sndstat_proc_entry);
+ snd_sndstat_proc_entry = NULL;
return 0;
}
diff --git a/sound/core/init.c b/sound/core/init.c
index 41e224986f3..7bdfd19e24a 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -1,6 +1,6 @@
/*
* Initialization routines
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,127 +19,310 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/device.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/ctype.h>
-#include <linux/pci.h>
#include <linux/pm.h>
-#include <linux/platform_device.h>
+#include <linux/completion.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
-struct snd_shutdown_f_ops {
- struct file_operations f_ops;
- struct snd_shutdown_f_ops *next;
+/* monitor files for graceful shutdown (hotplug) */
+struct snd_monitor_file {
+ struct file *file;
+ const struct file_operations *disconnected_f_op;
+ struct list_head shutdown_list; /* still need to shutdown */
+ struct list_head list; /* link of monitor files */
};
-unsigned int snd_cards_lock = 0; /* locked for registering/using */
-snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
-DEFINE_RWLOCK(snd_card_rwlock);
+static DEFINE_SPINLOCK(shutdown_lock);
+static LIST_HEAD(shutdown_files);
+
+static const struct file_operations snd_shutdown_f_ops;
+
+/* locked for registering/using */
+static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
+struct snd_card *snd_cards[SNDRV_CARDS];
+EXPORT_SYMBOL(snd_cards);
+
+static DEFINE_MUTEX(snd_card_mutex);
+
+static char *slots[SNDRV_CARDS];
+module_param_array(slots, charp, NULL, 0444);
+MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
+
+/* return non-zero if the given index is reserved for the given
+ * module via slots option
+ */
+static int module_slot_match(struct module *module, int idx)
+{
+ int match = 1;
+#ifdef MODULE
+ const char *s1, *s2;
+
+ if (!module || !*module->name || !slots[idx])
+ return 0;
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
+ s1 = module->name;
+ s2 = slots[idx];
+ if (*s2 == '!') {
+ match = 0; /* negative match */
+ s2++;
+ }
+ /* compare module name strings
+ * hyphens are handled as equivalent with underscore
+ */
+ for (;;) {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if (c1 == '-')
+ c1 = '_';
+ if (c2 == '-')
+ c2 = '_';
+ if (c1 != c2)
+ return !match;
+ if (!c1)
+ break;
+ }
+#endif /* MODULE */
+ return match;
+}
+
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
+int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
+EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif
-static void snd_card_id_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+#ifdef CONFIG_PROC_FS
+static void snd_card_id_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
snd_iprintf(buffer, "%s\n", entry->card->id);
}
-static void snd_card_free_thread(void * __card);
+static inline int init_info_for_card(struct snd_card *card)
+{
+ int err;
+ struct snd_info_entry *entry;
+
+ if ((err = snd_info_card_register(card)) < 0) {
+ dev_dbg(card->dev, "unable to create card info\n");
+ return err;
+ }
+ if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
+ dev_dbg(card->dev, "unable to create card entry\n");
+ return err;
+ }
+ entry->c.text.read = snd_card_id_read;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ card->proc_id = entry;
+ return 0;
+}
+#else /* !CONFIG_PROC_FS */
+#define init_info_for_card(card)
+#endif
+
+static int check_empty_slot(struct module *module, int slot)
+{
+ return !slots[slot] || !*slots[slot];
+}
+
+/* return an empty slot number (>= 0) found in the given bitmask @mask.
+ * @mask == -1 == 0xffffffff means: take any free slot up to 32
+ * when no slot is available, return the original @mask as is.
+ */
+static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
+ struct module *module)
+{
+ int slot;
+
+ for (slot = 0; slot < SNDRV_CARDS; slot++) {
+ if (slot < 32 && !(mask & (1U << slot)))
+ continue;
+ if (!test_bit(slot, snd_cards_lock)) {
+ if (check(module, slot))
+ return slot; /* found */
+ }
+ }
+ return mask; /* unchanged */
+}
+
+static int snd_card_do_free(struct snd_card *card);
+static const struct attribute_group *card_dev_attr_groups[];
+
+static void release_card_device(struct device *dev)
+{
+ snd_card_do_free(dev_to_snd_card(dev));
+}
/**
* snd_card_new - create and initialize a soundcard structure
+ * @parent: the parent device object
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
* @extra_size: allocate this extra size after the main soundcard structure
+ * @card_ret: the pointer to store the created card instance
*
* Creates and initializes a soundcard structure.
*
- * Returns kmallocated snd_card_t structure. Creates the ALSA control interface
- * (which is blocked until snd_card_register function is called).
+ * The function allocates snd_card instance via kzalloc with the given
+ * space for the driver to use freely. The allocated struct is stored
+ * in the given card_ret pointer.
+ *
+ * Return: Zero if successful or a negative error code.
*/
-snd_card_t *snd_card_new(int idx, const char *xid,
- struct module *module, int extra_size)
+int snd_card_new(struct device *parent, int idx, const char *xid,
+ struct module *module, int extra_size,
+ struct snd_card **card_ret)
{
- snd_card_t *card;
+ struct snd_card *card;
int err;
+ if (snd_BUG_ON(!card_ret))
+ return -EINVAL;
+ *card_ret = NULL;
+
if (extra_size < 0)
extra_size = 0;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
- if (card == NULL)
- return NULL;
- if (xid) {
- if (!snd_info_check_reserved_words(xid))
- goto __error;
+ if (!card)
+ return -ENOMEM;
+ if (extra_size > 0)
+ card->private_data = (char *)card + sizeof(struct snd_card);
+ if (xid)
strlcpy(card->id, xid, sizeof(card->id));
- }
err = 0;
- write_lock(&snd_card_rwlock);
- if (idx < 0) {
- int idx2;
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
- if (~snd_cards_lock & idx & 1<<idx2) {
- idx = idx2;
- if (idx >= snd_ecards_limit)
- snd_ecards_limit = idx + 1;
- break;
- }
- } else if (idx < snd_ecards_limit) {
- if (snd_cards_lock & (1 << idx))
- err = -ENODEV; /* invalid */
- } else if (idx < SNDRV_CARDS)
- snd_ecards_limit = idx + 1; /* increase the limit */
- else
+ mutex_lock(&snd_card_mutex);
+ if (idx < 0) /* first check the matching module-name slot */
+ idx = get_slot_from_bitmask(idx, module_slot_match, module);
+ if (idx < 0) /* if not matched, assign an empty slot */
+ idx = get_slot_from_bitmask(idx, check_empty_slot, module);
+ if (idx < 0)
err = -ENODEV;
- if (idx < 0 || err < 0) {
- write_unlock(&snd_card_rwlock);
- snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
- goto __error;
+ else if (idx < snd_ecards_limit) {
+ if (test_bit(idx, snd_cards_lock))
+ err = -EBUSY; /* invalid */
+ } else if (idx >= SNDRV_CARDS)
+ err = -ENODEV;
+ if (err < 0) {
+ mutex_unlock(&snd_card_mutex);
+ dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
+ idx, snd_ecards_limit - 1, err);
+ kfree(card);
+ return err;
}
- snd_cards_lock |= 1 << idx; /* lock it */
- write_unlock(&snd_card_rwlock);
+ set_bit(idx, snd_cards_lock); /* lock it */
+ if (idx >= snd_ecards_limit)
+ snd_ecards_limit = idx + 1; /* increase the limit */
+ mutex_unlock(&snd_card_mutex);
+ card->dev = parent;
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
+ mutex_init(&card->user_ctl_lock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
- init_waitqueue_head(&card->shutdown_sleep);
- INIT_WORK(&card->free_workq, snd_card_free_thread, card);
+ INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PM
- init_MUTEX(&card->power_lock);
+ mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
+
+ device_initialize(&card->card_dev);
+ card->card_dev.parent = parent;
+ card->card_dev.class = sound_class;
+ card->card_dev.release = release_card_device;
+ card->card_dev.groups = card_dev_attr_groups;
+ err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
+ if (err < 0)
+ goto __error;
+
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
- if ((err = snd_ctl_create(card)) < 0) {
- snd_printd("unable to register control minors\n");
+ err = snd_ctl_create(card);
+ if (err < 0) {
+ dev_err(parent, "unable to register control minors\n");
goto __error;
}
- if ((err = snd_info_card_create(card)) < 0) {
- snd_printd("unable to create card info\n");
+ err = snd_info_card_create(card);
+ if (err < 0) {
+ dev_err(parent, "unable to create card info\n");
goto __error_ctl;
}
- if (extra_size > 0)
- card->private_data = (char *)card + sizeof(snd_card_t);
- return card;
+ *card_ret = card;
+ return 0;
__error_ctl:
- snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
+ snd_device_free_all(card);
__error:
- kfree(card);
- return NULL;
+ put_device(&card->card_dev);
+ return err;
+}
+EXPORT_SYMBOL(snd_card_new);
+
+/* return non-zero if a card is already locked */
+int snd_card_locked(int card)
+{
+ int locked;
+
+ mutex_lock(&snd_card_mutex);
+ locked = test_bit(card, snd_cards_lock);
+ mutex_unlock(&snd_card_mutex);
+ return locked;
+}
+
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+ return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ return -ENODEV;
+}
+
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+ struct snd_monitor_file *df = NULL, *_df;
+
+ spin_lock(&shutdown_lock);
+ list_for_each_entry(_df, &shutdown_files, shutdown_list) {
+ if (_df->file == file) {
+ df = _df;
+ list_del_init(&df->shutdown_list);
+ break;
+ }
+ }
+ spin_unlock(&shutdown_lock);
+
+ if (likely(df)) {
+ if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
+ df->disconnected_f_op->fasync(-1, file, 0);
+ return df->disconnected_f_op->release(inode, file);
+ }
+
+ panic("%s(%p, %p) failed!", __func__, inode, file);
}
static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
@@ -147,25 +330,57 @@ static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
return POLLERR | POLLNVAL;
}
+static long snd_disconnect_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+ return -ENODEV;
+}
+
+static const struct file_operations snd_shutdown_f_ops =
+{
+ .owner = THIS_MODULE,
+ .llseek = snd_disconnect_llseek,
+ .read = snd_disconnect_read,
+ .write = snd_disconnect_write,
+ .release = snd_disconnect_release,
+ .poll = snd_disconnect_poll,
+ .unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = snd_disconnect_ioctl,
+#endif
+ .mmap = snd_disconnect_mmap,
+ .fasync = snd_disconnect_fasync
+};
+
/**
* snd_card_disconnect - disconnect all APIs from the file-operations (user space)
* @card: soundcard structure
*
* Disconnects all APIs from the file-operations (user space).
*
- * Returns zero, otherwise a negative error code.
+ * Return: Zero, otherwise a negative error code.
*
* Note: The current implementation replaces all active file->f_op with special
* dummy file operations (they do nothing except release).
*/
-int snd_card_disconnect(snd_card_t * card)
+int snd_card_disconnect(struct snd_card *card)
{
struct snd_monitor_file *mfile;
- struct file *file;
- struct snd_shutdown_f_ops *s_f_ops;
- struct file_operations *f_ops, *old_f_ops;
int err;
+ if (!card)
+ return -EINVAL;
+
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
@@ -175,47 +390,32 @@ int snd_card_disconnect(snd_card_t * card)
spin_unlock(&card->files_lock);
/* phase 1: disable fops (user space) operations for ALSA API */
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
- write_unlock(&snd_card_rwlock);
+ clear_bit(card->number, snd_cards_lock);
+ mutex_unlock(&snd_card_mutex);
/* phase 2: replace file->f_op with special dummy operations */
spin_lock(&card->files_lock);
- mfile = card->files;
- while (mfile) {
- file = mfile->file;
-
+ list_for_each_entry(mfile, &card->files_list, list) {
/* it's critical part, use endless loop */
/* we have no room to fail */
- s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC);
- if (s_f_ops == NULL)
- panic("Atomic allocation failed for snd_shutdown_f_ops!");
-
- f_ops = &s_f_ops->f_ops;
-
- memset(f_ops, 0, sizeof(*f_ops));
- f_ops->owner = file->f_op->owner;
- f_ops->release = file->f_op->release;
- f_ops->poll = snd_disconnect_poll;
+ mfile->disconnected_f_op = mfile->file->f_op;
- s_f_ops->next = card->s_f_ops;
- card->s_f_ops = s_f_ops;
-
- f_ops = fops_get(f_ops);
+ spin_lock(&shutdown_lock);
+ list_add(&mfile->shutdown_list, &shutdown_files);
+ spin_unlock(&shutdown_lock);
- old_f_ops = file->f_op;
- file->f_op = f_ops; /* must be atomic */
- fops_put(old_f_ops);
-
- mfile = mfile->next;
+ mfile->file->f_op = &snd_shutdown_f_ops;
+ fops_get(mfile->file->f_op);
}
spin_unlock(&card->files_lock);
/* phase 3: notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
#endif
@@ -223,16 +423,20 @@ int snd_card_disconnect(snd_card_t * card)
/* notify all devices that we are disconnected */
err = snd_device_disconnect_all(card);
if (err < 0)
- snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+ dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
+ snd_info_card_disconnect(card);
+ if (card->registered) {
+ device_del(&card->card_dev);
+ card->registered = false;
+ }
+#ifdef CONFIG_PM
+ wake_up(&card->power_sleep);
+#endif
return 0;
}
-#ifdef CONFIG_SND_GENERIC_DRIVER
-static void snd_generic_device_unregister(snd_card_t *card);
-#else
-#define snd_generic_device_unregister(x) /*NOP*/
-#endif
+EXPORT_SYMBOL(snd_card_disconnect);
/**
* snd_card_free - frees given soundcard structure
@@ -242,168 +446,235 @@ static void snd_generic_device_unregister(snd_card_t *card);
* devices automatically. That is, you don't have to release the devices
* by yourself.
*
- * Returns zero. Frees all associated devices and frees the control
+ * Return: Zero. Frees all associated devices and frees the control
* interface associated to given soundcard.
*/
-int snd_card_free(snd_card_t * card)
+static int snd_card_do_free(struct snd_card *card)
{
- struct snd_shutdown_f_ops *s_f_ops;
-
- if (card == NULL)
- return -EINVAL;
- write_lock(&snd_card_rwlock);
- snd_cards[card->number] = NULL;
- write_unlock(&snd_card_rwlock);
-
-#ifdef CONFIG_PM
- wake_up(&card->power_sleep);
-#endif
- /* wait, until all devices are ready for the free operation */
- wait_event(card->shutdown_sleep, card->files == NULL);
-
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
- if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (pre)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (normal)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (post)\n");
- /* Fatal, but this situation should never occur */
- }
+ snd_device_free_all(card);
if (card->private_free)
card->private_free(card);
- if (card->proc_id)
- snd_info_unregister(card->proc_id);
+ snd_info_free_entry(card->proc_id);
if (snd_info_card_free(card) < 0) {
- snd_printk(KERN_WARNING "unable to free card info\n");
+ dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
}
- snd_generic_device_unregister(card);
- while (card->s_f_ops) {
- s_f_ops = card->s_f_ops;
- card->s_f_ops = s_f_ops->next;
- kfree(s_f_ops);
- }
- write_lock(&snd_card_rwlock);
- snd_cards_lock &= ~(1 << card->number);
- write_unlock(&snd_card_rwlock);
+ if (card->release_completion)
+ complete(card->release_completion);
kfree(card);
return 0;
}
-static void snd_card_free_thread(void * __card)
+int snd_card_free_when_closed(struct snd_card *card)
{
- snd_card_t *card = __card;
- struct module * module = card->module;
+ int ret = snd_card_disconnect(card);
+ if (ret)
+ return ret;
+ put_device(&card->card_dev);
+ return 0;
+}
+EXPORT_SYMBOL(snd_card_free_when_closed);
- if (!try_module_get(module)) {
- snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
- module = NULL;
+int snd_card_free(struct snd_card *card)
+{
+ struct completion released;
+ int ret;
+
+ init_completion(&released);
+ card->release_completion = &released;
+ ret = snd_card_free_when_closed(card);
+ if (ret)
+ return ret;
+ /* wait, until all devices are ready for the free operation */
+ wait_for_completion(&released);
+ return 0;
+}
+EXPORT_SYMBOL(snd_card_free);
+
+/* retrieve the last word of shortname or longname */
+static const char *retrieve_id_from_card_name(const char *name)
+{
+ const char *spos = name;
+
+ while (*name) {
+ if (isspace(*name) && isalnum(name[1]))
+ spos = name + 1;
+ name++;
}
+ return spos;
+}
+
+/* return true if the given id string doesn't conflict any other card ids */
+static bool card_id_ok(struct snd_card *card, const char *id)
+{
+ int i;
+ if (!snd_info_check_reserved_words(id))
+ return false;
+ for (i = 0; i < snd_ecards_limit; i++) {
+ if (snd_cards[i] && snd_cards[i] != card &&
+ !strcmp(snd_cards[i]->id, id))
+ return false;
+ }
+ return true;
+}
- snd_card_free(card);
+/* copy to card->id only with valid letters from nid */
+static void copy_valid_id_string(struct snd_card *card, const char *src,
+ const char *nid)
+{
+ char *id = card->id;
+
+ while (*nid && !isalnum(*nid))
+ nid++;
+ if (isdigit(*nid))
+ *id++ = isalpha(*src) ? *src : 'D';
+ while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) {
+ if (isalnum(*nid))
+ *id++ = *nid;
+ nid++;
+ }
+ *id = 0;
+}
- module_put(module);
+/* Set card->id from the given string
+ * If the string conflicts with other ids, add a suffix to make it unique.
+ */
+static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
+ const char *nid)
+{
+ int len, loops;
+ bool is_default = false;
+ char *id;
+
+ copy_valid_id_string(card, src, nid);
+ id = card->id;
+
+ again:
+ /* use "Default" for obviously invalid strings
+ * ("card" conflicts with proc directories)
+ */
+ if (!*id || !strncmp(id, "card", 4)) {
+ strcpy(id, "Default");
+ is_default = true;
+ }
+
+ len = strlen(id);
+ for (loops = 0; loops < SNDRV_CARDS; loops++) {
+ char *spos;
+ char sfxstr[5]; /* "_012" */
+ int sfxlen;
+
+ if (card_id_ok(card, id))
+ return; /* OK */
+
+ /* Add _XYZ suffix */
+ sprintf(sfxstr, "_%X", loops + 1);
+ sfxlen = strlen(sfxstr);
+ if (len + sfxlen >= sizeof(card->id))
+ spos = id + sizeof(card->id) - sfxlen - 1;
+ else
+ spos = id + len;
+ strcpy(spos, sfxstr);
+ }
+ /* fallback to the default id */
+ if (!is_default) {
+ *id = 0;
+ goto again;
+ }
+ /* last resort... */
+ dev_err(card->dev, "unable to set card id (%s)\n", id);
+ if (card->proc_root->name)
+ strlcpy(card->id, card->proc_root->name, sizeof(card->id));
}
/**
- * snd_card_free_in_thread - call snd_card_free() in thread
+ * snd_card_set_id - set card identification name
* @card: soundcard structure
+ * @nid: new identification string
*
- * This function schedules the call of snd_card_free() function in a
- * work queue. When all devices are released (non-busy), the work
- * is woken up and calls snd_card_free().
- *
- * When a card can be disconnected at any time by hotplug service,
- * this function should be used in disconnect (or detach) callback
- * instead of calling snd_card_free() directly.
- *
- * Returns - zero otherwise a negative error code if the start of thread failed.
+ * This function sets the card identification and checks for name
+ * collisions.
*/
-int snd_card_free_in_thread(snd_card_t * card)
+void snd_card_set_id(struct snd_card *card, const char *nid)
{
- if (card->files == NULL) {
- snd_card_free(card);
- return 0;
- }
-
- if (schedule_work(&card->free_workq))
- return 0;
+ /* check if user specified own card->id */
+ if (card->id[0] != '\0')
+ return;
+ mutex_lock(&snd_card_mutex);
+ snd_card_set_id_no_lock(card, nid, nid);
+ mutex_unlock(&snd_card_mutex);
+}
+EXPORT_SYMBOL(snd_card_set_id);
- snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
- /* try to free the structure immediately */
- snd_card_free(card);
- return -EFAULT;
+static ssize_t
+card_id_show_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
-static void choose_default_id(snd_card_t * card)
+static ssize_t
+card_id_store_attr(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- int i, len, idx_flag = 0, loops = 8;
- char *id, *spos;
-
- id = spos = card->shortname;
- while (*id != '\0') {
- if (*id == ' ')
- spos = id + 1;
- id++;
- }
- id = card->id;
- while (*spos != '\0' && !isalnum(*spos))
- spos++;
- if (isdigit(*spos))
- *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D';
- while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
- if (isalnum(*spos))
- *id++ = *spos;
- spos++;
- }
- *id = '\0';
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ char buf1[sizeof(card->id)];
+ size_t copy = count > sizeof(card->id) - 1 ?
+ sizeof(card->id) - 1 : count;
+ size_t idx;
+ int c;
+
+ for (idx = 0; idx < copy; idx++) {
+ c = buf[idx];
+ if (!isalnum(c) && c != '_' && c != '-')
+ return -EINVAL;
+ }
+ memcpy(buf1, buf, copy);
+ buf1[copy] = '\0';
+ mutex_lock(&snd_card_mutex);
+ if (!card_id_ok(NULL, buf1)) {
+ mutex_unlock(&snd_card_mutex);
+ return -EEXIST;
+ }
+ strcpy(card->id, buf1);
+ snd_info_card_id_change(card);
+ mutex_unlock(&snd_card_mutex);
+
+ return count;
+}
- id = card->id;
-
- if (*id == '\0')
- strcpy(id, "default");
+static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
- while (1) {
- if (loops-- == 0) {
- snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
- strcpy(card->id, card->proc_root->name);
- return;
- }
- if (!snd_info_check_reserved_words(id))
- goto __change;
- for (i = 0; i < snd_ecards_limit; i++) {
- if (snd_cards[i] && !strcmp(snd_cards[i]->id, id))
- goto __change;
- }
- break;
-
- __change:
- len = strlen(id);
- if (idx_flag)
- id[len-1]++;
- else if ((size_t)len <= sizeof(card->id) - 3) {
- strcat(id, "_1");
- idx_flag++;
- } else {
- spos = id + len - 2;
- if ((size_t)len <= sizeof(card->id) - 2)
- spos++;
- *spos++ = '_';
- *spos++ = '1';
- *spos++ = '\0';
- idx_flag++;
- }
- }
+static ssize_t
+card_number_show_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
+static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+
+static struct attribute *card_dev_attrs[] = {
+ &dev_attr_id.attr,
+ &dev_attr_number.attr,
+ NULL
+};
+
+static struct attribute_group card_dev_attr_group = {
+ .attrs = card_dev_attrs,
+};
+
+static const struct attribute_group *card_dev_attr_groups[] = {
+ &card_dev_attr_group,
+ NULL
+};
+
/**
* snd_card_register - register the soundcard
* @card: soundcard structure
@@ -413,88 +684,95 @@ static void choose_default_id(snd_card_t * card)
* external accesses. Thus, you should call this function at the end
* of the initialization of the card.
*
- * Returns zero otherwise a negative error code if the registrain failed.
+ * Return: Zero otherwise a negative error code if the registration failed.
*/
-int snd_card_register(snd_card_t * card)
+int snd_card_register(struct snd_card *card)
{
int err;
- snd_info_entry_t *entry;
- snd_runtime_check(card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
+
+ if (!card->registered) {
+ err = device_add(&card->card_dev);
+ if (err < 0)
+ return err;
+ card->registered = true;
+ }
+
if ((err = snd_device_register_all(card)) < 0)
return err;
- write_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if (snd_cards[card->number]) {
/* already registered */
- write_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
return 0;
}
- if (card->id[0] == '\0')
- choose_default_id(card);
- snd_cards[card->number] = card;
- write_unlock(&snd_card_rwlock);
- if ((err = snd_info_card_register(card)) < 0) {
- snd_printd("unable to create card info\n");
- goto __skip_info;
+ if (*card->id) {
+ /* make a unique id name from the given string */
+ char tmpid[sizeof(card->id)];
+ memcpy(tmpid, card->id, sizeof(card->id));
+ snd_card_set_id_no_lock(card, tmpid, tmpid);
+ } else {
+ /* create an id from either shortname or longname */
+ const char *src;
+ src = *card->shortname ? card->shortname : card->longname;
+ snd_card_set_id_no_lock(card, src,
+ retrieve_id_from_card_name(src));
}
- if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
- snd_printd("unable to create card entry\n");
- goto __skip_info;
- }
- entry->c.text.read_size = PAGE_SIZE;
- entry->c.text.read = snd_card_id_read;
- if (snd_info_register(entry) < 0) {
- snd_info_free_entry(entry);
- entry = NULL;
- }
- card->proc_id = entry;
- __skip_info:
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+ snd_cards[card->number] = card;
+ mutex_unlock(&snd_card_mutex);
+ init_info_for_card(card);
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
return 0;
}
-static snd_info_entry_t *snd_card_info_entry = NULL;
+EXPORT_SYMBOL(snd_card_register);
+
+#ifdef CONFIG_PROC_FS
+static struct snd_info_entry *snd_card_info_entry;
-static void snd_card_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static void snd_card_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
int idx, count;
- snd_card_t *card;
+ struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
count++;
- snd_iprintf(buffer, "%i [%-15s]: %s - %s\n",
+ snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",
idx,
card->id,
card->driver,
card->shortname);
- snd_iprintf(buffer, " %s\n",
+ snd_iprintf(buffer, " %s\n",
card->longname);
}
- read_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
}
if (!count)
snd_iprintf(buffer, "--- no soundcards ---\n");
}
-#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
+#ifdef CONFIG_SND_OSSEMUL
-void snd_card_info_read_oss(snd_info_buffer_t * buffer)
+void snd_card_info_read_oss(struct snd_info_buffer *buffer)
{
int idx, count;
- snd_card_t *card;
+ struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
- read_unlock(&snd_card_rwlock);
+ mutex_unlock(&snd_card_mutex);
}
if (!count) {
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -504,28 +782,30 @@ void snd_card_info_read_oss(snd_info_buffer_t * buffer)
#endif
#ifdef MODULE
-static snd_info_entry_t *snd_card_module_info_entry;
-static void snd_card_module_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static struct snd_info_entry *snd_card_module_info_entry;
+static void snd_card_module_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
int idx;
- snd_card_t *card;
+ struct snd_card *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- read_lock(&snd_card_rwlock);
+ mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL)
- snd_iprintf(buffer, "%i %s\n", idx, card->module->name);
- read_unlock(&snd_card_rwlock);
+ snd_iprintf(buffer, "%2i %s\n",
+ idx, card->module->name);
+ mutex_unlock(&snd_card_mutex);
}
}
#endif
int __init snd_card_info_init(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL);
- snd_runtime_check(entry != NULL, return -ENOMEM);
- entry->c.text.read_size = PAGE_SIZE;
+ if (! entry)
+ return -ENOMEM;
entry->c.text.read = snd_card_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -536,7 +816,6 @@ int __init snd_card_info_init(void)
#ifdef MODULE
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_card_module_info_read;
if (snd_info_register(entry) < 0)
snd_info_free_entry(entry);
@@ -550,15 +829,15 @@ int __init snd_card_info_init(void)
int __exit snd_card_info_done(void)
{
- if (snd_card_info_entry)
- snd_info_unregister(snd_card_info_entry);
+ snd_info_free_entry(snd_card_info_entry);
#ifdef MODULE
- if (snd_card_module_info_entry)
- snd_info_unregister(snd_card_module_info_entry);
+ snd_info_free_entry(snd_card_module_info_entry);
#endif
return 0;
}
+#endif /* CONFIG_PROC_FS */
+
/**
* snd_component_add - add a component string
* @card: soundcard structure
@@ -567,10 +846,10 @@ int __exit snd_card_info_done(void)
* This function adds the component id string to the supported list.
* The component can be referred from the alsa-lib.
*
- * Returns zero otherwise a negative error code.
+ * Return: Zero otherwise a negative error code.
*/
-int snd_component_add(snd_card_t *card, const char *component)
+int snd_component_add(struct snd_card *card, const char *component)
{
char *ptr;
int len = strlen(component);
@@ -590,6 +869,8 @@ int snd_component_add(snd_card_t *card, const char *component)
return 0;
}
+EXPORT_SYMBOL(snd_component_add);
+
/**
* snd_card_file_add - add the file to the file list of the card
* @card: soundcard structure
@@ -599,9 +880,9 @@ int snd_component_add(snd_card_t *card, const char *component)
* This linked-list is used to keep tracking the connection state,
* and to avoid the release of busy resources by hotplug.
*
- * Returns zero or a negative error code.
+ * Return: zero or a negative error code.
*/
-int snd_card_file_add(snd_card_t *card, struct file *file)
+int snd_card_file_add(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile;
@@ -609,19 +890,22 @@ int snd_card_file_add(snd_card_t *card, struct file *file)
if (mfile == NULL)
return -ENOMEM;
mfile->file = file;
- mfile->next = NULL;
+ mfile->disconnected_f_op = NULL;
+ INIT_LIST_HEAD(&mfile->shutdown_list);
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
- mfile->next = card->files;
- card->files = mfile;
+ list_add(&mfile->list, &card->files_list);
+ get_device(&card->card_dev);
spin_unlock(&card->files_lock);
return 0;
}
+EXPORT_SYMBOL(snd_card_file_add);
+
/**
* snd_card_file_remove - remove the file from the file list
* @card: soundcard structure
@@ -629,142 +913,54 @@ int snd_card_file_add(snd_card_t *card, struct file *file)
*
* This function removes the file formerly added to the card via
* snd_card_file_add() function.
- * If all files are removed and the release of the card is
- * scheduled, it will wake up the the thread to call snd_card_free()
- * (see snd_card_free_in_thread() function).
+ * If all files are removed and snd_card_free_when_closed() was
+ * called beforehand, it processes the pending release of
+ * resources.
*
- * Returns zero or a negative error code.
+ * Return: Zero or a negative error code.
*/
-int snd_card_file_remove(snd_card_t *card, struct file *file)
+int snd_card_file_remove(struct snd_card *card, struct file *file)
{
- struct snd_monitor_file *mfile, *pfile = NULL;
+ struct snd_monitor_file *mfile, *found = NULL;
spin_lock(&card->files_lock);
- mfile = card->files;
- while (mfile) {
+ list_for_each_entry(mfile, &card->files_list, list) {
if (mfile->file == file) {
- if (pfile)
- pfile->next = mfile->next;
- else
- card->files = mfile->next;
+ list_del(&mfile->list);
+ spin_lock(&shutdown_lock);
+ list_del(&mfile->shutdown_list);
+ spin_unlock(&shutdown_lock);
+ if (mfile->disconnected_f_op)
+ fops_put(mfile->disconnected_f_op);
+ found = mfile;
break;
}
- pfile = mfile;
- mfile = mfile->next;
}
spin_unlock(&card->files_lock);
- if (card->files == NULL)
- wake_up(&card->shutdown_sleep);
- if (!mfile) {
- snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
+ if (!found) {
+ dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;
}
- kfree(mfile);
+ kfree(found);
+ put_device(&card->card_dev);
return 0;
}
-#ifdef CONFIG_SND_GENERIC_DRIVER
-/*
- * generic device without a proper bus using platform_device
- * (e.g. ISA)
- */
-struct snd_generic_device {
- struct platform_device pdev;
- snd_card_t *card;
-};
-
-#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card
-
-#define SND_GENERIC_NAME "snd_generic"
-
-#ifdef CONFIG_PM
-static int snd_generic_suspend(struct device *dev, pm_message_t state);
-static int snd_generic_resume(struct device *dev);
-#endif
-
-/* initialized in sound.c */
-struct device_driver snd_generic_driver = {
- .name = SND_GENERIC_NAME,
- .bus = &platform_bus_type,
-#ifdef CONFIG_PM
- .suspend = snd_generic_suspend,
- .resume = snd_generic_resume,
-#endif
-};
-
-void snd_generic_device_release(struct device *dev)
-{
-}
-
-static int snd_generic_device_register(snd_card_t *card)
-{
- struct snd_generic_device *dev;
- int err;
-
- if (card->generic_dev)
- return 0; /* already registered */
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (! dev) {
- snd_printk(KERN_ERR "can't allocate generic_device\n");
- return -ENOMEM;
- }
-
- dev->pdev.name = SND_GENERIC_NAME;
- dev->pdev.id = card->number;
- dev->pdev.dev.release = snd_generic_device_release;
- dev->card = card;
- if ((err = platform_device_register(&dev->pdev)) < 0) {
- kfree(dev);
- return err;
- }
- card->generic_dev = dev;
- return 0;
-}
-
-static void snd_generic_device_unregister(snd_card_t *card)
-{
- struct snd_generic_device *dev = card->generic_dev;
- if (dev) {
- platform_device_unregister(&dev->pdev);
- kfree(dev);
- card->generic_dev = NULL;
- }
-}
-
-/**
- * snd_card_set_generic_dev - assign the generic device to the card
- * @card: soundcard structure
- *
- * Assigns a generic device to the card. This function is provided as the
- * last resort, for devices without any proper bus. Thus this won't override
- * the device already assigned to the card.
- *
- * Returns zero if successful, or a negative error code.
- */
-int snd_card_set_generic_dev(snd_card_t *card)
-{
- int err;
- if ((err = snd_generic_device_register(card)) < 0)
- return err;
- if (! card->dev)
- snd_card_set_dev(card, &card->generic_dev->pdev.dev);
- return 0;
-}
-#endif /* CONFIG_SND_GENERIC_DRIVER */
+EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
* @card: soundcard structure
* @power_state: expected power state
- * @file: file structure for the O_NONBLOCK check (optional)
*
* Waits until the power-state is changed.
*
+ * Return: Zero if successful, or a negative error code.
+ *
* Note: the power lock must be active before call.
*/
-int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file)
+int snd_power_wait(struct snd_card *card, unsigned int power_state)
{
wait_queue_t wait;
int result = 0;
@@ -781,12 +977,6 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file
}
if (snd_power_get_state(card) == power_state)
break;
-#if 0 /* block all devices */
- if (file && (file->f_flags & O_NONBLOCK)) {
- result = -EAGAIN;
- break;
- }
-#endif
set_current_state(TASK_UNINTERRUPTIBLE);
snd_power_unlock(card);
schedule_timeout(30 * HZ);
@@ -796,107 +986,5 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file
return result;
}
-/**
- * snd_card_set_pm_callback - set the PCI power-management callbacks
- * @card: soundcard structure
- * @suspend: suspend callback function
- * @resume: resume callback function
- * @private_data: private data to pass to the callback functions
- *
- * Sets the power-management callback functions of the card.
- * These callbacks are called from ALSA's common PCI suspend/resume
- * handler and from the control API.
- */
-int snd_card_set_pm_callback(snd_card_t *card,
- int (*suspend)(snd_card_t *, pm_message_t),
- int (*resume)(snd_card_t *),
- void *private_data)
-{
- card->pm_suspend = suspend;
- card->pm_resume = resume;
- card->pm_private_data = private_data;
- return 0;
-}
-
-#ifdef CONFIG_SND_GENERIC_DRIVER
-/* suspend/resume callbacks for snd_generic platform device */
-static int snd_generic_suspend(struct device *dev, pm_message_t state)
-{
- snd_card_t *card;
-
- card = get_snd_generic_card(dev);
- if (card->power_state == SNDRV_CTL_POWER_D3hot)
- return 0;
- if (card->pm_suspend)
- card->pm_suspend(card, PMSG_SUSPEND);
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- return 0;
-}
-
-static int snd_generic_resume(struct device *dev)
-{
- snd_card_t *card;
-
- card = get_snd_generic_card(dev);
- if (card->power_state == SNDRV_CTL_POWER_D0)
- return 0;
- if (card->pm_suspend)
- card->pm_resume(card);
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-
-/**
- * snd_card_set_generic_pm_callback - set the generic power-management callbacks
- * @card: soundcard structure
- * @suspend: suspend callback function
- * @resume: resume callback function
- * @private_data: private data to pass to the callback functions
- *
- * Registers the power-management and sets the lowlevel callbacks for
- * the given card. These callbacks are called from the ALSA's common
- * PM handler and from the control API.
- */
-int snd_card_set_generic_pm_callback(snd_card_t *card,
- int (*suspend)(snd_card_t *, pm_message_t),
- int (*resume)(snd_card_t *),
- void *private_data)
-{
- int err;
- if ((err = snd_generic_device_register(card)) < 0)
- return err;
- return snd_card_set_pm_callback(card, suspend, resume, private_data);
-}
-#endif /* CONFIG_SND_GENERIC_DRIVER */
-
-#ifdef CONFIG_PCI
-int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
- snd_card_t *card = pci_get_drvdata(dev);
- int err;
- if (! card || ! card->pm_suspend)
- return 0;
- if (card->power_state == SNDRV_CTL_POWER_D3hot)
- return 0;
- err = card->pm_suspend(card, PMSG_SUSPEND);
- pci_save_state(dev);
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- return err;
-}
-
-int snd_card_pci_resume(struct pci_dev *dev)
-{
- snd_card_t *card = pci_get_drvdata(dev);
- if (! card || ! card->pm_resume)
- return 0;
- if (card->power_state == SNDRV_CTL_POWER_D0)
- return 0;
- /* restore the PCI config space */
- pci_restore_state(dev);
- card->pm_resume(card);
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif
-
+EXPORT_SYMBOL(snd_power_wait);
#endif /* CONFIG_PM */
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index 1a378951da5..31e8544d7f2 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -1,6 +1,6 @@
/*
* ISA DMA support functions
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#undef HAVE_REALLY_SLOW_DMA_CONTROLLER
-#include <sound/driver.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <asm/dma.h>
@@ -56,6 +56,8 @@ void snd_dma_program(unsigned long dma,
release_dma_lock(flags);
}
+EXPORT_SYMBOL(snd_dma_program);
+
/**
* snd_dma_disable - stop the ISA DMA transfer
* @dma: the dma number
@@ -72,32 +74,44 @@ void snd_dma_disable(unsigned long dma)
release_dma_lock(flags);
}
+EXPORT_SYMBOL(snd_dma_disable);
+
/**
* snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
* @dma: the dma number
* @size: the dma transfer size
*
- * Returns the current pointer in DMA tranfer buffer in bytes
+ * Return: The current pointer in DMA transfer buffer in bytes.
*/
unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
{
unsigned long flags;
- unsigned int result;
+ unsigned int result, result1;
flags = claim_dma_lock();
clear_dma_ff(dma);
if (!isa_dma_bridge_buggy)
disable_dma(dma);
result = get_dma_residue(dma);
+ /*
+ * HACK - read the counter again and choose higher value in order to
+ * avoid reading during counter lower byte roll over if the
+ * isa_dma_bridge_buggy is set.
+ */
+ result1 = get_dma_residue(dma);
if (!isa_dma_bridge_buggy)
enable_dma(dma);
release_dma_lock(flags);
+ if (unlikely(result < result1))
+ result = result1;
#ifdef CONFIG_SND_DEBUG
if (result > size)
- snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
+ pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
#endif
if (result >= size || result == 0)
return 0;
else
return size - result;
}
+
+EXPORT_SYMBOL(snd_dma_pointer);
diff --git a/sound/core/jack.c b/sound/core/jack.c
new file mode 100644
index 00000000000..8658578eb58
--- /dev/null
+++ b/sound/core/jack.c
@@ -0,0 +1,260 @@
+/*
+ * Jack abstraction layer
+ *
+ * Copyright 2008 Wolfson Microelectronics
+ *
+ * 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/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/core.h>
+
+static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
+ SW_HEADPHONE_INSERT,
+ SW_MICROPHONE_INSERT,
+ SW_LINEOUT_INSERT,
+ SW_JACK_PHYSICAL_INSERT,
+ SW_VIDEOOUT_INSERT,
+ SW_LINEIN_INSERT,
+};
+
+static int snd_jack_dev_disconnect(struct snd_device *device)
+{
+ struct snd_jack *jack = device->device_data;
+
+ if (!jack->input_dev)
+ return 0;
+
+ /* If the input device is registered with the input subsystem
+ * then we need to use a different deallocator. */
+ if (jack->registered)
+ input_unregister_device(jack->input_dev);
+ else
+ input_free_device(jack->input_dev);
+ jack->input_dev = NULL;
+ return 0;
+}
+
+static int snd_jack_dev_free(struct snd_device *device)
+{
+ struct snd_jack *jack = device->device_data;
+
+ if (jack->private_free)
+ jack->private_free(jack);
+
+ snd_jack_dev_disconnect(device);
+
+ kfree(jack->id);
+ kfree(jack);
+
+ return 0;
+}
+
+static int snd_jack_dev_register(struct snd_device *device)
+{
+ struct snd_jack *jack = device->device_data;
+ struct snd_card *card = device->card;
+ int err, i;
+
+ snprintf(jack->name, sizeof(jack->name), "%s %s",
+ card->shortname, jack->id);
+ jack->input_dev->name = jack->name;
+
+ /* Default to the sound card device. */
+ if (!jack->input_dev->dev.parent)
+ jack->input_dev->dev.parent = snd_card_get_device_link(card);
+
+ /* Add capabilities for any keys that are enabled */
+ for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
+ int testbit = SND_JACK_BTN_0 >> i;
+
+ if (!(jack->type & testbit))
+ continue;
+
+ if (!jack->key[i])
+ jack->key[i] = BTN_0 + i;
+
+ input_set_capability(jack->input_dev, EV_KEY, jack->key[i]);
+ }
+
+ err = input_register_device(jack->input_dev);
+ if (err == 0)
+ jack->registered = 1;
+
+ return err;
+}
+
+/**
+ * snd_jack_new - Create a new jack
+ * @card: the card instance
+ * @id: an identifying string for this jack
+ * @type: a bitmask of enum snd_jack_type values that can be detected by
+ * this jack
+ * @jjack: Used to provide the allocated jack object to the caller.
+ *
+ * Creates a new jack object.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ * On success @jjack will be initialised.
+ */
+int snd_jack_new(struct snd_card *card, const char *id, int type,
+ struct snd_jack **jjack)
+{
+ struct snd_jack *jack;
+ int err;
+ int i;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_jack_dev_free,
+ .dev_register = snd_jack_dev_register,
+ .dev_disconnect = snd_jack_dev_disconnect,
+ };
+
+ jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
+ if (jack == NULL)
+ return -ENOMEM;
+
+ jack->id = kstrdup(id, GFP_KERNEL);
+
+ jack->input_dev = input_allocate_device();
+ if (jack->input_dev == NULL) {
+ err = -ENOMEM;
+ goto fail_input;
+ }
+
+ jack->input_dev->phys = "ALSA";
+
+ jack->type = type;
+
+ for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
+ if (type & (1 << i))
+ input_set_capability(jack->input_dev, EV_SW,
+ jack_switch_types[i]);
+
+ err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
+ if (err < 0)
+ goto fail_input;
+
+ *jjack = jack;
+
+ return 0;
+
+fail_input:
+ input_free_device(jack->input_dev);
+ kfree(jack->id);
+ kfree(jack);
+ return err;
+}
+EXPORT_SYMBOL(snd_jack_new);
+
+/**
+ * snd_jack_set_parent - Set the parent device for a jack
+ *
+ * @jack: The jack to configure
+ * @parent: The device to set as parent for the jack.
+ *
+ * Set the parent for the jack devices in the device tree. This
+ * function is only valid prior to registration of the jack. If no
+ * parent is configured then the parent device will be the sound card.
+ */
+void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
+{
+ WARN_ON(jack->registered);
+
+ jack->input_dev->dev.parent = parent;
+}
+EXPORT_SYMBOL(snd_jack_set_parent);
+
+/**
+ * snd_jack_set_key - Set a key mapping on a jack
+ *
+ * @jack: The jack to configure
+ * @type: Jack report type for this key
+ * @keytype: Input layer key type to be reported
+ *
+ * Map a SND_JACK_BTN_ button type to an input layer key, allowing
+ * reporting of keys on accessories via the jack abstraction. If no
+ * mapping is provided but keys are enabled in the jack type then
+ * BTN_n numeric buttons will be reported.
+ *
+ * If jacks are not reporting via the input API this call will have no
+ * effect.
+ *
+ * Note that this is intended to be use by simple devices with small
+ * numbers of keys that can be reported. It is also possible to
+ * access the input device directly - devices with complex input
+ * capabilities on accessories should consider doing this rather than
+ * using this abstraction.
+ *
+ * This function may only be called prior to registration of the jack.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
+ int keytype)
+{
+ int key = fls(SND_JACK_BTN_0) - fls(type);
+
+ WARN_ON(jack->registered);
+
+ if (!keytype || key >= ARRAY_SIZE(jack->key))
+ return -EINVAL;
+
+ jack->type |= type;
+ jack->key[key] = keytype;
+
+ return 0;
+}
+EXPORT_SYMBOL(snd_jack_set_key);
+
+/**
+ * snd_jack_report - Report the current status of a jack
+ *
+ * @jack: The jack to report status for
+ * @status: The current status of the jack
+ */
+void snd_jack_report(struct snd_jack *jack, int status)
+{
+ int i;
+
+ if (!jack)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
+ int testbit = SND_JACK_BTN_0 >> i;
+
+ if (jack->type & testbit)
+ input_report_key(jack->input_dev, jack->key[i],
+ status & testbit);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
+ int testbit = 1 << i;
+ if (jack->type & testbit)
+ input_report_switch(jack->input_dev,
+ jack_switch_types[i],
+ status & testbit);
+ }
+
+ input_sync(jack->input_dev);
+}
+EXPORT_SYMBOL(snd_jack_report);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Jack detection support for ALSA");
+MODULE_LICENSE("GPL");
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 129abab5ce9..082509eb805 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Takashi Iwai <tiwai@suse.de>
*
* Generic memory allocators
@@ -21,133 +21,11 @@
*
*/
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <asm/uaccess.h>
#include <linux/dma-mapping.h>
-#include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/genalloc.h>
#include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
-
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Memory allocator for ALSA system.");
-MODULE_LICENSE("GPL");
-
-
-#ifndef SNDRV_CARDS
-#define SNDRV_CARDS 8
-#endif
-
-/*
- */
-
-void *snd_malloc_sgbuf_pages(struct device *device,
- size_t size, struct snd_dma_buffer *dmab,
- size_t *res_size);
-int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
-
-/*
- */
-
-static DECLARE_MUTEX(list_mutex);
-static LIST_HEAD(mem_list_head);
-
-/* buffer preservation list */
-struct snd_mem_list {
- struct snd_dma_buffer buffer;
- unsigned int id;
- struct list_head list;
-};
-
-/* id for pre-allocated buffers */
-#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
-
-#ifdef CONFIG_SND_DEBUG
-#define __ASTRING__(x) #x
-#define snd_assert(expr, args...) do {\
- if (!(expr)) {\
- printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
- args;\
- }\
-} while (0)
-#else
-#define snd_assert(expr, args...) /**/
-#endif
-
-/*
- * Hacks
- */
-
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-/*
- * A hack to allocate large buffers via dma_alloc_coherent()
- *
- * since dma_alloc_coherent always tries GFP_DMA when the requested
- * pci memory region is below 32bit, it happens quite often that even
- * 2 order of pages cannot be allocated.
- *
- * so in the following, we allocate at first without dma_mask, so that
- * allocation will be done without GFP_DMA. if the area doesn't match
- * with the requested region, then realloate with the original dma_mask
- * again.
- *
- * Really, we want to move this type of thing into dma_alloc_coherent()
- * so dma_mask doesn't have to be messed with.
- */
-
-static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle,
- gfp_t flags)
-{
- void *ret;
- u64 dma_mask, coherent_dma_mask;
-
- if (dev == NULL || !dev->dma_mask)
- return dma_alloc_coherent(dev, size, dma_handle, flags);
- dma_mask = *dev->dma_mask;
- coherent_dma_mask = dev->coherent_dma_mask;
- *dev->dma_mask = 0xffffffff; /* do without masking */
- dev->coherent_dma_mask = 0xffffffff; /* do without masking */
- ret = dma_alloc_coherent(dev, size, dma_handle, flags);
- *dev->dma_mask = dma_mask; /* restore */
- dev->coherent_dma_mask = coherent_dma_mask; /* restore */
- if (ret) {
- /* obtained address is out of range? */
- if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
- /* reallocate with the proper mask */
- dma_free_coherent(dev, size, ret, *dma_handle);
- ret = dma_alloc_coherent(dev, size, dma_handle, flags);
- }
- } else {
- /* wish to success now with the proper mask... */
- if (dma_mask != 0xffffffffUL) {
- /* allocation with GFP_ATOMIC to avoid the long stall */
- flags &= ~GFP_KERNEL;
- flags |= GFP_ATOMIC;
- ret = dma_alloc_coherent(dev, size, dma_handle, flags);
- }
- }
- return ret;
-}
-
-/* redefine dma_alloc_coherent for some architectures */
-#undef dma_alloc_coherent
-#define dma_alloc_coherent snd_dma_hack_alloc_coherent
-
-#endif /* arch */
-
-#if ! defined(__arm__)
-#define NEED_RESERVE_PAGES
-#endif
/*
*
@@ -155,32 +33,6 @@ static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
*
*/
-static long snd_allocated_pages; /* holding the number of allocated pages */
-
-static inline void inc_snd_pages(int order)
-{
- snd_allocated_pages += 1 << order;
-}
-
-static inline void dec_snd_pages(int order)
-{
- snd_allocated_pages -= 1 << order;
-}
-
-static void mark_pages(struct page *page, int order)
-{
- struct page *last_page = page + (1 << order);
- while (page < last_page)
- SetPageReserved(page++);
-}
-
-static void unmark_pages(struct page *page, int order)
-{
- struct page *last_page = page + (1 << order);
- while (page < last_page)
- ClearPageReserved(page++);
-}
-
/**
* snd_malloc_pages - allocate pages with the given size
* @size: the size to allocate in bytes
@@ -188,21 +40,19 @@ static void unmark_pages(struct page *page, int order)
*
* Allocates the physically contiguous pages with the given size.
*
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ * Return: The pointer of the buffer, or %NULL if no enough memory.
*/
void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
{
int pg;
- void *res;
- snd_assert(size > 0, return NULL);
- snd_assert(gfp_flags != 0, return NULL);
+ if (WARN_ON(!size))
+ return NULL;
+ if (WARN_ON(!gfp_flags))
+ return NULL;
+ gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
pg = get_order(size);
- if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
- mark_pages(virt_to_page(res), pg);
- inc_snd_pages(pg);
- }
- return res;
+ return (void *) __get_free_pages(gfp_flags, pg);
}
/**
@@ -219,8 +69,6 @@ void snd_free_pages(void *ptr, size_t size)
if (ptr == NULL)
return;
pg = get_order(size);
- dec_snd_pages(pg);
- unmark_pages(virt_to_page(ptr), pg);
free_pages((unsigned long) ptr, pg);
}
@@ -230,28 +78,21 @@ void snd_free_pages(void *ptr, size_t size)
*
*/
+#ifdef CONFIG_HAS_DMA
/* allocate the coherent DMA pages */
static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
{
int pg;
- void *res;
gfp_t gfp_flags;
- snd_assert(size > 0, return NULL);
- snd_assert(dma != NULL, return NULL);
+ if (WARN_ON(!dma))
+ return NULL;
pg = get_order(size);
gfp_flags = GFP_KERNEL
+ | __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
- res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
- if (res != NULL) {
-#ifdef NEED_RESERVE_PAGES
- mark_pages(virt_to_page(res), pg); /* should be dma_to_page() */
-#endif
- inc_snd_pages(pg);
- }
-
- return res;
+ return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
}
/* free the coherent DMA pages */
@@ -263,45 +104,50 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
if (ptr == NULL)
return;
pg = get_order(size);
- dec_snd_pages(pg);
-#ifdef NEED_RESERVE_PAGES
- unmark_pages(virt_to_page(ptr), pg); /* should be dma_to_page() */
-#endif
dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
}
-#ifdef CONFIG_SBUS
-
-static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
- dma_addr_t *dma_addr)
+#ifdef CONFIG_GENERIC_ALLOCATOR
+/**
+ * snd_malloc_dev_iram - allocate memory from on-chip internal ram
+ * @dmab: buffer allocation record to store the allocated data
+ * @size: number of bytes to allocate from the iram
+ *
+ * This function requires iram phandle provided via of_node
+ */
+static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size)
{
- struct sbus_dev *sdev = (struct sbus_dev *)dev;
- int pg;
- void *res;
+ struct device *dev = dmab->dev.dev;
+ struct gen_pool *pool = NULL;
- snd_assert(size > 0, return NULL);
- snd_assert(dma_addr != NULL, return NULL);
- pg = get_order(size);
- res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
- if (res != NULL)
- inc_snd_pages(pg);
- return res;
-}
+ dmab->area = NULL;
+ dmab->addr = 0;
-static void snd_free_sbus_pages(struct device *dev, size_t size,
- void *ptr, dma_addr_t dma_addr)
-{
- struct sbus_dev *sdev = (struct sbus_dev *)dev;
- int pg;
+ if (dev->of_node)
+ pool = of_get_named_gen_pool(dev->of_node, "iram", 0);
- if (ptr == NULL)
+ if (!pool)
return;
- pg = get_order(size);
- dec_snd_pages(pg);
- sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+
+ /* Assign the pool into private_data field */
+ dmab->private_data = pool;
+
+ dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr);
}
-#endif /* CONFIG_SBUS */
+/**
+ * snd_free_dev_iram - free allocated specific memory from on-chip internal ram
+ * @dmab: buffer allocation record to store the allocated data
+ */
+static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
+{
+ struct gen_pool *pool = dmab->private_data;
+
+ if (pool && dmab->area)
+ gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
+}
+#endif /* CONFIG_GENERIC_ALLOCATOR */
+#endif /* CONFIG_HAS_DMA */
/*
*
@@ -319,37 +165,49 @@ static void snd_free_sbus_pages(struct device *dev, size_t size,
*
* Calls the memory-allocator function for the corresponding
* buffer type.
- *
- * Returns zero if the buffer with the given size is allocated successfuly,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
*/
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
{
- snd_assert(size > 0, return -ENXIO);
- snd_assert(dmab != NULL, return -ENXIO);
+ if (WARN_ON(!size))
+ return -ENXIO;
+ if (WARN_ON(!dmab))
+ return -ENXIO;
dmab->dev.type = type;
dmab->dev.dev = device;
dmab->bytes = 0;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
- dmab->area = snd_malloc_pages(size, (unsigned long)device);
+ dmab->area = snd_malloc_pages(size,
+ (__force gfp_t)(unsigned long)device);
dmab->addr = 0;
break;
-#ifdef CONFIG_SBUS
- case SNDRV_DMA_TYPE_SBUS:
- dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
- break;
-#endif
+#ifdef CONFIG_HAS_DMA
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ case SNDRV_DMA_TYPE_DEV_IRAM:
+ snd_malloc_dev_iram(dmab, size);
+ if (dmab->area)
+ break;
+ /* Internal memory might have limited size and no enough space,
+ * so if we fail to malloc, try to fetch memory traditionally.
+ */
+ dmab->dev.type = SNDRV_DMA_TYPE_DEV;
+#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
break;
+#endif
+#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
break;
+#endif
default:
- printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
+ pr_err("snd-malloc: invalid device type %d\n", type);
dmab->area = NULL;
dmab->addr = 0;
return -ENXIO;
@@ -371,24 +229,26 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
* buffer type. When no space is left, this function reduces the size and
* tries to allocate again. The size actually allocated is stored in
* res_size argument.
- *
- * Returns zero if the buffer with the given size is allocated successfuly,
- * other a negative value at error.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
*/
int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
{
int err;
- snd_assert(size > 0, return -ENXIO);
- snd_assert(dmab != NULL, return -ENXIO);
-
while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
+ size_t aligned_size;
if (err != -ENOMEM)
return err;
- size >>= 1;
if (size <= PAGE_SIZE)
return -ENOMEM;
+ aligned_size = PAGE_SIZE << get_order(size);
+ if (size != aligned_size)
+ size = aligned_size;
+ else
+ size >>= 1;
}
if (! dmab->area)
return -ENOMEM;
@@ -408,265 +268,26 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
case SNDRV_DMA_TYPE_CONTINUOUS:
snd_free_pages(dmab->area, dmab->bytes);
break;
-#ifdef CONFIG_SBUS
- case SNDRV_DMA_TYPE_SBUS:
- snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
+#ifdef CONFIG_HAS_DMA
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ case SNDRV_DMA_TYPE_DEV_IRAM:
+ snd_free_dev_iram(dmab);
break;
-#endif
+#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
break;
+#endif
+#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
snd_free_sgbuf_pages(dmab);
break;
- default:
- printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
- }
-}
-
-
-/**
- * snd_dma_get_reserved - get the reserved buffer for the given device
- * @dmab: the buffer allocation record to store
- * @id: the buffer id
- *
- * Looks for the reserved-buffer list and re-uses if the same buffer
- * is found in the list. When the buffer is found, it's removed from the free list.
- *
- * Returns the size of buffer if the buffer is found, or zero if not found.
- */
-size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
-{
- struct list_head *p;
- struct snd_mem_list *mem;
-
- snd_assert(dmab, return 0);
-
- down(&list_mutex);
- list_for_each(p, &mem_list_head) {
- mem = list_entry(p, struct snd_mem_list, list);
- if (mem->id == id &&
- (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
- ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
- struct device *dev = dmab->dev.dev;
- list_del(p);
- *dmab = mem->buffer;
- if (dmab->dev.dev == NULL)
- dmab->dev.dev = dev;
- kfree(mem);
- up(&list_mutex);
- return dmab->bytes;
- }
- }
- up(&list_mutex);
- return 0;
-}
-
-/**
- * snd_dma_reserve_buf - reserve the buffer
- * @dmab: the buffer to reserve
- * @id: the buffer id
- *
- * Reserves the given buffer as a reserved buffer.
- *
- * Returns zero if successful, or a negative code at error.
- */
-int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
-{
- struct snd_mem_list *mem;
-
- snd_assert(dmab, return -EINVAL);
- mem = kmalloc(sizeof(*mem), GFP_KERNEL);
- if (! mem)
- return -ENOMEM;
- down(&list_mutex);
- mem->buffer = *dmab;
- mem->id = id;
- list_add_tail(&mem->list, &mem_list_head);
- up(&list_mutex);
- return 0;
-}
-
-/*
- * purge all reserved buffers
- */
-static void free_all_reserved_pages(void)
-{
- struct list_head *p;
- struct snd_mem_list *mem;
-
- down(&list_mutex);
- while (! list_empty(&mem_list_head)) {
- p = mem_list_head.next;
- mem = list_entry(p, struct snd_mem_list, list);
- list_del(p);
- snd_dma_free_pages(&mem->buffer);
- kfree(mem);
- }
- up(&list_mutex);
-}
-
-
-#ifdef CONFIG_PROC_FS
-/*
- * proc file interface
- */
-#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
-static struct proc_dir_entry *snd_mem_proc;
-
-static int snd_mem_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0;
- long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
- struct list_head *p;
- struct snd_mem_list *mem;
- int devno;
- static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
-
- down(&list_mutex);
- len += snprintf(page + len, count - len,
- "pages : %li bytes (%li pages per %likB)\n",
- pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
- devno = 0;
- list_for_each(p, &mem_list_head) {
- mem = list_entry(p, struct snd_mem_list, list);
- devno++;
- len += snprintf(page + len, count - len,
- "buffer %d : ID %08x : type %s\n",
- devno, mem->id, types[mem->buffer.dev.type]);
- len += snprintf(page + len, count - len,
- " addr = 0x%lx, size = %d bytes\n",
- (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes);
- }
- up(&list_mutex);
- return len;
-}
-
-/* FIXME: for pci only - other bus? */
-#ifdef CONFIG_PCI
-#define gettoken(bufp) strsep(bufp, " \t\n")
-
-static int snd_mem_proc_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char buf[128];
- char *token, *p;
-
- if (count > ARRAY_SIZE(buf) - 1)
- count = ARRAY_SIZE(buf) - 1;
- if (copy_from_user(buf, buffer, count))
- return -EFAULT;
- buf[ARRAY_SIZE(buf) - 1] = '\0';
-
- p = buf;
- token = gettoken(&p);
- if (! token || *token == '#')
- return (int)count;
- if (strcmp(token, "add") == 0) {
- char *endp;
- int vendor, device, size, buffers;
- long mask;
- int i, alloced;
- struct pci_dev *pci;
-
- if ((token = gettoken(&p)) == NULL ||
- (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
- (token = gettoken(&p)) == NULL ||
- (device = simple_strtol(token, NULL, 0)) <= 0 ||
- (token = gettoken(&p)) == NULL ||
- (mask = simple_strtol(token, NULL, 0)) < 0 ||
- (token = gettoken(&p)) == NULL ||
- (size = memparse(token, &endp)) < 64*1024 ||
- size > 16*1024*1024 /* too big */ ||
- (token = gettoken(&p)) == NULL ||
- (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
- buffers > 4) {
- printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
- return (int)count;
- }
- vendor &= 0xffff;
- device &= 0xffff;
-
- alloced = 0;
- pci = NULL;
- while ((pci = pci_get_device(vendor, device, pci)) != NULL) {
- if (mask > 0 && mask < 0xffffffff) {
- if (pci_set_dma_mask(pci, mask) < 0 ||
- pci_set_consistent_dma_mask(pci, mask) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
- return (int)count;
- }
- }
- for (i = 0; i < buffers; i++) {
- struct snd_dma_buffer dmab;
- memset(&dmab, 0, sizeof(dmab));
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- size, &dmab) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
- pci_dev_put(pci);
- return (int)count;
- }
- snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
- }
- alloced++;
- }
- if (! alloced) {
- for (i = 0; i < buffers; i++) {
- struct snd_dma_buffer dmab;
- memset(&dmab, 0, sizeof(dmab));
- /* FIXME: We can allocate only in ZONE_DMA
- * without a device pointer!
- */
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
- size, &dmab) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
- break;
- }
- snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
- }
- }
- } else if (strcmp(token, "erase") == 0)
- /* FIXME: need for releasing each buffer chunk? */
- free_all_reserved_pages();
- else
- printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
- return (int)count;
-}
-#endif /* CONFIG_PCI */
-#endif /* CONFIG_PROC_FS */
-
-/*
- * module entry
- */
-
-static int __init snd_mem_init(void)
-{
-#ifdef CONFIG_PROC_FS
- snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
- if (snd_mem_proc) {
- snd_mem_proc->read_proc = snd_mem_proc_read;
-#ifdef CONFIG_PCI
- snd_mem_proc->write_proc = snd_mem_proc_write;
#endif
+ default:
+ pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
}
-#endif
- return 0;
-}
-
-static void __exit snd_mem_exit(void)
-{
- remove_proc_entry(SND_MEM_PROC_FILE, NULL);
- free_all_reserved_pages();
- if (snd_allocated_pages > 0)
- printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
}
-
-module_init(snd_mem_init)
-module_exit(snd_mem_exit)
-
-
/*
* exports
*/
@@ -674,8 +295,5 @@ EXPORT_SYMBOL(snd_dma_alloc_pages);
EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
EXPORT_SYMBOL(snd_dma_free_pages);
-EXPORT_SYMBOL(snd_dma_get_reserved_buf);
-EXPORT_SYMBOL(snd_dma_reserve_buf);
-
EXPORT_SYMBOL(snd_malloc_pages);
EXPORT_SYMBOL(snd_free_pages);
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 7d8e2eebba5..36c0f1a2e18 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -1,7 +1,7 @@
/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
- * Memory allocation helpers.
+ * Misc memory accessors
*
*
* This program is free software; you can redistribute it and/or modify
@@ -20,221 +20,10 @@
*
*/
-#include <sound/driver.h>
+#include <linux/export.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/pci.h>
#include <sound/core.h>
-#include <sound/info.h>
-
-/*
- * memory allocation helpers and debug routines
- */
-
-#ifdef CONFIG_SND_DEBUG_MEMORY
-
-struct snd_alloc_track {
- unsigned long magic;
- void *caller;
- size_t size;
- struct list_head list;
- long data[0];
-};
-
-#define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned long)((struct snd_alloc_track *)0)->data)
-
-static long snd_alloc_kmalloc;
-static long snd_alloc_vmalloc;
-static LIST_HEAD(snd_alloc_kmalloc_list);
-static LIST_HEAD(snd_alloc_vmalloc_list);
-static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock);
-static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
-#define KMALLOC_MAGIC 0x87654321
-#define VMALLOC_MAGIC 0x87654320
-static snd_info_entry_t *snd_memory_info_entry;
-
-void __init snd_memory_init(void)
-{
- snd_alloc_kmalloc = 0;
- snd_alloc_vmalloc = 0;
-}
-
-void snd_memory_done(void)
-{
- struct list_head *head;
- struct snd_alloc_track *t;
-
- if (snd_alloc_kmalloc > 0)
- snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc);
- if (snd_alloc_vmalloc > 0)
- snd_printk(KERN_ERR "Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc);
- list_for_each_prev(head, &snd_alloc_kmalloc_list) {
- t = list_entry(head, struct snd_alloc_track, list);
- if (t->magic != KMALLOC_MAGIC) {
- snd_printk(KERN_ERR "Corrupted kmalloc\n");
- break;
- }
- snd_printk(KERN_ERR "kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
- }
- list_for_each_prev(head, &snd_alloc_vmalloc_list) {
- t = list_entry(head, struct snd_alloc_track, list);
- if (t->magic != VMALLOC_MAGIC) {
- snd_printk(KERN_ERR "Corrupted vmalloc\n");
- break;
- }
- snd_printk(KERN_ERR "vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
- }
-}
-
-static void *__snd_kmalloc(size_t size, gfp_t flags, void *caller)
-{
- unsigned long cpu_flags;
- struct snd_alloc_track *t;
- void *ptr;
-
- ptr = snd_wrapper_kmalloc(size + sizeof(struct snd_alloc_track), flags);
- if (ptr != NULL) {
- t = (struct snd_alloc_track *)ptr;
- t->magic = KMALLOC_MAGIC;
- t->caller = caller;
- spin_lock_irqsave(&snd_alloc_kmalloc_lock, cpu_flags);
- list_add_tail(&t->list, &snd_alloc_kmalloc_list);
- spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, cpu_flags);
- t->size = size;
- snd_alloc_kmalloc += size;
- ptr = t->data;
- }
- return ptr;
-}
-
-#define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0));
-void *snd_hidden_kmalloc(size_t size, gfp_t flags)
-{
- return _snd_kmalloc(size, flags);
-}
-
-void *snd_hidden_kzalloc(size_t size, gfp_t flags)
-{
- void *ret = _snd_kmalloc(size, flags);
- if (ret)
- memset(ret, 0, size);
- return ret;
-}
-EXPORT_SYMBOL(snd_hidden_kzalloc);
-
-void *snd_hidden_kcalloc(size_t n, size_t size, gfp_t flags)
-{
- void *ret = NULL;
- if (n != 0 && size > INT_MAX / n)
- return ret;
- return snd_hidden_kzalloc(n * size, flags);
-}
-
-void snd_hidden_kfree(const void *obj)
-{
- unsigned long flags;
- struct snd_alloc_track *t;
- if (obj == NULL)
- return;
- t = snd_alloc_track_entry(obj);
- if (t->magic != KMALLOC_MAGIC) {
- snd_printk(KERN_WARNING "bad kfree (called from %p)\n", __builtin_return_address(0));
- return;
- }
- spin_lock_irqsave(&snd_alloc_kmalloc_lock, flags);
- list_del(&t->list);
- spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, flags);
- t->magic = 0;
- snd_alloc_kmalloc -= t->size;
- obj = t;
- snd_wrapper_kfree(obj);
-}
-
-void *snd_hidden_vmalloc(unsigned long size)
-{
- void *ptr;
- ptr = snd_wrapper_vmalloc(size + sizeof(struct snd_alloc_track));
- if (ptr) {
- struct snd_alloc_track *t = (struct snd_alloc_track *)ptr;
- t->magic = VMALLOC_MAGIC;
- t->caller = __builtin_return_address(0);
- spin_lock(&snd_alloc_vmalloc_lock);
- list_add_tail(&t->list, &snd_alloc_vmalloc_list);
- spin_unlock(&snd_alloc_vmalloc_lock);
- t->size = size;
- snd_alloc_vmalloc += size;
- ptr = t->data;
- }
- return ptr;
-}
-
-void snd_hidden_vfree(void *obj)
-{
- struct snd_alloc_track *t;
- if (obj == NULL)
- return;
- t = snd_alloc_track_entry(obj);
- if (t->magic != VMALLOC_MAGIC) {
- snd_printk(KERN_ERR "bad vfree (called from %p)\n", __builtin_return_address(0));
- return;
- }
- spin_lock(&snd_alloc_vmalloc_lock);
- list_del(&t->list);
- spin_unlock(&snd_alloc_vmalloc_lock);
- t->magic = 0;
- snd_alloc_vmalloc -= t->size;
- obj = t;
- snd_wrapper_vfree(obj);
-}
-
-char *snd_hidden_kstrdup(const char *s, gfp_t flags)
-{
- int len;
- char *buf;
-
- if (!s) return NULL;
-
- len = strlen(s) + 1;
- buf = _snd_kmalloc(len, flags);
- if (buf)
- memcpy(buf, s, len);
- return buf;
-}
-
-static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
-{
- snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc);
- snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc);
-}
-
-int __init snd_memory_info_init(void)
-{
- snd_info_entry_t *entry;
-
- entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL);
- if (entry) {
- entry->c.text.read_size = 256;
- entry->c.text.read = snd_memory_info_read;
- if (snd_info_register(entry) < 0) {
- snd_info_free_entry(entry);
- entry = NULL;
- }
- }
- snd_memory_info_entry = entry;
- return 0;
-}
-
-int __exit snd_memory_info_done(void)
-{
- if (snd_memory_info_entry)
- snd_info_unregister(snd_memory_info_entry);
- return 0;
-}
-
-#endif /* CONFIG_SND_DEBUG_MEMORY */
/**
* copy_to_user_fromio - copy data from mmio-space to user-space
@@ -244,7 +33,7 @@ int __exit snd_memory_info_done(void)
*
* Copies the data from mmio-space to user-space.
*
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
*/
int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
{
@@ -267,6 +56,8 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
#endif
}
+EXPORT_SYMBOL(copy_to_user_fromio);
+
/**
* copy_from_user_toio - copy data from user-space to mmio-space
* @dst: the destination pointer on mmio-space
@@ -275,7 +66,7 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
*
* Copies the data from user-space to mmio-space.
*
- * Returns zero if successful, or non-zero on failure.
+ * Return: Zero if successful, or non-zero on failure.
*/
int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
{
@@ -297,3 +88,5 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
return 0;
#endif
}
+
+EXPORT_SYMBOL(copy_from_user_toio);
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 1a81fe4df21..30e027ecf4d 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -1,6 +1,6 @@
/*
* Misc and compatibility things
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,58 +19,135 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/moduleparam.h>
#include <linux/time.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
-int snd_task_name(struct task_struct *task, char *name, size_t size)
-{
- unsigned int idx;
+#ifdef CONFIG_SND_DEBUG
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+#define DEFAULT_DEBUG_LEVEL 2
+#else
+#define DEFAULT_DEBUG_LEVEL 1
+#endif
+
+static int debug = DEFAULT_DEBUG_LEVEL;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0 = disable)");
+
+#endif /* CONFIG_SND_DEBUG */
- snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
- for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
- name[idx] = task->comm[idx];
- name[idx] = '\0';
- return 0;
+void release_and_free_resource(struct resource *res)
+{
+ if (res) {
+ release_resource(res);
+ kfree(res);
+ }
}
+EXPORT_SYMBOL(release_and_free_resource);
+
#ifdef CONFIG_SND_VERBOSE_PRINTK
-void snd_verbose_printk(const char *file, int line, const char *format, ...)
+/* strip the leading path if the given path is absolute */
+static const char *sanity_file_name(const char *path)
+{
+ if (*path == '/')
+ return strrchr(path, '/') + 1;
+ else
+ return path;
+}
+#endif
+
+#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK)
+void __snd_printk(unsigned int level, const char *path, int line,
+ const char *format, ...)
{
va_list args;
-
- if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
- char tmp[] = "<0>";
- tmp[1] = format[1];
- printk("%sALSA %s:%d: ", tmp, file, line);
- format += 3;
- } else {
- printk("ALSA %s:%d: ", file, line);
- }
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+ int kern_level;
+ struct va_format vaf;
+ char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
+#endif
+
+#ifdef CONFIG_SND_DEBUG
+ if (debug < level)
+ return;
+#endif
+
va_start(args, format);
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+ vaf.fmt = format;
+ vaf.va = &args;
+
+ kern_level = printk_get_level(format);
+ if (kern_level) {
+ const char *end_of_header = printk_skip_level(format);
+ memcpy(verbose_fmt, format, end_of_header - format);
+ vaf.fmt = end_of_header;
+ } else if (level)
+ memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
+ printk(verbose_fmt, sanity_file_name(path), line, &vaf);
+
+#else
vprintk(format, args);
+#endif
va_end(args);
}
+EXPORT_SYMBOL_GPL(__snd_printk);
#endif
-#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
-void snd_verbose_printd(const char *file, int line, const char *format, ...)
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+/**
+ * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list
+ * @vendor: PCI SSV id
+ * @device: PCI SSD id
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID. When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup_id(u16 vendor, u16 device,
+ const struct snd_pci_quirk *list)
{
- va_list args;
-
- if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
- char tmp[] = "<0>";
- tmp[1] = format[1];
- printk("%sALSA %s:%d: ", tmp, file, line);
- format += 3;
- } else {
- printk(KERN_DEBUG "ALSA %s:%d: ", file, line);
+ const struct snd_pci_quirk *q;
+
+ for (q = list; q->subvendor; q++) {
+ if (q->subvendor != vendor)
+ continue;
+ if (!q->subdevice ||
+ (device & q->subdevice_mask) == q->subdevice)
+ return q;
}
- va_start(args, format);
- vprintk(format, args);
- va_end(args);
+ return NULL;
+}
+EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
+/**
+ * snd_pci_quirk_lookup - look up a PCI SSID quirk list
+ * @pci: pci_dev handle
+ * @list: quirk list, terminated by a null entry
+ *
+ * Look through the given quirk list and finds a matching entry
+ * with the same PCI SSID. When subdevice is 0, all subdevice
+ * values may match.
+ *
+ * Returns the matched entry pointer, or NULL if nothing matched.
+ */
+const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+ return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
+ pci->subsystem_device,
+ list);
}
+EXPORT_SYMBOL(snd_pci_quirk_lookup);
#endif
diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile
index e6d5a045ba2..10a79453245 100644
--- a/sound/core/oss/Makefile
+++ b/sound/core/oss/Makefile
@@ -1,12 +1,13 @@
#
# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
snd-mixer-oss-objs := mixer_oss.o
-snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \
- io.o copy.o linear.o mulaw.o route.o rate.o
+snd-pcm-oss-y := pcm_oss.o
+snd-pcm-oss-$(CONFIG_SND_PCM_OSS_PLUGINS) += pcm_plugin.o \
+ io.o copy.o linear.o mulaw.o route.o rate.o
obj-$(CONFIG_SND_MIXER_OSS) += snd-mixer-oss.o
obj-$(CONFIG_SND_PCM_OSS) += snd-pcm-oss.o
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c
index edecbe7417b..05b58d4fc2b 100644
--- a/sound/core/oss/copy.c
+++ b/sound/core/oss/copy.c
@@ -19,31 +19,31 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "pcm_plugin.h"
-static snd_pcm_sframes_t copy_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
unsigned int channel;
unsigned int nchannels;
- snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+ return -ENXIO;
if (frames == 0)
return 0;
nchannels = plugin->src_format.channels;
for (channel = 0; channel < nchannels; channel++) {
- snd_assert(src_channels->area.first % 8 == 0 &&
- src_channels->area.step % 8 == 0,
- return -ENXIO);
- snd_assert(dst_channels->area.first % 8 == 0 &&
- dst_channels->area.step % 8 == 0,
- return -ENXIO);
+ if (snd_BUG_ON(src_channels->area.first % 8 ||
+ src_channels->area.step % 8))
+ return -ENXIO;
+ if (snd_BUG_ON(dst_channels->area.first % 8 ||
+ dst_channels->area.step % 8))
+ return -ENXIO;
if (!src_channels->enabled) {
if (dst_channels->wanted)
snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
@@ -58,24 +58,29 @@ static snd_pcm_sframes_t copy_transfer(snd_pcm_plugin_t *plugin,
return frames;
}
-int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin)
{
int err;
- snd_pcm_plugin_t *plugin;
+ struct snd_pcm_plugin *plugin;
int width;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(src_format->format == dst_format->format, return -ENXIO);
- snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
- snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+ if (snd_BUG_ON(src_format->format != dst_format->format))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->rate != dst_format->rate))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->channels != dst_format->channels))
+ return -ENXIO;
width = snd_pcm_format_physical_width(src_format->format);
- snd_assert(width > 0, return -ENXIO);
+ if (snd_BUG_ON(width <= 0))
+ return -ENXIO;
err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
0, &plugin);
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
index bb1c99a5b73..6faa1d71920 100644
--- a/sound/core/oss/io.c
+++ b/sound/core/oss/io.c
@@ -1,6 +1,6 @@
/*
* PCM I/O Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
*
*
* This library is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -35,19 +34,22 @@
* Basic io plugin
*/
-static snd_pcm_sframes_t io_playback_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels ATTRIBUTE_UNUSED,
+static snd_pcm_sframes_t io_playback_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
- snd_assert(plugin != NULL, return -ENXIO);
- snd_assert(src_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin))
+ return -ENXIO;
+ if (snd_BUG_ON(!src_channels))
+ return -ENXIO;
if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
return pcm_write(plugin->plug, src_channels->area.addr, frames);
} else {
int channel, channels = plugin->dst_format.channels;
void **bufs = (void**)plugin->extra_data;
- snd_assert(bufs != NULL, return -ENXIO);
+ if (snd_BUG_ON(!bufs))
+ return -ENXIO;
for (channel = 0; channel < channels; channel++) {
if (src_channels[channel].enabled)
bufs[channel] = src_channels[channel].area.addr;
@@ -58,19 +60,22 @@ static snd_pcm_sframes_t io_playback_transfer(snd_pcm_plugin_t *plugin,
}
}
-static snd_pcm_sframes_t io_capture_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
- snd_pcm_plugin_channel_t *dst_channels,
+static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
- snd_assert(plugin != NULL, return -ENXIO);
- snd_assert(dst_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin))
+ return -ENXIO;
+ if (snd_BUG_ON(!dst_channels))
+ return -ENXIO;
if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
return pcm_read(plugin->plug, dst_channels->area.addr, frames);
} else {
int channel, channels = plugin->dst_format.channels;
void **bufs = (void**)plugin->extra_data;
- snd_assert(bufs != NULL, return -ENXIO);
+ if (snd_BUG_ON(!bufs))
+ return -ENXIO;
for (channel = 0; channel < channels; channel++) {
if (dst_channels[channel].enabled)
bufs[channel] = dst_channels[channel].area.addr;
@@ -82,13 +87,13 @@ static snd_pcm_sframes_t io_capture_transfer(snd_pcm_plugin_t *plugin,
return 0;
}
-static snd_pcm_sframes_t io_src_channels(snd_pcm_plugin_t *plugin,
+static snd_pcm_sframes_t io_src_channels(struct snd_pcm_plugin *plugin,
snd_pcm_uframes_t frames,
- snd_pcm_plugin_channel_t **channels)
+ struct snd_pcm_plugin_channel **channels)
{
int err;
unsigned int channel;
- snd_pcm_plugin_channel_t *v;
+ struct snd_pcm_plugin_channel *v;
err = snd_pcm_plugin_client_channels(plugin, frames, &v);
if (err < 0)
return err;
@@ -100,17 +105,19 @@ static snd_pcm_sframes_t io_src_channels(snd_pcm_plugin_t *plugin,
return frames;
}
-int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
- snd_pcm_hw_params_t *params,
- snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug,
+ struct snd_pcm_hw_params *params,
+ struct snd_pcm_plugin **r_plugin)
{
int err;
- snd_pcm_plugin_format_t format;
- snd_pcm_plugin_t *plugin;
+ struct snd_pcm_plugin_format format;
+ struct snd_pcm_plugin *plugin;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(plug != NULL && params != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plug || !params))
+ return -ENXIO;
format.format = params_format(params);
format.rate = params_rate(params);
format.channels = params_channels(params);
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index 12ed27a57b2..2045697f449 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -1,6 +1,6 @@
/*
* Linear conversion Plug-In
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>,
* Abramo Bagnara <abramo@alsa-project.org>
*
*
@@ -20,7 +20,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -30,20 +29,35 @@
* Basic linear conversion plugin
*/
-typedef struct linear_private_data {
- int conv;
-} linear_t;
+struct linear_priv {
+ int cvt_endian; /* need endian conversion? */
+ unsigned int src_ofs; /* byte offset in source format */
+ unsigned int dst_ofs; /* byte soffset in destination format */
+ unsigned int copy_ofs; /* byte offset in temporary u32 data */
+ unsigned int dst_bytes; /* byte size of destination format */
+ unsigned int copy_bytes; /* bytes to copy per conversion */
+ unsigned int flip; /* MSB flip for signeness, done after endian conv */
+};
-static void convert(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static inline void do_convert(struct linear_priv *data,
+ unsigned char *dst, unsigned char *src)
+{
+ unsigned int tmp = 0;
+ unsigned char *p = (unsigned char *)&tmp;
+
+ memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes);
+ if (data->cvt_endian)
+ tmp = swab32(tmp);
+ tmp ^= data->flip;
+ memcpy(dst, p + data->dst_ofs, data->dst_bytes);
+}
+
+static void convert(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
- linear_t *data = (linear_t *)plugin->extra_data;
- void *conv = conv_labels[data->conv];
+ struct linear_priv *data = (struct linear_priv *)plugin->extra_data;
int channel;
int nchannels = plugin->src_format.channels;
for (channel = 0; channel < nchannels; ++channel) {
@@ -64,38 +78,32 @@ static void convert(snd_pcm_plugin_t *plugin,
dst_step = dst_channels[channel].area.step / 8;
frames1 = frames;
while (frames1-- > 0) {
- goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
- after:
+ do_convert(data, dst, src);
src += src_step;
dst += dst_step;
}
}
}
-static snd_pcm_sframes_t linear_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
- linear_t *data;
-
- snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
- data = (linear_t *)plugin->extra_data;
+ if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+ return -ENXIO;
if (frames == 0)
return 0;
#ifdef CONFIG_SND_DEBUG
{
unsigned int channel;
for (channel = 0; channel < plugin->src_format.channels; channel++) {
- snd_assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0,
- return -ENXIO);
- snd_assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0,
- return -ENXIO);
+ if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+ src_channels[channel].area.step % 8))
+ return -ENXIO;
+ if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+ dst_channels[channel].area.step % 8))
+ return -ENXIO;
}
}
#endif
@@ -103,55 +111,67 @@ static snd_pcm_sframes_t linear_transfer(snd_pcm_plugin_t *plugin,
return frames;
}
-int conv_index(int src_format, int dst_format)
+static void init_data(struct linear_priv *data,
+ snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
{
- int src_endian, dst_endian, sign, src_width, dst_width;
+ int src_le, dst_le, src_bytes, dst_bytes;
- sign = (snd_pcm_format_signed(src_format) !=
- snd_pcm_format_signed(dst_format));
-#ifdef SNDRV_LITTLE_ENDIAN
- src_endian = snd_pcm_format_big_endian(src_format);
- dst_endian = snd_pcm_format_big_endian(dst_format);
-#else
- src_endian = snd_pcm_format_little_endian(src_format);
- dst_endian = snd_pcm_format_little_endian(dst_format);
-#endif
-
- if (src_endian < 0)
- src_endian = 0;
- if (dst_endian < 0)
- dst_endian = 0;
+ src_bytes = snd_pcm_format_width(src_format) / 8;
+ dst_bytes = snd_pcm_format_width(dst_format) / 8;
+ src_le = snd_pcm_format_little_endian(src_format) > 0;
+ dst_le = snd_pcm_format_little_endian(dst_format) > 0;
- src_width = snd_pcm_format_width(src_format) / 8 - 1;
- dst_width = snd_pcm_format_width(dst_format) / 8 - 1;
-
- return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian;
+ data->dst_bytes = dst_bytes;
+ data->cvt_endian = src_le != dst_le;
+ data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes;
+ if (src_le) {
+ data->copy_ofs = 4 - data->copy_bytes;
+ data->src_ofs = src_bytes - data->copy_bytes;
+ } else
+ data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 -
+ src_bytes;
+ if (dst_le)
+ data->dst_ofs = 4 - data->dst_bytes;
+ else
+ data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 -
+ dst_bytes;
+ if (snd_pcm_format_signed(src_format) !=
+ snd_pcm_format_signed(dst_format)) {
+ if (dst_le)
+ data->flip = (__force u32)cpu_to_le32(0x80000000);
+ else
+ data->flip = (__force u32)cpu_to_be32(0x80000000);
+ }
}
-int snd_pcm_plugin_build_linear(snd_pcm_plug_t *plug,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin)
{
int err;
- struct linear_private_data *data;
- snd_pcm_plugin_t *plugin;
+ struct linear_priv *data;
+ struct snd_pcm_plugin *plugin;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
- snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
- snd_assert(snd_pcm_format_linear(src_format->format) &&
- snd_pcm_format_linear(dst_format->format), return -ENXIO);
+ if (snd_BUG_ON(src_format->rate != dst_format->rate))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->channels != dst_format->channels))
+ return -ENXIO;
+ if (snd_BUG_ON(!snd_pcm_format_linear(src_format->format) ||
+ !snd_pcm_format_linear(dst_format->format)))
+ return -ENXIO;
err = snd_pcm_plugin_build(plug, "linear format conversion",
src_format, dst_format,
- sizeof(linear_t), &plugin);
+ sizeof(struct linear_priv), &plugin);
if (err < 0)
return err;
- data = (linear_t *)plugin->extra_data;
- data->conv = conv_index(src_format->format, dst_format->format);
+ data = (struct linear_priv *)plugin->extra_data;
+ init_data(data, src_format->format, dst_format->format);
plugin->transfer = linear_transfer;
*r_plugin = plugin;
return 0;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 69e1059112d..5e6349f00ec 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1,6 +1,6 @@
/*
* OSS emulation layer for the mixer interface
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,12 +19,11 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/control.h>
@@ -34,28 +33,38 @@
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
MODULE_LICENSE("GPL");
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
static int snd_mixer_oss_open(struct inode *inode, struct file *file)
{
- int cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
- snd_card_t *card;
- snd_mixer_oss_file_t *fmixer;
+ struct snd_card *card;
+ struct snd_mixer_oss_file *fmixer;
int err;
- if ((card = snd_cards[cardnum]) == NULL)
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+
+ card = snd_lookup_oss_minor_data(iminor(inode),
+ SNDRV_OSS_DEVICE_TYPE_MIXER);
+ if (card == NULL)
return -ENODEV;
- if (card->mixer_oss == NULL)
+ if (card->mixer_oss == NULL) {
+ snd_card_unref(card);
return -ENODEV;
+ }
err = snd_card_file_add(card, file);
- if (err < 0)
+ if (err < 0) {
+ snd_card_unref(card);
return err;
+ }
fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
if (fmixer == NULL) {
snd_card_file_remove(card, file);
+ snd_card_unref(card);
return -ENOMEM;
}
fmixer->card = card;
@@ -64,17 +73,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
if (!try_module_get(card->module)) {
kfree(fmixer);
snd_card_file_remove(card, file);
+ snd_card_unref(card);
return -EFAULT;
}
+ snd_card_unref(card);
return 0;
}
static int snd_mixer_oss_release(struct inode *inode, struct file *file)
{
- snd_mixer_oss_file_t *fmixer;
+ struct snd_mixer_oss_file *fmixer;
if (file->private_data) {
- fmixer = (snd_mixer_oss_file_t *) file->private_data;
+ fmixer = file->private_data;
module_put(fmixer->card->module);
snd_card_file_remove(fmixer->card, file);
kfree(fmixer);
@@ -82,11 +93,11 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
return 0;
}
-static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer,
+static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
mixer_info __user *_info)
{
- snd_card_t *card = fmixer->card;
- snd_mixer_oss_t *mixer = fmixer->mixer;
+ struct snd_card *card = fmixer->card;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
struct mixer_info info;
memset(&info, 0, sizeof(info));
@@ -98,11 +109,11 @@ static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer,
+static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
_old_mixer_info __user *_info)
{
- snd_card_t *card = fmixer->card;
- snd_mixer_oss_t *mixer = fmixer->mixer;
+ struct snd_card *card = fmixer->card;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
_old_mixer_info info;
memset(&info, 0, sizeof(info));
@@ -113,9 +124,9 @@ static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static int snd_mixer_oss_caps(snd_mixer_oss_file_t *fmixer)
+static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
int result = 0;
if (mixer == NULL)
@@ -125,10 +136,10 @@ static int snd_mixer_oss_caps(snd_mixer_oss_file_t *fmixer)
return result;
}
-static int snd_mixer_oss_devmask(snd_mixer_oss_file_t *fmixer)
+static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_mixer_oss_slot *pslot;
int result = 0, chn;
if (mixer == NULL)
@@ -141,10 +152,10 @@ static int snd_mixer_oss_devmask(snd_mixer_oss_file_t *fmixer)
return result;
}
-static int snd_mixer_oss_stereodevs(snd_mixer_oss_file_t *fmixer)
+static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_mixer_oss_slot *pslot;
int result = 0, chn;
if (mixer == NULL)
@@ -157,9 +168,9 @@ static int snd_mixer_oss_stereodevs(snd_mixer_oss_file_t *fmixer)
return result;
}
-static int snd_mixer_oss_recmask(snd_mixer_oss_file_t *fmixer)
+static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
int result = 0;
if (mixer == NULL)
@@ -167,7 +178,7 @@ static int snd_mixer_oss_recmask(snd_mixer_oss_file_t *fmixer)
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
result = mixer->mask_recsrc;
} else {
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss_slot *pslot;
int chn;
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
@@ -178,20 +189,21 @@ static int snd_mixer_oss_recmask(snd_mixer_oss_file_t *fmixer)
return result;
}
-static int snd_mixer_oss_get_recsrc(snd_mixer_oss_file_t *fmixer)
+static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
int result = 0;
if (mixer == NULL)
return -EIO;
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
int err;
- if ((err = mixer->get_recsrc(fmixer, &result)) < 0)
+ unsigned int index;
+ if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
return err;
- result = 1 << result;
+ result = 1 << index;
} else {
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss_slot *pslot;
int chn;
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
@@ -206,11 +218,12 @@ static int snd_mixer_oss_get_recsrc(snd_mixer_oss_file_t *fmixer)
return mixer->oss_recsrc = result;
}
-static int snd_mixer_oss_set_recsrc(snd_mixer_oss_file_t *fmixer, int recsrc)
+static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_mixer_oss_slot *pslot;
int chn, active;
+ unsigned int index;
int result = 0;
if (mixer == NULL)
@@ -219,8 +232,8 @@ static int snd_mixer_oss_set_recsrc(snd_mixer_oss_file_t *fmixer, int recsrc)
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
mixer->put_recsrc(fmixer, ffz(~recsrc));
- mixer->get_recsrc(fmixer, &result);
- result = 1 << result;
+ mixer->get_recsrc(fmixer, &index);
+ result = 1 << index;
}
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
@@ -243,10 +256,10 @@ static int snd_mixer_oss_set_recsrc(snd_mixer_oss_file_t *fmixer, int recsrc)
return result;
}
-static int snd_mixer_oss_get_volume(snd_mixer_oss_file_t *fmixer, int slot)
+static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_mixer_oss_slot *pslot;
int result = 0, left, right;
if (mixer == NULL || slot > 30)
@@ -258,8 +271,10 @@ static int snd_mixer_oss_get_volume(snd_mixer_oss_file_t *fmixer, int slot)
result = pslot->get_volume(fmixer, pslot, &left, &right);
if (!pslot->stereo)
right = left;
- snd_assert(left >= 0 && left <= 100, return -EIO);
- snd_assert(right >= 0 && right <= 100, return -EIO);
+ if (snd_BUG_ON(left < 0 || left > 100))
+ return -EIO;
+ if (snd_BUG_ON(right < 0 || right > 100))
+ return -EIO;
if (result >= 0) {
pslot->volume[0] = left;
pslot->volume[1] = right;
@@ -268,11 +283,11 @@ static int snd_mixer_oss_get_volume(snd_mixer_oss_file_t *fmixer, int slot)
return result;
}
-static int snd_mixer_oss_set_volume(snd_mixer_oss_file_t *fmixer,
+static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
int slot, int volume)
{
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_mixer_oss_slot *pslot;
int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
if (mixer == NULL || slot > 30)
@@ -293,13 +308,14 @@ static int snd_mixer_oss_set_volume(snd_mixer_oss_file_t *fmixer,
return (left & 0xff) | ((right & 0xff) << 8);
}
-static int snd_mixer_oss_ioctl1(snd_mixer_oss_file_t *fmixer, unsigned int cmd, unsigned long arg)
+static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int tmp;
- snd_assert(fmixer != NULL, return -ENXIO);
+ if (snd_BUG_ON(!fmixer))
+ return -ENXIO;
if (((cmd >> 8) & 0xff) == 'M') {
switch (cmd) {
case SOUND_MIXER_INFO:
@@ -362,14 +378,15 @@ static int snd_mixer_oss_ioctl1(snd_mixer_oss_file_t *fmixer, unsigned int cmd,
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
+ return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
}
-int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg)
+int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
{
- snd_mixer_oss_file_t fmixer;
+ struct snd_mixer_oss_file fmixer;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
if (card->mixer_oss == NULL)
return -ENXIO;
memset(&fmixer, 0, sizeof(fmixer));
@@ -389,21 +406,16 @@ int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long a
* REGISTRATION PART
*/
-static struct file_operations snd_mixer_oss_f_ops =
+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,
};
-static snd_minor_t snd_mixer_oss_reg =
-{
- .comment = "mixer",
- .f_ops = &snd_mixer_oss_f_ops,
-};
-
/*
* utilities
*/
@@ -432,16 +444,16 @@ static long snd_mixer_oss_conv2(long val, long min, long max)
}
#if 0
-static void snd_mixer_oss_recsrce_set(snd_card_t *card, int slot)
+static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
{
- snd_mixer_oss_t *mixer = card->mixer_oss;
+ struct snd_mixer_oss *mixer = card->mixer_oss;
if (mixer)
mixer->mask_recsrc |= 1 << slot;
}
-static int snd_mixer_oss_recsrce_get(snd_card_t *card, int slot)
+static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
{
- snd_mixer_oss_t *mixer = card->mixer_oss;
+ struct snd_mixer_oss *mixer = card->mixer_oss;
if (mixer && (mixer->mask_recsrc & (1 << slot)))
return 1;
return 0;
@@ -488,27 +500,27 @@ struct slot {
#define ID_UNKNOWN ((unsigned int)-1)
-static snd_kcontrol_t *snd_mixer_oss_test_id(snd_mixer_oss_t *mixer, const char *name, int index)
+static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
{
- snd_card_t * card = mixer->card;
- snd_ctl_elem_id_t id;
+ struct snd_card *card = mixer->card;
+ struct snd_ctl_elem_id id;
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, name);
+ strlcpy(id.name, name, sizeof(id.name));
id.index = index;
return snd_ctl_find_id(card, &id);
}
-static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
unsigned int numid,
int *left, int *right)
{
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
- snd_kcontrol_t *kctl;
- snd_card_t *card = fmixer->card;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
+ struct snd_kcontrol *kctl;
+ struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
@@ -521,9 +533,13 @@ static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer,
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
- snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
- snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
- snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
+ if (kctl->info(kctl, uinfo))
+ goto __unalloc;
+ if (kctl->get(kctl, uctl))
+ goto __unalloc;
+ if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
+ uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
+ goto __unalloc;
*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]);
@@ -533,16 +549,16 @@ static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer,
kfree(uinfo);
}
-static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
unsigned int numid,
int *left, int *right,
int route)
{
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
- snd_kcontrol_t *kctl;
- snd_card_t *card = fmixer->card;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
+ struct snd_kcontrol *kctl;
+ struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
@@ -555,8 +571,10 @@ static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer,
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
- snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
- snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
+ if (kctl->info(kctl, uinfo))
+ goto __unalloc;
+ if (kctl->get(kctl, uctl))
+ goto __unalloc;
if (!uctl->value.integer.value[0]) {
*left = 0;
if (uinfo->count == 1)
@@ -570,11 +588,11 @@ static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer,
kfree(uinfo);
}
-static int snd_mixer_oss_get_volume1(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int *left, int *right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
*left = *right = 100;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -596,32 +614,38 @@ static int snd_mixer_oss_get_volume1(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
unsigned int numid,
int left, int right)
{
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
- snd_kcontrol_t *kctl;
- snd_card_t *card = fmixer->card;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
+ 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)
+ if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+ up_read(&card->controls_rwsem);
return;
+ }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
- snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
- snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
+ if (kctl->info(kctl, uinfo))
+ goto __unalloc;
+ if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
+ uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
+ goto __unalloc;
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);
- snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
+ if ((res = kctl->put(kctl, uctl)) < 0)
+ goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
__unalloc:
@@ -630,30 +654,31 @@ static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer,
kfree(uinfo);
}
-static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
unsigned int numid,
int left, int right,
int route)
{
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
- snd_kcontrol_t *kctl;
- snd_card_t *card = fmixer->card;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
+ 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(&fmixer->card->controls_rwsem);
+ up_read(&card->controls_rwsem);
return;
}
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
goto __unalloc;
- snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
+ if (kctl->info(kctl, uinfo))
+ goto __unalloc;
if (uinfo->count > 1) {
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
@@ -664,7 +689,8 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer,
} else {
uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
}
- snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
+ if ((res = kctl->put(kctl, uctl)) < 0)
+ goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
__unalloc:
@@ -673,16 +699,19 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer,
kfree(uinfo);
}
-static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int left, int right)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
+ } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
+ snd_mixer_oss_put_volume1_vol(fmixer, pslot,
+ slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
@@ -691,19 +720,27 @@ static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer,
if (left || right) {
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
+ if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
+ snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
+ if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
+ snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
} else {
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
+ } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
+ snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
+ } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
+ snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
}
@@ -711,11 +748,11 @@ static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static int snd_mixer_oss_get_recsrc1_sw(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -724,11 +761,11 @@ static int snd_mixer_oss_get_recsrc1_sw(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static int snd_mixer_oss_get_recsrc1_route(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int *active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
int left, right;
left = right = 1;
@@ -737,53 +774,58 @@ static int snd_mixer_oss_get_recsrc1_route(snd_mixer_oss_file_t *fmixer,
return 0;
}
-static int snd_mixer_oss_put_recsrc1_sw(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
return 0;
}
-static int snd_mixer_oss_put_recsrc1_route(snd_mixer_oss_file_t *fmixer,
- snd_mixer_oss_slot_t *pslot,
+static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
+ struct snd_mixer_oss_slot *pslot,
int active)
{
- struct slot *slot = (struct slot *)pslot->private_data;
+ struct slot *slot = pslot->private_data;
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
return 0;
}
-static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int *active_index)
+static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
{
- snd_card_t *card = fmixer->card;
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_kcontrol_t *kctl;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_card *card = fmixer->card;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_kcontrol *kctl;
+ struct snd_mixer_oss_slot *pslot;
struct slot *slot;
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
int err, idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
- snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
- snd_runtime_check(!(err = kctl->get(kctl, uctl)), goto __unlock);
+ if (! kctl) {
+ err = -ENOENT;
+ goto __unlock;
+ }
+ if ((err = kctl->info(kctl, uinfo)) < 0)
+ goto __unlock;
+ if ((err = kctl->get(kctl, uctl)) < 0)
+ goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -796,20 +838,21 @@ static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int
err = 0;
__unlock:
up_read(&card->controls_rwsem);
+ __free_only:
kfree(uctl);
kfree(uinfo);
return err;
}
-static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int active_index)
+static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
{
- snd_card_t *card = fmixer->card;
- snd_mixer_oss_t *mixer = fmixer->mixer;
- snd_kcontrol_t *kctl;
- snd_mixer_oss_slot_t *pslot;
+ struct snd_card *card = fmixer->card;
+ struct snd_mixer_oss *mixer = fmixer->mixer;
+ struct snd_kcontrol *kctl;
+ struct snd_mixer_oss_slot *pslot;
struct slot *slot = NULL;
- snd_ctl_elem_info_t *uinfo;
- snd_ctl_elem_value_t *uctl;
+ struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_value *uctl;
int err;
unsigned int idx;
@@ -817,17 +860,21 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
err = -ENOMEM;
- goto __unlock;
+ goto __free_only;
}
down_read(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
- snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
+ if (! kctl) {
+ err = -ENOENT;
+ goto __unlock;
+ }
+ if ((err = kctl->info(kctl, uinfo)) < 0)
+ goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
pslot = &mixer->slots[idx];
- slot = (struct slot *)pslot->private_data;
+ slot = pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -836,15 +883,17 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int
break;
slot = NULL;
}
- snd_runtime_check(slot != NULL, goto __unlock);
+ if (! slot)
+ goto __unlock;
for (idx = 0; idx < uinfo->count; idx++)
uctl->value.enumerated.item[idx] = slot->capture_item;
- snd_runtime_check((err = kctl->put(kctl, uctl)) >= 0, );
+ 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;
@@ -856,11 +905,11 @@ struct snd_mixer_oss_assign_table {
int index;
};
-static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, const char *name, int index, int item)
+static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
{
- snd_ctl_elem_info_t *info;
- snd_kcontrol_t *kcontrol;
- snd_card_t *card = mixer->card;
+ struct snd_ctl_elem_info *info;
+ struct snd_kcontrol *kcontrol;
+ struct snd_card *card = mixer->card;
int err;
down_read(&card->controls_rwsem);
@@ -888,9 +937,9 @@ static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, c
return 0;
}
-static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn)
+static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
{
- struct slot *p = (struct slot *)chn->private_data;
+ struct slot *p = chn->private_data;
if (p) {
if (p->allocated && p->assigned) {
kfree(p->assigned->name);
@@ -900,7 +949,7 @@ static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn)
}
}
-static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot)
+static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
{
int idx = rslot->number; /* remember this */
if (rslot->private_free)
@@ -909,17 +958,79 @@ static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot)
rslot->number = idx;
}
+/* 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,
+ struct slot *slot)
+{
+ char str[64];
+ int err;
+
+ err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_GLOBAL);
+ if (err)
+ return err;
+ sprintf(str, "%s Switch", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_GSWITCH);
+ if (err)
+ return err;
+ sprintf(str, "%s Route", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_GROUTE);
+ if (err)
+ return err;
+ sprintf(str, "%s Volume", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_GVOLUME);
+ if (err)
+ return err;
+ sprintf(str, "%s Playback Switch", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_PSWITCH);
+ if (err)
+ return err;
+ sprintf(str, "%s Playback Route", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_PROUTE);
+ if (err)
+ return err;
+ sprintf(str, "%s Playback Volume", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_PVOLUME);
+ if (err)
+ return err;
+ sprintf(str, "%s Capture Switch", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_CSWITCH);
+ if (err)
+ return err;
+ sprintf(str, "%s Capture Route", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_CROUTE);
+ if (err)
+ return err;
+ sprintf(str, "%s Capture Volume", ptr->name);
+ err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+ SNDRV_MIXER_OSS_ITEM_CVOLUME);
+ if (err)
+ return err;
+
+ return 0;
+}
+
/*
* build an OSS mixer element.
* 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(snd_mixer_oss_t *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, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
{
struct slot slot;
struct slot *pslot;
- snd_kcontrol_t *kctl;
- snd_mixer_oss_slot_t *rslot;
+ struct snd_kcontrol *kctl;
+ struct snd_mixer_oss_slot *rslot;
char str[64];
/* check if already assigned */
@@ -928,58 +1039,21 @@ static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_os
memset(&slot, 0, sizeof(slot));
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
- if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index,
- SNDRV_MIXER_OSS_ITEM_GLOBAL))
- return 0;
- sprintf(str, "%s Switch", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_GSWITCH))
- return 0;
- sprintf(str, "%s Route", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_GROUTE))
- return 0;
- sprintf(str, "%s Volume", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_GVOLUME))
- return 0;
- sprintf(str, "%s Playback Switch", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_PSWITCH))
- return 0;
- sprintf(str, "%s Playback Route", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_PROUTE))
- return 0;
- sprintf(str, "%s Playback Volume", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_PVOLUME))
- return 0;
- sprintf(str, "%s Capture Switch", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_CSWITCH))
- return 0;
- sprintf(str, "%s Capture Route", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_CROUTE))
- return 0;
- sprintf(str, "%s Capture Volume", ptr->name);
- if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
- SNDRV_MIXER_OSS_ITEM_CVOLUME))
+ 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) {
- snd_ctl_elem_info_t *uinfo;
+ struct snd_ctl_elem_info *uinfo;
- uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+ uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
if (! uinfo) {
up_read(&mixer->card->controls_rwsem);
return -ENOMEM;
}
- memset(uinfo, 0, sizeof(*uinfo));
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
+ kfree(uinfo);
return 0;
}
strcpy(str, ptr->name);
@@ -995,6 +1069,7 @@ static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_os
uinfo->value.enumerated.item = slot.capture_item;
if (kctl->info(kctl, uinfo)) {
up_read(&mixer->card->controls_rwsem);
+ kfree(uinfo);
return 0;
}
if (!strcmp(uinfo->value.enumerated.name, str)) {
@@ -1007,8 +1082,9 @@ static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_os
}
up_read(&mixer->card->controls_rwsem);
if (slot.present != 0) {
- pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL);
- snd_runtime_check(pslot != NULL, return -ENOMEM);
+ pslot = kmalloc(sizeof(slot), GFP_KERNEL);
+ if (! pslot)
+ return -ENOMEM;
*pslot = slot;
pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
pslot->assigned = ptr;
@@ -1035,6 +1111,7 @@ static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_os
return 0;
}
+#ifdef CONFIG_PROC_FS
/*
*/
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
@@ -1070,13 +1147,13 @@ static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
* /proc interface
*/
-static void snd_mixer_oss_proc_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_mixer_oss_t *mixer = entry->private_data;
+ struct snd_mixer_oss *mixer = entry->private_data;
int i;
- down(&mixer->reg_mutex);
+ mutex_lock(&mixer->reg_mutex);
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
struct slot *p;
@@ -1091,14 +1168,15 @@ static void snd_mixer_oss_proc_read(snd_info_entry_t *entry,
else
snd_iprintf(buffer, "\"\" 0\n");
}
- up(&mixer->reg_mutex);
+ mutex_unlock(&mixer->reg_mutex);
}
-static void snd_mixer_oss_proc_write(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_mixer_oss_t *mixer = entry->private_data;
- char line[128], str[32], idxstr[16], *cptr;
+ struct snd_mixer_oss *mixer = entry->private_data;
+ char line[128], str[32], idxstr[16];
+ const char *cptr;
int ch, idx;
struct snd_mixer_oss_assign_table *tbl;
struct slot *slot;
@@ -1109,24 +1187,25 @@ static void snd_mixer_oss_proc_write(snd_info_entry_t *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 */
- down(&mixer->reg_mutex);
+ mutex_lock(&mixer->reg_mutex);
mixer_slot_clear(&mixer->slots[ch]);
- up(&mixer->reg_mutex);
+ mutex_unlock(&mixer->reg_mutex);
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;
}
- down(&mixer->reg_mutex);
+ 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))
@@ -1134,7 +1213,7 @@ static void snd_mixer_oss_proc_write(snd_info_entry_t *entry,
goto __unlock;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
if (! tbl) {
- snd_printk(KERN_ERR "mixer_oss: no memory\n");
+ pr_err("ALSA: mixer_oss: no memory\n");
goto __unlock;
}
tbl->oss_id = ch;
@@ -1149,13 +1228,13 @@ static void snd_mixer_oss_proc_write(snd_info_entry_t *entry,
kfree(tbl);
}
__unlock:
- up(&mixer->reg_mutex);
+ mutex_unlock(&mixer->reg_mutex);
}
}
-static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer)
+static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
mixer->card->proc_root);
@@ -1163,9 +1242,7 @@ static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer)
return;
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 8192;
entry->c.text.read = snd_mixer_oss_proc_read;
- entry->c.text.write_size = 8192;
entry->c.text.write = snd_mixer_oss_proc_write;
entry->private_data = mixer;
if (snd_info_register(entry) < 0) {
@@ -1175,15 +1252,17 @@ static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer)
mixer->proc_entry = entry;
}
-static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer)
+static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
{
- if (mixer->proc_entry) {
- snd_info_unregister(mixer->proc_entry);
- mixer->proc_entry = NULL;
- }
+ snd_info_free_entry(mixer->proc_entry);
+ mixer->proc_entry = NULL;
}
+#else /* !CONFIG_PROC_FS */
+#define snd_mixer_oss_proc_init(mix)
+#define snd_mixer_oss_proc_done(mix)
+#endif /* CONFIG_PROC_FS */
-static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
+static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
{
static struct snd_mixer_oss_assign_table table[] = {
{ SOUND_MIXER_VOLUME, "Master", 0 },
@@ -1194,7 +1273,9 @@ static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
{ SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */
{ SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */
{ SOUND_MIXER_PCM, "PCM", 0 },
- { SOUND_MIXER_SPEAKER, "PC Speaker", 0 },
+ { SOUND_MIXER_SPEAKER, "Beep", 0 },
+ { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */
+ { SOUND_MIXER_SPEAKER, "Speaker", 0 }, /* fallback */
{ SOUND_MIXER_LINE, "Line", 0 },
{ SOUND_MIXER_MIC, "Mic", 0 },
{ SOUND_MIXER_CD, "CD", 0 },
@@ -1216,6 +1297,8 @@ static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
{ SOUND_MIXER_DIGITAL3, "Digital", 2 },
{ SOUND_MIXER_PHONEIN, "Phone", 0 },
{ SOUND_MIXER_PHONEOUT, "Master Mono", 0 },
+ { SOUND_MIXER_PHONEOUT, "Speaker", 0 }, /*fallback*/
+ { SOUND_MIXER_PHONEOUT, "Mono", 0 }, /*fallback*/
{ SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */
{ SOUND_MIXER_VIDEO, "Video", 0 },
{ SOUND_MIXER_RADIO, "Radio", 0 },
@@ -1237,16 +1320,18 @@ static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
static int snd_mixer_oss_free1(void *private)
{
- snd_mixer_oss_t *mixer = private;
- snd_card_t * card;
+ struct snd_mixer_oss *mixer = private;
+ struct snd_card *card;
int idx;
- snd_assert(mixer != NULL, return -ENXIO);
+ if (!mixer)
+ return 0;
card = mixer->card;
- snd_assert(mixer == card->mixer_oss, return -ENXIO);
+ if (snd_BUG_ON(mixer != card->mixer_oss))
+ return -ENXIO;
card->mixer_oss = NULL;
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
- snd_mixer_oss_slot_t *chn = &mixer->slots[idx];
+ struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
if (chn->private_free)
chn->private_free(chn);
}
@@ -1254,24 +1339,23 @@ static int snd_mixer_oss_free1(void *private)
return 0;
}
-static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
+static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
{
- snd_mixer_oss_t *mixer;
+ 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;
- init_MUTEX(&mixer->reg_mutex);
- sprintf(name, "mixer%i%i", card->number, 0);
+ mutex_init(&mixer->reg_mutex);
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
- &snd_mixer_oss_reg,
- name)) < 0) {
- snd_printk("unable to register OSS mixer device %i:%i\n", card->number, 0);
+ &snd_mixer_oss_f_ops, card)) < 0) {
+ dev_err(card->dev,
+ "unable to register OSS mixer device %i:%i\n",
+ card->number, 0);
kfree(mixer);
return err;
}
@@ -1280,7 +1364,8 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
if (*card->mixername)
strlcpy(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,
@@ -1291,21 +1376,19 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
card->mixer_oss = mixer;
snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer);
- } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
- mixer = card->mixer_oss;
- if (mixer == NULL || !mixer->oss_dev_alloc)
- return 0;
- snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
- mixer->oss_dev_alloc = 0;
- } else { /* free */
+ } else {
mixer = card->mixer_oss;
if (mixer == NULL)
return 0;
+ if (mixer->oss_dev_alloc) {
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
- snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
+ snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
#endif
- if (mixer->oss_dev_alloc)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
+ mixer->oss_dev_alloc = 0;
+ }
+ if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
+ return 0;
snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer);
}
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 44ec4c66eb1..7915564bd39 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -1,6 +1,6 @@
/*
* Mu-Law conversion Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
* Uros Bizjak <uros@kss-loka.si>
*
* Based on reference implementation by Sun Microsystems, Inc.
@@ -21,7 +21,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -139,26 +138,39 @@ static int ulaw2linear(unsigned char u_val)
* Basic Mu-Law plugin
*/
-typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+typedef void (*mulaw_f)(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames);
-typedef struct mulaw_private_data {
+struct mulaw_priv {
mulaw_f func;
- int conv;
-} mulaw_t;
+ int cvt_endian; /* need endian conversion? */
+ unsigned int native_ofs; /* byte offset in native format */
+ unsigned int copy_ofs; /* byte offset in s16 format */
+ unsigned int native_bytes; /* byte size of the native format */
+ unsigned int copy_bytes; /* bytes to copy per conversion */
+ u16 flip; /* MSB flip for signedness, done after endian conversion */
+};
-static void mulaw_decode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static inline void cvt_s16_to_native(struct mulaw_priv *data,
+ unsigned char *dst, u16 sample)
+{
+ sample ^= data->flip;
+ if (data->cvt_endian)
+ sample = swab16(sample);
+ if (data->native_bytes > data->copy_bytes)
+ memset(dst, 0, data->native_bytes);
+ memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs,
+ data->copy_bytes);
+}
+
+static void mulaw_decode(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef PUT_S16_LABELS
- mulaw_t *data = (mulaw_t *)plugin->extra_data;
- void *put = put_s16_labels[data->conv];
+ struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data;
int channel;
int nchannels = plugin->src_format.channels;
for (channel = 0; channel < nchannels; ++channel) {
@@ -180,30 +192,33 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
frames1 = frames;
while (frames1-- > 0) {
signed short sample = ulaw2linear(*src);
- goto *put;
-#define PUT_S16_END after
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after:
+ cvt_s16_to_native(data, dst, sample);
src += src_step;
dst += dst_step;
}
}
}
-static void mulaw_encode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static inline signed short cvt_native_to_s16(struct mulaw_priv *data,
+ unsigned char *src)
+{
+ u16 sample = 0;
+ memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs,
+ data->copy_bytes);
+ if (data->cvt_endian)
+ sample = swab16(sample);
+ sample ^= data->flip;
+ return (signed short)sample;
+}
+
+static void mulaw_encode(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
-#define GET_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
- mulaw_t *data = (mulaw_t *)plugin->extra_data;
- void *get = get_s16_labels[data->conv];
+ struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data;
int channel;
int nchannels = plugin->src_format.channels;
- signed short sample = 0;
for (channel = 0; channel < nchannels; ++channel) {
char *src;
char *dst;
@@ -222,11 +237,7 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
dst_step = dst_channels[channel].area.step / 8;
frames1 = frames;
while (frames1-- > 0) {
- goto *get;
-#define GET_S16_END after
-#include "plugin_ops.h"
-#undef GET_S16_END
- after:
+ signed short sample = cvt_native_to_s16(data, src);
*dst = linear2ulaw(sample);
src += src_step;
dst += dst_step;
@@ -234,50 +245,75 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
}
}
-static snd_pcm_sframes_t mulaw_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
- mulaw_t *data;
+ struct mulaw_priv *data;
- snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+ return -ENXIO;
if (frames == 0)
return 0;
#ifdef CONFIG_SND_DEBUG
{
unsigned int channel;
for (channel = 0; channel < plugin->src_format.channels; channel++) {
- snd_assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0,
- return -ENXIO);
- snd_assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0,
- return -ENXIO);
+ if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+ src_channels[channel].area.step % 8))
+ return -ENXIO;
+ if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+ dst_channels[channel].area.step % 8))
+ return -ENXIO;
}
}
#endif
- data = (mulaw_t *)plugin->extra_data;
+ data = (struct mulaw_priv *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames);
return frames;
}
-int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *plug,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin)
+static void init_data(struct mulaw_priv *data, snd_pcm_format_t format)
+{
+#ifdef SNDRV_LITTLE_ENDIAN
+ data->cvt_endian = snd_pcm_format_big_endian(format) > 0;
+#else
+ data->cvt_endian = snd_pcm_format_little_endian(format) > 0;
+#endif
+ if (!snd_pcm_format_signed(format))
+ data->flip = 0x8000;
+ data->native_bytes = snd_pcm_format_physical_width(format) / 8;
+ data->copy_bytes = data->native_bytes < 2 ? 1 : 2;
+ if (snd_pcm_format_little_endian(format)) {
+ data->native_ofs = data->native_bytes - data->copy_bytes;
+ data->copy_ofs = 2 - data->copy_bytes;
+ } else {
+ /* S24 in 4bytes need an 1 byte offset */
+ data->native_ofs = data->native_bytes -
+ snd_pcm_format_width(format) / 8;
+ }
+}
+
+int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin)
{
int err;
- mulaw_t *data;
- snd_pcm_plugin_t *plugin;
- snd_pcm_plugin_format_t *format;
+ struct mulaw_priv *data;
+ struct snd_pcm_plugin *plugin;
+ struct snd_pcm_plugin_format *format;
mulaw_f func;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
- snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+ if (snd_BUG_ON(src_format->rate != dst_format->rate))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->channels != dst_format->channels))
+ return -ENXIO;
if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) {
format = src_format;
@@ -291,17 +327,17 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *plug,
snd_BUG();
return -EINVAL;
}
- snd_assert(snd_pcm_format_linear(format->format) != 0, return -ENXIO);
+ if (snd_BUG_ON(!snd_pcm_format_linear(format->format)))
+ return -ENXIO;
err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
src_format, dst_format,
- sizeof(mulaw_t), &plugin);
+ sizeof(struct mulaw_priv), &plugin);
if (err < 0)
return err;
- data = (mulaw_t*)plugin->extra_data;
+ data = (struct mulaw_priv *)plugin->extra_data;
data->func = func;
- data->conv = getput_index(format->format);
- snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL);
+ init_data(data, format->format);
plugin->transfer = mulaw_transfer;
*r_plugin = plugin;
return 0;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 842c28b2ed5..ada69d7a8d7 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer / OSS compatible
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -26,13 +26,12 @@
#define OSS_DEBUG
#endif
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/math64.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/minors.h>
@@ -42,14 +41,15 @@
#include <sound/info.h>
#include <linux/soundcard.h>
#include <sound/initval.h>
+#include <sound/mixer_oss.h>
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
-static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int dsp_map[SNDRV_CARDS];
static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-static int nonblock_open = 1;
+static bool nonblock_open = 1;
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
MODULE_LICENSE("GPL");
module_param_array(dsp_map, int, NULL, 0444);
@@ -61,10 +61,9 @@ MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
-extern int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg);
-static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file);
-static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file);
-static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file);
+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)
{
@@ -78,10 +77,495 @@ static inline void snd_leave_user(mm_segment_t fs)
set_fs(fs);
}
-static int snd_pcm_oss_plugin_clear(snd_pcm_substream_t *substream)
+/*
+ * helper functions to process hw_params
+ */
+static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
+{
+ int changed = 0;
+ if (i->min < min) {
+ i->min = min;
+ i->openmin = openmin;
+ changed = 1;
+ } else if (i->min == min && !i->openmin && openmin) {
+ i->openmin = 1;
+ changed = 1;
+ }
+ if (i->integer) {
+ if (i->openmin) {
+ i->min++;
+ i->openmin = 0;
+ }
+ }
+ if (snd_interval_checkempty(i)) {
+ snd_interval_none(i);
+ return -EINVAL;
+ }
+ return changed;
+}
+
+static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
+{
+ int changed = 0;
+ if (i->max > max) {
+ i->max = max;
+ i->openmax = openmax;
+ changed = 1;
+ } else if (i->max == max && !i->openmax && openmax) {
+ i->openmax = 1;
+ changed = 1;
+ }
+ if (i->integer) {
+ if (i->openmax) {
+ i->max--;
+ i->openmax = 0;
+ }
+ }
+ if (snd_interval_checkempty(i)) {
+ snd_interval_none(i);
+ return -EINVAL;
+ }
+ return changed;
+}
+
+static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
+{
+ struct snd_interval t;
+ t.empty = 0;
+ t.min = t.max = val;
+ t.openmin = t.openmax = 0;
+ t.integer = 1;
+ return snd_interval_refine(i, &t);
+}
+
+/**
+ * snd_pcm_hw_param_value_min
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the minimum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
+{
+ if (hw_is_mask(var)) {
+ if (dir)
+ *dir = 0;
+ return snd_mask_min(hw_param_mask_c(params, var));
+ }
+ if (hw_is_interval(var)) {
+ const struct snd_interval *i = hw_param_interval_c(params, var);
+ if (dir)
+ *dir = i->openmin;
+ return snd_interval_min(i);
+ }
+ return -EINVAL;
+}
+
+/**
+ * snd_pcm_hw_param_value_max
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the maximum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
+{
+ if (hw_is_mask(var)) {
+ if (dir)
+ *dir = 0;
+ return snd_mask_max(hw_param_mask_c(params, var));
+ }
+ if (hw_is_interval(var)) {
+ const struct snd_interval *i = hw_param_interval_c(params, var);
+ if (dir)
+ *dir = - (int) i->openmax;
+ return snd_interval_max(i);
+ }
+ return -EINVAL;
+}
+
+static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var,
+ const struct snd_mask *val)
+{
+ int changed;
+ changed = snd_mask_refine(hw_param_mask(params, var), val);
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var,
+ const struct snd_mask *val)
+{
+ int changed = _snd_pcm_hw_param_mask(params, var, val);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ int open = 0;
+ if (dir) {
+ if (dir > 0) {
+ open = 1;
+ } else if (dir < 0) {
+ if (val > 0) {
+ open = 1;
+ val--;
+ }
+ }
+ }
+ if (hw_is_mask(var))
+ changed = snd_mask_refine_min(hw_param_mask(params, var),
+ val + !!open);
+ else if (hw_is_interval(var))
+ changed = snd_interval_refine_min(hw_param_interval(params, var),
+ val, open);
+ else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_min
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: minimal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values < VAL. Reduce configuration space accordingly.
+ * Return new minimum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
+{
+ int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value_min(params, var, dir);
+}
+
+static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ int open = 0;
+ if (dir) {
+ if (dir < 0) {
+ open = 1;
+ } else if (dir > 0) {
+ open = 1;
+ val++;
+ }
+ }
+ if (hw_is_mask(var)) {
+ if (val == 0 && open) {
+ snd_mask_none(hw_param_mask(params, var));
+ changed = -EINVAL;
+ } else
+ changed = snd_mask_refine_max(hw_param_mask(params, var),
+ val - !!open);
+ } else if (hw_is_interval(var))
+ changed = snd_interval_refine_max(hw_param_interval(params, var),
+ val, open);
+ else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_max
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: maximal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values >= VAL + 1. Reduce configuration space accordingly.
+ * Return new maximum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int *dir)
+{
+ int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value_max(params, var, dir);
+}
+
+static int boundary_sub(int a, int adir,
+ int b, int bdir,
+ int *c, int *cdir)
+{
+ adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
+ bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
+ *c = a - b;
+ *cdir = adir - bdir;
+ if (*cdir == -2) {
+ (*c)--;
+ } else if (*cdir == 2) {
+ (*c)++;
+ }
+ return 0;
+}
+
+static int boundary_lt(unsigned int a, int adir,
+ unsigned int b, int bdir)
+{
+ if (adir < 0) {
+ a--;
+ adir = 1;
+ } else if (adir > 0)
+ adir = 1;
+ if (bdir < 0) {
+ b--;
+ bdir = 1;
+ } else if (bdir > 0)
+ bdir = 1;
+ return a < b || (a == b && adir < bdir);
+}
+
+/* Return 1 if min is nearer to best than max */
+static int boundary_nearer(int min, int mindir,
+ int best, int bestdir,
+ int max, int maxdir)
+{
+ int dmin, dmindir;
+ int dmax, dmaxdir;
+ boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
+ boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
+ return boundary_lt(dmin, dmindir, dmax, dmaxdir);
+}
+
+/**
+ * snd_pcm_hw_param_near
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @best: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS set PAR to the available value
+ * nearest to VAL. Reduce configuration space accordingly.
+ * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
+ * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
+ * Return the value found.
+ */
+static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int best,
+ int *dir)
+{
+ struct snd_pcm_hw_params *save = NULL;
+ int v;
+ unsigned int saved_min;
+ int last = 0;
+ int min, max;
+ int mindir, maxdir;
+ int valdir = dir ? *dir : 0;
+ /* FIXME */
+ if (best > INT_MAX)
+ best = INT_MAX;
+ min = max = best;
+ mindir = maxdir = valdir;
+ if (maxdir > 0)
+ maxdir = 0;
+ else if (maxdir == 0)
+ maxdir = -1;
+ else {
+ maxdir = 1;
+ max--;
+ }
+ save = kmalloc(sizeof(*save), GFP_KERNEL);
+ if (save == NULL)
+ return -ENOMEM;
+ *save = *params;
+ saved_min = min;
+ min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
+ if (min >= 0) {
+ struct snd_pcm_hw_params *params1;
+ 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);
+ return -ENOMEM;
+ }
+ *params1 = *save;
+ max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
+ if (max < 0) {
+ kfree(params1);
+ 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);
+ 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;
+}
+
+static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed;
+ if (hw_is_mask(var)) {
+ struct snd_mask *m = hw_param_mask(params, var);
+ if (val == 0 && dir < 0) {
+ changed = -EINVAL;
+ snd_mask_none(m);
+ } else {
+ if (dir > 0)
+ val++;
+ else if (dir < 0)
+ val--;
+ changed = snd_mask_refine_set(hw_param_mask(params, var), val);
+ }
+ } else if (hw_is_interval(var)) {
+ struct snd_interval *i = hw_param_interval(params, var);
+ if (val == 0 && dir < 0) {
+ changed = -EINVAL;
+ snd_interval_none(i);
+ } else if (dir == 0)
+ changed = snd_interval_refine_set(i, val);
+ else {
+ struct snd_interval t;
+ t.openmin = 1;
+ t.openmax = 1;
+ t.empty = 0;
+ t.integer = 0;
+ if (dir < 0) {
+ t.min = val - 1;
+ t.max = val;
+ } else {
+ t.min = val;
+ t.max = val+1;
+ }
+ changed = snd_interval_refine(i, &t);
+ }
+ } else
+ return -EINVAL;
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/**
+ * snd_pcm_hw_param_set
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all
+ * values != VAL. Reduce configuration space accordingly.
+ * Return VAL or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, unsigned int val,
+ int dir)
+{
+ int changed = _snd_pcm_hw_param_set(params, var, val, dir);
+ if (changed < 0)
+ return changed;
+ if (params->rmask) {
+ int err = snd_pcm_hw_refine(pcm, params);
+ if (err < 0)
+ return err;
+ }
+ return snd_pcm_hw_param_value(params, var, NULL);
+}
+
+static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var)
+{
+ int changed;
+ changed = snd_interval_setinteger(hw_param_interval(params, var));
+ if (changed) {
+ params->cmask |= 1 << var;
+ params->rmask |= 1 << var;
+ }
+ return changed;
+}
+
+/*
+ * plugin
+ */
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_plugin_t *plugin, *next;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_plugin *plugin, *next;
plugin = runtime->oss.plugin_first;
while (plugin) {
@@ -93,9 +577,9 @@ static int snd_pcm_oss_plugin_clear(snd_pcm_substream_t *substream)
return 0;
}
-static int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin)
+static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin)
{
- snd_pcm_runtime_t *runtime = plugin->plug->runtime;
+ struct snd_pcm_runtime *runtime = plugin->plug->runtime;
plugin->next = runtime->oss.plugin_first;
plugin->prev = NULL;
if (runtime->oss.plugin_first) {
@@ -108,9 +592,9 @@ static int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin)
return 0;
}
-int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
+int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin)
{
- snd_pcm_runtime_t *runtime = plugin->plug->runtime;
+ struct snd_pcm_runtime *runtime = plugin->plug->runtime;
plugin->next = NULL;
plugin->prev = runtime->oss.plugin_last;
if (runtime->oss.plugin_last) {
@@ -122,10 +606,11 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
}
return 0;
}
+#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
-static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames)
+static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
long buffer_size = snd_pcm_lib_buffer_bytes(substream);
long bytes = frames_to_bytes(runtime, frames);
if (buffer_size == runtime->oss.buffer_bytes)
@@ -135,23 +620,43 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames)
#else
{
u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
- u32 rem;
- div64_32(&bsize, buffer_size, &rem);
- return (long)bsize;
+ return div_u64(bsize, buffer_size);
}
#endif
}
-static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
+static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
long buffer_size = snd_pcm_lib_buffer_bytes(substream);
if (buffer_size == runtime->oss.buffer_bytes)
return bytes_to_frames(runtime, bytes);
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
}
-static int snd_pcm_oss_format_from(int format)
+static inline
+snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
+{
+ return runtime->hw_ptr_interrupt;
+}
+
+/* define extended formats in the recent OSS versions (if any) */
+/* linear formats */
+#define AFMT_S32_LE 0x00001000
+#define AFMT_S32_BE 0x00002000
+#define AFMT_S24_LE 0x00008000
+#define AFMT_S24_BE 0x00010000
+#define AFMT_S24_PACKED 0x00040000
+
+/* other supported formats */
+#define AFMT_FLOAT 0x00004000
+#define AFMT_SPDIF_RAW 0x00020000
+
+/* unsupported formats */
+#define AFMT_AC3 0x00000400
+#define AFMT_VORBIS 0x00000800
+
+static snd_pcm_format_t snd_pcm_oss_format_from(int format)
{
switch (format) {
case AFMT_MU_LAW: return SNDRV_PCM_FORMAT_MU_LAW;
@@ -164,11 +669,18 @@ static int snd_pcm_oss_format_from(int format)
case AFMT_U16_LE: return SNDRV_PCM_FORMAT_U16_LE;
case AFMT_U16_BE: return SNDRV_PCM_FORMAT_U16_BE;
case AFMT_MPEG: return SNDRV_PCM_FORMAT_MPEG;
+ case AFMT_S32_LE: return SNDRV_PCM_FORMAT_S32_LE;
+ case AFMT_S32_BE: return SNDRV_PCM_FORMAT_S32_BE;
+ case AFMT_S24_LE: return SNDRV_PCM_FORMAT_S24_LE;
+ case AFMT_S24_BE: return SNDRV_PCM_FORMAT_S24_BE;
+ case AFMT_S24_PACKED: return SNDRV_PCM_FORMAT_S24_3LE;
+ case AFMT_FLOAT: return SNDRV_PCM_FORMAT_FLOAT;
+ case AFMT_SPDIF_RAW: return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;
default: return SNDRV_PCM_FORMAT_U8;
}
}
-static int snd_pcm_oss_format_to(int format)
+static int snd_pcm_oss_format_to(snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW;
@@ -181,18 +693,25 @@ static int snd_pcm_oss_format_to(int format)
case SNDRV_PCM_FORMAT_U16_LE: return AFMT_U16_LE;
case SNDRV_PCM_FORMAT_U16_BE: return AFMT_U16_BE;
case SNDRV_PCM_FORMAT_MPEG: return AFMT_MPEG;
+ case SNDRV_PCM_FORMAT_S32_LE: return AFMT_S32_LE;
+ case SNDRV_PCM_FORMAT_S32_BE: return AFMT_S32_BE;
+ case SNDRV_PCM_FORMAT_S24_LE: return AFMT_S24_LE;
+ case SNDRV_PCM_FORMAT_S24_BE: return AFMT_S24_BE;
+ case SNDRV_PCM_FORMAT_S24_3LE: return AFMT_S24_PACKED;
+ case SNDRV_PCM_FORMAT_FLOAT: return AFMT_FLOAT;
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;
default: return -EINVAL;
}
}
-static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *oss_params,
- snd_pcm_hw_params_t *slave_params)
+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;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
size_t oss_frame_size;
oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
@@ -201,14 +720,13 @@ static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
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);
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes;
}
- if (substream->oss.setup &&
- substream->oss.setup->period_size > 16)
- oss_period_size = substream->oss.setup->period_size;
+ if (substream->oss.setup.period_size > 16)
+ oss_period_size = substream->oss.setup.period_size;
else if (runtime->oss.fragshift) {
oss_period_size = 1 << runtime->oss.fragshift;
if (oss_period_size > oss_buffer_size / 2)
@@ -250,10 +768,8 @@ static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
oss_periods = oss_buffer_size / oss_period_size;
- if (substream->oss.setup) {
- if (substream->oss.setup->periods > 1)
- oss_periods = substream->oss.setup->periods;
- }
+ if (substream->oss.setup.periods > 1)
+ 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)
@@ -270,18 +786,19 @@ static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
while (oss_period_size * oss_periods > oss_buffer_size)
oss_period_size /= 2;
- snd_assert(oss_period_size >= 16, return -EINVAL);
+ if (oss_period_size < 16)
+ return -EINVAL;
runtime->oss.period_bytes = oss_period_size;
runtime->oss.period_frames = 1;
runtime->oss.periods = oss_periods;
return 0;
}
-static int choose_rate(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params, unsigned int best_rate)
+static int choose_rate(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, unsigned int best_rate)
{
- snd_interval_t *it;
- snd_pcm_hw_params_t *save;
+ struct snd_interval *it;
+ struct snd_pcm_hw_params *save;
unsigned int rate, prev;
save = kmalloc(sizeof(*save), GFP_KERNEL);
@@ -317,49 +834,50 @@ static int choose_rate(snd_pcm_substream_t *substream,
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
}
-static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
+static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_hw_params_t *params, *sparams;
- snd_pcm_sw_params_t *sw_params;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_params *params, *sparams;
+ struct snd_pcm_sw_params *sw_params;
ssize_t oss_buffer_size, oss_period_size;
size_t oss_frame_size;
int err;
int direct;
- int format, sformat, n;
- snd_mask_t sformat_mask;
- snd_mask_t mask;
+ snd_pcm_format_t format, sformat;
+ int n;
+ 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);
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
if (!sw_params || !params || !sparams) {
- snd_printd("No memory\n");
+ pcm_dbg(substream->pcm, "No memory\n");
err = -ENOMEM;
goto failure;
}
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count))
direct = 1;
- } else {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- direct = (setup != NULL && setup->direct);
- }
+ else
+ direct = substream->oss.setup.direct;
_snd_pcm_hw_params_any(sparams);
_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask);
- if (atomic_read(&runtime->mmap_count))
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (atomic_read(&substream->mmap_count))
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else {
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
if (!direct)
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
}
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;
}
@@ -374,29 +892,33 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
else
sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
- if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {
- for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {
- if (snd_mask_test(&sformat_mask, sformat) &&
+ 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_pcm_oss_format_to(sformat) >= 0)
break;
}
- if (sformat > SNDRV_PCM_FORMAT_LAST) {
- snd_printd("Cannot find a format!!!\n");
+ if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) {
+ pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
err = -EINVAL;
goto failure;
}
}
- err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
- snd_assert(err >= 0, goto failure);
+ err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
+ if (err < 0)
+ goto failure;
if (direct) {
memcpy(params, sparams, sizeof(*params));
} else {
_snd_pcm_hw_params_any(params);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
- SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
+ (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
- snd_pcm_oss_format_from(runtime->oss.format), 0);
+ (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
runtime->oss.channels, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
@@ -412,6 +934,7 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
params_channels(params) / 8;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
snd_pcm_oss_plugin_clear(substream);
if (!direct) {
/* add necessary plugins */
@@ -419,14 +942,16 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
if ((err = snd_pcm_plug_format_plugins(substream,
params,
sparams)) < 0) {
- snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plug_format_plugins failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
goto failure;
}
if (runtime->oss.plugin_first) {
- snd_pcm_plugin_t *plugin;
+ 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);
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plugin_build_io failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
goto failure;
}
@@ -441,6 +966,7 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
}
}
}
+#endif
err = snd_pcm_oss_period_size(substream, params, sparams);
if (err < 0)
@@ -448,16 +974,18 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
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);
- snd_assert(err >= 0, goto failure);
+ if (err < 0)
+ goto failure;
err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
runtime->oss.periods, NULL);
- snd_assert(err >= 0, goto failure);
+ 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);
+ pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
goto failure;
}
@@ -467,18 +995,17 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
} else {
sw_params->start_threshold = runtime->boundary;
}
- if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ if (atomic_read(&substream->mmap_count) ||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE)
sw_params->stop_threshold = runtime->boundary;
else
sw_params->stop_threshold = runtime->buffer_size;
sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
sw_params->period_step = 1;
- sw_params->sleep_min = 0;
sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
1 : runtime->period_size;
- sw_params->xfer_align = 1;
- if (atomic_read(&runtime->mmap_count) ||
- (substream->oss.setup && substream->oss.setup->nosilence)) {
+ if (atomic_read(&substream->mmap_count) ||
+ substream->oss.setup.nosilence) {
sw_params->silence_threshold = 0;
sw_params->silence_size = 0;
} else {
@@ -491,22 +1018,30 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
}
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
- snd_printd("SW_PARAMS failed: %i\n", err);
+ pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
goto failure;
}
runtime->oss.periods = params_periods(sparams);
oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
- snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+ if (oss_period_size < 0) {
+ err = -EINVAL;
+ goto failure;
+ }
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
if (runtime->oss.plugin_first) {
err = snd_pcm_plug_alloc(substream, oss_period_size);
if (err < 0)
goto failure;
}
+#endif
oss_period_size *= oss_frame_size;
oss_buffer_size = oss_period_size * runtime->oss.periods;
- snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
+ if (oss_buffer_size < 0) {
+ err = -EINVAL;
+ goto failure;
+ }
runtime->oss.period_bytes = oss_period_size;
runtime->oss.buffer_bytes = oss_buffer_size;
@@ -522,10 +1057,15 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
runtime->oss.channels = params_channels(params);
runtime->oss.rate = params_rate(params);
- runtime->oss.params = 0;
- runtime->oss.prepare = 1;
vfree(runtime->oss.buffer);
runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);
+ if (!runtime->oss.buffer) {
+ err = -ENOMEM;
+ goto failure;
+ }
+
+ 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));
@@ -537,13 +1077,14 @@ failure:
kfree(sw_params);
kfree(params);
kfree(sparams);
+ mutex_unlock(&runtime->oss.params_lock);
return err;
}
-static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream)
+static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_file, struct snd_pcm_substream **r_substream)
{
int idx, err;
- snd_pcm_substream_t *asubstream = NULL, *substream;
+ struct snd_pcm_substream *asubstream = NULL, *substream;
for (idx = 0; idx < 2; idx++) {
substream = pcm_oss_file->streams[idx];
@@ -557,33 +1098,35 @@ static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, sn
return err;
}
}
- snd_assert(asubstream != NULL, return -EIO);
+ if (!asubstream)
+ return -EIO;
if (r_substream)
*r_substream = asubstream;
return 0;
}
-static int snd_pcm_oss_prepare(snd_pcm_substream_t *substream)
+static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
{
int err;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
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;
- runtime->oss.prev_hw_ptr_interrupt = 0;
+ runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
runtime->oss.buffer_used = 0;
return 0;
}
-static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream)
+static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
int err;
if (substream == NULL)
@@ -602,9 +1145,9 @@ static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream)
return 0;
}
-static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay)
+static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
snd_pcm_uframes_t frames;
int err = 0;
@@ -627,18 +1170,18 @@ static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, sn
return err;
}
-snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
+snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ 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) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: write: recovering from XRUN\n");
- else
- printk("pcm_oss: write: recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: write: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -647,10 +1190,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
snd_leave_user(fs);
} else {
- ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
@@ -662,19 +1205,19 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
return ret;
}
-snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
+snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t delay;
int ret;
while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: read: recovering from XRUN\n");
- else
- printk("pcm_oss: read: recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: read: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -690,10 +1233,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
snd_leave_user(fs);
} else {
- ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
}
if (ret == -EPIPE) {
if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
@@ -709,18 +1252,18 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
return ret;
}
-snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, 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)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ 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) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: writev: recovering from XRUN\n");
- else
- printk("pcm_oss: writev: recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: writev: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -745,18 +1288,18 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf
return ret;
}
-snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *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, int in_kernel)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ 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) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: readv: recovering from XRUN\n");
- else
- printk("pcm_oss: readv: recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: readv: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -780,15 +1323,16 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs
return ret;
}
-static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *buf, size_t bytes, int in_kernel)
+static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t frames, frames1;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
if (runtime->oss.plugin_first) {
- snd_pcm_plugin_channel_t *channels;
+ struct snd_pcm_plugin_channel *channels;
size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
if (!in_kernel) {
- if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
+ if (copy_from_user(runtime->oss.buffer, (const char __force __user *)buf, bytes))
return -EFAULT;
buf = runtime->oss.buffer;
}
@@ -800,7 +1344,9 @@ static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *bu
if (frames1 <= 0)
return frames1;
bytes = frames1 * oss_frame_bytes;
- } else {
+ } else
+#endif
+ {
frames = bytes_to_frames(runtime, bytes);
frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
if (frames1 <= 0)
@@ -810,70 +1356,81 @@ static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *bu
return bytes;
}
-static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __user *buf, size_t bytes)
+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;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ 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);
while (bytes > 0) {
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
if (tmp > 0) {
- if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp))
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
+ if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
+ tmp = -EFAULT;
+ goto err;
+ }
}
runtime->oss.buffer_used += tmp;
buf += tmp;
bytes -= tmp;
xfer += tmp;
- if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) ||
+ if (substream->oss.setup.partialfrag ||
runtime->oss.buffer_used == runtime->oss.period_bytes) {
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
runtime->oss.period_ptr += tmp;
runtime->oss.period_ptr %= runtime->oss.period_bytes;
if (runtime->oss.period_ptr == 0 ||
runtime->oss.period_ptr == runtime->oss.buffer_used)
runtime->oss.buffer_used = 0;
- else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
- return xfer > 0 ? xfer : -EAGAIN;
+ else if ((substream->f_flags & O_NONBLOCK) != 0) {
+ tmp = -EAGAIN;
+ goto err;
+ }
}
} else {
tmp = snd_pcm_oss_write2(substream,
(const char __force *)buf,
runtime->oss.period_bytes, 0);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
buf += tmp;
bytes -= tmp;
xfer += tmp;
- if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
+ if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
break;
}
}
+ mutex_unlock(&runtime->oss.params_lock);
return xfer;
+
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
-static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size_t bytes, int in_kernel)
+static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t frames, frames1;
- char __user *final_dst = (char __user *)buf;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+ char __user *final_dst = (char __force __user *)buf;
if (runtime->oss.plugin_first) {
- snd_pcm_plugin_channel_t *channels;
+ struct snd_pcm_plugin_channel *channels;
size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
if (!in_kernel)
buf = runtime->oss.buffer;
@@ -887,7 +1444,9 @@ static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size
bytes = frames1 * oss_frame_bytes;
if (!in_kernel && copy_to_user(final_dst, buf, bytes))
return -EFAULT;
- } else {
+ } else
+#endif
+ {
frames = bytes_to_frames(runtime, bytes);
frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
if (frames1 <= 0)
@@ -897,23 +1456,24 @@ static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size
return bytes;
}
-static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *buf, size_t bytes)
+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;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ 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);
while (bytes > 0) {
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);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
runtime->oss.period_ptr = tmp;
runtime->oss.buffer_used = tmp;
@@ -921,8 +1481,10 @@ static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *bu
tmp = bytes;
if ((size_t) tmp > runtime->oss.buffer_used)
tmp = runtime->oss.buffer_used;
- if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp))
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
+ if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {
+ tmp = -EFAULT;
+ goto err;
+ }
buf += tmp;
bytes -= tmp;
xfer += tmp;
@@ -931,53 +1493,62 @@ static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *bu
tmp = snd_pcm_oss_read2(substream, (char __force *)buf,
runtime->oss.period_bytes, 0);
if (tmp <= 0)
- return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ goto err;
runtime->oss.bytes += tmp;
buf += tmp;
bytes -= tmp;
xfer += tmp;
}
}
+ mutex_unlock(&runtime->oss.params_lock);
return xfer;
+
+ err:
+ mutex_unlock(&runtime->oss.params_lock);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
-static int snd_pcm_oss_reset(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ int i;
- substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
- if (substream != NULL) {
- snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
- substream->runtime->oss.prepare = 1;
- }
- substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- if (substream != NULL) {
- snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
- substream->runtime->oss.prepare = 1;
+ for (i = 0; i < 2; i++) {
+ substream = pcm_oss_file->streams[i];
+ if (!substream)
+ continue;
+ runtime = substream->runtime;
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ runtime->oss.prepare = 1;
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prev_hw_ptr_period = 0;
+ runtime->oss.period_ptr = 0;
}
return 0;
}
-static int snd_pcm_oss_post(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
- snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
}
/* note: all errors from the start action are ignored */
/* OSS apps do not know, how to handle them */
return 0;
}
-static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size)
+static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
ssize_t result = 0;
+ snd_pcm_state_t state;
long res;
wait_queue_t wait;
@@ -985,7 +1556,7 @@ static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size)
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
#ifdef OSS_DEBUG
- printk("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);
@@ -999,9 +1570,9 @@ static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size)
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_lock_irq(substream);
- res = runtime->status->state;
+ state = runtime->status->state;
snd_pcm_stream_unlock_irq(substream);
- if (res != SNDRV_PCM_STATE_RUNNING) {
+ if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING);
break;
}
@@ -1011,7 +1582,8 @@ static int snd_pcm_oss_sync1(snd_pcm_substream_t *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;
}
@@ -1020,12 +1592,12 @@ static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size)
return result;
}
-static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
{
int err = 0;
unsigned int saved_f_flags;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_format_t format;
unsigned long width;
size_t size;
@@ -1033,34 +1605,39 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
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("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)
+ if (err < 0) {
+ mutex_unlock(&runtime->oss.params_lock);
return err;
+ }
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
- printk("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)
+ if (err < 0) {
+ mutex_unlock(&runtime->oss.params_lock);
return err;
+ }
}
/*
* The ALSA's period might be a bit large than OSS one.
@@ -1080,8 +1657,9 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
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 __user *)runtime->oss.buffer, size1);
+ 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) {
@@ -1090,14 +1668,15 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
snd_pcm_lib_writev(substream, buffers, size);
}
}
+ mutex_unlock(&runtime->oss.params_lock);
/*
* finish sync: drain the buffer
*/
__direct:
- saved_f_flags = substream->ffile->f_flags;
- substream->ffile->f_flags &= ~O_NONBLOCK;
- err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
- substream->ffile->f_flags = saved_f_flags;
+ saved_f_flags = substream->f_flags;
+ substream->f_flags &= ~O_NONBLOCK;
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
+ substream->f_flags = saved_f_flags;
if (err < 0)
return err;
runtime->oss.prepare = 1;
@@ -1108,7 +1687,7 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
runtime = substream->runtime;
- err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (err < 0)
return err;
runtime->oss.buffer_used = 0;
@@ -1117,13 +1696,13 @@ static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
return 0;
}
-static int snd_pcm_oss_set_rate(snd_pcm_oss_file_t *pcm_oss_file, int rate)
+static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
{
int idx;
for (idx = 1; idx >= 0; --idx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
continue;
runtime = substream->runtime;
@@ -1139,9 +1718,9 @@ static int snd_pcm_oss_set_rate(snd_pcm_oss_file_t *pcm_oss_file, int rate)
return snd_pcm_oss_get_rate(pcm_oss_file);
}
-static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
@@ -1149,7 +1728,7 @@ static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file)
return substream->runtime->oss.rate;
}
-static int snd_pcm_oss_set_channels(snd_pcm_oss_file_t *pcm_oss_file, unsigned int channels)
+static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels)
{
int idx;
if (channels < 1)
@@ -1157,8 +1736,8 @@ static int snd_pcm_oss_set_channels(snd_pcm_oss_file_t *pcm_oss_file, unsigned i
if (channels > 128)
return -EINVAL;
for (idx = 1; idx >= 0; --idx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
continue;
runtime = substream->runtime;
@@ -1170,9 +1749,9 @@ static int snd_pcm_oss_set_channels(snd_pcm_oss_file_t *pcm_oss_file, unsigned i
return snd_pcm_oss_get_channels(pcm_oss_file);
}
-static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
@@ -1180,9 +1759,9 @@ static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file)
return substream->runtime->oss.channels;
}
-static int snd_pcm_oss_get_block_size(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
@@ -1190,29 +1769,30 @@ static int snd_pcm_oss_get_block_size(snd_pcm_oss_file_t *pcm_oss_file)
return substream->runtime->oss.period_bytes;
}
-static int snd_pcm_oss_get_formats(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
int direct;
- snd_pcm_hw_params_t *params;
+ struct snd_pcm_hw_params *params;
unsigned int formats = 0;
- snd_mask_t format_mask;
+ struct snd_mask format_mask;
int fmt;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
return err;
- if (atomic_read(&substream->runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count))
direct = 1;
- } else {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- direct = (setup != NULL && setup->direct);
- }
+ else
+ direct = substream->oss.setup.direct;
if (!direct)
return AFMT_MU_LAW | AFMT_U8 |
AFMT_S16_LE | AFMT_S16_BE |
AFMT_S8 | AFMT_U16_LE |
- AFMT_U16_BE;
+ AFMT_U16_BE |
+ AFMT_S32_LE | AFMT_S32_BE |
+ AFMT_S24_LE | AFMT_S24_BE |
+ AFMT_S24_PACKED;
params = kmalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
@@ -1220,7 +1800,8 @@ static int snd_pcm_oss_get_formats(snd_pcm_oss_file_t *pcm_oss_file)
err = snd_pcm_hw_refine(substream, params);
format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
kfree(params);
- snd_assert(err >= 0, return err);
+ if (err < 0)
+ return err;
for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(&format_mask, fmt)) {
int f = snd_pcm_oss_format_to(fmt);
@@ -1231,17 +1812,19 @@ static int snd_pcm_oss_get_formats(snd_pcm_oss_file_t *pcm_oss_file)
return formats;
}
-static int snd_pcm_oss_set_format(snd_pcm_oss_file_t *pcm_oss_file, int format)
+static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
{
int formats, idx;
if (format != AFMT_QUERY) {
formats = snd_pcm_oss_get_formats(pcm_oss_file);
+ if (formats < 0)
+ return formats;
if (!(formats & format))
format = AFMT_U8;
for (idx = 1; idx >= 0; --idx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
continue;
runtime = substream->runtime;
@@ -1254,9 +1837,9 @@ static int snd_pcm_oss_set_format(snd_pcm_oss_file_t *pcm_oss_file, int format)
return snd_pcm_oss_get_format(pcm_oss_file);
}
-static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
@@ -1264,9 +1847,9 @@ static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file)
return substream->runtime->oss.format;
}
-static int snd_pcm_oss_set_subdivide1(snd_pcm_substream_t *substream, int subdivide)
+static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
return 0;
@@ -1287,12 +1870,12 @@ static int snd_pcm_oss_set_subdivide1(snd_pcm_substream_t *substream, int subdiv
return subdivide;
}
-static int snd_pcm_oss_set_subdivide(snd_pcm_oss_file_t *pcm_oss_file, int subdivide)
+static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int subdivide)
{
int err = -EINVAL, idx;
for (idx = 1; idx >= 0; --idx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
if (substream == NULL)
continue;
if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
@@ -1301,9 +1884,9 @@ static int snd_pcm_oss_set_subdivide(snd_pcm_oss_file_t *pcm_oss_file, int subdi
return err;
}
-static int snd_pcm_oss_set_fragment1(snd_pcm_substream_t *substream, unsigned int val)
+static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
return 0;
@@ -1320,12 +1903,12 @@ static int snd_pcm_oss_set_fragment1(snd_pcm_substream_t *substream, unsigned in
return 0;
}
-static int snd_pcm_oss_set_fragment(snd_pcm_oss_file_t *pcm_oss_file, unsigned int val)
+static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsigned int val)
{
int err = -EINVAL, idx;
for (idx = 1; idx >= 0; --idx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
if (substream == NULL)
continue;
if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
@@ -1336,11 +1919,13 @@ static int snd_pcm_oss_set_fragment(snd_pcm_oss_file_t *pcm_oss_file, unsigned i
static int snd_pcm_oss_nonblock(struct file * file)
{
+ spin_lock(&file->f_lock);
file->f_flags |= O_NONBLOCK;
+ spin_unlock(&file->f_lock);
return 0;
}
-static int snd_pcm_oss_get_caps1(snd_pcm_substream_t *substream, int res)
+static int snd_pcm_oss_get_caps1(struct snd_pcm_substream *substream, int res)
{
if (substream == NULL) {
@@ -1356,7 +1941,7 @@ static int snd_pcm_oss_get_caps1(snd_pcm_substream_t *substream, int res)
/* all ALSA drivers can return actual pointer in ring buffer */
#if defined(DSP_CAP_REALTIME) && 0
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
res &= ~DSP_CAP_REALTIME;
}
@@ -1364,36 +1949,37 @@ static int snd_pcm_oss_get_caps1(snd_pcm_substream_t *substream, int res)
return res;
}
-static int snd_pcm_oss_get_caps(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
{
int result, idx;
result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME;
for (idx = 0; idx < 2; idx++) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
result = snd_pcm_oss_get_caps1(substream, result);
}
result |= 0x0001; /* revision - same as SB AWE 64 */
return result;
}
-static void snd_pcm_oss_simulate_fill(snd_pcm_substream_t *substream, snd_pcm_uframes_t hw_ptr)
+static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t hw_ptr)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t appl_ptr;
appl_ptr = hw_ptr + runtime->buffer_size;
appl_ptr %= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
}
-static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger)
+static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int trigger)
{
- snd_pcm_runtime_t *runtime;
- snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
int err, cmd;
#ifdef OSS_DEBUG
- printk("pcm_oss: trigger = 0x%x\n", trigger);
+ pcm_dbg(substream->pcm, "pcm_oss: trigger = 0x%x\n", trigger);
#endif
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -1412,8 +1998,9 @@ static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger
if (trigger & PCM_ENABLE_OUTPUT) {
if (runtime->oss.trigger)
goto _skip1;
- if (atomic_read(&psubstream->runtime->mmap_count))
- snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
+ if (atomic_read(&psubstream->mmap_count))
+ snd_pcm_oss_simulate_fill(psubstream,
+ get_hw_ptr_period(runtime));
runtime->oss.trigger = 1;
runtime->start_threshold = 1;
cmd = SNDRV_PCM_IOCTL_START;
@@ -1425,7 +2012,7 @@ static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL);
+ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
if (err < 0)
return err;
}
@@ -1446,7 +2033,7 @@ static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL);
+ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
if (err < 0)
return err;
}
@@ -1454,9 +2041,9 @@ static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger
return 0;
}
-static int snd_pcm_oss_get_trigger(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
+ struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
int result = 0;
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -1468,10 +2055,10 @@ static int snd_pcm_oss_get_trigger(snd_pcm_oss_file_t *pcm_oss_file)
return result;
}
-static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
{
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t delay;
int err;
@@ -1483,7 +2070,7 @@ static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file)
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare)
return 0;
- err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
if (err == -EPIPE)
delay = 0; /* hack for broken OSS applications */
else if (err < 0)
@@ -1491,10 +2078,10 @@ static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file)
return snd_pcm_oss_bytes(substream, delay);
}
-static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct count_info __user * _info)
+static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct count_info __user * _info)
{
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t delay;
int fixup;
struct count_info info;
@@ -1530,21 +2117,21 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str
if (err < 0)
return err;
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
- if (atomic_read(&runtime->mmap_count)) {
+ if (atomic_read(&substream->mmap_count)) {
snd_pcm_sframes_t n;
- n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
+ delay = get_hw_ptr_period(runtime);
+ n = delay - runtime->oss.prev_hw_ptr_period;
if (n < 0)
n += runtime->boundary;
info.blocks = n / runtime->period_size;
- runtime->oss.prev_hw_ptr_interrupt = delay;
+ runtime->oss.prev_hw_ptr_period = delay;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_pcm_oss_simulate_fill(substream, delay);
info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
} else {
delay = snd_pcm_oss_bytes(substream, delay);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- if (setup && setup->buggyptr)
+ if (substream->oss.setup.buggyptr)
info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
else
info.blocks = (delay + fixup) / runtime->oss.period_bytes;
@@ -1560,10 +2147,10 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str
return 0;
}
-static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
+static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
{
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t avail;
int fixup;
struct audio_buf_info info;
@@ -1612,65 +2199,81 @@ static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, s
}
#ifdef OSS_DEBUG
- printk("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;
return 0;
}
-static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
+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;
}
-static snd_pcm_oss_setup_t *snd_pcm_oss_look_for_setup(snd_pcm_t *pcm, int stream, const char *task_name)
+static const char *strip_task_path(const char *path)
{
- const char *ptr, *ptrl;
- snd_pcm_oss_setup_t *setup;
-
- down(&pcm->streams[stream].oss.setup_mutex);
- for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
- if (!strcmp(setup->task_name, task_name)) {
- up(&pcm->streams[stream].oss.setup_mutex);
- return setup;
- }
- }
- ptr = ptrl = task_name;
- while (*ptr) {
+ const char *ptr, *ptrl = NULL;
+ for (ptr = path; *ptr; ptr++) {
if (*ptr == '/')
ptrl = ptr + 1;
- ptr++;
- }
- if (ptrl == task_name) {
- goto __not_found;
- return NULL;
}
- for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
- if (!strcmp(setup->task_name, ptrl)) {
- up(&pcm->streams[stream].oss.setup_mutex);
- return setup;
+ return ptrl;
+}
+
+static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
+ const char *task_name,
+ struct snd_pcm_oss_setup *rsetup)
+{
+ struct snd_pcm_oss_setup *setup;
+
+ mutex_lock(&pcm->streams[stream].oss.setup_mutex);
+ do {
+ for (setup = pcm->streams[stream].oss.setup_list; setup;
+ setup = setup->next) {
+ if (!strcmp(setup->task_name, task_name))
+ goto out;
}
- }
- __not_found:
- up(&pcm->streams[stream].oss.setup_mutex);
- return NULL;
+ } while ((task_name = strip_task_path(task_name)) != NULL);
+ 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
+ substream->oss.oss = 0;
}
-static void snd_pcm_oss_init_substream(snd_pcm_substream_t *substream,
- snd_pcm_oss_setup_t *setup,
+static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
+ struct snd_pcm_oss_setup *setup,
int minor)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
substream->oss.oss = 1;
- substream->oss.setup = setup;
+ substream->oss.setup = *setup;
+ if (setup->nonblock)
+ substream->f_flags |= O_NONBLOCK;
+ else if (setup->block)
+ substream->f_flags &= ~O_NONBLOCK;
runtime = substream->runtime;
runtime->oss.params = 1;
runtime->oss.trigger = 1;
runtime->oss.rate = 8000;
+ mutex_init(&runtime->oss.params_lock);
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM_8:
runtime->oss.format = AFMT_U8;
@@ -1685,60 +2288,36 @@ static void snd_pcm_oss_init_substream(snd_pcm_substream_t *substream,
runtime->oss.fragshift = 0;
runtime->oss.maxfrags = 0;
runtime->oss.subdivision = 0;
+ substream->pcm_release = snd_pcm_oss_release_substream;
}
-static void snd_pcm_oss_release_substream(snd_pcm_substream_t *substream)
-{
- snd_pcm_runtime_t *runtime;
- runtime = substream->runtime;
- vfree(runtime->oss.buffer);
- snd_pcm_oss_plugin_clear(substream);
- substream->oss.file = NULL;
- substream->oss.oss = 0;
-}
-
-static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
+static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
{
int cidx;
- snd_assert(pcm_oss_file != NULL, return -ENXIO);
+ if (!pcm_oss_file)
+ return 0;
for (cidx = 0; cidx < 2; ++cidx) {
- snd_pcm_substream_t *substream = pcm_oss_file->streams[cidx];
- snd_pcm_runtime_t *runtime;
- if (substream == NULL)
- continue;
- runtime = substream->runtime;
-
- snd_pcm_stream_lock_irq(substream);
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
- snd_pcm_stream_unlock_irq(substream);
- if (substream->ffile != NULL) {
- if (substream->ops->hw_free != NULL)
- substream->ops->hw_free(substream);
- substream->ops->close(substream);
- substream->ffile = NULL;
- }
- snd_pcm_oss_release_substream(substream);
- snd_pcm_release_substream(substream);
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
+ if (substream)
+ snd_pcm_release_substream(substream);
}
kfree(pcm_oss_file);
return 0;
}
static int snd_pcm_oss_open_file(struct file *file,
- snd_pcm_t *pcm,
- snd_pcm_oss_file_t **rpcm_oss_file,
+ struct snd_pcm *pcm,
+ struct snd_pcm_oss_file **rpcm_oss_file,
int minor,
- snd_pcm_oss_setup_t *psetup,
- snd_pcm_oss_setup_t *csetup)
+ struct snd_pcm_oss_setup *setup)
{
- int err = 0;
- snd_pcm_oss_file_t *pcm_oss_file;
- snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
- unsigned int f_mode = file->f_mode;
+ int idx, err;
+ struct snd_pcm_oss_file *pcm_oss_file;
+ struct snd_pcm_substream *substream;
+ fmode_t f_mode = file->f_mode;
- snd_assert(rpcm_oss_file != NULL, return -EINVAL);
- *rpcm_oss_file = NULL;
+ if (rpcm_oss_file)
+ *rpcm_oss_file = NULL;
pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
if (pcm_oss_file == NULL)
@@ -1747,98 +2326,71 @@ static int snd_pcm_oss_open_file(struct file *file,
if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
f_mode = FMODE_WRITE;
- if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) {
- if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &psubstream)) < 0) {
+
+ file->f_flags &= ~O_APPEND;
+ for (idx = 0; idx < 2; idx++) {
+ if (setup[idx].disable)
+ continue;
+ if (! pcm->streams[idx].substream_count)
+ continue; /* no matching substream */
+ if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (! (f_mode & FMODE_WRITE))
+ continue;
+ } else {
+ if (! (f_mode & FMODE_READ))
+ continue;
+ }
+ err = snd_pcm_open_substream(pcm, idx, file, &substream);
+ if (err < 0) {
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream;
- }
- if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) {
- if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &csubstream)) < 0) {
- if (!(f_mode & FMODE_WRITE) || err != -ENODEV) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- } else {
- csubstream = NULL;
- }
- }
- pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream;
+
+ pcm_oss_file->streams[idx] = substream;
+ substream->file = pcm_oss_file;
+ snd_pcm_oss_init_substream(substream, &setup[idx], minor);
}
- if (psubstream == NULL && csubstream == NULL) {
+ if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) {
snd_pcm_oss_release_file(pcm_oss_file);
return -EINVAL;
}
- if (psubstream != NULL) {
- psubstream->oss.file = pcm_oss_file;
- err = snd_pcm_hw_constraints_init(psubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_init failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- if ((err = psubstream->ops->open(psubstream)) < 0) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- psubstream->ffile = file;
- err = snd_pcm_hw_constraints_complete(psubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_complete failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- snd_pcm_oss_init_substream(psubstream, psetup, minor);
- }
- if (csubstream != NULL) {
- csubstream->oss.file = pcm_oss_file;
- err = snd_pcm_hw_constraints_init(csubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_init failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- if ((err = csubstream->ops->open(csubstream)) < 0) {
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- csubstream->ffile = file;
- err = snd_pcm_hw_constraints_complete(csubstream);
- if (err < 0) {
- snd_printd("snd_pcm_hw_constraint_complete failed\n");
- snd_pcm_oss_release_file(pcm_oss_file);
- return err;
- }
- snd_pcm_oss_init_substream(csubstream, csetup, minor);
- }
file->private_data = pcm_oss_file;
- *rpcm_oss_file = pcm_oss_file;
+ if (rpcm_oss_file)
+ *rpcm_oss_file = pcm_oss_file;
return 0;
}
+static int snd_task_name(struct task_struct *task, char *name, size_t size)
+{
+ unsigned int idx;
+
+ if (snd_BUG_ON(!task || !name || size < 2))
+ return -EINVAL;
+ for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
+ name[idx] = task->comm[idx];
+ name[idx] = '\0';
+ return 0;
+}
+
static int snd_pcm_oss_open(struct inode *inode, struct file *file)
{
- int minor = iminor(inode);
- int cardnum = SNDRV_MINOR_OSS_CARD(minor);
- int device;
int err;
char task_name[32];
- snd_pcm_t *pcm;
- snd_pcm_oss_file_t *pcm_oss_file;
- snd_pcm_oss_setup_t *psetup = NULL, *csetup = NULL;
+ struct snd_pcm *pcm;
+ struct snd_pcm_oss_file *pcm_oss_file;
+ struct snd_pcm_oss_setup setup[2];
int nonblock;
wait_queue_t wait;
- snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
- device = SNDRV_MINOR_OSS_DEVICE(minor) == SNDRV_MINOR_OSS_PCM1 ?
- adsp_map[cardnum] : dsp_map[cardnum];
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
- pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + device];
+ pcm = snd_lookup_oss_minor_data(iminor(inode),
+ SNDRV_OSS_DEVICE_TYPE_PCM);
if (pcm == NULL) {
err = -ENODEV;
goto __error1;
@@ -1854,32 +2406,24 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
err = -EFAULT;
goto __error;
}
+ memset(setup, 0, sizeof(setup));
if (file->f_mode & FMODE_WRITE)
- psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
+ snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ task_name, &setup[0]);
if (file->f_mode & FMODE_READ)
- csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);
+ snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ task_name, &setup[1]);
nonblock = !!(file->f_flags & O_NONBLOCK);
- if (psetup && !psetup->disable) {
- if (psetup->nonblock)
- nonblock = 1;
- else if (psetup->block)
- nonblock = 0;
- } else if (csetup && !csetup->disable) {
- if (csetup->nonblock)
- nonblock = 1;
- else if (csetup->block)
- nonblock = 0;
- }
if (!nonblock)
nonblock = nonblock_open;
init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait);
- down(&pcm->open_mutex);
+ mutex_lock(&pcm->open_mutex);
while (1) {
err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
- minor, psetup, csetup);
+ iminor(inode), setup);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -1890,18 +2434,23 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
} else
break;
set_current_state(TASK_INTERRUPTIBLE);
- up(&pcm->open_mutex);
+ mutex_unlock(&pcm->open_mutex);
schedule();
- down(&pcm->open_mutex);
+ mutex_lock(&pcm->open_mutex);
+ if (pcm->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
}
remove_wait_queue(&pcm->open_wait, &wait);
- up(&pcm->open_mutex);
+ mutex_unlock(&pcm->open_mutex);
if (err < 0)
goto __error;
+ snd_card_unref(pcm->card);
return err;
__error:
@@ -1909,25 +2458,29 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
__error2:
snd_card_file_remove(pcm->card, file);
__error1:
+ if (pcm)
+ snd_card_unref(pcm->card);
return err;
}
static int snd_pcm_oss_release(struct inode *inode, struct file *file)
{
- snd_pcm_t *pcm;
- snd_pcm_substream_t *substream;
- snd_pcm_oss_file_t *pcm_oss_file;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_oss_file *pcm_oss_file;
pcm_oss_file = file->private_data;
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
- snd_assert(substream != NULL, return -ENXIO);
+ if (snd_BUG_ON(!substream))
+ return -ENXIO;
pcm = substream->pcm;
- snd_pcm_oss_sync(pcm_oss_file);
- down(&pcm->open_mutex);
+ if (!pcm->card->shutdown)
+ snd_pcm_oss_sync(pcm_oss_file);
+ mutex_lock(&pcm->open_mutex);
snd_pcm_oss_release_file(pcm_oss_file);
- up(&pcm->open_mutex);
+ mutex_unlock(&pcm->open_mutex);
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
snd_card_file_remove(pcm->card, file);
@@ -1936,7 +2489,7 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_pcm_oss_file_t *pcm_oss_file;
+ struct snd_pcm_oss_file *pcm_oss_file;
int __user *p = (int __user *)arg;
int res;
@@ -1947,21 +2500,22 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
return put_user(1, p);
#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int idx;
for (idx = 0; idx < 2; ++idx) {
substream = pcm_oss_file->streams[idx];
if (substream != NULL)
break;
}
- snd_assert(substream != NULL, return -ENXIO);
+ if (snd_BUG_ON(idx >= 2))
+ return -ENXIO;
return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
}
#endif
if (((cmd >> 8) & 0xff) != 'P')
return -EINVAL;
#ifdef OSS_DEBUG
- printk("pcm_oss: ioctl = 0x%x\n", cmd);
+ pr_debug("pcm_oss: ioctl = 0x%x\n", cmd);
#endif
switch (cmd) {
case SNDCTL_DSP_RESET:
@@ -2088,7 +2642,7 @@ 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;
}
@@ -2102,19 +2656,22 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
- snd_pcm_oss_file_t *pcm_oss_file;
- snd_pcm_substream_t *substream;
+ struct snd_pcm_oss_file *pcm_oss_file;
+ struct snd_pcm_substream *substream;
pcm_oss_file = file->private_data;
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream == NULL)
return -ENXIO;
+ substream->f_flags = file->f_flags & O_NONBLOCK;
#ifndef OSS_DEBUG
return snd_pcm_oss_read1(substream, buf, count);
#else
{
ssize_t res = snd_pcm_oss_read1(substream, buf, count);
- printk("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
@@ -2122,46 +2679,50 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
- snd_pcm_oss_file_t *pcm_oss_file;
- snd_pcm_substream_t *substream;
+ struct snd_pcm_oss_file *pcm_oss_file;
+ struct snd_pcm_substream *substream;
long result;
pcm_oss_file = file->private_data;
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
return -ENXIO;
- up(&file->f_dentry->d_inode->i_sem);
+ substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
- down(&file->f_dentry->d_inode->i_sem);
#ifdef OSS_DEBUG
- printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
+ pcm_dbg(substream->pcm, "pcm_oss: write %li bytes (wrote %li bytes)\n",
+ (long)count, (long)result);
#endif
return result;
}
-static int snd_pcm_oss_playback_ready(snd_pcm_substream_t *substream)
+static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
- return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ if (atomic_read(&substream->mmap_count))
+ return runtime->oss.prev_hw_ptr_period !=
+ get_hw_ptr_period(runtime);
else
- return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
+ return snd_pcm_playback_avail(runtime) >=
+ runtime->oss.period_frames;
}
-static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
+static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- if (atomic_read(&runtime->mmap_count))
- return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ if (atomic_read(&substream->mmap_count))
+ return runtime->oss.prev_hw_ptr_period !=
+ get_hw_ptr_period(runtime);
else
- return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
+ return snd_pcm_capture_avail(runtime) >=
+ runtime->oss.period_frames;
}
static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
{
- snd_pcm_oss_file_t *pcm_oss_file;
+ struct snd_pcm_oss_file *pcm_oss_file;
unsigned int mask;
- snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
+ struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
pcm_oss_file = file->private_data;
@@ -2170,7 +2731,7 @@ static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
mask = 0;
if (psubstream != NULL) {
- snd_pcm_runtime_t *runtime = psubstream->runtime;
+ 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 &&
@@ -2180,8 +2741,8 @@ static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
snd_pcm_stream_unlock_irq(psubstream);
}
if (csubstream != NULL) {
- snd_pcm_runtime_t *runtime = csubstream->runtime;
- enum sndrv_pcm_state ostate;
+ 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 ||
@@ -2189,7 +2750,7 @@ static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
mask |= POLLIN | POLLRDNORM;
snd_pcm_stream_unlock_irq(csubstream);
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
- snd_pcm_oss_file_t ofile;
+ struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
runtime->oss.trigger = 0;
@@ -2202,13 +2763,13 @@ static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
{
- snd_pcm_oss_file_t *pcm_oss_file;
- snd_pcm_substream_t *substream = NULL;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_oss_file *pcm_oss_file;
+ struct snd_pcm_substream *substream = NULL;
+ struct snd_pcm_runtime *runtime;
int err;
#ifdef OSS_DEBUG
- printk("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))) {
@@ -2243,8 +2804,10 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
if ((err = snd_pcm_oss_change_params(substream)) < 0)
return err;
}
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
if (runtime->oss.plugin_first != NULL)
return -EIO;
+#endif
if (area->vm_pgoff != 0)
return -EINVAL;
@@ -2256,7 +2819,8 @@ 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("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
+ pr_debug("pcm_oss: mmap ok, bytes = 0x%x\n",
+ runtime->oss.mmap_bytes);
#endif
/* In mmap mode we never stop */
runtime->stop_threshold = runtime->boundary;
@@ -2264,16 +2828,17 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
return 0;
}
+#ifdef CONFIG_SND_VERBOSE_PROCFS
/*
* /proc interface
*/
-static void snd_pcm_oss_proc_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
- snd_pcm_oss_setup_t *setup = pstr->oss.setup_list;
- down(&pstr->oss.setup_mutex);
+ struct snd_pcm_str *pstr = entry->private_data;
+ struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
+ mutex_lock(&pstr->oss.setup_mutex);
while (setup) {
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
setup->task_name,
@@ -2287,18 +2852,13 @@ static void snd_pcm_oss_proc_read(snd_info_entry_t *entry,
setup->nosilence ? " no-silence" : "");
setup = setup->next;
}
- up(&pstr->oss.setup_mutex);
+ mutex_unlock(&pstr->oss.setup_mutex);
}
-static void snd_pcm_oss_proc_free_setup_list(snd_pcm_str_t * pstr)
+static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
{
- unsigned int idx;
- snd_pcm_substream_t *substream;
- snd_pcm_oss_setup_t *setup, *setupn;
+ struct snd_pcm_oss_setup *setup, *setupn;
- for (idx = 0, substream = pstr->substream;
- idx < pstr->substream_count; idx++, substream = substream->next)
- substream->oss.setup = NULL;
for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
setup; setup = setupn) {
setupn = setup->next;
@@ -2308,21 +2868,22 @@ static void snd_pcm_oss_proc_free_setup_list(snd_pcm_str_t * pstr)
pstr->oss.setup_list = NULL;
}
-static void snd_pcm_oss_proc_write(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
- char line[128], str[32], task_name[32], *ptr;
+ struct snd_pcm_str *pstr = entry->private_data;
+ char line[128], str[32], task_name[32];
+ const char *ptr;
int idx1;
- snd_pcm_oss_setup_t *setup, *setup1, template;
+ struct snd_pcm_oss_setup *setup, *setup1, template;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
- down(&pstr->oss.setup_mutex);
+ mutex_lock(&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);
- up(&pstr->oss.setup_mutex);
+ mutex_unlock(&pstr->oss.setup_mutex);
continue;
}
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -2359,39 +2920,44 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry,
}
} while (*str);
if (setup == NULL) {
- setup = (snd_pcm_oss_setup_t *) kmalloc(sizeof(snd_pcm_oss_setup_t), GFP_KERNEL);
- if (setup) {
- if (pstr->oss.setup_list == NULL) {
- pstr->oss.setup_list = setup;
- } else {
- for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next);
- setup1->next = setup;
- }
- template.task_name = kstrdup(task_name, GFP_KERNEL);
- } else {
+ setup = kmalloc(sizeof(*setup), GFP_KERNEL);
+ if (! setup) {
+ buffer->error = -ENOMEM;
+ mutex_unlock(&pstr->oss.setup_mutex);
+ return;
+ }
+ if (pstr->oss.setup_list == NULL)
+ pstr->oss.setup_list = setup;
+ else {
+ for (setup1 = pstr->oss.setup_list;
+ setup1->next; setup1 = setup1->next);
+ setup1->next = setup;
+ }
+ template.task_name = kstrdup(task_name, GFP_KERNEL);
+ if (! template.task_name) {
+ kfree(setup);
buffer->error = -ENOMEM;
+ mutex_unlock(&pstr->oss.setup_mutex);
+ return;
}
}
- if (setup)
- *setup = template;
- up(&pstr->oss.setup_mutex);
+ *setup = template;
+ mutex_unlock(&pstr->oss.setup_mutex);
}
}
-static void snd_pcm_oss_proc_init(snd_pcm_t *pcm)
+static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
{
int stream;
for (stream = 0; stream < 2; ++stream) {
- snd_info_entry_t *entry;
- snd_pcm_str_t *pstr = &pcm->streams[stream];
+ struct snd_info_entry *entry;
+ 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->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
- entry->c.text.read_size = 8192;
entry->c.text.read = snd_pcm_oss_proc_read;
- entry->c.text.write_size = 8192;
entry->c.text.write = snd_pcm_oss_proc_write;
entry->private_data = pstr;
if (snd_info_register(entry) < 0) {
@@ -2403,54 +2969,50 @@ static void snd_pcm_oss_proc_init(snd_pcm_t *pcm)
}
}
-static void snd_pcm_oss_proc_done(snd_pcm_t *pcm)
+static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
{
int stream;
for (stream = 0; stream < 2; ++stream) {
- snd_pcm_str_t *pstr = &pcm->streams[stream];
- if (pstr->oss.proc_entry) {
- snd_info_unregister(pstr->oss.proc_entry);
- pstr->oss.proc_entry = NULL;
- snd_pcm_oss_proc_free_setup_list(pstr);
- }
+ struct snd_pcm_str *pstr = &pcm->streams[stream];
+ snd_info_free_entry(pstr->oss.proc_entry);
+ pstr->oss.proc_entry = NULL;
+ snd_pcm_oss_proc_free_setup_list(pstr);
}
}
+#else /* !CONFIG_SND_VERBOSE_PROCFS */
+#define snd_pcm_oss_proc_init(pcm)
+#define snd_pcm_oss_proc_done(pcm)
+#endif /* CONFIG_SND_VERBOSE_PROCFS */
/*
* ENTRY functions
*/
-static struct file_operations snd_pcm_oss_f_reg =
+static const struct file_operations snd_pcm_oss_f_reg =
{
.owner = THIS_MODULE,
.read = snd_pcm_oss_read,
.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,
.mmap = snd_pcm_oss_mmap,
};
-static snd_minor_t snd_pcm_oss_reg =
-{
- .comment = "digital audio",
- .f_ops = &snd_pcm_oss_f_reg,
-};
-
-static void register_oss_dsp(snd_pcm_t *pcm, int index)
+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_reg,
- name) < 0) {
- snd_printk("unable to register OSS PCM device %i:%i\n", pcm->card->number, pcm->device);
+ pcm->card, index, &snd_pcm_oss_f_reg,
+ pcm) < 0) {
+ pcm_err(pcm, "unable to register OSS PCM device %i:%i\n",
+ pcm->card->number, pcm->device);
}
}
-static int snd_pcm_oss_register_minor(snd_pcm_t * pcm)
+static int snd_pcm_oss_register_minor(struct snd_pcm *pcm)
{
pcm->oss.reg = 0;
if (dsp_map[pcm->card->number] == (int)pcm->device) {
@@ -2481,7 +3043,7 @@ static int snd_pcm_oss_register_minor(snd_pcm_t * pcm)
return 0;
}
-static int snd_pcm_oss_disconnect_minor(snd_pcm_t * pcm)
+static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
{
if (pcm->oss.reg) {
if (pcm->oss.reg_mask & 1) {
@@ -2494,26 +3056,24 @@ static int snd_pcm_oss_disconnect_minor(snd_pcm_t * pcm)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 1);
}
- }
- return 0;
-}
-
-static int snd_pcm_oss_unregister_minor(snd_pcm_t * pcm)
-{
- snd_pcm_oss_disconnect_minor(pcm);
- if (pcm->oss.reg) {
if (dsp_map[pcm->card->number] == (int)pcm->device) {
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
#endif
}
pcm->oss.reg = 0;
- snd_pcm_oss_proc_done(pcm);
}
return 0;
}
-static snd_pcm_notify_t snd_pcm_oss_notify =
+static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
+{
+ snd_pcm_oss_disconnect_minor(pcm);
+ snd_pcm_oss_proc_done(pcm);
+ return 0;
+}
+
+static struct snd_pcm_notify snd_pcm_oss_notify =
{
.n_register = snd_pcm_oss_register_minor,
.n_disconnect = snd_pcm_oss_disconnect_minor,
@@ -2528,11 +3088,13 @@ 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("invalid dsp_map[%d] = %d\n", i, dsp_map[i]);
+ 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("invalid adsp_map[%d] = %d\n", i, adsp_map[i]);
+ pr_err("ALSA: pcm_oss: invalid adsp_map[%d] = %d\n",
+ i, adsp_map[i]);
adsp_map[i] = 1;
}
}
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index fc23373c000..727ac44d39f 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -1,6 +1,6 @@
/*
* PCM Plug-In shared (kernel/library) code
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
@@ -24,7 +24,6 @@
#define PLUGIN_DEBUG
#endif
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
@@ -36,26 +35,6 @@
#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
-static int snd_pcm_plugin_src_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask)
-{
- bitset_t *vmask = plugin->src_vmask;
- bitset_copy(vmask, dst_vmask, plugin->src_format.channels);
- *src_vmask = vmask;
- return 0;
-}
-
-static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask)
-{
- bitset_t *vmask = plugin->dst_vmask;
- bitset_copy(vmask, src_vmask, plugin->dst_format.channels);
- *dst_vmask = vmask;
- return 0;
-}
-
/*
* because some cards might have rates "very close", we ignore
* all "resampling" requests within +-5%
@@ -67,13 +46,13 @@ static int rate_match(unsigned int src_rate, unsigned int dst_rate)
return dst_rate >= low && dst_rate <= high;
}
-static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
+static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
{
- snd_pcm_plugin_format_t *format;
+ struct snd_pcm_plugin_format *format;
ssize_t width;
size_t size;
unsigned int channel;
- snd_pcm_plugin_channel_t *c;
+ struct snd_pcm_plugin_channel *c;
if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
format = &plugin->src_format;
@@ -83,7 +62,8 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
return width;
size = frames * format->channels * width;
- snd_assert((size % 8) == 0, return -ENXIO);
+ if (snd_BUG_ON(size % 8))
+ return -ENXIO;
size /= 8;
if (plugin->buf_frames < frames) {
vfree(plugin->buf);
@@ -105,7 +85,8 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram
c->area.step = format->channels * width;
}
} else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
- snd_assert((size % format->channels) == 0,);
+ if (snd_BUG_ON(size % format->channels))
+ return -EINVAL;
size /= format->channels;
for (channel = 0; channel < format->channels; channel++, c++) {
c->frames = frames;
@@ -120,27 +101,30 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t fram
return 0;
}
-int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames)
+int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
{
int err;
- snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
+ if (snd_BUG_ON(!snd_pcm_plug_first(plug)))
+ return -ENXIO;
if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
+ struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
while (plugin->next) {
if (plugin->dst_frames)
frames = plugin->dst_frames(plugin, frames);
- snd_assert(frames > 0, return -ENXIO);
+ if (snd_BUG_ON(frames <= 0))
+ return -ENXIO;
plugin = plugin->next;
err = snd_pcm_plugin_alloc(plugin, frames);
if (err < 0)
return err;
}
} else {
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
+ struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
while (plugin->prev) {
if (plugin->src_frames)
frames = plugin->src_frames(plugin, frames);
- snd_assert(frames > 0, return -ENXIO);
+ if (snd_BUG_ON(frames <= 0))
+ return -ENXIO;
plugin = plugin->prev;
err = snd_pcm_plugin_alloc(plugin, frames);
if (err < 0)
@@ -151,26 +135,28 @@ int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames)
}
-snd_pcm_sframes_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
+snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
snd_pcm_uframes_t frames,
- snd_pcm_plugin_channel_t **channels)
+ struct snd_pcm_plugin_channel **channels)
{
*channels = plugin->buf_channels;
return frames;
}
-int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
+int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
const char *name,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
size_t extra,
- snd_pcm_plugin_t **ret)
+ struct snd_pcm_plugin **ret)
{
- snd_pcm_plugin_t *plugin;
+ struct snd_pcm_plugin *plugin;
unsigned int channels;
- snd_assert(plug != NULL, return -ENXIO);
- snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plug))
+ return -ENXIO;
+ if (snd_BUG_ON(!src_format || !dst_format))
+ return -ENXIO;
plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
if (plugin == NULL)
return -ENOMEM;
@@ -180,10 +166,10 @@ int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
plugin->src_format = *src_format;
plugin->src_width = snd_pcm_format_physical_width(src_format->format);
- snd_assert(plugin->src_width > 0, );
+ snd_BUG_ON(plugin->src_width <= 0);
plugin->dst_format = *dst_format;
plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
- snd_assert(plugin->dst_width > 0, );
+ snd_BUG_ON(plugin->dst_width <= 0);
if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
channels = src_format->channels;
else
@@ -193,24 +179,12 @@ int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
snd_pcm_plugin_free(plugin);
return -ENOMEM;
}
- plugin->src_vmask = bitset_alloc(src_format->channels);
- if (plugin->src_vmask == NULL) {
- snd_pcm_plugin_free(plugin);
- return -ENOMEM;
- }
- plugin->dst_vmask = bitset_alloc(dst_format->channels);
- if (plugin->dst_vmask == NULL) {
- snd_pcm_plugin_free(plugin);
- return -ENOMEM;
- }
plugin->client_channels = snd_pcm_plugin_client_channels;
- plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
- plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
*ret = plugin;
return 0;
}
-int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin)
+int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
{
if (! plugin)
return 0;
@@ -218,20 +192,20 @@ int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin)
plugin->private_free(plugin);
kfree(plugin->buf_channels);
vfree(plugin->buf);
- kfree(plugin->src_vmask);
- kfree(plugin->dst_vmask);
kfree(plugin);
return 0;
}
-snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t drv_frames)
+snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
{
- snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
- int stream = snd_pcm_plug_stream(plug);
+ struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
+ int stream;
- snd_assert(plug != NULL, return -ENXIO);
+ 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) {
@@ -253,16 +227,18 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, snd_pcm_uframes
return drv_frames;
}
-snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t clt_frames)
+snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
{
- snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
+ struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
snd_pcm_sframes_t frames;
- int stream = snd_pcm_plug_stream(plug);
+ int stream;
- snd_assert(plug != NULL, return -ENXIO);
+ 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) {
@@ -290,30 +266,36 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, snd_pcm_uframes_
return frames;
}
-static int snd_pcm_plug_formats(snd_mask_t *mask, int format)
+static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format)
{
- snd_mask_t formats = *mask;
+ struct snd_mask formats = *mask;
u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
+ SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
- snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
+ 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);
- return snd_mask_test(&formats, format);
+ return snd_mask_test(&formats, (__force int)format);
}
-static int preferred_formats[] = {
+static snd_pcm_format_t preferred_formats[] = {
SNDRV_PCM_FORMAT_S16_LE,
SNDRV_PCM_FORMAT_S16_BE,
SNDRV_PCM_FORMAT_U16_LE,
SNDRV_PCM_FORMAT_U16_BE,
+ SNDRV_PCM_FORMAT_S24_3LE,
+ SNDRV_PCM_FORMAT_S24_3BE,
+ SNDRV_PCM_FORMAT_U24_3LE,
+ SNDRV_PCM_FORMAT_U24_3BE,
SNDRV_PCM_FORMAT_S24_LE,
SNDRV_PCM_FORMAT_S24_BE,
SNDRV_PCM_FORMAT_U24_LE,
@@ -326,65 +308,65 @@ static int preferred_formats[] = {
SNDRV_PCM_FORMAT_U8
};
-int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask)
+snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
+ struct snd_mask *format_mask)
{
- if (snd_mask_test(format_mask, format))
+ int i;
+
+ if (snd_mask_test(format_mask, (__force int)format))
return format;
- if (! snd_pcm_plug_formats(format_mask, format))
- return -EINVAL;
+ if (!snd_pcm_plug_formats(format_mask, format))
+ return (__force snd_pcm_format_t)-EINVAL;
if (snd_pcm_format_linear(format)) {
- int width = snd_pcm_format_width(format);
- int unsignd = snd_pcm_format_unsigned(format);
- int big = snd_pcm_format_big_endian(format);
- int format1;
- int wid, width1=width;
- int dwidth1 = 8;
- for (wid = 0; wid < 4; ++wid) {
- int end, big1 = big;
- for (end = 0; end < 2; ++end) {
- int sgn, unsignd1 = unsignd;
- for (sgn = 0; sgn < 2; ++sgn) {
- format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
- if (format1 >= 0 &&
- snd_mask_test(format_mask, format1))
- goto _found;
- unsignd1 = !unsignd1;
- }
- big1 = !big1;
- }
- if (width1 == 32) {
- dwidth1 = -dwidth1;
- width1 = width;
+ unsigned int width = snd_pcm_format_width(format);
+ int unsignd = snd_pcm_format_unsigned(format) > 0;
+ int big = snd_pcm_format_big_endian(format) > 0;
+ unsigned int badness, best = -1;
+ snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
+ for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
+ snd_pcm_format_t f = preferred_formats[i];
+ unsigned int w;
+ if (!snd_mask_test(format_mask, (__force int)f))
+ continue;
+ w = snd_pcm_format_width(f);
+ if (w >= width)
+ badness = w - width;
+ else
+ badness = width - w + 32;
+ badness += snd_pcm_format_unsigned(f) != unsignd;
+ badness += snd_pcm_format_big_endian(f) != big;
+ if (badness < best) {
+ best_format = f;
+ best = badness;
}
- width1 += dwidth1;
}
- return -EINVAL;
- _found:
- return format1;
+ if ((__force int)best_format >= 0)
+ return best_format;
+ else
+ return (__force snd_pcm_format_t)-EINVAL;
} else {
- unsigned int i;
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW:
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
- int format1 = preferred_formats[i];
- if (snd_mask_test(format_mask, format1))
+ snd_pcm_format_t format1 = preferred_formats[i];
+ if (snd_mask_test(format_mask, (__force int)format1))
return format1;
}
default:
- return -EINVAL;
+ return (__force snd_pcm_format_t)-EINVAL;
}
}
}
-int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_params_t *slave_params)
+int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
+ struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_params *slave_params)
{
- snd_pcm_plugin_format_t tmpformat;
- snd_pcm_plugin_format_t dstformat;
- snd_pcm_plugin_format_t srcformat;
- int src_access, dst_access;
- snd_pcm_plugin_t *plugin = NULL;
+ struct snd_pcm_plugin_format tmpformat;
+ struct snd_pcm_plugin_format dstformat;
+ struct snd_pcm_plugin_format srcformat;
+ snd_pcm_access_t src_access, dst_access;
+ struct snd_pcm_plugin *plugin = NULL;
int err;
int stream = snd_pcm_plug_stream(plug);
int slave_interleaved = (params_channels(slave_params) == 1 ||
@@ -429,24 +411,14 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
dstformat.channels);
/* Format change (linearization) */
- if ((srcformat.format != dstformat.format ||
- !rate_match(srcformat.rate, dstformat.rate) ||
- srcformat.channels != dstformat.channels) &&
- !snd_pcm_format_linear(srcformat.format)) {
- if (snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- else
- tmpformat.format = SNDRV_PCM_FORMAT_S16;
- switch (srcformat.format) {
- case SNDRV_PCM_FORMAT_MU_LAW:
- err = snd_pcm_plugin_build_mulaw(plug,
- &srcformat, &tmpformat,
- &plugin);
- break;
- default:
+ if (! rate_match(srcformat.rate, dstformat.rate) &&
+ ! snd_pcm_format_linear(srcformat.format)) {
+ if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
return -EINVAL;
- }
- pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
+ tmpformat.format = SNDRV_PCM_FORMAT_S16;
+ err = snd_pcm_plugin_build_mulaw(plug,
+ &srcformat, &tmpformat,
+ &plugin);
if (err < 0)
return err;
err = snd_pcm_plugin_append(plugin);
@@ -460,35 +432,11 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
/* channels reduction */
if (srcformat.channels > dstformat.channels) {
- int sv = srcformat.channels;
- int dv = dstformat.channels;
- route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
- if (ttable == NULL)
- return -ENOMEM;
-#if 1
- if (sv == 2 && dv == 1) {
- ttable[0] = HALF;
- ttable[1] = HALF;
- } else
-#endif
- {
- int v;
- for (v = 0; v < dv; ++v)
- ttable[v * sv + v] = FULL;
- }
tmpformat.channels = dstformat.channels;
- if (rate_match(srcformat.rate, dstformat.rate) &&
- snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- err = snd_pcm_plugin_build_route(plug,
- &srcformat, &tmpformat,
- ttable, &plugin);
- kfree(ttable);
+ err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
+ if (err < 0)
return err;
- }
err = snd_pcm_plugin_append(plugin);
if (err < 0) {
snd_pcm_plugin_free(plugin);
@@ -500,18 +448,29 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
/* rate resampling */
if (!rate_match(srcformat.rate, dstformat.rate)) {
+ if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
+ /* convert to S16 for resampling */
+ tmpformat.format = SNDRV_PCM_FORMAT_S16;
+ err = snd_pcm_plugin_build_linear(plug,
+ &srcformat, &tmpformat,
+ &plugin);
+ if (err < 0)
+ return err;
+ err = snd_pcm_plugin_append(plugin);
+ if (err < 0) {
+ snd_pcm_plugin_free(plugin);
+ return err;
+ }
+ srcformat = tmpformat;
+ src_access = dst_access;
+ }
tmpformat.rate = dstformat.rate;
- if (srcformat.channels == dstformat.channels &&
- snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
err = snd_pcm_plugin_build_rate(plug,
&srcformat, &tmpformat,
&plugin);
pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
+ if (err < 0)
return err;
- }
err = snd_pcm_plugin_append(plugin);
if (err < 0) {
snd_pcm_plugin_free(plugin);
@@ -521,56 +480,11 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
src_access = dst_access;
}
- /* channels extension */
- if (srcformat.channels < dstformat.channels) {
- int sv = srcformat.channels;
- int dv = dstformat.channels;
- route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
- if (ttable == NULL)
- return -ENOMEM;
-#if 0
- {
- int v;
- for (v = 0; v < sv; ++v)
- ttable[v * sv + v] = FULL;
- }
-#else
- {
- /* Playback is spreaded on all channels */
- int vd, vs;
- for (vd = 0, vs = 0; vd < dv; ++vd) {
- ttable[vd * sv + vs] = FULL;
- vs++;
- if (vs == sv)
- vs = 0;
- }
- }
-#endif
- tmpformat.channels = dstformat.channels;
- if (snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- err = snd_pcm_plugin_build_route(plug,
- &srcformat, &tmpformat,
- ttable, &plugin);
- kfree(ttable);
- pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- srcformat = tmpformat;
- src_access = dst_access;
- }
-
/* format change */
if (srcformat.format != dstformat.format) {
tmpformat.format = dstformat.format;
- if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
+ if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
+ tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
err = snd_pcm_plugin_build_mulaw(plug,
&srcformat, &tmpformat,
&plugin);
@@ -595,6 +509,22 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
src_access = dst_access;
}
+ /* channels extension */
+ if (srcformat.channels < dstformat.channels) {
+ tmpformat.channels = dstformat.channels;
+ err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
+ pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
+ if (err < 0)
+ return err;
+ err = snd_pcm_plugin_append(plugin);
+ if (err < 0) {
+ snd_pcm_plugin_free(plugin);
+ return err;
+ }
+ srcformat = tmpformat;
+ src_access = dst_access;
+ }
+
/* de-interleave */
if (src_access != dst_access) {
err = snd_pcm_plugin_build_copy(plug,
@@ -614,18 +544,19 @@ int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
return 0;
}
-snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
+snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug,
char *buf,
snd_pcm_uframes_t count,
- snd_pcm_plugin_channel_t **channels)
+ struct snd_pcm_plugin_channel **channels)
{
- snd_pcm_plugin_t *plugin;
- snd_pcm_plugin_channel_t *v;
- snd_pcm_plugin_format_t *format;
+ struct snd_pcm_plugin *plugin;
+ struct snd_pcm_plugin_channel *v;
+ struct snd_pcm_plugin_format *format;
int width, nchannels, channel;
int stream = snd_pcm_plug_stream(plug);
- snd_assert(buf != NULL, return -ENXIO);
+ if (snd_BUG_ON(!buf))
+ return -ENXIO;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
plugin = snd_pcm_plug_first(plug);
format = &plugin->src_format;
@@ -638,7 +569,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
return width;
nchannels = format->channels;
- snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
+ if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
+ format->channels > 1))
+ return -ENXIO;
for (channel = 0; channel < nchannels; channel++, v++) {
v->frames = count;
v->enabled = 1;
@@ -650,102 +583,13 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
return count;
}
-static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug,
- bitset_t *client_vmask)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
- if (plugin == NULL) {
- return 0;
- } else {
- int schannels = plugin->dst_format.channels;
- bitset_t bs[bitset_size(schannels)];
- bitset_t *srcmask;
- bitset_t *dstmask = bs;
- int err;
- bitset_one(dstmask, schannels);
-
- while (1) {
- err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
- if (err < 0)
- return err;
- dstmask = srcmask;
- if (plugin->prev == NULL)
- break;
- plugin = plugin->prev;
- }
- bitset_and(client_vmask, dstmask, plugin->src_format.channels);
- return 0;
- }
-}
-
-static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug,
- snd_pcm_plugin_channel_t *src_channels)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
- unsigned int nchannels = plugin->src_format.channels;
- bitset_t bs[bitset_size(nchannels)];
- bitset_t *srcmask = bs;
- int err;
- unsigned int channel;
- for (channel = 0; channel < nchannels; channel++) {
- if (src_channels[channel].enabled)
- bitset_set(srcmask, channel);
- else
- bitset_reset(srcmask, channel);
- }
- err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
- if (err < 0)
- return err;
- for (channel = 0; channel < nchannels; channel++) {
- if (!bitset_get(srcmask, channel))
- src_channels[channel].enabled = 0;
- }
- return 0;
-}
-
-static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug,
- snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *client_channels)
+snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size)
{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
- unsigned int nchannels = plugin->dst_format.channels;
- bitset_t bs[bitset_size(nchannels)];
- bitset_t *dstmask = bs;
- bitset_t *srcmask;
- int err;
- unsigned int channel;
- for (channel = 0; channel < nchannels; channel++) {
- if (client_channels[channel].enabled)
- bitset_set(dstmask, channel);
- else
- bitset_reset(dstmask, channel);
- }
- while (plugin) {
- err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
- if (err < 0)
- return err;
- dstmask = srcmask;
- plugin = plugin->prev;
- }
- plugin = snd_pcm_plug_first(plug);
- nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; channel++) {
- if (!bitset_get(dstmask, channel))
- src_channels[channel].enabled = 0;
- }
- return 0;
-}
-
-snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size)
-{
- snd_pcm_plugin_t *plugin, *next;
- snd_pcm_plugin_channel_t *dst_channels;
+ struct snd_pcm_plugin *plugin, *next;
+ struct snd_pcm_plugin_channel *dst_channels;
int err;
snd_pcm_sframes_t frames = size;
- if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
- return err;
-
plugin = snd_pcm_plug_first(plug);
while (plugin && frames > 0) {
if ((next = plugin->next) != NULL) {
@@ -771,10 +615,10 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plug
return snd_pcm_plug_client_size(plug, frames);
}
-snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size)
+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)
{
- snd_pcm_plugin_t *plugin, *next;
- snd_pcm_plugin_channel_t *src_channels, *dst_channels;
+ struct snd_pcm_plugin *plugin, *next;
+ struct snd_pcm_plugin_channel *src_channels, *dst_channels;
snd_pcm_sframes_t frames = size;
int err;
@@ -790,10 +634,6 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugi
return err;
}
frames = err;
- if (!plugin->prev) {
- if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0)
- return err;
- }
} else {
dst_channels = dst_channels_final;
}
@@ -806,8 +646,8 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugi
return frames;
}
-int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
- size_t samples, int format)
+int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
+ size_t samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
unsigned char *dst;
@@ -852,9 +692,9 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offs
return 0;
}
-int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset,
- const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
- size_t samples, int format)
+int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
+ const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
+ size_t samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
char *src, *dst;
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index 0f86ce47749..a5035c2369a 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -3,7 +3,7 @@
/*
* Digital Audio (Plugin interface) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -22,229 +22,164 @@
*
*/
-#ifndef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#endif
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
-typedef unsigned int bitset_t;
-
-static inline size_t bitset_size(int nbits)
-{
- return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
-}
-
-static inline bitset_t *bitset_alloc(int nbits)
-{
- return kcalloc(bitset_size(nbits), sizeof(bitset_t), GFP_KERNEL);
-}
-
-static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- bitmap[pos / bits] |= 1 << (pos % bits);
-}
-
-static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- bitmap[pos / bits] &= ~(1 << (pos % bits));
-}
-
-static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- return !!(bitmap[pos / bits] & (1 << (pos % bits)));
-}
-
-static inline void bitset_copy(bitset_t *dst, bitset_t *src, unsigned int nbits)
-{
- memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
-}
-
-static inline void bitset_and(bitset_t *dst, bitset_t *bs, unsigned int nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ &= *bs++;
-}
-
-static inline void bitset_or(bitset_t *dst, bitset_t *bs, unsigned int nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ |= *bs++;
-}
-
-static inline void bitset_zero(bitset_t *dst, unsigned int nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ = 0;
-}
-
-static inline void bitset_one(bitset_t *dst, unsigned int nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ = ~(bitset_t)0;
-}
-
-#define snd_pcm_plug_t snd_pcm_substream_t
#define snd_pcm_plug_stream(plug) ((plug)->stream)
-typedef enum {
+enum snd_pcm_plugin_action {
INIT = 0,
PREPARE = 1,
-} snd_pcm_plugin_action_t;
+};
-typedef struct _snd_pcm_channel_area {
+struct snd_pcm_channel_area {
void *addr; /* base address of channel samples */
unsigned int first; /* offset to first sample in bits */
unsigned int step; /* samples distance in bits */
-} snd_pcm_channel_area_t;
+};
-typedef struct _snd_pcm_plugin_channel {
+struct snd_pcm_plugin_channel {
void *aptr; /* pointer to the allocated area */
- snd_pcm_channel_area_t area;
+ struct snd_pcm_channel_area area;
snd_pcm_uframes_t frames; /* allocated frames */
unsigned int enabled:1; /* channel need to be processed */
unsigned int wanted:1; /* channel is wanted */
-} snd_pcm_plugin_channel_t;
+};
-typedef struct _snd_pcm_plugin_format {
- int format;
+struct snd_pcm_plugin_format {
+ snd_pcm_format_t format;
unsigned int rate;
unsigned int channels;
-} snd_pcm_plugin_format_t;
+};
-struct _snd_pcm_plugin {
+struct snd_pcm_plugin {
const char *name; /* plug-in name */
int stream;
- snd_pcm_plugin_format_t src_format; /* source format */
- snd_pcm_plugin_format_t dst_format; /* destination format */
+ struct snd_pcm_plugin_format src_format; /* source format */
+ struct snd_pcm_plugin_format dst_format; /* destination format */
int src_width; /* sample width in bits */
int dst_width; /* sample width in bits */
- int access;
- snd_pcm_sframes_t (*src_frames)(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t dst_frames);
- snd_pcm_sframes_t (*dst_frames)(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t src_frames);
- snd_pcm_sframes_t (*client_channels)(snd_pcm_plugin_t *plugin,
- snd_pcm_uframes_t frames,
- snd_pcm_plugin_channel_t **channels);
- int (*src_channels_mask)(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask);
- int (*dst_channels_mask)(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask);
- snd_pcm_sframes_t (*transfer)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- snd_pcm_uframes_t frames);
- int (*action)(snd_pcm_plugin_t *plugin,
- snd_pcm_plugin_action_t action,
+ snd_pcm_access_t access;
+ snd_pcm_sframes_t (*src_frames)(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t dst_frames);
+ snd_pcm_sframes_t (*dst_frames)(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t src_frames);
+ snd_pcm_sframes_t (*client_channels)(struct snd_pcm_plugin *plugin,
+ snd_pcm_uframes_t frames,
+ struct snd_pcm_plugin_channel **channels);
+ snd_pcm_sframes_t (*transfer)(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
+ snd_pcm_uframes_t frames);
+ int (*action)(struct snd_pcm_plugin *plugin,
+ enum snd_pcm_plugin_action action,
unsigned long data);
- snd_pcm_plugin_t *prev;
- snd_pcm_plugin_t *next;
- snd_pcm_plug_t *plug;
+ struct snd_pcm_plugin *prev;
+ struct snd_pcm_plugin *next;
+ struct snd_pcm_substream *plug;
void *private_data;
- void (*private_free)(snd_pcm_plugin_t *plugin);
+ void (*private_free)(struct snd_pcm_plugin *plugin);
char *buf;
snd_pcm_uframes_t buf_frames;
- snd_pcm_plugin_channel_t *buf_channels;
- bitset_t *src_vmask;
- bitset_t *dst_vmask;
+ struct snd_pcm_plugin_channel *buf_channels;
char extra_data[0];
};
-int snd_pcm_plugin_build(snd_pcm_plug_t *handle,
+int snd_pcm_plugin_build(struct snd_pcm_substream *handle,
const char *name,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
size_t extra,
- snd_pcm_plugin_t **ret);
-int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
-int snd_pcm_plugin_clear(snd_pcm_plugin_t **first);
-int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames);
-snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *handle, snd_pcm_uframes_t drv_size);
-snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *handle, snd_pcm_uframes_t clt_size);
+ 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);
#define FULL ROUTE_PLUGIN_RESOLUTION
#define HALF ROUTE_PLUGIN_RESOLUTION / 2
-typedef int route_ttable_entry_t;
-
-int snd_pcm_plugin_build_io(snd_pcm_plug_t *handle,
- snd_pcm_hw_params_t *params,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_linear(snd_pcm_plug_t *handle,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *handle,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_rate(snd_pcm_plug_t *handle,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_route(snd_pcm_plug_t *handle,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- route_ttable_entry_t *ttable,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_copy(snd_pcm_plug_t *handle,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin);
-
-int snd_pcm_plug_format_plugins(snd_pcm_plug_t *substream,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_params_t *slave_params);
-
-int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask);
-
-int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
-
-snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *handle, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *handle, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size);
-
-snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *handle,
- char *buf, snd_pcm_uframes_t count,
- snd_pcm_plugin_channel_t **channels);
-
-snd_pcm_sframes_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
- snd_pcm_uframes_t frames,
- snd_pcm_plugin_channel_t **channels);
-
-int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
- size_t samples, int format);
-int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_channel, size_t src_offset,
- const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
- size_t samples, int format);
-
-void *snd_pcm_plug_buf_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t size);
-void snd_pcm_plug_buf_unlock(snd_pcm_plug_t *plug, void *ptr);
-snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t size, int in_kernel);
-snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t size, int in_kernel);
-snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel);
-snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel);
-
-
-
-#define ROUTE_PLUGIN_RESOLUTION 16
-
-int getput_index(int format);
-int copy_index(int format);
-int conv_index(int src_format, int dst_format);
-
-void zero_channel(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *dst_channel,
- size_t samples);
+
+int snd_pcm_plugin_build_io(struct snd_pcm_substream *handle,
+ struct snd_pcm_hw_params *params,
+ struct snd_pcm_plugin **r_plugin);
+int snd_pcm_plugin_build_linear(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin);
+int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin);
+int snd_pcm_plugin_build_rate(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin);
+int snd_pcm_plugin_build_route(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin);
+int snd_pcm_plugin_build_copy(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin);
+
+int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ 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);
+
+int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin);
+
+snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_channel *src_channels,
+ snd_pcm_uframes_t size);
+snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *handle,
+ struct snd_pcm_plugin_channel *dst_channels_final,
+ snd_pcm_uframes_t size);
+
+snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *handle,
+ char *buf, snd_pcm_uframes_t count,
+ struct snd_pcm_plugin_channel **channels);
+
+snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
+ snd_pcm_uframes_t frames,
+ struct snd_pcm_plugin_channel **channels);
+
+int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_channel,
+ size_t dst_offset,
+ size_t samples, snd_pcm_format_t format);
+int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
+ size_t src_offset,
+ const struct snd_pcm_channel_area *dst_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);
+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);
+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
#ifdef PLUGIN_DEBUG
-#define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
+#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
#else
-#define pdprintf( fmt, args... )
+#define pdprintf(fmt, args...)
#endif
#endif /* __PCM_PLUGIN_H */
diff --git a/sound/core/oss/plugin_ops.h b/sound/core/oss/plugin_ops.h
deleted file mode 100644
index 0607e956608..00000000000
--- a/sound/core/oss/plugin_ops.h
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Plugin sample operators with fast switch
- * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#define as_u8(ptr) (*(u_int8_t*)(ptr))
-#define as_u16(ptr) (*(u_int16_t*)(ptr))
-#define as_u32(ptr) (*(u_int32_t*)(ptr))
-#define as_u64(ptr) (*(u_int64_t*)(ptr))
-#define as_s8(ptr) (*(int8_t*)(ptr))
-#define as_s16(ptr) (*(int16_t*)(ptr))
-#define as_s32(ptr) (*(int32_t*)(ptr))
-#define as_s64(ptr) (*(int64_t*)(ptr))
-
-#ifdef COPY_LABELS
-static void *copy_labels[4] = {
- &&copy_8,
- &&copy_16,
- &&copy_32,
- &&copy_64
-};
-#endif
-
-#ifdef COPY_END
-while(0) {
-copy_8: as_s8(dst) = as_s8(src); goto COPY_END;
-copy_16: as_s16(dst) = as_s16(src); goto COPY_END;
-copy_32: as_s32(dst) = as_s32(src); goto COPY_END;
-copy_64: as_s64(dst) = as_s64(src); goto COPY_END;
-}
-#endif
-
-#ifdef CONV_LABELS
-/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
-static void *conv_labels[4 * 2 * 2 * 4 * 2] = {
- &&conv_xxx1_xxx1, /* 8h -> 8h */
- &&conv_xxx1_xxx1, /* 8h -> 8s */
- &&conv_xxx1_xx10, /* 8h -> 16h */
- &&conv_xxx1_xx01, /* 8h -> 16s */
- &&conv_xxx1_x100, /* 8h -> 24h */
- &&conv_xxx1_001x, /* 8h -> 24s */
- &&conv_xxx1_1000, /* 8h -> 32h */
- &&conv_xxx1_0001, /* 8h -> 32s */
- &&conv_xxx1_xxx9, /* 8h ^> 8h */
- &&conv_xxx1_xxx9, /* 8h ^> 8s */
- &&conv_xxx1_xx90, /* 8h ^> 16h */
- &&conv_xxx1_xx09, /* 8h ^> 16s */
- &&conv_xxx1_x900, /* 8h ^> 24h */
- &&conv_xxx1_009x, /* 8h ^> 24s */
- &&conv_xxx1_9000, /* 8h ^> 32h */
- &&conv_xxx1_0009, /* 8h ^> 32s */
- &&conv_xxx1_xxx1, /* 8s -> 8h */
- &&conv_xxx1_xxx1, /* 8s -> 8s */
- &&conv_xxx1_xx10, /* 8s -> 16h */
- &&conv_xxx1_xx01, /* 8s -> 16s */
- &&conv_xxx1_x100, /* 8s -> 24h */
- &&conv_xxx1_001x, /* 8s -> 24s */
- &&conv_xxx1_1000, /* 8s -> 32h */
- &&conv_xxx1_0001, /* 8s -> 32s */
- &&conv_xxx1_xxx9, /* 8s ^> 8h */
- &&conv_xxx1_xxx9, /* 8s ^> 8s */
- &&conv_xxx1_xx90, /* 8s ^> 16h */
- &&conv_xxx1_xx09, /* 8s ^> 16s */
- &&conv_xxx1_x900, /* 8s ^> 24h */
- &&conv_xxx1_009x, /* 8s ^> 24s */
- &&conv_xxx1_9000, /* 8s ^> 32h */
- &&conv_xxx1_0009, /* 8s ^> 32s */
- &&conv_xx12_xxx1, /* 16h -> 8h */
- &&conv_xx12_xxx1, /* 16h -> 8s */
- &&conv_xx12_xx12, /* 16h -> 16h */
- &&conv_xx12_xx21, /* 16h -> 16s */
- &&conv_xx12_x120, /* 16h -> 24h */
- &&conv_xx12_021x, /* 16h -> 24s */
- &&conv_xx12_1200, /* 16h -> 32h */
- &&conv_xx12_0021, /* 16h -> 32s */
- &&conv_xx12_xxx9, /* 16h ^> 8h */
- &&conv_xx12_xxx9, /* 16h ^> 8s */
- &&conv_xx12_xx92, /* 16h ^> 16h */
- &&conv_xx12_xx29, /* 16h ^> 16s */
- &&conv_xx12_x920, /* 16h ^> 24h */
- &&conv_xx12_029x, /* 16h ^> 24s */
- &&conv_xx12_9200, /* 16h ^> 32h */
- &&conv_xx12_0029, /* 16h ^> 32s */
- &&conv_xx12_xxx2, /* 16s -> 8h */
- &&conv_xx12_xxx2, /* 16s -> 8s */
- &&conv_xx12_xx21, /* 16s -> 16h */
- &&conv_xx12_xx12, /* 16s -> 16s */
- &&conv_xx12_x210, /* 16s -> 24h */
- &&conv_xx12_012x, /* 16s -> 24s */
- &&conv_xx12_2100, /* 16s -> 32h */
- &&conv_xx12_0012, /* 16s -> 32s */
- &&conv_xx12_xxxA, /* 16s ^> 8h */
- &&conv_xx12_xxxA, /* 16s ^> 8s */
- &&conv_xx12_xxA1, /* 16s ^> 16h */
- &&conv_xx12_xx1A, /* 16s ^> 16s */
- &&conv_xx12_xA10, /* 16s ^> 24h */
- &&conv_xx12_01Ax, /* 16s ^> 24s */
- &&conv_xx12_A100, /* 16s ^> 32h */
- &&conv_xx12_001A, /* 16s ^> 32s */
- &&conv_x123_xxx1, /* 24h -> 8h */
- &&conv_x123_xxx1, /* 24h -> 8s */
- &&conv_x123_xx12, /* 24h -> 16h */
- &&conv_x123_xx21, /* 24h -> 16s */
- &&conv_x123_x123, /* 24h -> 24h */
- &&conv_x123_321x, /* 24h -> 24s */
- &&conv_x123_1230, /* 24h -> 32h */
- &&conv_x123_0321, /* 24h -> 32s */
- &&conv_x123_xxx9, /* 24h ^> 8h */
- &&conv_x123_xxx9, /* 24h ^> 8s */
- &&conv_x123_xx92, /* 24h ^> 16h */
- &&conv_x123_xx29, /* 24h ^> 16s */
- &&conv_x123_x923, /* 24h ^> 24h */
- &&conv_x123_329x, /* 24h ^> 24s */
- &&conv_x123_9230, /* 24h ^> 32h */
- &&conv_x123_0329, /* 24h ^> 32s */
- &&conv_123x_xxx3, /* 24s -> 8h */
- &&conv_123x_xxx3, /* 24s -> 8s */
- &&conv_123x_xx32, /* 24s -> 16h */
- &&conv_123x_xx23, /* 24s -> 16s */
- &&conv_123x_x321, /* 24s -> 24h */
- &&conv_123x_123x, /* 24s -> 24s */
- &&conv_123x_3210, /* 24s -> 32h */
- &&conv_123x_0123, /* 24s -> 32s */
- &&conv_123x_xxxB, /* 24s ^> 8h */
- &&conv_123x_xxxB, /* 24s ^> 8s */
- &&conv_123x_xxB2, /* 24s ^> 16h */
- &&conv_123x_xx2B, /* 24s ^> 16s */
- &&conv_123x_xB21, /* 24s ^> 24h */
- &&conv_123x_12Bx, /* 24s ^> 24s */
- &&conv_123x_B210, /* 24s ^> 32h */
- &&conv_123x_012B, /* 24s ^> 32s */
- &&conv_1234_xxx1, /* 32h -> 8h */
- &&conv_1234_xxx1, /* 32h -> 8s */
- &&conv_1234_xx12, /* 32h -> 16h */
- &&conv_1234_xx21, /* 32h -> 16s */
- &&conv_1234_x123, /* 32h -> 24h */
- &&conv_1234_321x, /* 32h -> 24s */
- &&conv_1234_1234, /* 32h -> 32h */
- &&conv_1234_4321, /* 32h -> 32s */
- &&conv_1234_xxx9, /* 32h ^> 8h */
- &&conv_1234_xxx9, /* 32h ^> 8s */
- &&conv_1234_xx92, /* 32h ^> 16h */
- &&conv_1234_xx29, /* 32h ^> 16s */
- &&conv_1234_x923, /* 32h ^> 24h */
- &&conv_1234_329x, /* 32h ^> 24s */
- &&conv_1234_9234, /* 32h ^> 32h */
- &&conv_1234_4329, /* 32h ^> 32s */
- &&conv_1234_xxx4, /* 32s -> 8h */
- &&conv_1234_xxx4, /* 32s -> 8s */
- &&conv_1234_xx43, /* 32s -> 16h */
- &&conv_1234_xx34, /* 32s -> 16s */
- &&conv_1234_x432, /* 32s -> 24h */
- &&conv_1234_234x, /* 32s -> 24s */
- &&conv_1234_4321, /* 32s -> 32h */
- &&conv_1234_1234, /* 32s -> 32s */
- &&conv_1234_xxxC, /* 32s ^> 8h */
- &&conv_1234_xxxC, /* 32s ^> 8s */
- &&conv_1234_xxC3, /* 32s ^> 16h */
- &&conv_1234_xx3C, /* 32s ^> 16s */
- &&conv_1234_xC32, /* 32s ^> 24h */
- &&conv_1234_23Cx, /* 32s ^> 24s */
- &&conv_1234_C321, /* 32s ^> 32h */
- &&conv_1234_123C, /* 32s ^> 32s */
-};
-#endif
-
-#ifdef CONV_END
-while(0) {
-conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END;
-conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END;
-conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END;
-conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END;
-conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END;
-conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END;
-conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END;
-conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END;
-conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
-conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END;
-conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END;
-conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
-conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END;
-conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END;
-conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END;
-conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END;
-conv_xx12_xx21: as_u16(dst) = swab16(as_u16(src)); goto CONV_END;
-conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
-conv_xx12_021x: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END;
-conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END;
-conv_xx12_0021: as_u32(dst) = (u_int32_t)swab16(as_u16(src)); goto CONV_END;
-conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END;
-conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END;
-conv_xx12_xx29: as_u16(dst) = swab16(as_u16(src)) ^ 0x80; goto CONV_END;
-conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END;
-conv_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80) << 8; goto CONV_END;
-conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END;
-conv_xx12_0029: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80); goto CONV_END;
-conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END;
-conv_xx12_x210: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END;
-conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
-conv_xx12_2100: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 16; goto CONV_END;
-conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END;
-conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END;
-conv_xx12_xxA1: as_u16(dst) = swab16(as_u16(src) ^ 0x80); goto CONV_END;
-conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END;
-conv_xx12_xA10: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 8; goto CONV_END;
-conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END;
-conv_xx12_A100: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto CONV_END;
-conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END;
-conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END;
-conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END;
-conv_x123_xx21: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END;
-conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END;
-conv_x123_321x: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
-conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
-conv_x123_0321: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END;
-conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END;
-conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END;
-conv_x123_xx29: as_u16(dst) = swab16(as_u32(src) >> 8) ^ 0x80; goto CONV_END;
-conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END;
-conv_x123_329x: as_u32(dst) = swab32(as_u32(src)) ^ 0x8000; goto CONV_END;
-conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END;
-conv_x123_0329: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END;
-conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END;
-conv_123x_xx32: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END;
-conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END;
-conv_123x_x321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
-conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END;
-conv_123x_3210: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END;
-conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
-conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END;
-conv_123x_xxB2: as_u16(dst) = swab16((as_u32(src) >> 8) ^ 0x80); goto CONV_END;
-conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END;
-conv_123x_xB21: as_u32(dst) = swab32(as_u32(src)) ^ 0x800000; goto CONV_END;
-conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END;
-conv_123x_B210: as_u32(dst) = swab32(as_u32(src) ^ 0x8000) << 8; goto CONV_END;
-conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END;
-conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END;
-conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END;
-conv_1234_xx21: as_u16(dst) = swab16(as_u32(src) >> 16); goto CONV_END;
-conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
-conv_1234_321x: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END;
-conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END;
-conv_1234_4321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
-conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END;
-conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END;
-conv_1234_xx29: as_u16(dst) = swab16(as_u32(src) >> 16) ^ 0x80; goto CONV_END;
-conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END;
-conv_1234_329x: as_u32(dst) = (swab32(as_u32(src)) ^ 0x80) << 8; goto CONV_END;
-conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END;
-conv_1234_4329: as_u32(dst) = swab32(as_u32(src)) ^ 0x80; goto CONV_END;
-conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END;
-conv_1234_xx43: as_u16(dst) = swab16(as_u32(src)); goto CONV_END;
-conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END;
-conv_1234_x432: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END;
-conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
-conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END;
-conv_1234_xxC3: as_u16(dst) = swab16(as_u32(src) ^ 0x80); goto CONV_END;
-conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END;
-conv_1234_xC32: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END;
-conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END;
-conv_1234_C321: as_u32(dst) = swab32(as_u32(src) ^ 0x80); goto CONV_END;
-conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END;
-}
-#endif
-
-#ifdef GET_S16_LABELS
-/* src_wid src_endswap unsigned */
-static void *get_s16_labels[4 * 2 * 2] = {
- &&get_s16_xxx1_xx10, /* 8h -> 16h */
- &&get_s16_xxx1_xx90, /* 8h ^> 16h */
- &&get_s16_xxx1_xx10, /* 8s -> 16h */
- &&get_s16_xxx1_xx90, /* 8s ^> 16h */
- &&get_s16_xx12_xx12, /* 16h -> 16h */
- &&get_s16_xx12_xx92, /* 16h ^> 16h */
- &&get_s16_xx12_xx21, /* 16s -> 16h */
- &&get_s16_xx12_xxA1, /* 16s ^> 16h */
- &&get_s16_x123_xx12, /* 24h -> 16h */
- &&get_s16_x123_xx92, /* 24h ^> 16h */
- &&get_s16_123x_xx32, /* 24s -> 16h */
- &&get_s16_123x_xxB2, /* 24s ^> 16h */
- &&get_s16_1234_xx12, /* 32h -> 16h */
- &&get_s16_1234_xx92, /* 32h ^> 16h */
- &&get_s16_1234_xx43, /* 32s -> 16h */
- &&get_s16_1234_xxC3, /* 32s ^> 16h */
-};
-#endif
-
-#ifdef GET_S16_END
-while(0) {
-get_s16_xxx1_xx10: sample = (u_int16_t)as_u8(src) << 8; goto GET_S16_END;
-get_s16_xxx1_xx90: sample = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto GET_S16_END;
-get_s16_xx12_xx12: sample = as_u16(src); goto GET_S16_END;
-get_s16_xx12_xx92: sample = as_u16(src) ^ 0x8000; goto GET_S16_END;
-get_s16_xx12_xx21: sample = swab16(as_u16(src)); goto GET_S16_END;
-get_s16_xx12_xxA1: sample = swab16(as_u16(src) ^ 0x80); goto GET_S16_END;
-get_s16_x123_xx12: sample = as_u32(src) >> 8; goto GET_S16_END;
-get_s16_x123_xx92: sample = (as_u32(src) >> 8) ^ 0x8000; goto GET_S16_END;
-get_s16_123x_xx32: sample = swab16(as_u32(src) >> 8); goto GET_S16_END;
-get_s16_123x_xxB2: sample = swab16((as_u32(src) >> 8) ^ 0x8000); goto GET_S16_END;
-get_s16_1234_xx12: sample = as_u32(src) >> 16; goto GET_S16_END;
-get_s16_1234_xx92: sample = (as_u32(src) >> 16) ^ 0x8000; goto GET_S16_END;
-get_s16_1234_xx43: sample = swab16(as_u32(src)); goto GET_S16_END;
-get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END;
-}
-#endif
-
-#ifdef PUT_S16_LABELS
-/* dst_wid dst_endswap unsigned */
-static void *put_s16_labels[4 * 2 * 2] = {
- &&put_s16_xx12_xxx1, /* 16h -> 8h */
- &&put_s16_xx12_xxx9, /* 16h ^> 8h */
- &&put_s16_xx12_xxx1, /* 16h -> 8s */
- &&put_s16_xx12_xxx9, /* 16h ^> 8s */
- &&put_s16_xx12_xx12, /* 16h -> 16h */
- &&put_s16_xx12_xx92, /* 16h ^> 16h */
- &&put_s16_xx12_xx21, /* 16h -> 16s */
- &&put_s16_xx12_xx29, /* 16h ^> 16s */
- &&put_s16_xx12_x120, /* 16h -> 24h */
- &&put_s16_xx12_x920, /* 16h ^> 24h */
- &&put_s16_xx12_021x, /* 16h -> 24s */
- &&put_s16_xx12_029x, /* 16h ^> 24s */
- &&put_s16_xx12_1200, /* 16h -> 32h */
- &&put_s16_xx12_9200, /* 16h ^> 32h */
- &&put_s16_xx12_0021, /* 16h -> 32s */
- &&put_s16_xx12_0029, /* 16h ^> 32s */
-};
-#endif
-
-#ifdef PUT_S16_END
-while (0) {
-put_s16_xx12_xxx1: as_u8(dst) = sample >> 8; goto PUT_S16_END;
-put_s16_xx12_xxx9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT_S16_END;
-put_s16_xx12_xx12: as_u16(dst) = sample; goto PUT_S16_END;
-put_s16_xx12_xx92: as_u16(dst) = sample ^ 0x8000; goto PUT_S16_END;
-put_s16_xx12_xx21: as_u16(dst) = swab16(sample); goto PUT_S16_END;
-put_s16_xx12_xx29: as_u16(dst) = swab16(sample) ^ 0x80; goto PUT_S16_END;
-put_s16_xx12_x120: as_u32(dst) = (u_int32_t)sample << 8; goto PUT_S16_END;
-put_s16_xx12_x920: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 8; goto PUT_S16_END;
-put_s16_xx12_021x: as_u32(dst) = (u_int32_t)swab16(sample) << 8; goto PUT_S16_END;
-put_s16_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(sample) ^ 0x80) << 8; goto PUT_S16_END;
-put_s16_xx12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT_S16_END;
-put_s16_xx12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT_S16_END;
-put_s16_xx12_0021: as_u32(dst) = (u_int32_t)swab16(sample); goto PUT_S16_END;
-put_s16_xx12_0029: as_u32(dst) = (u_int32_t)swab16(sample) ^ 0x80; goto PUT_S16_END;
-}
-#endif
-
-#if 0
-#ifdef GET32_LABELS
-/* src_wid src_endswap unsigned */
-static void *get32_labels[4 * 2 * 2] = {
- &&get32_xxx1_1000, /* 8h -> 32h */
- &&get32_xxx1_9000, /* 8h ^> 32h */
- &&get32_xxx1_1000, /* 8s -> 32h */
- &&get32_xxx1_9000, /* 8s ^> 32h */
- &&get32_xx12_1200, /* 16h -> 32h */
- &&get32_xx12_9200, /* 16h ^> 32h */
- &&get32_xx12_2100, /* 16s -> 32h */
- &&get32_xx12_A100, /* 16s ^> 32h */
- &&get32_x123_1230, /* 24h -> 32h */
- &&get32_x123_9230, /* 24h ^> 32h */
- &&get32_123x_3210, /* 24s -> 32h */
- &&get32_123x_B210, /* 24s ^> 32h */
- &&get32_1234_1234, /* 32h -> 32h */
- &&get32_1234_9234, /* 32h ^> 32h */
- &&get32_1234_4321, /* 32s -> 32h */
- &&get32_1234_C321, /* 32s ^> 32h */
-};
-#endif
-
-#ifdef GET32_END
-while (0) {
-get32_xxx1_1000: sample = (u_int32_t)as_u8(src) << 24; goto GET32_END;
-get32_xxx1_9000: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto GET32_END;
-get32_xx12_1200: sample = (u_int32_t)as_u16(src) << 16; goto GET32_END;
-get32_xx12_9200: sample = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto GET32_END;
-get32_xx12_2100: sample = (u_int32_t)swab16(as_u16(src)) << 16; goto GET32_END;
-get32_xx12_A100: sample = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto GET32_END;
-get32_x123_1230: sample = as_u32(src) << 8; goto GET32_END;
-get32_x123_9230: sample = (as_u32(src) << 8) ^ 0x80000000; goto GET32_END;
-get32_123x_3210: sample = swab32(as_u32(src) >> 8); goto GET32_END;
-get32_123x_B210: sample = swab32((as_u32(src) >> 8) ^ 0x80); goto GET32_END;
-get32_1234_1234: sample = as_u32(src); goto GET32_END;
-get32_1234_9234: sample = as_u32(src) ^ 0x80000000; goto GET32_END;
-get32_1234_4321: sample = swab32(as_u32(src)); goto GET32_END;
-get32_1234_C321: sample = swab32(as_u32(src) ^ 0x80); goto GET32_END;
-}
-#endif
-#endif
-
-#ifdef PUT_U32_LABELS
-/* dst_wid dst_endswap unsigned */
-static void *put_u32_labels[4 * 2 * 2] = {
- &&put_u32_1234_xxx9, /* u32h -> s8h */
- &&put_u32_1234_xxx1, /* u32h -> u8h */
- &&put_u32_1234_xxx9, /* u32h -> s8s */
- &&put_u32_1234_xxx1, /* u32h -> u8s */
- &&put_u32_1234_xx92, /* u32h -> s16h */
- &&put_u32_1234_xx12, /* u32h -> u16h */
- &&put_u32_1234_xx29, /* u32h -> s16s */
- &&put_u32_1234_xx21, /* u32h -> u16s */
- &&put_u32_1234_x923, /* u32h -> s24h */
- &&put_u32_1234_x123, /* u32h -> u24h */
- &&put_u32_1234_329x, /* u32h -> s24s */
- &&put_u32_1234_321x, /* u32h -> u24s */
- &&put_u32_1234_9234, /* u32h -> s32h */
- &&put_u32_1234_1234, /* u32h -> u32h */
- &&put_u32_1234_4329, /* u32h -> s32s */
- &&put_u32_1234_4321, /* u32h -> u32s */
-};
-#endif
-
-#ifdef PUT_U32_END
-while (0) {
-put_u32_1234_xxx1: as_u8(dst) = sample >> 24; goto PUT_U32_END;
-put_u32_1234_xxx9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_xx12: as_u16(dst) = sample >> 16; goto PUT_U32_END;
-put_u32_1234_xx92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT_U32_END;
-put_u32_1234_xx21: as_u16(dst) = swab16(sample >> 16); goto PUT_U32_END;
-put_u32_1234_xx29: as_u16(dst) = swab16(sample >> 16) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_x123: as_u32(dst) = sample >> 8; goto PUT_U32_END;
-put_u32_1234_x923: as_u32(dst) = (sample >> 8) ^ 0x800000; goto PUT_U32_END;
-put_u32_1234_321x: as_u32(dst) = swab32(sample) << 8; goto PUT_U32_END;
-put_u32_1234_329x: as_u32(dst) = (swab32(sample) ^ 0x80) << 8; goto PUT_U32_END;
-put_u32_1234_1234: as_u32(dst) = sample; goto PUT_U32_END;
-put_u32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_U32_END;
-put_u32_1234_4321: as_u32(dst) = swab32(sample); goto PUT_U32_END;
-put_u32_1234_4329: as_u32(dst) = swab32(sample) ^ 0x80; goto PUT_U32_END;
-}
-#endif
-
-#ifdef GET_U_LABELS
-/* width endswap unsigned*/
-static void *get_u_labels[4 * 2 * 2] = {
- &&get_u_s8, /* s8 -> u8 */
- &&get_u_u8, /* u8 -> u8 */
- &&get_u_s8, /* s8 -> u8 */
- &&get_u_u8, /* u8 -> u8 */
- &&get_u_s16h, /* s16h -> u16h */
- &&get_u_u16h, /* u16h -> u16h */
- &&get_u_s16s, /* s16s -> u16h */
- &&get_u_u16s, /* u16s -> u16h */
- &&get_u_s24h, /* s24h -> u32h */
- &&get_u_u24h, /* u24h -> u32h */
- &&get_u_s24s, /* s24s -> u32h */
- &&get_u_u24s, /* u24s -> u32h */
- &&get_u_s32h, /* s32h -> u32h */
- &&get_u_u32h, /* u32h -> u32h */
- &&get_u_s32s, /* s32s -> u32h */
- &&get_u_u32s, /* u32s -> u32h */
-};
-#endif
-
-#ifdef GET_U_END
-while (0) {
-get_u_s8: sample = as_u8(src) ^ 0x80; goto GET_U_END;
-get_u_u8: sample = as_u8(src); goto GET_U_END;
-get_u_s16h: sample = as_u16(src) ^ 0x8000; goto GET_U_END;
-get_u_u16h: sample = as_u16(src); goto GET_U_END;
-get_u_s16s: sample = swab16(as_u16(src) ^ 0x80); goto GET_U_END;
-get_u_u16s: sample = swab16(as_u16(src)); goto GET_U_END;
-get_u_s24h: sample = (as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24h: sample = as_u32(src); goto GET_U_END;
-get_u_s24s: sample = swab32(as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24s: sample = swab32(as_u32(src)); goto GET_U_END;
-get_u_s32h: sample = as_u32(src) ^ 0x80000000; goto GET_U_END;
-get_u_u32h: sample = as_u32(src); goto GET_U_END;
-get_u_s32s: sample = swab32(as_u32(src) ^ 0x80); goto GET_U_END;
-get_u_u32s: sample = swab32(as_u32(src)); goto GET_U_END;
-}
-#endif
-
-#if 0
-#ifdef PUT_LABELS
-/* width endswap unsigned */
-static void *put_labels[4 * 2 * 2] = {
- &&put_s8, /* s8 -> s8 */
- &&put_u8, /* u8 -> s8 */
- &&put_s8, /* s8 -> s8 */
- &&put_u8, /* u8 -> s8 */
- &&put_s16h, /* s16h -> s16h */
- &&put_u16h, /* u16h -> s16h */
- &&put_s16s, /* s16s -> s16h */
- &&put_u16s, /* u16s -> s16h */
- &&put_s24h, /* s24h -> s32h */
- &&put_u24h, /* u24h -> s32h */
- &&put_s24s, /* s24s -> s32h */
- &&put_u24s, /* u24s -> s32h */
- &&put_s32h, /* s32h -> s32h */
- &&put_u32h, /* u32h -> s32h */
- &&put_s32s, /* s32s -> s32h */
- &&put_u32s, /* u32s -> s32h */
-};
-#endif
-
-#ifdef PUT_END
-put_s8: as_s8(dst) = sample; goto PUT_END;
-put_u8: as_u8(dst) = sample ^ 0x80; goto PUT_END;
-put_s16h: as_s16(dst) = sample; goto PUT_END;
-put_u16h: as_u16(dst) = sample ^ 0x8000; goto PUT_END;
-put_s16s: as_s16(dst) = swab16(sample); goto PUT_END;
-put_u16s: as_u16(dst) = swab16(sample ^ 0x80); goto PUT_END;
-put_s24h: as_s24(dst) = sample & 0xffffff; goto PUT_END;
-put_u24h: as_u24(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s24s: as_s24(dst) = swab32(sample & 0xffffff); goto PUT_END;
-put_u24s: as_u24(dst) = swab32(sample ^ 0x80); goto PUT_END;
-put_s32h: as_s32(dst) = sample; goto PUT_END;
-put_u32h: as_u32(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s32s: as_s32(dst) = swab32(sample); goto PUT_END;
-put_u32s: as_u32(dst) = swab32(sample ^ 0x80); goto PUT_END;
-#endif
-#endif
-
-#undef as_u8
-#undef as_u16
-#undef as_u32
-#undef as_s8
-#undef as_s16
-#undef as_s32
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 1096ec18671..2fa9299a440 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -1,6 +1,6 @@
/*
* Rate conversion Plug-In
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
*
*
* This library is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -33,29 +32,28 @@
* Basic rate conversion plugin
*/
-typedef struct {
+struct rate_channel {
signed short last_S1;
signed short last_S2;
-} rate_channel_t;
+};
-typedef void (*rate_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+typedef void (*rate_f)(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
int src_frames, int dst_frames);
-typedef struct rate_private_data {
+struct rate_priv {
unsigned int pitch;
unsigned int pos;
rate_f func;
- int get, put;
snd_pcm_sframes_t old_src_frames, old_dst_frames;
- rate_channel_t channels[0];
-} rate_t;
+ struct rate_channel channels[0];
+};
-static void rate_init(snd_pcm_plugin_t *plugin)
+static void rate_init(struct snd_pcm_plugin *plugin)
{
unsigned int channel;
- rate_t *data = (rate_t *)plugin->extra_data;
+ struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
data->pos = 0;
for (channel = 0; channel < plugin->src_format.channels; channel++) {
data->channels[channel].last_S1 = 0;
@@ -63,29 +61,20 @@ static void rate_init(snd_pcm_plugin_t *plugin)
}
}
-static void resample_expand(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static void resample_expand(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
int src_frames, int dst_frames)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
- char *src, *dst;
+ signed short *src, *dst;
unsigned int channel;
int src_step, dst_step;
int src_frames1, dst_frames1;
- rate_t *data = (rate_t *)plugin->extra_data;
- rate_channel_t *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
- void *get = get_s16_labels[data->get];
- void *put = put_s16_labels[data->put];
- signed short sample = 0;
+ struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
+ struct rate_channel *rchannels = data->channels;
for (channel = 0; channel < plugin->src_format.channels; channel++) {
pos = data->pos;
@@ -98,10 +87,12 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
continue;
}
dst_channels[channel].enabled = 1;
- src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
+ src = (signed short *)src_channels[channel].area.addr +
+ src_channels[channel].area.first / 8 / 2;
+ dst = (signed short *)dst_channels[channel].area.addr +
+ dst_channels[channel].area.first / 8 / 2;
+ src_step = src_channels[channel].area.step / 8 / 2;
+ dst_step = dst_channels[channel].area.step / 8 / 2;
src_frames1 = src_frames;
dst_frames1 = dst_frames;
while (dst_frames1-- > 0) {
@@ -109,12 +100,7 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
pos &= R_MASK;
S1 = S2;
if (src_frames1-- > 0) {
- goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
- after_get:
- S2 = sample;
+ S2 = *src;
src += src_step;
}
}
@@ -123,12 +109,7 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
val = -32768;
else if (val > 32767)
val = 32767;
- sample = val;
- goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after_put:
+ *dst = val;
dst += dst_step;
pos += data->pitch;
}
@@ -139,29 +120,20 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
data->pos = pos;
}
-static void resample_shrink(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static void resample_shrink(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
int src_frames, int dst_frames)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
- char *src, *dst;
+ signed short *src, *dst;
unsigned int channel;
int src_step, dst_step;
int src_frames1, dst_frames1;
- rate_t *data = (rate_t *)plugin->extra_data;
- rate_channel_t *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
- void *get = get_s16_labels[data->get];
- void *put = put_s16_labels[data->put];
- signed short sample = 0;
+ struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
+ struct rate_channel *rchannels = data->channels;
for (channel = 0; channel < plugin->src_format.channels; ++channel) {
pos = data->pos;
@@ -174,21 +146,18 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
continue;
}
dst_channels[channel].enabled = 1;
- src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
+ src = (signed short *)src_channels[channel].area.addr +
+ src_channels[channel].area.first / 8 / 2;
+ dst = (signed short *)dst_channels[channel].area.addr +
+ dst_channels[channel].area.first / 8 / 2;
+ src_step = src_channels[channel].area.step / 8 / 2;
+ dst_step = dst_channels[channel].area.step / 8 / 2;
src_frames1 = src_frames;
dst_frames1 = dst_frames;
while (dst_frames1 > 0) {
S1 = S2;
if (src_frames1-- > 0) {
- goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
- after_get:
- S2 = sample;
+ S2 = *src;
src += src_step;
}
if (pos & ~R_MASK) {
@@ -198,12 +167,7 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
val = -32768;
else if (val > 32767)
val = 32767;
- sample = val;
- goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after_put:
+ *dst = val;
dst += dst_step;
dst_frames1--;
}
@@ -216,15 +180,16 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
data->pos = pos;
}
-static snd_pcm_sframes_t rate_src_frames(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
{
- rate_t *data;
+ struct rate_priv *data;
snd_pcm_sframes_t res;
- snd_assert(plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin))
+ return -ENXIO;
if (frames == 0)
return 0;
- data = (rate_t *)plugin->extra_data;
+ data = (struct rate_priv *)plugin->extra_data;
if (plugin->src_format.rate < plugin->dst_format.rate) {
res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
} else {
@@ -248,15 +213,16 @@ static snd_pcm_sframes_t rate_src_frames(snd_pcm_plugin_t *plugin, snd_pcm_ufram
return res;
}
-static snd_pcm_sframes_t rate_dst_frames(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
{
- rate_t *data;
+ struct rate_priv *data;
snd_pcm_sframes_t res;
- snd_assert(plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin))
+ return -ENXIO;
if (frames == 0)
return 0;
- data = (rate_t *)plugin->extra_data;
+ data = (struct rate_priv *)plugin->extra_data;
if (plugin->src_format.rate < plugin->dst_format.rate) {
res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
} else {
@@ -280,27 +246,28 @@ static snd_pcm_sframes_t rate_dst_frames(snd_pcm_plugin_t *plugin, snd_pcm_ufram
return res;
}
-static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
+static snd_pcm_sframes_t rate_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
snd_pcm_uframes_t frames)
{
snd_pcm_uframes_t dst_frames;
- rate_t *data;
+ struct rate_priv *data;
- snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+ return -ENXIO;
if (frames == 0)
return 0;
#ifdef CONFIG_SND_DEBUG
{
unsigned int channel;
for (channel = 0; channel < plugin->src_format.channels; channel++) {
- snd_assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0,
- return -ENXIO);
- snd_assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0,
- return -ENXIO);
+ if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
+ src_channels[channel].area.step % 8))
+ return -ENXIO;
+ if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
+ dst_channels[channel].area.step % 8))
+ return -ENXIO;
}
}
#endif
@@ -308,16 +275,17 @@ static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin,
dst_frames = rate_dst_frames(plugin, frames);
if (dst_frames > dst_channels[0].frames)
dst_frames = dst_channels[0].frames;
- data = (rate_t *)plugin->extra_data;
+ data = (struct rate_priv *)plugin->extra_data;
data->func(plugin, src_channels, dst_channels, frames, dst_frames);
return dst_frames;
}
-static int rate_action(snd_pcm_plugin_t *plugin,
- snd_pcm_plugin_action_t action,
- unsigned long udata ATTRIBUTE_UNUSED)
+static int rate_action(struct snd_pcm_plugin *plugin,
+ enum snd_pcm_plugin_action action,
+ unsigned long udata)
{
- snd_assert(plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin))
+ return -ENXIO;
switch (action) {
case INIT:
case PREPARE:
@@ -329,36 +297,38 @@ static int rate_action(snd_pcm_plugin_t *plugin,
return 0; /* silenty ignore other actions */
}
-int snd_pcm_plugin_build_rate(snd_pcm_plug_t *plug,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin)
{
int err;
- rate_t *data;
- snd_pcm_plugin_t *plugin;
+ struct rate_priv *data;
+ struct snd_pcm_plugin *plugin;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
- snd_assert(src_format->channels > 0, return -ENXIO);
- snd_assert(snd_pcm_format_linear(src_format->format) != 0, return -ENXIO);
- snd_assert(snd_pcm_format_linear(dst_format->format) != 0, return -ENXIO);
- snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
+ if (snd_BUG_ON(src_format->channels != dst_format->channels))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->channels <= 0))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->format != SNDRV_PCM_FORMAT_S16))
+ return -ENXIO;
+ if (snd_BUG_ON(dst_format->format != SNDRV_PCM_FORMAT_S16))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->rate == dst_format->rate))
+ return -ENXIO;
err = snd_pcm_plugin_build(plug, "rate conversion",
src_format, dst_format,
- sizeof(rate_t) + src_format->channels * sizeof(rate_channel_t),
+ sizeof(struct rate_priv) +
+ src_format->channels * sizeof(struct rate_channel),
&plugin);
if (err < 0)
return err;
- data = (rate_t *)plugin->extra_data;
- data->get = getput_index(src_format->format);
- snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
- data->put = getput_index(dst_format->format);
- snd_assert(data->put >= 0 && data->put < 4*2*2, return -EINVAL);
-
+ data = (struct rate_priv *)plugin->extra_data;
if (src_format->rate < dst_format->rate) {
data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
data->func = resample_expand;
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index c955b7dfdb3..c8171f5783c 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -1,5 +1,5 @@
/*
- * Attenuated route Plug-In
+ * Route Plug-In
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
@@ -19,501 +19,91 @@
*
*/
-#include <sound/driver.h>
-#include <linux/slab.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "pcm_plugin.h"
-/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
-#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
-#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
-#elif ROUTE_PLUGIN_RESOLUTION == 16
-#define div(a) a >>= 4
-#else
-#error "Add some code here"
-#endif
-
-typedef struct ttable_dst ttable_dst_t;
-typedef struct route_private_data route_t;
-
-typedef void (*route_channel_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, snd_pcm_uframes_t frames);
-
-typedef struct {
- int channel;
- int as_int;
-} ttable_src_t;
-
-struct ttable_dst {
- int att; /* Attenuated */
- unsigned int nsrcs;
- ttable_src_t* srcs;
- route_channel_f func;
-};
-
-struct route_private_data {
- enum {R_UINT32=0, R_UINT64=1} sum_type;
- int get, put;
- int conv;
- int src_sample_size;
- ttable_dst_t ttable[0];
-};
-
-typedef union {
- u_int32_t as_uint32;
- u_int64_t as_uint64;
-} sum_t;
-
-
-static void route_to_channel_from_zero(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames)
+static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
+ snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
- if (dst_channel->wanted)
- snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format);
- dst_channel->enabled = 0;
-}
-
-static void route_to_channel_from_one(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, snd_pcm_uframes_t frames)
-{
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
- route_t *data = (route_t *)plugin->extra_data;
- void *conv;
- const snd_pcm_plugin_channel_t *src_channel = NULL;
- unsigned int srcidx;
- char *src, *dst;
- int src_step, dst_step;
- for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
- src_channel = &src_channels[ttable->srcs[srcidx].channel];
- if (src_channel->area.addr != NULL)
- break;
- }
- if (srcidx == ttable->nsrcs) {
- route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
- return;
- }
-
- dst_channel->enabled = 1;
- conv = conv_labels[data->conv];
- src = src_channel->area.addr + src_channel->area.first / 8;
- src_step = src_channel->area.step / 8;
- dst = dst_channel->area.addr + dst_channel->area.first / 8;
- dst_step = dst_channel->area.step / 8;
- while (frames-- > 0) {
- goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
- after:
- src += src_step;
- dst += dst_step;
+ int dst = 0;
+ for (; dst < ndsts; ++dst) {
+ if (dvp->wanted)
+ snd_pcm_area_silence(&dvp->area, 0, frames, format);
+ dvp->enabled = 0;
+ dvp++;
}
}
-static void route_to_channel(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, snd_pcm_uframes_t frames)
+static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
+ struct snd_pcm_plugin_channel *dst_channel,
+ snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
-#define GET_U_LABELS
-#define PUT_U32_LABELS
-#include "plugin_ops.h"
-#undef GET_U_LABELS
-#undef PUT_U32_LABELS
- static void *zero_labels[2] = { &&zero_int32, &&zero_int64 };
- /* sum_type att */
- static void *add_labels[2 * 2] = { &&add_int32_noatt, &&add_int32_att,
- &&add_int64_noatt, &&add_int64_att,
- };
- /* sum_type att shift */
- static void *norm_labels[2 * 2 * 4] = { NULL,
- &&norm_int32_8_noatt,
- &&norm_int32_16_noatt,
- &&norm_int32_24_noatt,
- NULL,
- &&norm_int32_8_att,
- &&norm_int32_16_att,
- &&norm_int32_24_att,
- &&norm_int64_0_noatt,
- &&norm_int64_8_noatt,
- &&norm_int64_16_noatt,
- &&norm_int64_24_noatt,
- &&norm_int64_0_att,
- &&norm_int64_8_att,
- &&norm_int64_16_att,
- &&norm_int64_24_att,
- };
- route_t *data = (route_t *)plugin->extra_data;
- void *zero, *get, *add, *norm, *put_u32;
- int nsrcs = ttable->nsrcs;
- char *dst;
- int dst_step;
- char *srcs[nsrcs];
- int src_steps[nsrcs];
- ttable_src_t src_tt[nsrcs];
- u_int32_t sample = 0;
- int srcidx, srcidx1 = 0;
- for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
- const snd_pcm_plugin_channel_t *src_channel = &src_channels[ttable->srcs[srcidx].channel];
- if (!src_channel->enabled)
- continue;
- srcs[srcidx1] = src_channel->area.addr + src_channel->area.first / 8;
- src_steps[srcidx1] = src_channel->area.step / 8;
- src_tt[srcidx1] = ttable->srcs[srcidx];
- srcidx1++;
- }
- nsrcs = srcidx1;
- if (nsrcs == 0) {
- route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
- return;
- } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
- route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames);
- return;
- }
-
dst_channel->enabled = 1;
- zero = zero_labels[data->sum_type];
- get = get_u_labels[data->get];
- add = add_labels[data->sum_type * 2 + ttable->att];
- norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
- put_u32 = put_u32_labels[data->put];
- dst = dst_channel->area.addr + dst_channel->area.first / 8;
- dst_step = dst_channel->area.step / 8;
-
- while (frames-- > 0) {
- ttable_src_t *ttp = src_tt;
- sum_t sum;
-
- /* Zero sum */
- goto *zero;
- zero_int32:
- sum.as_uint32 = 0;
- goto zero_end;
- zero_int64:
- sum.as_uint64 = 0;
- goto zero_end;
- zero_end:
- for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
- char *src = srcs[srcidx];
-
- /* Get sample */
- goto *get;
-#define GET_U_END after_get
-#include "plugin_ops.h"
-#undef GET_U_END
- after_get:
-
- /* Sum */
- goto *add;
- add_int32_att:
- sum.as_uint32 += sample * ttp->as_int;
- goto after_sum;
- add_int32_noatt:
- if (ttp->as_int)
- sum.as_uint32 += sample;
- goto after_sum;
- add_int64_att:
- sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
- goto after_sum;
- add_int64_noatt:
- if (ttp->as_int)
- sum.as_uint64 += sample;
- goto after_sum;
- after_sum:
- srcs[srcidx] += src_steps[srcidx];
- ttp++;
- }
-
- /* Normalization */
- goto *norm;
- norm_int32_8_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_8_att:
- sum.as_uint64 <<= 8;
- norm_int64_0_att:
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_16_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_16_att:
- sum.as_uint64 <<= 16;
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_24_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_24_att:
- sum.as_uint64 <<= 24;
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_8_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_8_noatt:
- sum.as_uint64 <<= 8;
- goto norm_int;
-
- norm_int32_16_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_16_noatt:
- sum.as_uint64 <<= 16;
- goto norm_int;
-
- norm_int32_24_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_24_noatt:
- sum.as_uint64 <<= 24;
- goto norm_int;
-
- norm_int64_0_noatt:
- norm_int:
- if (sum.as_uint64 > (u_int32_t)0xffffffff)
- sample = (u_int32_t)0xffffffff;
- else
- sample = sum.as_uint64;
- goto after_norm;
-
- after_norm:
-
- /* Put sample */
- goto *put_u32;
-#define PUT_U32_END after_put_u32
-#include "plugin_ops.h"
-#undef PUT_U32_END
- after_put_u32:
-
- dst += dst_step;
- }
+ snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
}
-static int route_src_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask)
+static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
+ const struct snd_pcm_plugin_channel *src_channels,
+ struct snd_pcm_plugin_channel *dst_channels,
+ snd_pcm_uframes_t frames)
{
- route_t *data = (route_t *)plugin->extra_data;
- int schannels = plugin->src_format.channels;
- int dchannels = plugin->dst_format.channels;
- bitset_t *vmask = plugin->src_vmask;
- int channel;
- ttable_dst_t *dp = data->ttable;
- bitset_zero(vmask, schannels);
- for (channel = 0; channel < dchannels; channel++, dp++) {
- unsigned int src;
- ttable_src_t *sp;
- if (!bitset_get(dst_vmask, channel))
- continue;
- sp = dp->srcs;
- for (src = 0; src < dp->nsrcs; src++, sp++)
- bitset_set(vmask, sp->channel);
- }
- *src_vmask = vmask;
- return 0;
-}
-
-static int route_dst_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask)
-{
- route_t *data = (route_t *)plugin->extra_data;
- int dchannels = plugin->dst_format.channels;
- bitset_t *vmask = plugin->dst_vmask;
- int channel;
- ttable_dst_t *dp = data->ttable;
- bitset_zero(vmask, dchannels);
- for (channel = 0; channel < dchannels; channel++, dp++) {
- unsigned int src;
- ttable_src_t *sp;
- sp = dp->srcs;
- for (src = 0; src < dp->nsrcs; src++, sp++) {
- if (bitset_get(src_vmask, sp->channel)) {
- bitset_set(vmask, channel);
- break;
- }
- }
- }
- *dst_vmask = vmask;
- return 0;
-}
-
-static void route_free(snd_pcm_plugin_t *plugin)
-{
- route_t *data = (route_t *)plugin->extra_data;
- unsigned int dst_channel;
- for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
- kfree(data->ttable[dst_channel].srcs);
- }
-}
-
-static int route_load_ttable(snd_pcm_plugin_t *plugin,
- const route_ttable_entry_t* src_ttable)
-{
- route_t *data;
- unsigned int src_channel, dst_channel;
- const route_ttable_entry_t *sptr;
- ttable_dst_t *dptr;
- if (src_ttable == NULL)
- return 0;
- data = (route_t *)plugin->extra_data;
- dptr = data->ttable;
- sptr = src_ttable;
- plugin->private_free = route_free;
- for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
- route_ttable_entry_t t = 0;
- int att = 0;
- int nsrcs = 0;
- ttable_src_t srcs[plugin->src_format.channels];
- for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) {
- snd_assert(*sptr >= 0 || *sptr <= FULL, return -ENXIO);
- if (*sptr != 0) {
- srcs[nsrcs].channel = src_channel;
- srcs[nsrcs].as_int = *sptr;
- if (*sptr != FULL)
- att = 1;
- t += *sptr;
- nsrcs++;
- }
- sptr++;
- }
- dptr->att = att;
- dptr->nsrcs = nsrcs;
- if (nsrcs == 0)
- dptr->func = route_to_channel_from_zero;
- else if (nsrcs == 1 && !att)
- dptr->func = route_to_channel_from_one;
- else
- dptr->func = route_to_channel;
- if (nsrcs > 0) {
- int srcidx;
- dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL);
- for(srcidx = 0; srcidx < nsrcs; srcidx++)
- dptr->srcs[srcidx] = srcs[srcidx];
- } else
- dptr->srcs = NULL;
- dptr++;
- }
- return 0;
-}
-
-static snd_pcm_sframes_t route_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- snd_pcm_uframes_t frames)
-{
- route_t *data;
- int src_nchannels, dst_nchannels;
- int dst_channel;
- ttable_dst_t *ttp;
- snd_pcm_plugin_channel_t *dvp;
+ int nsrcs, ndsts, dst;
+ struct snd_pcm_plugin_channel *dvp;
+ snd_pcm_format_t format;
- snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+ if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
+ return -ENXIO;
if (frames == 0)
return 0;
- data = (route_t *)plugin->extra_data;
- src_nchannels = plugin->src_format.channels;
- dst_nchannels = plugin->dst_format.channels;
+ nsrcs = plugin->src_format.channels;
+ ndsts = plugin->dst_format.channels;
-#ifdef CONFIG_SND_DEBUG
- {
- int src_channel;
- for (src_channel = 0; src_channel < src_nchannels; ++src_channel) {
- snd_assert(src_channels[src_channel].area.first % 8 == 0 ||
- src_channels[src_channel].area.step % 8 == 0,
- return -ENXIO);
- }
- for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
- snd_assert(dst_channels[dst_channel].area.first % 8 == 0 ||
- dst_channels[dst_channel].area.step % 8 == 0,
- return -ENXIO);
+ format = plugin->dst_format.format;
+ dvp = dst_channels;
+ if (nsrcs <= 1) {
+ /* expand to all channels */
+ for (dst = 0; dst < ndsts; ++dst) {
+ copy_area(src_channels, dvp, frames, format);
+ dvp++;
}
+ return frames;
}
-#endif
- ttp = data->ttable;
- dvp = dst_channels;
- for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
- ttp->func(plugin, src_channels, dvp, ttp, frames);
+ for (dst = 0; dst < ndsts && dst < nsrcs; ++dst) {
+ copy_area(src_channels, dvp, frames, format);
dvp++;
- ttp++;
+ src_channels++;
}
+ if (dst < ndsts)
+ zero_areas(dvp, ndsts - dst, frames, format);
return frames;
}
-int getput_index(int format)
-{
- int sign, width, endian;
- sign = !snd_pcm_format_signed(format);
- width = snd_pcm_format_width(format) / 8 - 1;
- if (width < 0 || width > 3) {
- snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
- width = 0;
- }
-#ifdef SNDRV_LITTLE_ENDIAN
- endian = snd_pcm_format_big_endian(format);
-#else
- endian = snd_pcm_format_little_endian(format);
-#endif
- if (endian < 0)
- endian = 0;
- return width * 4 + endian * 2 + sign;
-}
-
-int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
- snd_pcm_plugin_format_t *src_format,
- snd_pcm_plugin_format_t *dst_format,
- route_ttable_entry_t *ttable,
- snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug,
+ struct snd_pcm_plugin_format *src_format,
+ struct snd_pcm_plugin_format *dst_format,
+ struct snd_pcm_plugin **r_plugin)
{
- route_t *data;
- snd_pcm_plugin_t *plugin;
+ struct snd_pcm_plugin *plugin;
int err;
- snd_assert(r_plugin != NULL, return -ENXIO);
+ if (snd_BUG_ON(!r_plugin))
+ return -ENXIO;
*r_plugin = NULL;
- snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
- snd_assert(snd_pcm_format_linear(src_format->format) != 0 &&
- snd_pcm_format_linear(dst_format->format) != 0,
- return -ENXIO);
+ if (snd_BUG_ON(src_format->rate != dst_format->rate))
+ return -ENXIO;
+ if (snd_BUG_ON(src_format->format != dst_format->format))
+ return -ENXIO;
- err = snd_pcm_plugin_build(plug, "attenuated route conversion",
- src_format, dst_format,
- sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->channels,
- &plugin);
+ err = snd_pcm_plugin_build(plug, "route conversion",
+ src_format, dst_format, 0, &plugin);
if (err < 0)
return err;
- data = (route_t *) plugin->extra_data;
-
- data->get = getput_index(src_format->format);
- snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
- data->put = getput_index(dst_format->format);
- snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
- data->conv = conv_index(src_format->format, dst_format->format);
-
- if (snd_pcm_format_width(src_format->format) == 32)
- data->sum_type = R_UINT64;
- else
- data->sum_type = R_UINT32;
- data->src_sample_size = snd_pcm_format_width(src_format->format) / 8;
-
- if ((err = route_load_ttable(plugin, ttable)) < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
plugin->transfer = route_transfer;
- plugin->src_channels_mask = route_src_channels_mask;
- plugin->dst_channels_mask = route_dst_channels_mask;
*r_plugin = plugin;
return 0;
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 1be470e942e..43932e8dce6 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,37 +19,81 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/info.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
MODULE_LICENSE("GPL");
-snd_pcm_t *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES];
+static LIST_HEAD(snd_pcm_devices);
static LIST_HEAD(snd_pcm_notify_list);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
-static int snd_pcm_free(snd_pcm_t *pcm);
-static int snd_pcm_dev_free(snd_device_t *device);
-static int snd_pcm_dev_register(snd_device_t *device);
-static int snd_pcm_dev_disconnect(snd_device_t *device);
-static int snd_pcm_dev_unregister(snd_device_t *device);
+static int snd_pcm_free(struct snd_pcm *pcm);
+static int snd_pcm_dev_free(struct snd_device *device);
+static int snd_pcm_dev_register(struct snd_device *device);
+static int snd_pcm_dev_disconnect(struct snd_device *device);
-static int snd_pcm_control_ioctl(snd_card_t * card,
- snd_ctl_file_t * control,
- unsigned int cmd, unsigned long arg)
+static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
+{
+ struct snd_pcm *pcm;
+
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ if (pcm->internal)
+ continue;
+ if (pcm->card == card && pcm->device == device)
+ return pcm;
+ }
+ return NULL;
+}
+
+static int snd_pcm_next(struct snd_card *card, int device)
+{
+ struct snd_pcm *pcm;
+
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ if (pcm->internal)
+ continue;
+ if (pcm->card == card && pcm->device > device)
+ return pcm->device;
+ else if (pcm->card->number > card->number)
+ return -1;
+ }
+ return -1;
+}
+
+static int snd_pcm_add(struct snd_pcm *newpcm)
{
- unsigned int tmp;
+ struct snd_pcm *pcm;
+
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ if (pcm->card == newpcm->card && pcm->device == newpcm->device)
+ return -EBUSY;
+ if (pcm->card->number > newpcm->card->number ||
+ (pcm->card == newpcm->card &&
+ pcm->device > newpcm->device)) {
+ list_add(&newpcm->list, pcm->list.prev);
+ return 0;
+ }
+ }
+ list_add_tail(&newpcm->list, &snd_pcm_devices);
+ return 0;
+}
- tmp = card->number * SNDRV_PCM_DEVICES;
+static int snd_pcm_control_ioctl(struct snd_card *card,
+ struct snd_ctl_file *control,
+ unsigned int cmd, unsigned long arg)
+{
switch (cmd) {
case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
{
@@ -57,51 +101,59 @@ static int snd_pcm_control_ioctl(snd_card_t * card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
- device = device < 0 ? 0 : device + 1;
- while (device < SNDRV_PCM_DEVICES) {
- if (snd_pcm_devices[tmp + device])
- break;
- device++;
- }
- if (device == SNDRV_PCM_DEVICES)
- device = -1;
+ mutex_lock(&register_mutex);
+ device = snd_pcm_next(card, device);
+ mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
}
case SNDRV_CTL_IOCTL_PCM_INFO:
{
- snd_pcm_info_t __user *info;
+ struct snd_pcm_info __user *info;
unsigned int device, subdevice;
- snd_pcm_stream_t stream;
- snd_pcm_t *pcm;
- snd_pcm_str_t *pstr;
- snd_pcm_substream_t *substream;
- info = (snd_pcm_info_t __user *)arg;
+ int stream;
+ struct snd_pcm *pcm;
+ struct snd_pcm_str *pstr;
+ struct snd_pcm_substream *substream;
+ int err;
+
+ info = (struct snd_pcm_info __user *)arg;
if (get_user(device, &info->device))
return -EFAULT;
- if (device >= SNDRV_PCM_DEVICES)
- return -ENXIO;
- pcm = snd_pcm_devices[tmp + device];
- if (pcm == NULL)
- return -ENXIO;
if (get_user(stream, &info->stream))
return -EFAULT;
if (stream < 0 || stream > 1)
return -EINVAL;
- pstr = &pcm->streams[stream];
- if (pstr->substream_count == 0)
- return -ENOENT;
if (get_user(subdevice, &info->subdevice))
return -EFAULT;
- if (subdevice >= pstr->substream_count)
- return -ENXIO;
- for (substream = pstr->substream; substream; substream = substream->next)
+ mutex_lock(&register_mutex);
+ pcm = snd_pcm_get(card, device);
+ if (pcm == NULL) {
+ err = -ENXIO;
+ goto _error;
+ }
+ pstr = &pcm->streams[stream];
+ if (pstr->substream_count == 0) {
+ err = -ENOENT;
+ goto _error;
+ }
+ if (subdevice >= pstr->substream_count) {
+ err = -ENXIO;
+ goto _error;
+ }
+ for (substream = pstr->substream; substream;
+ substream = substream->next)
if (substream->number == (int)subdevice)
break;
- if (substream == NULL)
- return -ENXIO;
- return snd_pcm_info_user(substream, info);
+ if (substream == NULL) {
+ err = -ENXIO;
+ goto _error;
+ }
+ err = snd_pcm_info_user(substream, info);
+ _error:
+ mutex_unlock(&register_mutex);
+ return err;
}
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
{
@@ -115,40 +167,8 @@ static int snd_pcm_control_ioctl(snd_card_t * card,
}
return -ENOIOCTLCMD;
}
-#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
-#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
-#define READY(v) [SNDRV_PCM_READY_##v] = #v
-#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
-#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
-#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
-#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
-#define START(v) [SNDRV_PCM_START_##v] = #v
-#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
-#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
-
-static char *snd_pcm_stream_names[] = {
- STREAM(PLAYBACK),
- STREAM(CAPTURE),
-};
-
-static char *snd_pcm_state_names[] = {
- STATE(OPEN),
- STATE(SETUP),
- STATE(PREPARED),
- STATE(RUNNING),
- STATE(XRUN),
- STATE(DRAINING),
- STATE(PAUSED),
- STATE(SUSPENDED),
-};
-static char *snd_pcm_access_names[] = {
- ACCESS(MMAP_INTERLEAVED),
- ACCESS(MMAP_NONINTERLEAVED),
- ACCESS(MMAP_COMPLEX),
- ACCESS(RW_INTERLEAVED),
- ACCESS(RW_NONINTERLEAVED),
-};
+#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
static char *snd_pcm_format_names[] = {
FORMAT(S8),
@@ -189,6 +209,56 @@ static char *snd_pcm_format_names[] = {
FORMAT(S18_3BE),
FORMAT(U18_3LE),
FORMAT(U18_3BE),
+ FORMAT(G723_24),
+ FORMAT(G723_24_1B),
+ FORMAT(G723_40),
+ FORMAT(G723_40_1B),
+ FORMAT(DSD_U8),
+ FORMAT(DSD_U16_LE),
+};
+
+const char *snd_pcm_format_name(snd_pcm_format_t format)
+{
+ if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
+ return "Unknown";
+ return snd_pcm_format_names[(__force unsigned int)format];
+}
+EXPORT_SYMBOL_GPL(snd_pcm_format_name);
+
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+
+#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
+#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
+#define READY(v) [SNDRV_PCM_READY_##v] = #v
+#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
+#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
+#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
+#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
+#define START(v) [SNDRV_PCM_START_##v] = #v
+#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
+
+static char *snd_pcm_stream_names[] = {
+ STREAM(PLAYBACK),
+ STREAM(CAPTURE),
+};
+
+static char *snd_pcm_state_names[] = {
+ STATE(OPEN),
+ STATE(SETUP),
+ STATE(PREPARED),
+ STATE(RUNNING),
+ STATE(XRUN),
+ STATE(DRAINING),
+ STATE(PAUSED),
+ STATE(SUSPENDED),
+};
+
+static char *snd_pcm_access_names[] = {
+ ACCESS(MMAP_INTERLEAVED),
+ ACCESS(MMAP_NONINTERLEAVED),
+ ACCESS(MMAP_COMPLEX),
+ ACCESS(RW_INTERLEAVED),
+ ACCESS(RW_NONINTERLEAVED),
};
static char *snd_pcm_subformat_names[] = {
@@ -197,47 +267,37 @@ static char *snd_pcm_subformat_names[] = {
static char *snd_pcm_tstamp_mode_names[] = {
TSTAMP(NONE),
- TSTAMP(MMAP),
+ TSTAMP(ENABLE),
};
-static const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
+static const char *snd_pcm_stream_name(int stream)
{
- snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL);
return snd_pcm_stream_names[stream];
}
static const char *snd_pcm_access_name(snd_pcm_access_t access)
{
- snd_assert(access <= SNDRV_PCM_ACCESS_LAST, return NULL);
- return snd_pcm_access_names[access];
-}
-
-const char *snd_pcm_format_name(snd_pcm_format_t format)
-{
- snd_assert(format <= SNDRV_PCM_FORMAT_LAST, return NULL);
- return snd_pcm_format_names[format];
+ return snd_pcm_access_names[(__force int)access];
}
static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
{
- snd_assert(subformat <= SNDRV_PCM_SUBFORMAT_LAST, return NULL);
- return snd_pcm_subformat_names[subformat];
+ return snd_pcm_subformat_names[(__force int)subformat];
}
-static const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode)
+static const char *snd_pcm_tstamp_mode_name(int mode)
{
- snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL);
return snd_pcm_tstamp_mode_names[mode];
}
static const char *snd_pcm_state_name(snd_pcm_state_t state)
{
- snd_assert(state <= SNDRV_PCM_STATE_LAST, return NULL);
- return snd_pcm_state_names[state];
+ return snd_pcm_state_names[(__force int)state];
}
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#include <linux/soundcard.h>
+
static const char *snd_pcm_oss_format_name(int format)
{
switch (format) {
@@ -267,17 +327,19 @@ static const char *snd_pcm_oss_format_name(int format)
}
#endif
-#ifdef CONFIG_PROC_FS
-static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buffer_t *buffer)
+static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_info_t *info;
+ struct snd_pcm_info *info;
int err;
- snd_runtime_check(substream, return);
+ if (! substream)
+ return;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (! info) {
- printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n");
+ pcm_dbg(substream->pcm,
+ "snd_pcm_proc_info_read: cannot malloc\n");
return;
}
@@ -301,29 +363,34 @@ static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buff
kfree(info);
}
-static void snd_pcm_stream_proc_info_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_proc_info_read(((snd_pcm_str_t *)entry->private_data)->substream, buffer);
+ snd_pcm_proc_info_read(((struct snd_pcm_str *)entry->private_data)->substream,
+ buffer);
}
-static void snd_pcm_substream_proc_info_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_proc_info_read((snd_pcm_substream_t *)entry->private_data, buffer);
+ snd_pcm_proc_info_read(entry->private_data, buffer);
}
-static void snd_pcm_substream_proc_hw_params_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_pcm_runtime *runtime;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
- snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- snd_pcm_stream_unlock_irq(substream);
- return;
+ goto unlock;
}
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@@ -332,8 +399,7 @@ static void snd_pcm_substream_proc_hw_params_read(snd_info_entry_t *entry, snd_i
snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den);
snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);
snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);
- snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
if (substream->oss.oss) {
snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);
@@ -343,53 +409,60 @@ static void snd_pcm_substream_proc_hw_params_read(snd_info_entry_t *entry, snd_i
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
- snd_pcm_stream_unlock_irq(substream);
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
-static void snd_pcm_substream_proc_sw_params_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_pcm_runtime *runtime;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
- snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- snd_pcm_stream_unlock_irq(substream);
- return;
+ goto unlock;
}
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
- snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min);
snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
- snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align);
snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
- snd_pcm_stream_unlock_irq(substream);
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
-static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_status_t status;
+ struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_status status;
int err;
+
+ mutex_lock(&substream->pcm->open_mutex);
+ runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- return;
+ goto unlock;
}
memset(&status, 0, sizeof(status));
err = snd_pcm_status(substream, &status);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
- return;
+ goto unlock;
}
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
+ snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
snd_iprintf(buffer, "tstamp : %ld.%09ld\n",
@@ -400,29 +473,32 @@ static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info
snd_iprintf(buffer, "-----\n");
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
+ unlock:
+ mutex_unlock(&substream->pcm->open_mutex);
}
-#endif
-#ifdef CONFIG_SND_DEBUG
-static void snd_pcm_xrun_debug_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
+ struct snd_pcm_str *pstr = entry->private_data;
snd_iprintf(buffer, "%d\n", pstr->xrun_debug);
}
-static void snd_pcm_xrun_debug_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void snd_pcm_xrun_debug_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
+ struct snd_pcm_str *pstr = entry->private_data;
char line[64];
if (!snd_info_get_line(buffer, line, sizeof(line)))
pstr->xrun_debug = simple_strtoul(line, NULL, 10);
}
#endif
-static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr)
+static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
{
- snd_pcm_t *pcm = pstr->pcm;
- snd_info_entry_t *entry;
+ struct snd_pcm *pcm = pstr->pcm;
+ struct snd_info_entry *entry;
char name[16];
sprintf(name, "pcm%i%c", pcm->device,
@@ -437,7 +513,7 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr)
pstr->proc_root = entry;
if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read);
+ snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -445,11 +521,10 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr)
}
pstr->proc_info_entry = entry;
-#ifdef CONFIG_SND_DEBUG
- if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root)) != NULL) {
- entry->c.text.read_size = 64;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
+ pstr->proc_root)) != NULL) {
entry->c.text.read = snd_pcm_xrun_debug_read;
- entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_xrun_debug_write;
entry->mode |= S_IWUSR;
entry->private_data = pstr;
@@ -463,29 +538,23 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr)
return 0;
}
-static int snd_pcm_stream_proc_done(snd_pcm_str_t *pstr)
+static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
{
-#ifdef CONFIG_SND_DEBUG
- if (pstr->proc_xrun_debug_entry) {
- snd_info_unregister(pstr->proc_xrun_debug_entry);
- pstr->proc_xrun_debug_entry = NULL;
- }
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ snd_info_free_entry(pstr->proc_xrun_debug_entry);
+ pstr->proc_xrun_debug_entry = NULL;
#endif
- if (pstr->proc_info_entry) {
- snd_info_unregister(pstr->proc_info_entry);
- pstr->proc_info_entry = NULL;
- }
- if (pstr->proc_root) {
- snd_info_unregister(pstr->proc_root);
- pstr->proc_root = NULL;
- }
+ snd_info_free_entry(pstr->proc_info_entry);
+ pstr->proc_info_entry = NULL;
+ snd_info_free_entry(pstr->proc_root);
+ pstr->proc_root = NULL;
return 0;
}
-static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
+static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
{
- snd_info_entry_t *entry;
- snd_card_t *card;
+ struct snd_info_entry *entry;
+ struct snd_card *card;
char name[16];
card = substream->pcm->card;
@@ -501,7 +570,8 @@ static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
substream->proc_root = entry;
if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_info_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -510,7 +580,8 @@ static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
substream->proc_info_entry = entry;
if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_hw_params_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -519,7 +590,8 @@ static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
substream->proc_hw_params_entry = entry;
if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_sw_params_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -528,7 +600,8 @@ static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
substream->proc_sw_params_entry = entry;
if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
- snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read);
+ snd_info_set_text_ops(entry, substream,
+ snd_pcm_substream_proc_status_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
@@ -538,31 +611,27 @@ static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
return 0;
}
-
-static int snd_pcm_substream_proc_done(snd_pcm_substream_t *substream)
+
+static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
{
- if (substream->proc_info_entry) {
- snd_info_unregister(substream->proc_info_entry);
- substream->proc_info_entry = NULL;
- }
- if (substream->proc_hw_params_entry) {
- snd_info_unregister(substream->proc_hw_params_entry);
- substream->proc_hw_params_entry = NULL;
- }
- if (substream->proc_sw_params_entry) {
- snd_info_unregister(substream->proc_sw_params_entry);
- substream->proc_sw_params_entry = NULL;
- }
- if (substream->proc_status_entry) {
- snd_info_unregister(substream->proc_status_entry);
- substream->proc_status_entry = NULL;
- }
- if (substream->proc_root) {
- snd_info_unregister(substream->proc_root);
- substream->proc_root = NULL;
- }
+ snd_info_free_entry(substream->proc_info_entry);
+ substream->proc_info_entry = NULL;
+ snd_info_free_entry(substream->proc_hw_params_entry);
+ substream->proc_hw_params_entry = NULL;
+ snd_info_free_entry(substream->proc_sw_params_entry);
+ substream->proc_sw_params_entry = NULL;
+ snd_info_free_entry(substream->proc_status_entry);
+ substream->proc_status_entry = NULL;
+ snd_info_free_entry(substream->proc_root);
+ substream->proc_root = NULL;
return 0;
}
+#else /* !CONFIG_SND_VERBOSE_PROCFS */
+static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; }
+static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; }
+static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; }
+static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
+#endif /* CONFIG_SND_VERBOSE_PROCFS */
/**
* snd_pcm_new_stream - create a new PCM stream
@@ -575,31 +644,34 @@ static int snd_pcm_substream_proc_done(snd_pcm_substream_t *substream)
* calling this, i.e. zero must be given to the argument of
* snd_pcm_new().
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count)
+int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
{
int idx, err;
- snd_pcm_str_t *pstr = &pcm->streams[stream];
- snd_pcm_substream_t *substream, *prev;
+ struct snd_pcm_str *pstr = &pcm->streams[stream];
+ struct snd_pcm_substream *substream, *prev;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- init_MUTEX(&pstr->oss.setup_mutex);
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
+ mutex_init(&pstr->oss.setup_mutex);
#endif
pstr->stream = stream;
pstr->pcm = pcm;
pstr->substream_count = substream_count;
- pstr->reg = &snd_pcm_reg[stream];
- if (substream_count > 0) {
+ if (substream_count > 0 && !pcm->internal) {
err = snd_pcm_stream_proc_init(pstr);
- if (err < 0)
+ if (err < 0) {
+ pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
return err;
+ }
}
prev = NULL;
for (idx = 0, prev = NULL; idx < substream_count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);
- if (substream == NULL)
+ if (substream == NULL) {
+ pcm_err(pcm, "Cannot allocate PCM substream\n");
return -ENOMEM;
+ }
substream->pcm = pcm;
substream->pstr = pstr;
substream->number = idx;
@@ -610,61 +682,58 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count)
pstr->substream = substream;
else
prev->next = substream;
- err = snd_pcm_substream_proc_init(substream);
- if (err < 0) {
- kfree(substream);
- return err;
+
+ if (!pcm->internal) {
+ err = snd_pcm_substream_proc_init(substream);
+ if (err < 0) {
+ pcm_err(pcm,
+ "Error in snd_pcm_stream_proc_init\n");
+ if (prev == NULL)
+ pstr->substream = NULL;
+ else
+ prev->next = NULL;
+ kfree(substream);
+ return err;
+ }
}
substream->group = &substream->self_group;
spin_lock_init(&substream->self_group.lock);
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
- spin_lock_init(&substream->timer_lock);
+ atomic_set(&substream->mmap_count, 0);
prev = substream;
}
return 0;
}
-/**
- * snd_pcm_new - create a new PCM instance
- * @card: the card instance
- * @id: the id string
- * @device: the device index (zero based)
- * @playback_count: the number of substreams for playback
- * @capture_count: the number of substreams for capture
- * @rpcm: the pointer to store the new pcm instance
- *
- * Creates a new PCM instance.
- *
- * The pcm operators have to be set afterwards to the new instance
- * via snd_pcm_set_ops().
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_pcm_new(snd_card_t * card, char *id, int device,
- int playback_count, int capture_count,
- snd_pcm_t ** rpcm)
+EXPORT_SYMBOL(snd_pcm_new_stream);
+
+static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
+ int playback_count, int capture_count, bool internal,
+ struct snd_pcm **rpcm)
{
- snd_pcm_t *pcm;
+ struct snd_pcm *pcm;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
- .dev_unregister = snd_pcm_dev_unregister
};
- snd_assert(rpcm != NULL, return -EINVAL);
- *rpcm = NULL;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ if (rpcm)
+ *rpcm = NULL;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
- if (pcm == NULL)
+ if (pcm == NULL) {
+ dev_err(card->dev, "Cannot allocate PCM\n");
return -ENOMEM;
+ }
pcm->card = card;
pcm->device = device;
- if (id) {
+ pcm->internal = internal;
+ if (id)
strlcpy(pcm->id, id, sizeof(pcm->id));
- }
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
snd_pcm_free(pcm);
return err;
@@ -673,31 +742,86 @@ int snd_pcm_new(snd_card_t * card, char *id, int device,
snd_pcm_free(pcm);
return err;
}
- init_MUTEX(&pcm->open_mutex);
+ mutex_init(&pcm->open_mutex);
init_waitqueue_head(&pcm->open_wait);
if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
snd_pcm_free(pcm);
return err;
}
- *rpcm = pcm;
+ if (rpcm)
+ *rpcm = pcm;
return 0;
}
-static void snd_pcm_free_stream(snd_pcm_str_t * pstr)
+/**
+ * snd_pcm_new - create a new PCM instance
+ * @card: the card instance
+ * @id: the id string
+ * @device: the device index (zero based)
+ * @playback_count: the number of substreams for playback
+ * @capture_count: the number of substreams for capture
+ * @rpcm: the pointer to store the new pcm instance
+ *
+ * Creates a new PCM instance.
+ *
+ * The pcm operators have to be set afterwards to the new instance
+ * via snd_pcm_set_ops().
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_new(struct snd_card *card, const char *id, int device,
+ int playback_count, int capture_count, struct snd_pcm **rpcm)
{
- snd_pcm_substream_t *substream, *substream_next;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- snd_pcm_oss_setup_t *setup, *setupn;
+ return _snd_pcm_new(card, id, device, playback_count, capture_count,
+ false, rpcm);
+}
+EXPORT_SYMBOL(snd_pcm_new);
+
+/**
+ * snd_pcm_new_internal - create a new internal PCM instance
+ * @card: the card instance
+ * @id: the id string
+ * @device: the device index (zero based - shared with normal PCMs)
+ * @playback_count: the number of substreams for playback
+ * @capture_count: the number of substreams for capture
+ * @rpcm: the pointer to store the new pcm instance
+ *
+ * Creates a new internal PCM instance with no userspace device or procfs
+ * entries. This is used by ASoC Back End PCMs in order to create a PCM that
+ * will only be used internally by kernel drivers. i.e. it cannot be opened
+ * by userspace. It provides existing ASoC components drivers with a substream
+ * and access to any private data.
+ *
+ * The pcm operators have to be set afterwards to the new instance
+ * via snd_pcm_set_ops().
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
+ int playback_count, int capture_count,
+ struct snd_pcm **rpcm)
+{
+ return _snd_pcm_new(card, id, device, playback_count, capture_count,
+ true, rpcm);
+}
+EXPORT_SYMBOL(snd_pcm_new_internal);
+
+static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
+{
+ struct snd_pcm_substream *substream, *substream_next;
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
+ struct snd_pcm_oss_setup *setup, *setupn;
#endif
substream = pstr->substream;
while (substream) {
substream_next = substream->next;
+ snd_pcm_timer_done(substream);
snd_pcm_substream_proc_done(substream);
kfree(substream);
substream = substream_next;
}
snd_pcm_stream_proc_done(pstr);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
for (setup = pstr->oss.setup_list; setup; setup = setupn) {
setupn = setup->next;
kfree(setup->task_name);
@@ -706,9 +830,15 @@ static void snd_pcm_free_stream(snd_pcm_str_t * pstr)
#endif
}
-static int snd_pcm_free(snd_pcm_t *pcm)
+static int snd_pcm_free(struct snd_pcm *pcm)
{
- snd_assert(pcm != NULL, return -ENXIO);
+ struct snd_pcm_notify *notify;
+
+ if (!pcm)
+ return 0;
+ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
+ notify->n_unregister(pcm);
+ }
if (pcm->private_free)
pcm->private_free(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -718,50 +848,42 @@ static int snd_pcm_free(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_dev_free(snd_device_t *device)
+static int snd_pcm_dev_free(struct snd_device *device)
{
- snd_pcm_t *pcm = device->device_data;
+ struct snd_pcm *pcm = device->device_data;
return snd_pcm_free(pcm);
}
-static void snd_pcm_tick_timer_func(unsigned long data)
+int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
+ struct file *file,
+ struct snd_pcm_substream **rsubstream)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t*) data;
- snd_pcm_tick_elapsed(substream);
-}
-
-int snd_pcm_open_substream(snd_pcm_t *pcm, int stream,
- snd_pcm_substream_t **rsubstream)
-{
- snd_pcm_str_t * pstr;
- snd_pcm_substream_t * substream;
- snd_pcm_runtime_t * runtime;
- snd_ctl_file_t *kctl;
- snd_card_t *card;
- struct list_head *list;
+ struct snd_pcm_str * pstr;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ struct snd_ctl_file *kctl;
+ struct snd_card *card;
int prefer_subdevice = -1;
size_t size;
- snd_assert(rsubstream != NULL, return -EINVAL);
+ if (snd_BUG_ON(!pcm || !rsubstream))
+ return -ENXIO;
*rsubstream = NULL;
- snd_assert(pcm != NULL, return -ENXIO);
pstr = &pcm->streams[stream];
- if (pstr->substream == NULL)
+ if (pstr->substream == NULL || pstr->substream_count == 0)
return -ENODEV;
card = pcm->card;
- down_read(&card->controls_rwsem);
- list_for_each(list, &card->ctl_files) {
- kctl = snd_ctl_file(list);
- if (kctl->pid == current->pid) {
+ read_lock(&card->ctl_files_rwlock);
+ list_for_each_entry(kctl, &card->ctl_files, list) {
+ if (kctl->pid == task_pid(current)) {
prefer_subdevice = kctl->prefer_pcm_subdevice;
- break;
+ if (prefer_subdevice != -1)
+ break;
}
}
- up_read(&card->controls_rwsem);
+ read_unlock(&card->ctl_files_rwlock);
- if (pstr->substream_count == 0)
- return -ENODEV;
switch (stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
@@ -783,6 +905,26 @@ int snd_pcm_open_substream(snd_pcm_t *pcm, int stream,
return -EINVAL;
}
+ if (file->f_flags & O_APPEND) {
+ if (prefer_subdevice < 0) {
+ if (pstr->substream_count > 1)
+ return -EINVAL; /* must be unique */
+ substream = pstr->substream;
+ } else {
+ for (substream = pstr->substream; substream;
+ substream = substream->next)
+ if (substream->number == prefer_subdevice)
+ break;
+ }
+ if (! substream)
+ return -ENODEV;
+ if (! SUBSTREAM_BUSY(substream))
+ return -EBADFD;
+ substream->ref_count++;
+ *rsubstream = substream;
+ return 0;
+ }
+
if (prefer_subdevice >= 0) {
for (substream = pstr->substream; substream; substream = substream->next)
if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
@@ -799,7 +941,7 @@ int snd_pcm_open_substream(snd_pcm_t *pcm, int stream,
if (runtime == NULL)
return -ENOMEM;
- size = PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t));
+ size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
runtime->status = snd_malloc_pages(size, GFP_KERNEL);
if (runtime->status == NULL) {
kfree(runtime);
@@ -807,130 +949,188 @@ int snd_pcm_open_substream(snd_pcm_t *pcm, int stream,
}
memset((void*)runtime->status, 0, size);
- size = PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t));
+ size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
runtime->control = snd_malloc_pages(size, GFP_KERNEL);
if (runtime->control == NULL) {
- snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)));
+ snd_free_pages((void*)runtime->status,
+ PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
kfree(runtime);
return -ENOMEM;
}
memset((void*)runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep);
- atomic_set(&runtime->mmap_count, 0);
- init_timer(&runtime->tick_timer);
- runtime->tick_timer.function = snd_pcm_tick_timer_func;
- runtime->tick_timer.data = (unsigned long) substream;
+ init_waitqueue_head(&runtime->tsleep);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
substream->runtime = runtime;
substream->private_data = pcm->private_data;
+ substream->ref_count = 1;
+ substream->f_flags = file->f_flags;
+ substream->pid = get_pid(task_pid(current));
pstr->substream_opened++;
*rsubstream = substream;
return 0;
}
-void snd_pcm_release_substream(snd_pcm_substream_t *substream)
+void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t * runtime;
- substream->file = NULL;
+ struct snd_pcm_runtime *runtime;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return);
if (runtime->private_free != NULL)
runtime->private_free(runtime);
- snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)));
- snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)));
+ snd_free_pages((void*)runtime->status,
+ PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
+ snd_free_pages((void*)runtime->control,
+ PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
kfree(runtime->hw_constraints.rules);
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ kfree(runtime->hwptr_log);
+#endif
kfree(runtime);
substream->runtime = NULL;
+ put_pid(substream->pid);
+ substream->pid = NULL;
substream->pstr->substream_opened--;
}
-static int snd_pcm_dev_register(snd_device_t *device)
+static ssize_t show_pcm_class(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int idx, cidx, err;
- unsigned short minor;
- snd_pcm_substream_t *substream;
- struct list_head *list;
+ struct snd_pcm *pcm;
+ const char *str;
+ static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
+ [SNDRV_PCM_CLASS_GENERIC] = "generic",
+ [SNDRV_PCM_CLASS_MULTI] = "multi",
+ [SNDRV_PCM_CLASS_MODEM] = "modem",
+ [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
+ };
+
+ if (! (pcm = dev_get_drvdata(dev)) ||
+ pcm->dev_class > SNDRV_PCM_CLASS_LAST)
+ str = "none";
+ else
+ str = strs[pcm->dev_class];
+ return snprintf(buf, PAGE_SIZE, "%s\n", str);
+}
+
+static DEVICE_ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+static struct attribute *pcm_dev_attrs[] = {
+ &dev_attr_pcm_class.attr,
+ NULL
+};
+
+static struct attribute_group pcm_dev_attr_group = {
+ .attrs = pcm_dev_attrs,
+};
+
+static const struct attribute_group *pcm_dev_attr_groups[] = {
+ &pcm_dev_attr_group,
+ NULL
+};
+
+static int snd_pcm_dev_register(struct snd_device *device)
+{
+ int cidx, err;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_notify *notify;
char str[16];
- snd_pcm_t *pcm = device->device_data;
-
- snd_assert(pcm != NULL && device != NULL, return -ENXIO);
- down(&register_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- if (snd_pcm_devices[idx]) {
- up(&register_mutex);
- return -EBUSY;
+ struct snd_pcm *pcm;
+ struct device *dev;
+
+ if (snd_BUG_ON(!device || !device->device_data))
+ return -ENXIO;
+ pcm = device->device_data;
+ mutex_lock(&register_mutex);
+ err = snd_pcm_add(pcm);
+ if (err) {
+ mutex_unlock(&register_mutex);
+ return err;
}
- snd_pcm_devices[idx] = pcm;
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
- if (pcm->streams[cidx].substream == NULL)
+ if (pcm->streams[cidx].substream == NULL || pcm->internal)
continue;
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
- minor = SNDRV_MINOR_PCM_PLAYBACK + idx;
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
case SNDRV_PCM_STREAM_CAPTURE:
sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
- minor = SNDRV_MINOR_PCM_CAPTURE + idx;
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
- if ((err = snd_register_device(devtype, pcm->card, pcm->device, pcm->streams[cidx].reg, str)) < 0) {
- snd_pcm_devices[idx] = NULL;
- up(&register_mutex);
+ /* device pointer to use, pcm->dev takes precedence if
+ * it is assigned, otherwise fall back to card's device
+ * if possible */
+ dev = pcm->dev;
+ if (!dev)
+ dev = snd_card_get_device_link(pcm->card);
+ /* register pcm */
+ err = snd_register_device_for_dev(devtype, pcm->card,
+ pcm->device,
+ &snd_pcm_f_ops[cidx],
+ pcm, str, dev);
+ if (err < 0) {
+ list_del(&pcm->list);
+ mutex_unlock(&register_mutex);
return err;
}
+
+ dev = snd_get_device(devtype, pcm->card, pcm->device);
+ if (dev) {
+ err = sysfs_create_groups(&dev->kobj,
+ pcm_dev_attr_groups);
+ if (err < 0)
+ dev_warn(dev,
+ "pcm %d:%d: cannot create sysfs groups\n",
+ pcm->card->number, pcm->device);
+ put_device(dev);
+ }
+
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
- list_for_each(list, &snd_pcm_notify_list) {
- snd_pcm_notify_t *notify;
- notify = list_entry(list, snd_pcm_notify_t, list);
+
+ list_for_each_entry(notify, &snd_pcm_notify_list, list)
notify->n_register(pcm);
- }
- up(&register_mutex);
+
+ mutex_unlock(&register_mutex);
return 0;
}
-static int snd_pcm_dev_disconnect(snd_device_t *device)
+static int snd_pcm_dev_disconnect(struct snd_device *device)
{
- snd_pcm_t *pcm = device->device_data;
- struct list_head *list;
- snd_pcm_substream_t *substream;
- int idx, cidx;
-
- down(&register_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- snd_pcm_devices[idx] = NULL;
+ struct snd_pcm *pcm = device->device_data;
+ struct snd_pcm_notify *notify;
+ struct snd_pcm_substream *substream;
+ int cidx, devtype;
+
+ mutex_lock(&register_mutex);
+ if (list_empty(&pcm->list))
+ goto unlock;
+
+ mutex_lock(&pcm->open_mutex);
+ wake_up(&pcm->open_wait);
+ list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++)
- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
- if (substream->runtime)
+ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime) {
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
- list_for_each(list, &snd_pcm_notify_list) {
- snd_pcm_notify_t *notify;
- notify = list_entry(list, snd_pcm_notify_t, list);
+ wake_up(&substream->runtime->sleep);
+ wake_up(&substream->runtime->tsleep);
+ }
+ snd_pcm_stream_unlock_irq(substream);
+ }
+ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
notify->n_disconnect(pcm);
}
- up(&register_mutex);
- return 0;
-}
-
-static int snd_pcm_dev_unregister(snd_device_t *device)
-{
- int idx, cidx, devtype;
- snd_pcm_substream_t *substream;
- struct list_head *list;
- snd_pcm_t *pcm = device->device_data;
-
- snd_assert(pcm != NULL, return -ENXIO);
- down(&register_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- snd_pcm_devices[idx] = NULL;
for (cidx = 0; cidx < 2; cidx++) {
devtype = -1;
switch (cidx) {
@@ -942,88 +1142,103 @@ static int snd_pcm_dev_unregister(snd_device_t *device)
break;
}
snd_unregister_device(devtype, pcm->card, pcm->device);
- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
- snd_pcm_timer_done(substream);
- }
- list_for_each(list, &snd_pcm_notify_list) {
- snd_pcm_notify_t *notify;
- notify = list_entry(list, snd_pcm_notify_t, list);
- notify->n_unregister(pcm);
+ if (pcm->streams[cidx].chmap_kctl) {
+ snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
+ pcm->streams[cidx].chmap_kctl = NULL;
+ }
}
- up(&register_mutex);
- return snd_pcm_free(pcm);
+ mutex_unlock(&pcm->open_mutex);
+ unlock:
+ mutex_unlock(&register_mutex);
+ return 0;
}
-int snd_pcm_notify(snd_pcm_notify_t *notify, int nfree)
+int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
- int idx;
+ struct snd_pcm *pcm;
- snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
- down(&register_mutex);
+ if (snd_BUG_ON(!notify ||
+ !notify->n_register ||
+ !notify->n_unregister ||
+ !notify->n_disconnect))
+ return -EINVAL;
+ mutex_lock(&register_mutex);
if (nfree) {
list_del(&notify->list);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- if (snd_pcm_devices[idx] == NULL)
- continue;
- notify->n_unregister(snd_pcm_devices[idx]);
- }
+ list_for_each_entry(pcm, &snd_pcm_devices, list)
+ notify->n_unregister(pcm);
} else {
list_add_tail(&notify->list, &snd_pcm_notify_list);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- if (snd_pcm_devices[idx] == NULL)
- continue;
- notify->n_register(snd_pcm_devices[idx]);
- }
+ list_for_each_entry(pcm, &snd_pcm_devices, list)
+ notify->n_register(pcm);
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
+EXPORT_SYMBOL(snd_pcm_notify);
+
+#ifdef CONFIG_PROC_FS
/*
* Info interface
*/
-static void snd_pcm_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static void snd_pcm_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- int idx;
- snd_pcm_t *pcm;
+ struct snd_pcm *pcm;
- down(&register_mutex);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- pcm = snd_pcm_devices[idx];
- if (pcm == NULL)
- continue;
- snd_iprintf(buffer, "%02i-%02i: %s : %s", idx / SNDRV_PCM_DEVICES,
- idx % SNDRV_PCM_DEVICES, pcm->id, pcm->name);
+ mutex_lock(&register_mutex);
+ list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ snd_iprintf(buffer, "%02i-%02i: %s : %s",
+ pcm->card->number, pcm->device, pcm->id, pcm->name);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
- snd_iprintf(buffer, " : playback %i", pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
+ snd_iprintf(buffer, " : playback %i",
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
- snd_iprintf(buffer, " : capture %i", pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
+ snd_iprintf(buffer, " : capture %i",
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
snd_iprintf(buffer, "\n");
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
}
-/*
- * ENTRY functions
- */
-
-static snd_info_entry_t *snd_pcm_proc_entry = NULL;
+static struct snd_info_entry *snd_pcm_proc_entry;
-static int __init alsa_pcm_init(void)
+static void snd_pcm_proc_init(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
- snd_ctl_register_ioctl(snd_pcm_control_ioctl);
- snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
- snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read);
+ snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
entry = NULL;
}
}
snd_pcm_proc_entry = entry;
+}
+
+static void snd_pcm_proc_done(void)
+{
+ snd_info_free_entry(snd_pcm_proc_entry);
+}
+
+#else /* !CONFIG_PROC_FS */
+#define snd_pcm_proc_init()
+#define snd_pcm_proc_done()
+#endif /* CONFIG_PROC_FS */
+
+
+/*
+ * ENTRY functions
+ */
+
+static int __init alsa_pcm_init(void)
+{
+ snd_ctl_register_ioctl(snd_pcm_control_ioctl);
+ snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
+ snd_pcm_proc_init();
return 0;
}
@@ -1031,45 +1246,8 @@ static void __exit alsa_pcm_exit(void)
{
snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
- if (snd_pcm_proc_entry) {
- snd_info_unregister(snd_pcm_proc_entry);
- snd_pcm_proc_entry = NULL;
- }
+ snd_pcm_proc_done();
}
module_init(alsa_pcm_init)
module_exit(alsa_pcm_exit)
-
-EXPORT_SYMBOL(snd_pcm_devices);
-EXPORT_SYMBOL(snd_pcm_new);
-EXPORT_SYMBOL(snd_pcm_new_stream);
-EXPORT_SYMBOL(snd_pcm_notify);
-EXPORT_SYMBOL(snd_pcm_open_substream);
-EXPORT_SYMBOL(snd_pcm_release_substream);
-EXPORT_SYMBOL(snd_pcm_format_name);
- /* pcm_native.c */
-EXPORT_SYMBOL(snd_pcm_link_rwlock);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_pcm_suspend);
-EXPORT_SYMBOL(snd_pcm_suspend_all);
-#endif
-EXPORT_SYMBOL(snd_pcm_kernel_playback_ioctl);
-EXPORT_SYMBOL(snd_pcm_kernel_capture_ioctl);
-EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
-EXPORT_SYMBOL(snd_pcm_mmap_data);
-#if SNDRV_PCM_INFO_MMAP_IOMEM
-EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
-#endif
- /* pcm_misc.c */
-EXPORT_SYMBOL(snd_pcm_format_signed);
-EXPORT_SYMBOL(snd_pcm_format_unsigned);
-EXPORT_SYMBOL(snd_pcm_format_linear);
-EXPORT_SYMBOL(snd_pcm_format_little_endian);
-EXPORT_SYMBOL(snd_pcm_format_big_endian);
-EXPORT_SYMBOL(snd_pcm_format_width);
-EXPORT_SYMBOL(snd_pcm_format_physical_width);
-EXPORT_SYMBOL(snd_pcm_format_size);
-EXPORT_SYMBOL(snd_pcm_format_silence_64);
-EXPORT_SYMBOL(snd_pcm_format_set_silence);
-EXPORT_SYMBOL(snd_pcm_build_linear_format);
-EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 4b6307df846..af49721ba0e 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -21,8 +21,9 @@
/* This file included from pcm_native.c */
#include <linux/compat.h>
+#include <linux/slab.h>
-static int snd_pcm_ioctl_delay_compat(snd_pcm_substream_t *substream,
+static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,
s32 __user *src)
{
snd_pcm_sframes_t delay;
@@ -39,7 +40,7 @@ static int snd_pcm_ioctl_delay_compat(snd_pcm_substream_t *substream,
return err;
}
-static int snd_pcm_ioctl_rewind_compat(snd_pcm_substream_t *substream,
+static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream,
u32 __user *src)
{
snd_pcm_uframes_t frames;
@@ -56,7 +57,7 @@ static int snd_pcm_ioctl_rewind_compat(snd_pcm_substream_t *substream,
return err < 0 ? err : 0;
}
-static int snd_pcm_ioctl_forward_compat(snd_pcm_substream_t *substream,
+static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream,
u32 __user *src)
{
snd_pcm_uframes_t frames;
@@ -73,12 +74,12 @@ static int snd_pcm_ioctl_forward_compat(snd_pcm_substream_t *substream,
return err < 0 ? err : 0;
}
-struct sndrv_pcm_hw_params32 {
+struct snd_pcm_hw_params32 {
u32 flags;
- struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
- struct sndrv_mask mres[5]; /* reserved masks */
- struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
- struct sndrv_interval ires[9]; /* reserved intervals */
+ struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
+ struct snd_mask mres[5]; /* reserved masks */
+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+ struct snd_interval ires[9]; /* reserved intervals */
u32 rmask;
u32 cmask;
u32 info;
@@ -89,7 +90,7 @@ struct sndrv_pcm_hw_params32 {
unsigned char reserved[64];
};
-struct sndrv_pcm_sw_params32 {
+struct snd_pcm_sw_params32 {
s32 tstamp_mode;
u32 period_step;
u32 sleep_min;
@@ -104,7 +105,7 @@ struct sndrv_pcm_sw_params32 {
};
/* recalcuate the boundary within 32bit */
-static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
+static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t boundary;
@@ -116,10 +117,10 @@ static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
return boundary;
}
-static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
- struct sndrv_pcm_sw_params32 __user *src)
+static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream,
+ struct snd_pcm_sw_params32 __user *src)
{
- snd_pcm_sw_params_t params;
+ struct snd_pcm_sw_params params;
snd_pcm_uframes_t boundary;
int err;
@@ -149,17 +150,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
return err;
}
-struct sndrv_pcm_channel_info32 {
+struct snd_pcm_channel_info32 {
u32 channel;
u32 offset;
u32 first;
u32 step;
};
-static int snd_pcm_ioctl_channel_info_compat(snd_pcm_substream_t *substream,
- struct sndrv_pcm_channel_info32 __user *src)
+static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream,
+ struct snd_pcm_channel_info32 __user *src)
{
- snd_pcm_channel_info_t info;
+ struct snd_pcm_channel_info info;
int err;
if (get_user(info.channel, &src->channel) ||
@@ -178,7 +179,7 @@ static int snd_pcm_ioctl_channel_info_compat(snd_pcm_substream_t *substream,
return err;
}
-struct sndrv_pcm_status32 {
+struct snd_pcm_status32 {
s32 state;
struct compat_timespec trigger_tstamp;
struct compat_timespec tstamp;
@@ -189,14 +190,16 @@ struct sndrv_pcm_status32 {
u32 avail_max;
u32 overrange;
s32 suspended_state;
- unsigned char reserved[60];
+ u32 reserved_alignment;
+ struct compat_timespec audio_tstamp;
+ unsigned char reserved[56-sizeof(struct compat_timespec)];
} __attribute__((packed));
-static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
- struct sndrv_pcm_status32 __user *src)
+static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
+ struct snd_pcm_status32 __user *src)
{
- snd_pcm_status_t status;
+ struct snd_pcm_status status;
int err;
err = snd_pcm_status(substream, &status);
@@ -204,42 +207,38 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
return err;
if (put_user(status.state, &src->state) ||
- put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) ||
- put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) ||
- put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
- put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+ compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
+ compat_put_timespec(&status.tstamp, &src->tstamp) ||
put_user(status.appl_ptr, &src->appl_ptr) ||
put_user(status.hw_ptr, &src->hw_ptr) ||
put_user(status.delay, &src->delay) ||
put_user(status.avail, &src->avail) ||
put_user(status.avail_max, &src->avail_max) ||
put_user(status.overrange, &src->overrange) ||
- put_user(status.suspended_state, &src->suspended_state))
+ put_user(status.suspended_state, &src->suspended_state) ||
+ compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp))
return -EFAULT;
return err;
}
/* both for HW_PARAMS and HW_REFINE */
-static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
+static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
int refine,
- struct sndrv_pcm_hw_params32 __user *data32)
+ struct snd_pcm_hw_params32 __user *data32)
{
- struct sndrv_pcm_hw_params *data;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_hw_params *data;
+ struct snd_pcm_runtime *runtime;
int err;
if (! (runtime = substream->runtime))
return -ENOTTY;
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
/* only fifo_size is different, so just copy all */
- if (copy_from_user(data, data32, sizeof(*data32))) {
- err = -EFAULT;
- goto error;
- }
+ data = memdup_user(data32, sizeof(*data32));
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
if (refine)
err = snd_pcm_hw_refine(substream, data);
else
@@ -265,14 +264,14 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
/*
*/
-struct sndrv_xferi32 {
+struct snd_xferi32 {
s32 result;
u32 buf;
u32 frames;
};
-static int snd_pcm_ioctl_xferi_compat(snd_pcm_substream_t *substream,
- int dir, struct sndrv_xferi32 __user *data32)
+static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
+ int dir, struct snd_xferi32 __user *data32)
{
compat_caddr_t buf;
u32 frames;
@@ -303,7 +302,7 @@ static int snd_pcm_ioctl_xferi_compat(snd_pcm_substream_t *substream,
/* snd_xfern needs remapping of bufs */
-struct sndrv_xfern32 {
+struct snd_xfern32 {
s32 result;
u32 bufs; /* this is void **; */
u32 frames;
@@ -315,8 +314,8 @@ struct sndrv_xfern32 {
* handler there expands again the same 128 pointers on stack, so it is better
* to handle the function (calling pcm_readv/writev) directly in this handler.
*/
-static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
- int dir, struct sndrv_xfern32 __user *data32)
+static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
+ int dir, struct snd_xfern32 __user *data32)
{
compat_caddr_t buf;
compat_caddr_t __user *bufptr;
@@ -344,7 +343,7 @@ static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
kfree(bufs);
return -EFAULT;
}
- bufs[ch] = compat_ptr(ptr);
+ bufs[i] = compat_ptr(ptr);
bufptr++;
}
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
@@ -360,44 +359,46 @@ static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
}
-struct sndrv_pcm_mmap_status32 {
+struct snd_pcm_mmap_status32 {
s32 state;
s32 pad1;
u32 hw_ptr;
struct compat_timespec tstamp;
s32 suspended_state;
+ struct compat_timespec audio_tstamp;
} __attribute__((packed));
-struct sndrv_pcm_mmap_control32 {
+struct snd_pcm_mmap_control32 {
u32 appl_ptr;
u32 avail_min;
};
-struct sndrv_pcm_sync_ptr32 {
+struct snd_pcm_sync_ptr32 {
u32 flags;
union {
- struct sndrv_pcm_mmap_status32 status;
+ struct snd_pcm_mmap_status32 status;
unsigned char reserved[64];
} s;
union {
- struct sndrv_pcm_mmap_control32 control;
+ struct snd_pcm_mmap_control32 control;
unsigned char reserved[64];
} c;
} __attribute__((packed));
-static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
- struct sndrv_pcm_sync_ptr32 __user *src)
+static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
+ struct snd_pcm_sync_ptr32 __user *src)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- volatile struct sndrv_pcm_mmap_status *status;
- volatile struct sndrv_pcm_mmap_control *control;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ volatile struct snd_pcm_mmap_status *status;
+ volatile struct snd_pcm_mmap_control *control;
u32 sflags;
- struct sndrv_pcm_mmap_control scontrol;
- struct sndrv_pcm_mmap_status sstatus;
+ struct snd_pcm_mmap_control scontrol;
+ struct snd_pcm_mmap_status sstatus;
snd_pcm_uframes_t boundary;
int err;
- snd_assert(runtime, return -EINVAL);
+ if (snd_BUG_ON(!runtime))
+ return -EINVAL;
if (get_user(sflags, &src->flags) ||
get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
@@ -427,12 +428,14 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
+ sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
- put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) ||
- put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) ||
+ compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
+ compat_put_timespec(&sstatus.audio_tstamp,
+ &src->s.status.audio_tstamp) ||
put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
put_user(scontrol.avail_min, &src->c.control.avail_min))
return -EFAULT;
@@ -444,26 +447,26 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
/*
*/
enum {
- SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
- SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
- SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
- SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
+ SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
+ SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
+ SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
+ SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
- SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
+ SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
- SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
- SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
- SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
- SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
- SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
+ SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
+ SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
+ SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
+ SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
+ SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
};
static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
void __user *argp = compat_ptr(arg);
pcm_file = file->private_data;
@@ -478,12 +481,13 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
* mmap of PCM status/control records because of the size
* incompatibility.
*/
- substream->no_mmap_ctrl = 1;
+ pcm_file->no_compat_mmap = 1;
switch (cmd) {
case SNDRV_PCM_IOCTL_PVERSION:
case SNDRV_PCM_IOCTL_INFO:
case SNDRV_PCM_IOCTL_TSTAMP:
+ case SNDRV_PCM_IOCTL_TTSTAMP:
case SNDRV_PCM_IOCTL_HWSYNC:
case SNDRV_PCM_IOCTL_PREPARE:
case SNDRV_PCM_IOCTL_RESET:
@@ -497,9 +501,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
case SNDRV_PCM_IOCTL_LINK:
case SNDRV_PCM_IOCTL_UNLINK:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return snd_pcm_playback_ioctl1(substream, cmd, argp);
+ return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
else
- return snd_pcm_capture_ioctl1(substream, cmd, argp);
+ return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
case SNDRV_PCM_IOCTL_HW_REFINE32:
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
case SNDRV_PCM_IOCTL_HW_PARAMS32:
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
new file mode 100644
index 00000000000..76cbb9ec953
--- /dev/null
+++ b/sound/core/pcm_dmaengine.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2012, Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Based on:
+ * imx-pcm-dma-mx2.c, Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ * mxs-pcm.c, Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * ep93xx-pcm.c, Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <sound/dmaengine_pcm.h>
+
+struct dmaengine_pcm_runtime_data {
+ struct dma_chan *dma_chan;
+ dma_cookie_t cookie;
+
+ unsigned int pos;
+};
+
+static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
+ const struct snd_pcm_substream *substream)
+{
+ return substream->runtime->private_data;
+}
+
+struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+ return prtd->dma_chan;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan);
+
+/**
+ * snd_hwparams_to_dma_slave_config - Convert hw_params to dma_slave_config
+ * @substream: PCM substream
+ * @params: hw_params
+ * @slave_config: DMA slave config
+ *
+ * This function can be used to initialize a dma_slave_config from a substream
+ * and hw_params in a dmaengine based PCM driver implementation.
+ */
+int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
+ const struct snd_pcm_hw_params *params,
+ struct dma_slave_config *slave_config)
+{
+ enum dma_slave_buswidth buswidth;
+ int bits;
+
+ bits = snd_pcm_format_physical_width(params_format(params));
+ if (bits < 8 || bits > 64)
+ return -EINVAL;
+ else if (bits == 8)
+ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ else if (bits == 16)
+ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ else if (bits <= 32)
+ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ else
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ slave_config->direction = DMA_MEM_TO_DEV;
+ slave_config->dst_addr_width = buswidth;
+ } else {
+ slave_config->direction = DMA_DEV_TO_MEM;
+ slave_config->src_addr_width = buswidth;
+ }
+
+ slave_config->device_fc = false;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
+
+/**
+ * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
+ * using DAI DMA data.
+ * @substream: PCM substream
+ * @dma_data: DAI DMA data
+ * @slave_config: DMA slave configuration
+ *
+ * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
+ * slave_id fields of the DMA slave config from the same fields of the DAI DMA
+ * data struct. The src and dst fields will be initialized depending on the
+ * direction of the substream. If the substream is a playback stream the dst
+ * fields will be initialized, if it is a capture stream the src fields will be
+ * initialized. The {dst,src}_addr_width field will only be initialized if the
+ * addr_width field of the DAI DMA data struct is not equal to
+ * DMA_SLAVE_BUSWIDTH_UNDEFINED.
+ */
+void snd_dmaengine_pcm_set_config_from_dai_data(
+ const struct snd_pcm_substream *substream,
+ const struct snd_dmaengine_dai_dma_data *dma_data,
+ struct dma_slave_config *slave_config)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ slave_config->dst_addr = dma_data->addr;
+ slave_config->dst_maxburst = dma_data->maxburst;
+ if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ slave_config->dst_addr_width = dma_data->addr_width;
+ } else {
+ slave_config->src_addr = dma_data->addr;
+ slave_config->src_maxburst = dma_data->maxburst;
+ if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+ slave_config->src_addr_width = dma_data->addr_width;
+ }
+
+ slave_config->slave_id = dma_data->slave_id;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
+
+static void dmaengine_pcm_dma_complete(void *arg)
+{
+ struct snd_pcm_substream *substream = arg;
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+ prtd->pos += snd_pcm_lib_period_bytes(substream);
+ if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
+ prtd->pos = 0;
+
+ snd_pcm_period_elapsed(substream);
+}
+
+static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ struct dma_chan *chan = prtd->dma_chan;
+ struct dma_async_tx_descriptor *desc;
+ enum dma_transfer_direction direction;
+ unsigned long flags = DMA_CTRL_ACK;
+
+ direction = snd_pcm_substream_to_dma_direction(substream);
+
+ if (!substream->runtime->no_period_wakeup)
+ flags |= DMA_PREP_INTERRUPT;
+
+ prtd->pos = 0;
+ desc = dmaengine_prep_dma_cyclic(chan,
+ substream->runtime->dma_addr,
+ snd_pcm_lib_buffer_bytes(substream),
+ snd_pcm_lib_period_bytes(substream), direction, flags);
+
+ if (!desc)
+ return -ENOMEM;
+
+ desc->callback = dmaengine_pcm_dma_complete;
+ desc->callback_param = substream;
+ prtd->cookie = dmaengine_submit(desc);
+
+ return 0;
+}
+
+/**
+ * snd_dmaengine_pcm_trigger - dmaengine based PCM trigger implementation
+ * @substream: PCM substream
+ * @cmd: Trigger command
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function can be used as the PCM trigger callback for dmaengine based PCM
+ * driver implementations.
+ */
+int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ ret = dmaengine_pcm_prepare_and_submit(substream);
+ if (ret)
+ return ret;
+ dma_async_issue_pending(prtd->dma_chan);
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dmaengine_resume(prtd->dma_chan);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (runtime->info & SNDRV_PCM_INFO_PAUSE)
+ dmaengine_pause(prtd->dma_chan);
+ else
+ dmaengine_terminate_all(prtd->dma_chan);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ dmaengine_pause(prtd->dma_chan);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ dmaengine_terminate_all(prtd->dma_chan);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
+
+/**
+ * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function is deprecated and should not be used by new drivers, as its
+ * results may be unreliable.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ return bytes_to_frames(substream->runtime, prtd->pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
+
+/**
+ * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function can be used as the PCM pointer callback for dmaengine based PCM
+ * driver implementations.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ struct dma_tx_state state;
+ enum dma_status status;
+ unsigned int buf_size;
+ unsigned int pos = 0;
+
+ status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+ if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
+ buf_size = snd_pcm_lib_buffer_bytes(substream);
+ if (state.residue > 0 && state.residue <= buf_size)
+ pos = buf_size - state.residue;
+ }
+
+ return bytes_to_frames(substream->runtime, pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
+
+/**
+ * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns NULL or the requested DMA channel.
+ *
+ * This function request a DMA channel for usage with dmaengine PCM.
+ */
+struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
+ void *filter_data)
+{
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_CYCLIC, mask);
+
+ return dma_request_channel(mask, filter_fn, filter_data);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
+
+/**
+ * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
+ * @substream: PCM substream
+ * @chan: DMA channel to use for data transfers
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * The function should usually be called from the pcm open callback. Note that
+ * this function will use private_data field of the substream's runtime. So it
+ * is not availabe to your pcm driver implementation.
+ */
+int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
+ struct dma_chan *chan)
+{
+ struct dmaengine_pcm_runtime_data *prtd;
+ int ret;
+
+ if (!chan)
+ return -ENXIO;
+
+ ret = snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ return ret;
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (!prtd)
+ return -ENOMEM;
+
+ prtd->dma_chan = chan;
+
+ substream->runtime->private_data = prtd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
+
+/**
+ * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
+ * @substream: PCM substream
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function will request a DMA channel using the passed filter function and
+ * data. The function should usually be called from the pcm open callback. Note
+ * that this function will use private_data field of the substream's runtime. So
+ * it is not availabe to your pcm driver implementation.
+ */
+int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
+ dma_filter_fn filter_fn, void *filter_data)
+{
+ return snd_dmaengine_pcm_open(substream,
+ snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
+
+/**
+ * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
+ * @substream: PCM substream
+ */
+int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+ kfree(prtd);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
+
+/**
+ * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
+ * @substream: PCM substream
+ *
+ * Releases the DMA channel associated with the PCM substream.
+ */
+int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+ dma_release_channel(prtd->dma_chan);
+
+ return snd_dmaengine_pcm_close(substream);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 0503980c23d..9acc77eae48 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Abramo Bagnara <abramo@alsa-project.org>
*
*
@@ -20,11 +20,13 @@
*
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -39,9 +41,9 @@
*
* when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
*/
-void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t new_hw_ptr)
+void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t frames, ofs, transfer;
if (runtime->silence_size < runtime->boundary) {
@@ -56,9 +58,8 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
runtime->silence_filled = 0;
runtime->silence_start = runtime->control->appl_ptr;
}
- if (runtime->silence_filled == runtime->buffer_size)
+ if (runtime->silence_filled >= runtime->buffer_size)
return;
- snd_assert(runtime->silence_filled <= runtime->buffer_size, return);
noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
return;
@@ -68,6 +69,8 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
} else {
if (new_hw_ptr == ULONG_MAX) { /* initialization */
snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
+ if (avail > runtime->buffer_size)
+ avail = runtime->buffer_size;
runtime->silence_filled = avail > 0 ? avail : 0;
runtime->silence_start = (runtime->status->hw_ptr +
runtime->silence_filled) %
@@ -80,19 +83,18 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
runtime->silence_filled -= frames;
if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
runtime->silence_filled = 0;
- runtime->silence_start = (ofs + frames) - runtime->buffer_size;
+ runtime->silence_start = new_hw_ptr;
} else {
- runtime->silence_start = ofs - runtime->silence_filled;
+ runtime->silence_start = ofs;
}
- if ((snd_pcm_sframes_t)runtime->silence_start < 0)
- runtime->silence_start += runtime->boundary;
}
frames = runtime->buffer_size - runtime->silence_filled;
}
- snd_assert(frames <= runtime->buffer_size, return);
+ if (snd_BUG_ON(frames > runtime->buffer_size))
+ return;
if (frames == 0)
return;
- ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
+ ofs = runtime->silence_start % runtime->buffer_size;
while (frames > 0) {
transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
@@ -100,7 +102,7 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
if (substream->ops->silence) {
int err;
err = substream->ops->silence(substream, -1, ofs, transfer);
- snd_assert(err >= 0, );
+ snd_BUG_ON(err < 0);
} else {
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
@@ -112,7 +114,7 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
for (c = 0; c < channels; ++c) {
int err;
err = substream->ops->silence(substream, c, ofs, transfer);
- snd_assert(err >= 0, );
+ snd_BUG_ON(err < 0);
}
} else {
size_t dma_csize = runtime->dma_bytes / channels;
@@ -128,43 +130,152 @@ void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t
}
}
-static void xrun(snd_pcm_substream_t *substream)
+#ifdef CONFIG_SND_DEBUG
+void snd_pcm_debug_name(struct snd_pcm_substream *substream,
+ char *name, size_t len)
+{
+ snprintf(name, len, "pcmC%dD%d%c:%d",
+ substream->pcm->card->number,
+ substream->pcm->device,
+ substream->stream ? 'c' : 'p',
+ substream->number);
+}
+EXPORT_SYMBOL(snd_pcm_debug_name);
+#endif
+
+#define XRUN_DEBUG_BASIC (1<<0)
+#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
+#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
+#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
+#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
+#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
+#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
+
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+
+#define xrun_debug(substream, mask) \
+ ((substream)->pstr->xrun_debug & (mask))
+#else
+#define xrun_debug(substream, mask) 0
+#endif
+
+#define dump_stack_on_xrun(substream) do { \
+ if (xrun_debug(substream, XRUN_DEBUG_STACK)) \
+ dump_stack(); \
+ } while (0)
+
+static void xrun(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-#ifdef CONFIG_SND_DEBUG
- if (substream->pstr->xrun_debug) {
- snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
- substream->pcm->card->number,
- substream->pcm->device,
- substream->stream ? 'c' : 'p');
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
+ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
+ char name[16];
+ snd_pcm_debug_name(substream, name, sizeof(name));
+ pcm_warn(substream->pcm, "XRUN: %s\n", name);
+ dump_stack_on_xrun(substream);
}
-#endif
}
-static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(snd_pcm_substream_t *substream,
- snd_pcm_runtime_t *runtime)
-{
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define hw_ptr_error(substream, fmt, args...) \
+ do { \
+ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
+ xrun_log_show(substream); \
+ pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \
+ dump_stack_on_xrun(substream); \
+ } \
+ } while (0)
+
+#define XRUN_LOG_CNT 10
+
+struct hwptr_log_entry {
+ unsigned int in_interrupt;
+ unsigned long jiffies;
snd_pcm_uframes_t pos;
+ snd_pcm_uframes_t period_size;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t old_hw_ptr;
+ snd_pcm_uframes_t hw_ptr_base;
+};
+
+struct snd_pcm_hwptr_log {
+ unsigned int idx;
+ unsigned int hit: 1;
+ struct hwptr_log_entry entries[XRUN_LOG_CNT];
+};
+
+static void xrun_log(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t pos, int in_interrupt)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
+ struct hwptr_log_entry *entry;
+
+ if (log == NULL) {
+ log = kzalloc(sizeof(*log), GFP_ATOMIC);
+ if (log == NULL)
+ return;
+ runtime->hwptr_log = log;
+ } else {
+ if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
+ return;
+ }
+ entry = &log->entries[log->idx];
+ entry->in_interrupt = in_interrupt;
+ entry->jiffies = jiffies;
+ entry->pos = pos;
+ entry->period_size = runtime->period_size;
+ entry->buffer_size = runtime->buffer_size;
+ entry->old_hw_ptr = runtime->status->hw_ptr;
+ entry->hw_ptr_base = runtime->hw_ptr_base;
+ log->idx = (log->idx + 1) % XRUN_LOG_CNT;
+}
- pos = substream->ops->pointer(substream);
- if (pos == SNDRV_PCM_POS_XRUN)
- return pos; /* XRUN */
- if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
- snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
-#ifdef CONFIG_SND_DEBUG
- if (pos >= runtime->buffer_size) {
- snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
- } else
-#endif
- snd_runtime_check(pos < runtime->buffer_size, return 0);
- pos -= pos % runtime->min_align;
- return pos;
+static void xrun_log_show(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
+ struct hwptr_log_entry *entry;
+ char name[16];
+ unsigned int idx;
+ int cnt;
+
+ if (log == NULL)
+ return;
+ if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
+ return;
+ snd_pcm_debug_name(substream, name, sizeof(name));
+ for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
+ entry = &log->entries[idx];
+ if (entry->period_size == 0)
+ break;
+ pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
+ "hwptr=%ld/%ld\n",
+ name, entry->in_interrupt ? "[Q] " : "",
+ entry->jiffies,
+ (unsigned long)entry->pos,
+ (unsigned long)entry->period_size,
+ (unsigned long)entry->buffer_size,
+ (unsigned long)entry->old_hw_ptr,
+ (unsigned long)entry->hw_ptr_base);
+ idx++;
+ idx %= XRUN_LOG_CNT;
+ }
+ log->hit = 1;
}
-static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream,
- snd_pcm_runtime_t *runtime)
+#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
+
+#define hw_ptr_error(substream, fmt, args...) do { } while (0)
+#define xrun_log(substream, pos, in_interrupt) do { } while (0)
+#define xrun_log_show(substream) do { } while (0)
+
+#endif
+
+int snd_pcm_update_state(struct snd_pcm_substream *substream,
+ struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t avail;
@@ -174,104 +285,277 @@ static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream,
avail = snd_pcm_capture_avail(runtime);
if (avail > runtime->avail_max)
runtime->avail_max = avail;
- if (avail >= runtime->stop_threshold) {
- if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+ if (avail >= runtime->buffer_size) {
snd_pcm_drain_done(substream);
- else
+ return -EPIPE;
+ }
+ } else {
+ if (avail >= runtime->stop_threshold) {
xrun(substream);
- return -EPIPE;
+ return -EPIPE;
+ }
}
- if (avail >= runtime->control->avail_min)
+ if (runtime->twake) {
+ if (avail >= runtime->twake)
+ wake_up(&runtime->tsleep);
+ } else if (avail >= runtime->control->avail_min)
wake_up(&runtime->sleep);
return 0;
}
-static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream)
+static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
+ unsigned int in_interrupt)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
- snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
- snd_pcm_sframes_t delta;
+ snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
+ snd_pcm_sframes_t hdelta, delta;
+ unsigned long jdelta;
+ unsigned long curr_jiffies;
+ struct timespec curr_tstamp;
+ struct timespec audio_tstamp;
+ int crossed_boundary = 0;
+
+ old_hw_ptr = runtime->status->hw_ptr;
+
+ /*
+ * group pointer, time and jiffies reads to allow for more
+ * accurate correlations/corrections.
+ * The values are stored at the end of this routine after
+ * corrections for hw_ptr position
+ */
+ pos = substream->ops->pointer(substream);
+ curr_jiffies = jiffies;
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+ snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+
+ if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
+ (substream->ops->wall_clock))
+ substream->ops->wall_clock(substream, &audio_tstamp);
+ }
- pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
if (pos == SNDRV_PCM_POS_XRUN) {
xrun(substream);
return -EPIPE;
}
- if (runtime->period_size == runtime->buffer_size)
- goto __next_buf;
- new_hw_ptr = runtime->hw_ptr_base + pos;
- hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
-
- delta = hw_ptr_interrupt - new_hw_ptr;
- if (delta > 0) {
- if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_DEBUG
- if (runtime->periods > 1 && substream->pstr->xrun_debug) {
- snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
+ if (pos >= runtime->buffer_size) {
+ if (printk_ratelimit()) {
+ char name[16];
+ snd_pcm_debug_name(substream, name, sizeof(name));
+ xrun_log_show(substream);
+ pcm_err(substream->pcm,
+ "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+ name, pos, runtime->buffer_size,
+ runtime->period_size);
+ }
+ pos = 0;
+ }
+ pos -= pos % runtime->min_align;
+ if (xrun_debug(substream, XRUN_DEBUG_LOG))
+ xrun_log(substream, pos, in_interrupt);
+ hw_base = runtime->hw_ptr_base;
+ new_hw_ptr = hw_base + pos;
+ if (in_interrupt) {
+ /* we know that one period was processed */
+ /* delta = "expected next hw_ptr" for in_interrupt != 0 */
+ delta = runtime->hw_ptr_interrupt + runtime->period_size;
+ if (delta > new_hw_ptr) {
+ /* check for double acknowledged interrupts */
+ hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
+ if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary) {
+ hw_base = 0;
+ crossed_boundary++;
+ }
+ new_hw_ptr = hw_base + pos;
+ goto __delta;
}
-#endif
- return 0;
}
- __next_buf:
- runtime->hw_ptr_base += runtime->buffer_size;
- if (runtime->hw_ptr_base == runtime->boundary)
- runtime->hw_ptr_base = 0;
- new_hw_ptr = runtime->hw_ptr_base + pos;
}
+ /* new_hw_ptr might be lower than old_hw_ptr in case when */
+ /* pointer crosses the end of the ring buffer */
+ if (new_hw_ptr < old_hw_ptr) {
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary) {
+ hw_base = 0;
+ crossed_boundary++;
+ }
+ new_hw_ptr = hw_base + pos;
+ }
+ __delta:
+ delta = new_hw_ptr - old_hw_ptr;
+ if (delta < 0)
+ delta += runtime->boundary;
+ if (xrun_debug(substream, in_interrupt ?
+ XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
+ char name[16];
+ snd_pcm_debug_name(substream, name, sizeof(name));
+ pcm_dbg(substream->pcm,
+ "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n",
+ in_interrupt ? "period" : "hwptr",
+ name,
+ (unsigned int)pos,
+ (unsigned int)runtime->period_size,
+ (unsigned int)runtime->buffer_size,
+ (unsigned long)delta,
+ (unsigned long)old_hw_ptr,
+ (unsigned long)new_hw_ptr,
+ (unsigned long)runtime->hw_ptr_base);
+ }
+
+ if (runtime->no_period_wakeup) {
+ snd_pcm_sframes_t xrun_threshold;
+ /*
+ * Without regular period interrupts, we have to check
+ * the elapsed time to detect xruns.
+ */
+ jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
+ if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
+ goto no_delta_check;
+ hdelta = jdelta - delta * HZ / runtime->rate;
+ xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
+ while (hdelta > xrun_threshold) {
+ delta += runtime->buffer_size;
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary) {
+ hw_base = 0;
+ crossed_boundary++;
+ }
+ new_hw_ptr = hw_base + pos;
+ hdelta -= runtime->hw_ptr_buffer_jiffies;
+ }
+ goto no_delta_check;
+ }
+
+ /* something must be really wrong */
+ if (delta >= runtime->buffer_size + runtime->period_size) {
+ hw_ptr_error(substream,
+ "Unexpected hw_pointer value %s"
+ "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
+ "old_hw_ptr=%ld)\n",
+ in_interrupt ? "[Q] " : "[P]",
+ substream->stream, (long)pos,
+ (long)new_hw_ptr, (long)old_hw_ptr);
+ return 0;
+ }
+
+ /* Do jiffies check only in xrun_debug mode */
+ if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
+ goto no_jiffies_check;
+
+ /* Skip the jiffies check for hardwares with BATCH flag.
+ * Such hardware usually just increases the position at each IRQ,
+ * thus it can't give any strange position.
+ */
+ if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
+ goto no_jiffies_check;
+ hdelta = delta;
+ if (hdelta < runtime->delay)
+ goto no_jiffies_check;
+ hdelta -= runtime->delay;
+ jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
+ if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
+ delta = jdelta /
+ (((runtime->period_size * HZ) / runtime->rate)
+ + HZ/100);
+ /* move new_hw_ptr according jiffies not pos variable */
+ new_hw_ptr = old_hw_ptr;
+ hw_base = delta;
+ /* use loop to avoid checks for delta overflows */
+ /* the delta value is small or zero in most cases */
+ while (delta > 0) {
+ new_hw_ptr += runtime->period_size;
+ if (new_hw_ptr >= runtime->boundary) {
+ new_hw_ptr -= runtime->boundary;
+ crossed_boundary--;
+ }
+ delta--;
+ }
+ /* align hw_base to buffer_size */
+ hw_ptr_error(substream,
+ "hw_ptr skipping! %s"
+ "(pos=%ld, delta=%ld, period=%ld, "
+ "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
+ in_interrupt ? "[Q] " : "",
+ (long)pos, (long)hdelta,
+ (long)runtime->period_size, jdelta,
+ ((hdelta * HZ) / runtime->rate), hw_base,
+ (unsigned long)old_hw_ptr,
+ (unsigned long)new_hw_ptr);
+ /* reset values to proper state */
+ delta = 0;
+ hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
+ }
+ no_jiffies_check:
+ if (delta > runtime->period_size + runtime->period_size / 2) {
+ hw_ptr_error(substream,
+ "Lost interrupts? %s"
+ "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
+ "old_hw_ptr=%ld)\n",
+ in_interrupt ? "[Q] " : "",
+ substream->stream, (long)delta,
+ (long)new_hw_ptr,
+ (long)old_hw_ptr);
+ }
+
+ no_delta_check:
+ if (runtime->status->hw_ptr == new_hw_ptr)
+ return 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
+ if (in_interrupt) {
+ delta = new_hw_ptr - runtime->hw_ptr_interrupt;
+ if (delta < 0)
+ delta += runtime->boundary;
+ delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
+ runtime->hw_ptr_interrupt += delta;
+ if (runtime->hw_ptr_interrupt >= runtime->boundary)
+ runtime->hw_ptr_interrupt -= runtime->boundary;
+ }
+ runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
- runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
+ runtime->hw_ptr_jiffies = curr_jiffies;
+ if (crossed_boundary) {
+ snd_BUG_ON(crossed_boundary != 1);
+ runtime->hw_ptr_wrap += runtime->boundary;
+ }
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+ runtime->status->tstamp = curr_tstamp;
+
+ if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
+ /*
+ * no wall clock available, provide audio timestamp
+ * derived from pointer position+delay
+ */
+ u64 audio_frames, audio_nsecs;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_frames = runtime->hw_ptr_wrap
+ + runtime->status->hw_ptr
+ - runtime->delay;
+ else
+ audio_frames = runtime->hw_ptr_wrap
+ + runtime->status->hw_ptr
+ + runtime->delay;
+ audio_nsecs = div_u64(audio_frames * 1000000000LL,
+ runtime->rate);
+ audio_tstamp = ns_to_timespec(audio_nsecs);
+ }
+ runtime->status->audio_tstamp = audio_tstamp;
+ }
- return snd_pcm_update_hw_ptr_post(substream, runtime);
+ return snd_pcm_update_state(substream, runtime);
}
/* CAUTION: call it with irq disabled */
-int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
+int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_uframes_t pos;
- snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
- snd_pcm_sframes_t delta;
-
- old_hw_ptr = runtime->status->hw_ptr;
- pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
- if (pos == SNDRV_PCM_POS_XRUN) {
- xrun(substream);
- return -EPIPE;
- }
- new_hw_ptr = runtime->hw_ptr_base + pos;
-
- delta = old_hw_ptr - new_hw_ptr;
- if (delta > 0) {
- if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_DEBUG
- if (runtime->periods > 2 && substream->pstr->xrun_debug) {
- snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
- }
-#endif
- return 0;
- }
- runtime->hw_ptr_base += runtime->buffer_size;
- if (runtime->hw_ptr_base == runtime->boundary)
- runtime->hw_ptr_base = 0;
- new_hw_ptr = runtime->hw_ptr_base + pos;
- }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, new_hw_ptr);
-
- runtime->status->hw_ptr = new_hw_ptr;
-
- return snd_pcm_update_hw_ptr_post(substream, runtime);
+ return snd_pcm_update_hw_ptr0(substream, 0);
}
/**
@@ -282,15 +566,17 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
*
* Sets the given PCM operators to the pcm instance.
*/
-void snd_pcm_set_ops(snd_pcm_t *pcm, int direction, snd_pcm_ops_t *ops)
+void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
+ const struct snd_pcm_ops *ops)
{
- snd_pcm_str_t *stream = &pcm->streams[direction];
- snd_pcm_substream_t *substream;
+ struct snd_pcm_str *stream = &pcm->streams[direction];
+ struct snd_pcm_substream *substream;
for (substream = stream->substream; substream != NULL; substream = substream->next)
substream->ops = ops;
}
+EXPORT_SYMBOL(snd_pcm_set_ops);
/**
* snd_pcm_sync - set the PCM sync id
@@ -298,9 +584,9 @@ void snd_pcm_set_ops(snd_pcm_t *pcm, int direction, snd_pcm_ops_t *ops)
*
* Sets the PCM sync identifier for the card.
*/
-void snd_pcm_set_sync(snd_pcm_substream_t * substream)
+void snd_pcm_set_sync(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
runtime->sync.id32[0] = substream->pcm->card->number;
runtime->sync.id32[1] = -1;
@@ -308,13 +594,12 @@ void snd_pcm_set_sync(snd_pcm_substream_t * substream)
runtime->sync.id32[3] = -1;
}
+EXPORT_SYMBOL(snd_pcm_set_sync);
+
/*
* Standard ioctl routine
*/
-/* Code taken from alsa-lib */
-#define assert(a) snd_assert((a), return -EINVAL)
-
static inline unsigned int div32(unsigned int a, unsigned int b,
unsigned int *r)
{
@@ -359,11 +644,11 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
{
u_int64_t n = (u_int64_t) a * b;
if (c == 0) {
- snd_assert(n > 0, );
+ snd_BUG_ON(!n);
*r = 0;
return UINT_MAX;
}
- div64_32(&n, c, r);
+ n = div_u64_rem(n, c, r);
if (n >= UINT_MAX) {
*r = 0;
return UINT_MAX;
@@ -371,56 +656,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
return n;
}
-static int snd_interval_refine_min(snd_interval_t *i, unsigned int min, int openmin)
-{
- int changed = 0;
- assert(!snd_interval_empty(i));
- if (i->min < min) {
- i->min = min;
- i->openmin = openmin;
- changed = 1;
- } else if (i->min == min && !i->openmin && openmin) {
- i->openmin = 1;
- changed = 1;
- }
- if (i->integer) {
- if (i->openmin) {
- i->min++;
- i->openmin = 0;
- }
- }
- if (snd_interval_checkempty(i)) {
- snd_interval_none(i);
- return -EINVAL;
- }
- return changed;
-}
-
-static int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int openmax)
-{
- int changed = 0;
- assert(!snd_interval_empty(i));
- if (i->max > max) {
- i->max = max;
- i->openmax = openmax;
- changed = 1;
- } else if (i->max == max && !i->openmax && openmax) {
- i->openmax = 1;
- changed = 1;
- }
- if (i->integer) {
- if (i->openmax) {
- i->max--;
- i->openmax = 0;
- }
- }
- if (snd_interval_checkempty(i)) {
- snd_interval_none(i);
- return -EINVAL;
- }
- return changed;
-}
-
/**
* snd_interval_refine - refine the interval value of configurator
* @i: the interval value to refine
@@ -430,12 +665,14 @@ static int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int open
* The interval is changed to the range satisfying both intervals.
* The interval status (min, max, integer, etc.) are evaluated.
*
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v)
+int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
{
int changed = 0;
- assert(!snd_interval_empty(i));
+ if (snd_BUG_ON(snd_interval_empty(i)))
+ return -EINVAL;
if (i->min < v->min) {
i->min = v->min;
i->openmin = v->openmin;
@@ -474,9 +711,12 @@ int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v)
return changed;
}
-static int snd_interval_refine_first(snd_interval_t *i)
+EXPORT_SYMBOL(snd_interval_refine);
+
+static int snd_interval_refine_first(struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
+ if (snd_BUG_ON(snd_interval_empty(i)))
+ return -EINVAL;
if (snd_interval_single(i))
return 0;
i->max = i->min;
@@ -486,9 +726,10 @@ static int snd_interval_refine_first(snd_interval_t *i)
return 1;
}
-static int snd_interval_refine_last(snd_interval_t *i)
+static int snd_interval_refine_last(struct snd_interval *i)
{
- assert(!snd_interval_empty(i));
+ if (snd_BUG_ON(snd_interval_empty(i)))
+ return -EINVAL;
if (snd_interval_single(i))
return 0;
i->min = i->max;
@@ -498,17 +739,7 @@ static int snd_interval_refine_last(snd_interval_t *i)
return 1;
}
-static int snd_interval_refine_set(snd_interval_t *i, unsigned int val)
-{
- snd_interval_t t;
- t.empty = 0;
- t.min = t.max = val;
- t.openmin = t.openmax = 0;
- t.integer = 1;
- return snd_interval_refine(i, &t);
-}
-
-void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c)
+void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
{
if (a->empty || b->empty) {
snd_interval_none(c);
@@ -532,7 +763,7 @@ void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_inte
*
* Returns non-zero if the value is changed, zero if not changed.
*/
-void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c)
+void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
{
unsigned int r;
if (a->empty || b->empty) {
@@ -567,8 +798,8 @@ void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_inte
*
* Returns non-zero if the value is changed, zero if not changed.
*/
-void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b,
- unsigned int k, snd_interval_t *c)
+void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b,
+ unsigned int k, struct snd_interval *c)
{
unsigned int r;
if (a->empty || b->empty) {
@@ -598,8 +829,8 @@ void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b,
*
* Returns non-zero if the value is changed, zero if not changed.
*/
-void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k,
- const snd_interval_t *b, snd_interval_t *c)
+void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
+ const struct snd_interval *b, struct snd_interval *c)
{
unsigned int r;
if (a->empty || b->empty) {
@@ -623,7 +854,6 @@ void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k,
c->integer = 0;
}
-#undef assert
/* ---- */
@@ -635,16 +865,20 @@ void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k,
* @nump: pointer to store the resultant numerator
* @denp: pointer to store the resultant denominator
*
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-int snd_interval_ratnum(snd_interval_t *i,
- unsigned int rats_count, ratnum_t *rats,
- unsigned int *nump, unsigned int *denp)
+int snd_interval_ratnum(struct snd_interval *i,
+ unsigned int rats_count, struct snd_ratnum *rats,
+ unsigned int *nump, unsigned int *denp)
{
- unsigned int best_num, best_diff, best_den;
+ unsigned int best_num, best_den;
+ int best_diff;
unsigned int k;
- snd_interval_t t;
+ struct snd_interval t;
int err;
+ unsigned int result_num, result_den;
+ int result_diff;
best_num = best_den = best_diff = 0;
for (k = 0; k < rats_count; ++k) {
@@ -654,7 +888,7 @@ int snd_interval_ratnum(snd_interval_t *i,
int diff;
if (q == 0)
q = 1;
- den = div_down(num, q);
+ den = div_up(num, q);
if (den < rats[k].den_min)
continue;
if (den > rats[k].den_max)
@@ -666,6 +900,8 @@ int snd_interval_ratnum(snd_interval_t *i,
den -= r;
}
diff = num - q * den;
+ if (diff < 0)
+ diff = -diff;
if (best_num == 0 ||
diff * best_den < best_diff * den) {
best_diff = diff;
@@ -680,6 +916,9 @@ int snd_interval_ratnum(snd_interval_t *i,
t.min = div_down(best_num, best_den);
t.openmin = !!(best_num % best_den);
+ result_num = best_num;
+ result_diff = best_diff;
+ result_den = best_den;
best_num = best_den = best_diff = 0;
for (k = 0; k < rats_count; ++k) {
unsigned int num = rats[k].num;
@@ -690,7 +929,7 @@ int snd_interval_ratnum(snd_interval_t *i,
i->empty = 1;
return -EINVAL;
}
- den = div_up(num, q);
+ den = div_down(num, q);
if (den > rats[k].den_max)
continue;
if (den < rats[k].den_min)
@@ -702,6 +941,8 @@ int snd_interval_ratnum(snd_interval_t *i,
den += rats[k].den_step - r;
}
diff = q * den - num;
+ if (diff < 0)
+ diff = -diff;
if (best_num == 0 ||
diff * best_den < best_diff * den) {
best_diff = diff;
@@ -721,31 +962,38 @@ int snd_interval_ratnum(snd_interval_t *i,
return err;
if (snd_interval_single(i)) {
+ if (best_diff * result_den < result_diff * best_den) {
+ result_num = best_num;
+ result_den = best_den;
+ }
if (nump)
- *nump = best_num;
+ *nump = result_num;
if (denp)
- *denp = best_den;
+ *denp = result_den;
}
return err;
}
+EXPORT_SYMBOL(snd_interval_ratnum);
+
/**
* snd_interval_ratden - refine the interval value
* @i: interval to refine
- * @rats_count: number of ratden_t
- * @rats: ratden_t array
+ * @rats_count: number of struct ratden
+ * @rats: struct ratden array
* @nump: pointer to store the resultant numerator
* @denp: pointer to store the resultant denominator
*
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-static int snd_interval_ratden(snd_interval_t *i,
- unsigned int rats_count, ratden_t *rats,
+static int snd_interval_ratden(struct snd_interval *i,
+ unsigned int rats_count, struct snd_ratden *rats,
unsigned int *nump, unsigned int *denp)
{
unsigned int best_num, best_diff, best_den;
unsigned int k;
- snd_interval_t t;
+ struct snd_interval t;
int err;
best_num = best_den = best_diff = 0;
@@ -836,50 +1084,36 @@ static int snd_interval_ratden(snd_interval_t *i,
* When mask is non-zero, only the elements corresponding to bit 1 are
* evaluated.
*
- * Returns non-zero if the value is changed, zero if not changed.
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-int snd_interval_list(snd_interval_t *i, unsigned int count, unsigned int *list, unsigned int mask)
+int snd_interval_list(struct snd_interval *i, unsigned int count,
+ const unsigned int *list, unsigned int mask)
{
unsigned int k;
- int changed = 0;
+ struct snd_interval list_range;
+
+ if (!count) {
+ i->empty = 1;
+ return -EINVAL;
+ }
+ snd_interval_any(&list_range);
+ list_range.min = UINT_MAX;
+ list_range.max = 0;
for (k = 0; k < count; k++) {
if (mask && !(mask & (1 << k)))
continue;
- if (i->min == list[k] && !i->openmin)
- goto _l1;
- if (i->min < list[k]) {
- i->min = list[k];
- i->openmin = 0;
- changed = 1;
- goto _l1;
- }
- }
- i->empty = 1;
- return -EINVAL;
- _l1:
- for (k = count; k-- > 0;) {
- if (mask && !(mask & (1 << k)))
+ if (!snd_interval_test(i, list[k]))
continue;
- if (i->max == list[k] && !i->openmax)
- goto _l2;
- if (i->max > list[k]) {
- i->max = list[k];
- i->openmax = 0;
- changed = 1;
- goto _l2;
- }
+ list_range.min = min(list_range.min, list[k]);
+ list_range.max = max(list_range.max, list[k]);
}
- i->empty = 1;
- return -EINVAL;
- _l2:
- if (snd_interval_checkempty(i)) {
- i->empty = 1;
- return -EINVAL;
- }
- return changed;
+ return snd_interval_refine(i, &list_range);
}
-static int snd_interval_step(snd_interval_t *i, unsigned int min, unsigned int step)
+EXPORT_SYMBOL(snd_interval_list);
+
+static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
{
unsigned int n;
int changed = 0;
@@ -911,24 +1145,26 @@ static int snd_interval_step(snd_interval_t *i, unsigned int min, unsigned int s
* @private: the private data pointer passed to function
* @dep: the dependent variables
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, unsigned int cond,
+int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
int var,
snd_pcm_hw_rule_func_t func, void *private,
int dep, ...)
{
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
- snd_pcm_hw_rule_t *c;
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
+ struct snd_pcm_hw_rule *c;
unsigned int k;
va_list args;
va_start(args, dep);
if (constrs->rules_num >= constrs->rules_all) {
- snd_pcm_hw_rule_t *new;
+ struct snd_pcm_hw_rule *new;
unsigned int new_rules = constrs->rules_all + 16;
new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
- if (!new)
+ if (!new) {
+ va_end(args);
return -ENOMEM;
+ }
if (constrs->rules) {
memcpy(new, constrs->rules,
constrs->rules_num * sizeof(*c));
@@ -944,7 +1180,10 @@ int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, unsigned int cond,
c->private = private;
k = 0;
while (1) {
- snd_assert(k < ARRAY_SIZE(c->deps), return -EINVAL);
+ if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) {
+ va_end(args);
+ return -EINVAL;
+ }
c->deps[k++] = dep;
if (dep < 0)
break;
@@ -953,21 +1192,25 @@ int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, unsigned int cond,
constrs->rules_num++;
va_end(args);
return 0;
-}
+}
+
+EXPORT_SYMBOL(snd_pcm_hw_rule_add);
/**
- * snd_pcm_hw_constraint_mask
+ * snd_pcm_hw_constraint_mask - apply the given bitmap mask constraint
* @runtime: PCM runtime instance
* @var: hw_params variable to apply the mask
* @mask: the bitmap mask
*
- * Apply the constraint of the given bitmap mask to a mask parameter.
+ * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
+int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
u_int32_t mask)
{
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
- snd_mask_t *maskp = constrs_mask(constrs, var);
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
+ struct snd_mask *maskp = constrs_mask(constrs, var);
*maskp->bits &= mask;
memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
if (*maskp->bits == 0)
@@ -976,18 +1219,20 @@ int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t va
}
/**
- * snd_pcm_hw_constraint_mask64
+ * snd_pcm_hw_constraint_mask64 - apply the given bitmap mask constraint
* @runtime: PCM runtime instance
* @var: hw_params variable to apply the mask
* @mask: the 64bit bitmap mask
*
- * Apply the constraint of the given bitmap mask to a mask parameter.
+ * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
+int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
u_int64_t mask)
{
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
- snd_mask_t *maskp = constrs_mask(constrs, var);
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
+ struct snd_mask *maskp = constrs_mask(constrs, var);
maskp->bits[0] &= (u_int32_t)mask;
maskp->bits[1] &= (u_int32_t)(mask >> 32);
memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
@@ -995,34 +1240,43 @@ int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t
return -EINVAL;
return 0;
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64);
/**
- * snd_pcm_hw_constraint_integer
+ * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
* @runtime: PCM runtime instance
* @var: hw_params variable to apply the integer constraint
*
* Apply the constraint of integer to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-int snd_pcm_hw_constraint_integer(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var)
+int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
{
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
return snd_interval_setinteger(constrs_interval(constrs, var));
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+
/**
- * snd_pcm_hw_constraint_minmax
+ * snd_pcm_hw_constraint_minmax - apply a min/max range constraint to an interval
* @runtime: PCM runtime instance
* @var: hw_params variable to apply the range
* @min: the minimal value
* @max: the maximal value
*
* Apply the min/max range constraint to an interval parameter.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
*/
-int snd_pcm_hw_constraint_minmax(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
+int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
unsigned int min, unsigned int max)
{
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
- snd_interval_t t;
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
+ struct snd_interval t;
t.min = min;
t.max = max;
t.openmin = t.openmax = 0;
@@ -1030,37 +1284,43 @@ int snd_pcm_hw_constraint_minmax(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t
return snd_interval_refine(constrs_interval(constrs, var), &t);
}
-static int snd_pcm_hw_rule_list(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
+
+static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_pcm_hw_constraint_list_t *list = rule->private;
+ struct snd_pcm_hw_constraint_list *list = rule->private;
return snd_interval_list(hw_param_interval(params, rule->var), list->count, list->list, list->mask);
}
/**
- * snd_pcm_hw_constraint_list
+ * snd_pcm_hw_constraint_list - apply a list of constraints to a parameter
* @runtime: PCM runtime instance
* @cond: condition bits
* @var: hw_params variable to apply the list constraint
* @l: list
*
* Apply the list of constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_list(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
- snd_pcm_hw_constraint_list_t *l)
+ const struct snd_pcm_hw_constraint_list *l)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
- snd_pcm_hw_rule_list, l,
+ snd_pcm_hw_rule_list, (void *)l,
var, -1);
}
-static int snd_pcm_hw_rule_ratnums(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
+
+static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_pcm_hw_constraint_ratnums_t *r = rule->private;
+ struct snd_pcm_hw_constraint_ratnums *r = rule->private;
unsigned int num = 0, den = 0;
int err;
err = snd_interval_ratnum(hw_param_interval(params, rule->var),
@@ -1073,26 +1333,30 @@ static int snd_pcm_hw_rule_ratnums(snd_pcm_hw_params_t *params,
}
/**
- * snd_pcm_hw_constraint_ratnums
+ * snd_pcm_hw_constraint_ratnums - apply ratnums constraint to a parameter
* @runtime: PCM runtime instance
* @cond: condition bits
* @var: hw_params variable to apply the ratnums constraint
- * @r: ratnums_t constriants
+ * @r: struct snd_ratnums constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_ratnums(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
- snd_pcm_hw_constraint_ratnums_t *r)
+ struct snd_pcm_hw_constraint_ratnums *r)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
snd_pcm_hw_rule_ratnums, r,
var, -1);
}
-static int snd_pcm_hw_rule_ratdens(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
+
+static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_pcm_hw_constraint_ratdens_t *r = rule->private;
+ struct snd_pcm_hw_constraint_ratdens *r = rule->private;
unsigned int num = 0, den = 0;
int err = snd_interval_ratden(hw_param_interval(params, rule->var),
r->nrats, r->rats, &num, &den);
@@ -1104,42 +1368,48 @@ static int snd_pcm_hw_rule_ratdens(snd_pcm_hw_params_t *params,
}
/**
- * snd_pcm_hw_constraint_ratdens
+ * snd_pcm_hw_constraint_ratdens - apply ratdens constraint to a parameter
* @runtime: PCM runtime instance
* @cond: condition bits
* @var: hw_params variable to apply the ratdens constraint
- * @r: ratdens_t constriants
+ * @r: struct snd_ratdens constriants
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_ratdens(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
- snd_pcm_hw_constraint_ratdens_t *r)
+ struct snd_pcm_hw_constraint_ratdens *r)
{
return snd_pcm_hw_rule_add(runtime, cond, var,
snd_pcm_hw_rule_ratdens, r,
var, -1);
}
-static int snd_pcm_hw_rule_msbits(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
+
+static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
unsigned int l = (unsigned long) rule->private;
int width = l & 0xffff;
unsigned int msbits = l >> 16;
- snd_interval_t *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+ struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
if (snd_interval_single(i) && snd_interval_value(i) == width)
params->msbits = msbits;
return 0;
}
/**
- * snd_pcm_hw_constraint_msbits
+ * snd_pcm_hw_constraint_msbits - add a hw constraint msbits rule
* @runtime: PCM runtime instance
* @cond: condition bits
* @width: sample bits width
* @msbits: msbits width
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_msbits(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
unsigned int cond,
unsigned int width,
unsigned int msbits)
@@ -1151,21 +1421,25 @@ int snd_pcm_hw_constraint_msbits(snd_pcm_runtime_t *runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
}
-static int snd_pcm_hw_rule_step(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
+
+static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
unsigned long step = (unsigned long) rule->private;
return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
}
/**
- * snd_pcm_hw_constraint_step
+ * snd_pcm_hw_constraint_step - add a hw constraint step rule
* @runtime: PCM runtime instance
* @cond: condition bits
* @var: hw_params variable to apply the step constraint
* @step: step size
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var,
unsigned long step)
@@ -1175,9 +1449,11 @@ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime,
var, -1);
}
-static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
+
+static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
- static int pow2_sizes[] = {
+ static unsigned int pow2_sizes[] = {
1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
@@ -1188,12 +1464,14 @@ static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *
}
/**
- * snd_pcm_hw_constraint_pow2
+ * snd_pcm_hw_constraint_pow2 - add a hw constraint power-of-2 rule
* @runtime: PCM runtime instance
* @cond: condition bits
* @var: hw_params variable to apply the power-of-2 constraint
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var)
{
@@ -1202,14 +1480,37 @@ int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
var, -1);
}
-/* To use the same code we have in alsa-lib */
-#define snd_pcm_t snd_pcm_substream_t
-#define assert(i) snd_assert((i), return -EINVAL)
-#ifndef INT_MIN
-#define INT_MIN ((int)((unsigned int)INT_MAX+1))
-#endif
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
+
+static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
+ struct snd_interval *rate;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ return snd_interval_list(rate, 1, &base_rate, 0);
+}
+
+/**
+ * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
+ * @runtime: PCM runtime instance
+ * @base_rate: the rate at which the hardware does not resample
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
+ unsigned int base_rate)
+{
+ return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
+ SNDRV_PCM_HW_PARAM_RATE,
+ snd_pcm_hw_rule_noresample_func,
+ (void *)(uintptr_t)base_rate,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+}
+EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);
-static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params,
+static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
if (hw_is_mask(var)) {
@@ -1227,19 +1528,7 @@ static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params,
snd_BUG();
}
-#if 0
-/*
- * snd_pcm_hw_param_any
- */
-int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var)
-{
- _snd_pcm_hw_param_any(params, var);
- return snd_pcm_hw_refine(pcm, params);
-}
-#endif /* 0 */
-
-void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
+void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
{
unsigned int k;
memset(params, 0, sizeof(*params));
@@ -1250,33 +1539,22 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
params->info = ~0U;
}
-#if 0
-/*
- * snd_pcm_hw_params_any
- *
- * Fill PARAMS with full configuration space boundaries
- */
-int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
- _snd_pcm_hw_params_any(params);
- return snd_pcm_hw_refine(pcm, params);
-}
-#endif /* 0 */
+EXPORT_SYMBOL(_snd_pcm_hw_params_any);
/**
- * snd_pcm_hw_param_value
+ * snd_pcm_hw_param_value - return @params field @var value
* @params: the hw_params instance
* @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
+ * @dir: pointer to the direction (-1,0,1) or %NULL
*
- * Return the value for field PAR if it's fixed in configuration space
- * defined by PARAMS. Return -EINVAL otherwise
+ * Return: The value for field @var if it's fixed in configuration space
+ * defined by @params. -%EINVAL otherwise.
*/
-static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
if (hw_is_mask(var)) {
- const snd_mask_t *mask = hw_param_mask_c(params, var);
+ const struct snd_mask *mask = hw_param_mask_c(params, var);
if (!snd_mask_single(mask))
return -EINVAL;
if (dir)
@@ -1284,70 +1562,19 @@ static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params,
return snd_mask_value(mask);
}
if (hw_is_interval(var)) {
- const snd_interval_t *i = hw_param_interval_c(params, var);
+ const struct snd_interval *i = hw_param_interval_c(params, var);
if (!snd_interval_single(i))
return -EINVAL;
if (dir)
*dir = i->openmin;
return snd_interval_value(i);
}
- assert(0);
- return -EINVAL;
-}
-
-/**
- * snd_pcm_hw_param_value_min
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the minimum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
-{
- if (hw_is_mask(var)) {
- if (dir)
- *dir = 0;
- return snd_mask_min(hw_param_mask_c(params, var));
- }
- if (hw_is_interval(var)) {
- const snd_interval_t *i = hw_param_interval_c(params, var);
- if (dir)
- *dir = i->openmin;
- return snd_interval_min(i);
- }
- assert(0);
return -EINVAL;
}
-/**
- * snd_pcm_hw_param_value_max
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the maximum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_max(const snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
-{
- if (hw_is_mask(var)) {
- if (dir)
- *dir = 0;
- return snd_mask_max(hw_param_mask_c(params, var));
- }
- if (hw_is_interval(var)) {
- const snd_interval_t *i = hw_param_interval_c(params, var);
- if (dir)
- *dir = - (int) i->openmax;
- return snd_interval_max(i);
- }
- assert(0);
- return -EINVAL;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_value);
-void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params,
+void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
if (hw_is_mask(var)) {
@@ -1363,44 +1590,9 @@ void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params,
}
}
-int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var)
-{
- int changed;
- assert(hw_is_interval(var));
- changed = snd_interval_setinteger(hw_param_interval(params, var));
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-#if 0
-/*
- * snd_pcm_hw_param_setinteger
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * non integer values. Reduce configuration space accordingly.
- * Return -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var)
-{
- int changed = _snd_pcm_hw_param_setinteger(params, var);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return 0;
-}
-#endif /* 0 */
+EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
-static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
+static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
int changed;
@@ -1408,10 +1600,8 @@ static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
changed = snd_mask_refine_first(hw_param_mask(params, var));
else if (hw_is_interval(var))
changed = snd_interval_refine_first(hw_param_interval(params, var));
- else {
- assert(0);
+ else
return -EINVAL;
- }
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
@@ -1421,31 +1611,35 @@ static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
/**
- * snd_pcm_hw_param_first
+ * snd_pcm_hw_param_first - refine config space and return minimum value
* @pcm: PCM instance
* @params: the hw_params instance
* @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
+ * @dir: pointer to the direction (-1,0,1) or %NULL
*
- * Inside configuration space defined by PARAMS remove from PAR all
+ * Inside configuration space defined by @params remove from @var all
* values > minimum. Reduce configuration space accordingly.
- * Return the minimum.
+ *
+ * Return: The minimum, or a negative error code on failure.
*/
-static int snd_pcm_hw_param_first(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_first(params, var);
if (changed < 0)
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- assert(err >= 0);
+ if (snd_BUG_ON(err < 0))
+ return err;
}
return snd_pcm_hw_param_value(params, var, dir);
}
-static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
+EXPORT_SYMBOL(snd_pcm_hw_param_first);
+
+static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
int changed;
@@ -1453,10 +1647,8 @@ static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
changed = snd_mask_refine_last(hw_param_mask(params, var));
else if (hw_is_interval(var))
changed = snd_interval_refine_last(hw_param_interval(params, var));
- else {
- assert(0);
+ else
return -EINVAL;
- }
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
@@ -1466,456 +1658,95 @@ static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
/**
- * snd_pcm_hw_param_last
+ * snd_pcm_hw_param_last - refine config space and return maximum value
* @pcm: PCM instance
* @params: the hw_params instance
* @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
+ * @dir: pointer to the direction (-1,0,1) or %NULL
*
- * Inside configuration space defined by PARAMS remove from PAR all
+ * Inside configuration space defined by @params remove from @var all
* values < maximum. Reduce configuration space accordingly.
- * Return the maximum.
- */
-static int snd_pcm_hw_param_last(snd_pcm_t *pcm,
- snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, int *dir)
-{
- int changed = _snd_pcm_hw_param_last(params, var);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- assert(err >= 0);
- }
- return snd_pcm_hw_param_value(params, var, dir);
-}
-
-int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed;
- int open = 0;
- if (dir) {
- if (dir > 0) {
- open = 1;
- } else if (dir < 0) {
- if (val > 0) {
- open = 1;
- val--;
- }
- }
- }
- if (hw_is_mask(var))
- changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open);
- else if (hw_is_interval(var))
- changed = snd_interval_refine_min(hw_param_interval(params, var), val, open);
- else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_min
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: minimal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * values < VAL. Reduce configuration space accordingly.
- * Return new minimum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int *dir)
-{
- int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value_min(params, var, dir);
-}
-
-static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int dir)
-{
- int changed;
- int open = 0;
- if (dir) {
- if (dir < 0) {
- open = 1;
- } else if (dir > 0) {
- open = 1;
- val++;
- }
- }
- if (hw_is_mask(var)) {
- if (val == 0 && open) {
- snd_mask_none(hw_param_mask(params, var));
- changed = -EINVAL;
- } else
- changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open);
- } else if (hw_is_interval(var))
- changed = snd_interval_refine_max(hw_param_interval(params, var), val, open);
- else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_max
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: maximal value
- * @dir: pointer to the direction (-1,0,1) or NULL
*
- * Inside configuration space defined by PARAMS remove from PAR all
- * values >= VAL + 1. Reduce configuration space accordingly.
- * Return new maximum or -EINVAL if the configuration space is empty
+ * Return: The maximum, or a negative error code on failure.
*/
-static int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val,
- int *dir)
+int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params,
+ snd_pcm_hw_param_t var, int *dir)
{
- int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value_max(params, var, dir);
-}
-
-int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed;
- if (hw_is_mask(var)) {
- snd_mask_t *m = hw_param_mask(params, var);
- if (val == 0 && dir < 0) {
- changed = -EINVAL;
- snd_mask_none(m);
- } else {
- if (dir > 0)
- val++;
- else if (dir < 0)
- val--;
- changed = snd_mask_refine_set(hw_param_mask(params, var), val);
- }
- } else if (hw_is_interval(var)) {
- snd_interval_t *i = hw_param_interval(params, var);
- if (val == 0 && dir < 0) {
- changed = -EINVAL;
- snd_interval_none(i);
- } else if (dir == 0)
- changed = snd_interval_refine_set(i, val);
- else {
- snd_interval_t t;
- t.openmin = 1;
- t.openmax = 1;
- t.empty = 0;
- t.integer = 0;
- if (dir < 0) {
- t.min = val - 1;
- t.max = val;
- } else {
- t.min = val;
- t.max = val+1;
- }
- changed = snd_interval_refine(i, &t);
- }
- } else {
- assert(0);
- return -EINVAL;
- }
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_set
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all
- * values != VAL. Reduce configuration space accordingly.
- * Return VAL or -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
- int changed = _snd_pcm_hw_param_set(params, var, val, dir);
- if (changed < 0)
- return changed;
- if (params->rmask) {
- int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
- return err;
- }
- return snd_pcm_hw_param_value(params, var, NULL);
-}
-
-static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, const snd_mask_t *val)
-{
- int changed;
- assert(hw_is_mask(var));
- changed = snd_mask_refine(hw_param_mask(params, var), val);
- if (changed) {
- params->cmask |= 1 << var;
- params->rmask |= 1 << var;
- }
- return changed;
-}
-
-/**
- * snd_pcm_hw_param_mask
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: mask to apply
- *
- * Inside configuration space defined by PARAMS remove from PAR all values
- * not contained in MASK. Reduce configuration space accordingly.
- * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return 0 on success or -EINVAL
- * if the configuration space is empty
- */
-int snd_pcm_hw_param_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, const snd_mask_t *val)
-{
- int changed = _snd_pcm_hw_param_mask(params, var, val);
+ int changed = _snd_pcm_hw_param_last(params, var);
if (changed < 0)
return changed;
if (params->rmask) {
int err = snd_pcm_hw_refine(pcm, params);
- if (err < 0)
+ if (snd_BUG_ON(err < 0))
return err;
}
- return 0;
-}
-
-static int boundary_sub(int a, int adir,
- int b, int bdir,
- int *c, int *cdir)
-{
- adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
- bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
- *c = a - b;
- *cdir = adir - bdir;
- if (*cdir == -2) {
- assert(*c > INT_MIN);
- (*c)--;
- } else if (*cdir == 2) {
- assert(*c < INT_MAX);
- (*c)++;
- }
- return 0;
-}
-
-static int boundary_lt(unsigned int a, int adir,
- unsigned int b, int bdir)
-{
- assert(a > 0 || adir >= 0);
- assert(b > 0 || bdir >= 0);
- if (adir < 0) {
- a--;
- adir = 1;
- } else if (adir > 0)
- adir = 1;
- if (bdir < 0) {
- b--;
- bdir = 1;
- } else if (bdir > 0)
- bdir = 1;
- return a < b || (a == b && adir < bdir);
-}
-
-/* Return 1 if min is nearer to best than max */
-static int boundary_nearer(int min, int mindir,
- int best, int bestdir,
- int max, int maxdir)
-{
- int dmin, dmindir;
- int dmax, dmaxdir;
- boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
- boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
- return boundary_lt(dmin, dmindir, dmax, dmaxdir);
+ return snd_pcm_hw_param_value(params, var, dir);
}
-/**
- * snd_pcm_hw_param_near
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @best: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS set PAR to the available value
- * nearest to VAL. Reduce configuration space accordingly.
- * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return the value found.
- */
-int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, unsigned int best, int *dir)
-{
- snd_pcm_hw_params_t *save = NULL;
- int v;
- unsigned int saved_min;
- int last = 0;
- int min, max;
- int mindir, maxdir;
- int valdir = dir ? *dir : 0;
- /* FIXME */
- if (best > INT_MAX)
- best = INT_MAX;
- min = max = best;
- mindir = maxdir = valdir;
- if (maxdir > 0)
- maxdir = 0;
- else if (maxdir == 0)
- maxdir = -1;
- else {
- maxdir = 1;
- max--;
- }
- save = kmalloc(sizeof(*save), GFP_KERNEL);
- if (save == NULL)
- return -ENOMEM;
- *save = *params;
- saved_min = min;
- min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
- if (min >= 0) {
- snd_pcm_hw_params_t *params1;
- 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);
- return -ENOMEM;
- }
- *params1 = *save;
- max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
- if (max < 0) {
- kfree(params1);
- 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);
- assert(max >= 0);
- 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);
- assert(v >= 0);
- return v;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_last);
/**
- * snd_pcm_hw_param_choose
+ * snd_pcm_hw_param_choose - choose a configuration defined by @params
* @pcm: PCM instance
* @params: the hw_params instance
*
- * Choose one configuration from configuration space defined by PARAMS
+ * Choose one configuration from configuration space defined by @params.
* The configuration chosen is that obtained fixing in this order:
* first access, first format, first subformat, min channels,
* min rate, min period time, max buffer size, min tick time
+ *
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
- int err;
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_ACCESS, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_FORMAT, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_SUBFORMAT, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_CHANNELS, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_RATE, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_last(pcm, params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL);
- assert(err >= 0);
-
- err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_TICK_TIME, NULL);
- assert(err >= 0);
+int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
+ struct snd_pcm_hw_params *params)
+{
+ static int vars[] = {
+ SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_RATE,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ SNDRV_PCM_HW_PARAM_TICK_TIME,
+ -1
+ };
+ int err, *v;
+ for (v = vars; *v != -1; v++) {
+ if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
+ err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
+ else
+ err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
+ if (snd_BUG_ON(err < 0))
+ return err;
+ }
return 0;
}
-#undef snd_pcm_t
-#undef assert
-
-static int snd_pcm_lib_ioctl_reset(snd_pcm_substream_t *substream,
+static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
void *arg)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags;
snd_pcm_stream_lock_irqsave(substream, flags);
if (snd_pcm_running(substream) &&
snd_pcm_update_hw_ptr(substream) >= 0)
runtime->status->hw_ptr %= runtime->buffer_size;
- else
+ else {
runtime->status->hw_ptr = 0;
+ runtime->hw_ptr_wrap = 0;
+ }
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
-static int snd_pcm_lib_ioctl_channel_info(snd_pcm_substream_t *substream,
+static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
void *arg)
{
- snd_pcm_channel_info_t *info = arg;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_channel_info *info = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int width;
if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
info->offset = -1;
@@ -1946,6 +1777,23 @@ static int snd_pcm_lib_ioctl_channel_info(snd_pcm_substream_t *substream,
return 0;
}
+static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
+ void *arg)
+{
+ struct snd_pcm_hw_params *params = arg;
+ snd_pcm_format_t format;
+ int channels, width;
+
+ params->fifo_size = substream->runtime->hw.fifo_size;
+ if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
+ format = params_format(params);
+ channels = params_channels(params);
+ width = snd_pcm_format_physical_width(format);
+ params->fifo_size /= width * channels;
+ }
+ return 0;
+}
+
/**
* snd_pcm_lib_ioctl - a generic PCM ioctl callback
* @substream: the pcm substream instance
@@ -1955,9 +1803,9 @@ static int snd_pcm_lib_ioctl_channel_info(snd_pcm_substream_t *substream,
* Processes the generic ioctl commands for PCM.
* Can be passed as the ioctl callback for PCM ops.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_ioctl(snd_pcm_substream_t *substream,
+int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
switch (cmd) {
@@ -1967,104 +1815,13 @@ int snd_pcm_lib_ioctl(snd_pcm_substream_t *substream,
return snd_pcm_lib_ioctl_reset(substream, arg);
case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
return snd_pcm_lib_ioctl_channel_info(substream, arg);
+ case SNDRV_PCM_IOCTL1_FIFO_SIZE:
+ return snd_pcm_lib_ioctl_fifo_size(substream, arg);
}
return -ENXIO;
}
-/*
- * Conditions
- */
-
-static void snd_pcm_system_tick_set(snd_pcm_substream_t *substream,
- unsigned long ticks)
-{
- snd_pcm_runtime_t *runtime = substream->runtime;
- if (ticks == 0)
- del_timer(&runtime->tick_timer);
- else {
- ticks += (1000000 / HZ) - 1;
- ticks /= (1000000 / HZ);
- mod_timer(&runtime->tick_timer, jiffies + ticks);
- }
-}
-
-/* Temporary alias */
-void snd_pcm_tick_set(snd_pcm_substream_t *substream, unsigned long ticks)
-{
- snd_pcm_system_tick_set(substream, ticks);
-}
-
-void snd_pcm_tick_prepare(snd_pcm_substream_t *substream)
-{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_uframes_t frames = ULONG_MAX;
- snd_pcm_uframes_t avail, dist;
- unsigned int ticks;
- u_int64_t n;
- u_int32_t r;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (runtime->silence_size >= runtime->boundary) {
- frames = 1;
- } else if (runtime->silence_size > 0 &&
- runtime->silence_filled < runtime->buffer_size) {
- snd_pcm_sframes_t noise_dist;
- noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
- snd_assert(noise_dist <= (snd_pcm_sframes_t)runtime->silence_threshold, );
- frames = noise_dist - runtime->silence_threshold;
- }
- avail = snd_pcm_playback_avail(runtime);
- } else {
- avail = snd_pcm_capture_avail(runtime);
- }
- if (avail < runtime->control->avail_min) {
- snd_pcm_sframes_t n = runtime->control->avail_min - avail;
- if (n > 0 && frames > (snd_pcm_uframes_t)n)
- frames = n;
- }
- if (avail < runtime->buffer_size) {
- snd_pcm_sframes_t n = runtime->buffer_size - avail;
- if (n > 0 && frames > (snd_pcm_uframes_t)n)
- frames = n;
- }
- if (frames == ULONG_MAX) {
- snd_pcm_tick_set(substream, 0);
- return;
- }
- dist = runtime->status->hw_ptr - runtime->hw_ptr_base;
- /* Distance to next interrupt */
- dist = runtime->period_size - dist % runtime->period_size;
- if (dist <= frames) {
- snd_pcm_tick_set(substream, 0);
- return;
- }
- /* the base time is us */
- n = frames;
- n *= 1000000;
- div64_32(&n, runtime->tick_time * runtime->rate, &r);
- ticks = n + (r > 0 ? 1 : 0);
- if (ticks < runtime->sleep_min)
- ticks = runtime->sleep_min;
- snd_pcm_tick_set(substream, (unsigned long) ticks);
-}
-
-void snd_pcm_tick_elapsed(snd_pcm_substream_t *substream)
-{
- snd_pcm_runtime_t *runtime;
- unsigned long flags;
-
- snd_assert(substream != NULL, return);
- runtime = substream->runtime;
- snd_assert(runtime != NULL, return);
-
- snd_pcm_stream_lock_irqsave(substream, flags);
- if (!snd_pcm_running(substream) ||
- snd_pcm_update_hw_ptr(substream) < 0)
- goto _end;
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
- _end:
- snd_pcm_stream_unlock_irqrestore(substream, flags);
-}
+EXPORT_SYMBOL(snd_pcm_lib_ioctl);
/**
* snd_pcm_period_elapsed - update the pcm status for the next period
@@ -2072,32 +1829,30 @@ void snd_pcm_tick_elapsed(snd_pcm_substream_t *substream)
*
* This function is called from the interrupt handler when the
* PCM has processed the period size. It will update the current
- * pointer, set up the tick, wake up sleepers, etc.
+ * pointer, wake up sleepers, etc.
*
* Even if more than one periods have elapsed since the last call, you
* have to call this only once.
*/
-void snd_pcm_period_elapsed(snd_pcm_substream_t *substream)
+void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
unsigned long flags;
- snd_assert(substream != NULL, return);
+ if (PCM_RUNTIME_CHECK(substream))
+ return;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return);
if (runtime->transfer_ack_begin)
runtime->transfer_ack_begin(substream);
snd_pcm_stream_lock_irqsave(substream, flags);
if (!snd_pcm_running(substream) ||
- snd_pcm_update_hw_ptr_interrupt(substream) < 0)
+ snd_pcm_update_hw_ptr0(substream, 1) < 0)
goto _end;
if (substream->timer_running)
snd_timer_interrupt(substream->timer, 1);
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
_end:
snd_pcm_stream_unlock_irqrestore(substream, flags);
if (runtime->transfer_ack_end)
@@ -2105,12 +1860,106 @@ void snd_pcm_period_elapsed(snd_pcm_substream_t *substream)
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
}
-static int snd_pcm_lib_write_transfer(snd_pcm_substream_t *substream,
+EXPORT_SYMBOL(snd_pcm_period_elapsed);
+
+/*
+ * Wait until avail_min data becomes available
+ * Returns a negative error code if any error occurs during operation.
+ * The available space is stored on availp. When err = 0 and avail = 0
+ * on the capture stream, it indicates the stream is in DRAINING state.
+ */
+static int wait_for_avail(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t *availp)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ wait_queue_t wait;
+ int err = 0;
+ snd_pcm_uframes_t avail = 0;
+ long wait_time, tout;
+
+ init_waitqueue_entry(&wait, current);
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&runtime->tsleep, &wait);
+
+ if (runtime->no_period_wakeup)
+ wait_time = MAX_SCHEDULE_TIMEOUT;
+ else {
+ wait_time = 10;
+ if (runtime->rate) {
+ long t = runtime->period_size * 2 / runtime->rate;
+ wait_time = max(t, wait_time);
+ }
+ wait_time = msecs_to_jiffies(wait_time * 1000);
+ }
+
+ for (;;) {
+ if (signal_pending(current)) {
+ err = -ERESTARTSYS;
+ break;
+ }
+
+ /*
+ * We need to check if space became available already
+ * (and thus the wakeup happened already) first to close
+ * the race of space already having become available.
+ * This check must happen after been added to the waitqueue
+ * and having current state be INTERRUPTIBLE.
+ */
+ if (is_playback)
+ avail = snd_pcm_playback_avail(runtime);
+ else
+ avail = snd_pcm_capture_avail(runtime);
+ if (avail >= runtime->twake)
+ break;
+ snd_pcm_stream_unlock_irq(substream);
+
+ tout = schedule_timeout(wait_time);
+
+ snd_pcm_stream_lock_irq(substream);
+ set_current_state(TASK_INTERRUPTIBLE);
+ switch (runtime->status->state) {
+ case SNDRV_PCM_STATE_SUSPENDED:
+ err = -ESTRPIPE;
+ goto _endloop;
+ case SNDRV_PCM_STATE_XRUN:
+ err = -EPIPE;
+ goto _endloop;
+ case SNDRV_PCM_STATE_DRAINING:
+ if (is_playback)
+ err = -EPIPE;
+ else
+ avail = 0; /* indicate draining */
+ goto _endloop;
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_DISCONNECTED:
+ err = -EBADFD;
+ goto _endloop;
+ case SNDRV_PCM_STATE_PAUSED:
+ continue;
+ }
+ if (!tout) {
+ pcm_dbg(substream->pcm,
+ "%s write error (DMA or IRQ trouble?)\n",
+ is_playback ? "playback" : "capture");
+ err = -EIO;
+ break;
+ }
+ }
+ _endloop:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&runtime->tsleep, &wait);
+ *availp = avail;
+ return err;
+}
+
+static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
if (substream->ops->copy) {
@@ -2118,32 +1967,30 @@ static int snd_pcm_lib_write_transfer(snd_pcm_substream_t *substream,
return err;
} else {
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
- snd_assert(runtime->dma_area, return -EFAULT);
if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
return -EFAULT;
}
return 0;
}
-typedef int (*transfer_f)(snd_pcm_substream_t *substream, unsigned int hwoff,
+typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t size);
-static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
+static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
unsigned long data,
snd_pcm_uframes_t size,
int nonblock,
transfer_f transfer)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
+ snd_pcm_uframes_t avail;
int err = 0;
if (size == 0)
return 0;
- if (size > runtime->xfer_align)
- size -= size % runtime->xfer_align;
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
@@ -2162,99 +2009,40 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
goto _end_unlock;
}
+ runtime->twake = runtime->control->avail_min ? : 1;
+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_update_hw_ptr(substream);
+ avail = snd_pcm_playback_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
- snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;
- if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_update_hw_ptr(substream);
- avail = snd_pcm_playback_avail(runtime);
- if (((avail < runtime->control->avail_min && size > avail) ||
- (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
- wait_queue_t wait;
- enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
- long tout;
-
+ if (!avail) {
if (nonblock) {
err = -EAGAIN;
goto _end_unlock;
}
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&runtime->sleep, &wait);
- while (1) {
- if (signal_pending(current)) {
- state = SIGNALED;
- break;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- snd_pcm_stream_unlock_irq(substream);
- tout = schedule_timeout(10 * HZ);
- snd_pcm_stream_lock_irq(substream);
- if (tout == 0) {
- if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
- runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
- state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
- break;
- }
- }
- switch (runtime->status->state) {
- case SNDRV_PCM_STATE_XRUN:
- case SNDRV_PCM_STATE_DRAINING:
- state = ERROR;
- goto _end_loop;
- case SNDRV_PCM_STATE_SUSPENDED:
- state = SUSPENDED;
- goto _end_loop;
- case SNDRV_PCM_STATE_SETUP:
- state = DROPPED;
- goto _end_loop;
- default:
- break;
- }
- avail = snd_pcm_playback_avail(runtime);
- if (avail >= runtime->control->avail_min) {
- state = READY;
- break;
- }
- }
- _end_loop:
- remove_wait_queue(&runtime->sleep, &wait);
-
- switch (state) {
- case ERROR:
- err = -EPIPE;
- goto _end_unlock;
- case SUSPENDED:
- err = -ESTRPIPE;
- goto _end_unlock;
- case SIGNALED:
- err = -ERESTARTSYS;
- goto _end_unlock;
- case EXPIRED:
- snd_printd("playback write error (DMA or IRQ trouble?)\n");
- err = -EIO;
- goto _end_unlock;
- case DROPPED:
- err = -EBADFD;
+ runtime->twake = min_t(snd_pcm_uframes_t, size,
+ runtime->control->avail_min ? : 1);
+ err = wait_for_avail(substream, &avail);
+ if (err < 0)
goto _end_unlock;
- default:
- break;
- }
}
- if (avail > runtime->xfer_align)
- avail -= avail % runtime->xfer_align;
frames = size > avail ? avail : size;
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
if (frames > cont)
frames = cont;
- snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+ if (snd_BUG_ON(!frames)) {
+ runtime->twake = 0;
+ snd_pcm_stream_unlock_irq(substream);
+ return -EINVAL;
+ }
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
- if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
- goto _end;
+ err = transfer(substream, appl_ofs, data, offset, frames);
snd_pcm_stream_lock_irq(substream);
+ if (err < 0)
+ goto _end_unlock;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
@@ -2275,47 +2063,47 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
offset += frames;
size -= frames;
xfer += frames;
+ avail -= frames;
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
err = snd_pcm_start(substream);
if (err < 0)
goto _end_unlock;
}
- if (runtime->sleep_min &&
- runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_tick_prepare(substream);
}
_end_unlock:
+ runtime->twake = 0;
+ if (xfer > 0 && err >= 0)
+ snd_pcm_update_state(substream, runtime);
snd_pcm_stream_unlock_irq(substream);
- _end:
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
-snd_pcm_sframes_t snd_pcm_lib_write(snd_pcm_substream_t *substream, const void __user *buf, snd_pcm_uframes_t size)
+/* sanity-check for read/write methods */
+static int pcm_sanity_check(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
- int nonblock;
-
- snd_assert(substream != NULL, return -ENXIO);
+ struct snd_pcm_runtime *runtime;
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
- snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
+ if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+ return -EINVAL;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
+ return 0;
+}
- snd_assert(substream->ffile != NULL, return -ENXIO);
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
+snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+{
+ struct snd_pcm_runtime *runtime;
+ int nonblock;
+ int err;
+
+ err = pcm_sanity_check(substream);
+ if (err < 0)
+ return err;
+ runtime = substream->runtime;
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
runtime->channels > 1)
@@ -2324,18 +2112,21 @@ snd_pcm_sframes_t snd_pcm_lib_write(snd_pcm_substream_t *substream, const void _
snd_pcm_lib_write_transfer);
}
-static int snd_pcm_lib_writev_transfer(snd_pcm_substream_t *substream,
+EXPORT_SYMBOL(snd_pcm_lib_write);
+
+static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
void __user **bufs = (void __user **)data;
int channels = runtime->channels;
int c;
if (substream->ops->copy) {
- snd_assert(substream->ops->silence != NULL, return -EINVAL);
+ if (snd_BUG_ON(!substream->ops->silence))
+ return -EINVAL;
for (c = 0; c < channels; ++c, ++bufs) {
if (*bufs == NULL) {
if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
@@ -2349,7 +2140,6 @@ static int snd_pcm_lib_writev_transfer(snd_pcm_substream_t *substream,
} else {
/* default transfer behaviour */
size_t dma_csize = runtime->dma_bytes / channels;
- snd_assert(runtime->dma_area, return -EFAULT);
for (c = 0; c < channels; ++c, ++bufs) {
char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
if (*bufs == NULL) {
@@ -2364,33 +2154,19 @@ static int snd_pcm_lib_writev_transfer(snd_pcm_substream_t *substream,
return 0;
}
-snd_pcm_sframes_t snd_pcm_lib_writev(snd_pcm_substream_t *substream,
+snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
void __user **bufs,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
int nonblock;
+ int err;
- snd_assert(substream != NULL, return -ENXIO);
+ err = pcm_sanity_check(substream);
+ if (err < 0)
+ return err;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
- snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
-
- snd_assert(substream->ffile != NULL, return -ENXIO);
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
@@ -2398,12 +2174,14 @@ snd_pcm_sframes_t snd_pcm_lib_writev(snd_pcm_substream_t *substream,
nonblock, snd_pcm_lib_writev_transfer);
}
-static int snd_pcm_lib_read_transfer(snd_pcm_substream_t *substream,
+EXPORT_SYMBOL(snd_pcm_lib_writev);
+
+static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
if (substream->ops->copy) {
@@ -2411,28 +2189,26 @@ static int snd_pcm_lib_read_transfer(snd_pcm_substream_t *substream,
return err;
} else {
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
- snd_assert(runtime->dma_area, return -EFAULT);
if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
return -EFAULT;
}
return 0;
}
-static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
+static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
unsigned long data,
snd_pcm_uframes_t size,
int nonblock,
transfer_f transfer)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
+ snd_pcm_uframes_t avail;
int err = 0;
if (size == 0)
return 0;
- if (size > runtime->xfer_align)
- size -= size % runtime->xfer_align;
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
@@ -2458,106 +2234,47 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
goto _end_unlock;
}
+ runtime->twake = runtime->control->avail_min ? : 1;
+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_update_hw_ptr(substream);
+ avail = snd_pcm_capture_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
- snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;
- if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_update_hw_ptr(substream);
- __draining:
- avail = snd_pcm_capture_avail(runtime);
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
- if (avail < runtime->xfer_align) {
- err = -EPIPE;
+ if (!avail) {
+ if (runtime->status->state ==
+ SNDRV_PCM_STATE_DRAINING) {
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
goto _end_unlock;
}
- } else if ((avail < runtime->control->avail_min && size > avail) ||
- (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
- wait_queue_t wait;
- enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
- long tout;
-
if (nonblock) {
err = -EAGAIN;
goto _end_unlock;
}
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&runtime->sleep, &wait);
- while (1) {
- if (signal_pending(current)) {
- state = SIGNALED;
- break;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- snd_pcm_stream_unlock_irq(substream);
- tout = schedule_timeout(10 * HZ);
- snd_pcm_stream_lock_irq(substream);
- if (tout == 0) {
- if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
- runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
- state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
- break;
- }
- }
- switch (runtime->status->state) {
- case SNDRV_PCM_STATE_XRUN:
- state = ERROR;
- goto _end_loop;
- case SNDRV_PCM_STATE_SUSPENDED:
- state = SUSPENDED;
- goto _end_loop;
- case SNDRV_PCM_STATE_DRAINING:
- goto __draining;
- case SNDRV_PCM_STATE_SETUP:
- state = DROPPED;
- goto _end_loop;
- default:
- break;
- }
- avail = snd_pcm_capture_avail(runtime);
- if (avail >= runtime->control->avail_min) {
- state = READY;
- break;
- }
- }
- _end_loop:
- remove_wait_queue(&runtime->sleep, &wait);
-
- switch (state) {
- case ERROR:
- err = -EPIPE;
- goto _end_unlock;
- case SUSPENDED:
- err = -ESTRPIPE;
- goto _end_unlock;
- case SIGNALED:
- err = -ERESTARTSYS;
- goto _end_unlock;
- case EXPIRED:
- snd_printd("capture read error (DMA or IRQ trouble?)\n");
- err = -EIO;
- goto _end_unlock;
- case DROPPED:
- err = -EBADFD;
+ runtime->twake = min_t(snd_pcm_uframes_t, size,
+ runtime->control->avail_min ? : 1);
+ err = wait_for_avail(substream, &avail);
+ if (err < 0)
goto _end_unlock;
- default:
- break;
- }
+ if (!avail)
+ continue; /* draining */
}
- if (avail > runtime->xfer_align)
- avail -= avail % runtime->xfer_align;
frames = size > avail ? avail : size;
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
if (frames > cont)
frames = cont;
- snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+ if (snd_BUG_ON(!frames)) {
+ runtime->twake = 0;
+ snd_pcm_stream_unlock_irq(substream);
+ return -EINVAL;
+ }
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
- if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
- goto _end;
+ err = transfer(substream, appl_ofs, data, offset, frames);
snd_pcm_stream_lock_irq(substream);
+ if (err < 0)
+ goto _end_unlock;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
@@ -2578,52 +2295,40 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
offset += frames;
size -= frames;
xfer += frames;
- if (runtime->sleep_min &&
- runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_tick_prepare(substream);
+ avail -= frames;
}
_end_unlock:
+ runtime->twake = 0;
+ if (xfer > 0 && err >= 0)
+ snd_pcm_update_state(substream, runtime);
snd_pcm_stream_unlock_irq(substream);
- _end:
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
-snd_pcm_sframes_t snd_pcm_lib_read(snd_pcm_substream_t *substream, void __user *buf, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
int nonblock;
+ int err;
- snd_assert(substream != NULL, return -ENXIO);
+ err = pcm_sanity_check(substream);
+ if (err < 0)
+ return err;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
- snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
- return -EBADFD;
-
- snd_assert(substream->ffile != NULL, return -ENXIO);
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
}
-static int snd_pcm_lib_readv_transfer(snd_pcm_substream_t *substream,
+EXPORT_SYMBOL(snd_pcm_lib_read);
+
+static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
unsigned int hwoff,
unsigned long data, unsigned int off,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
void __user **bufs = (void __user **)data;
int channels = runtime->channels;
@@ -2639,7 +2344,6 @@ static int snd_pcm_lib_readv_transfer(snd_pcm_substream_t *substream,
}
} else {
snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
- snd_assert(runtime->dma_area, return -EFAULT);
for (c = 0; c < channels; ++c, ++bufs) {
char *hwbuf;
char __user *buf;
@@ -2655,85 +2359,238 @@ static int snd_pcm_lib_readv_transfer(snd_pcm_substream_t *substream,
return 0;
}
-snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream,
+snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
void __user **bufs,
snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
int nonblock;
+ int err;
- snd_assert(substream != NULL, return -ENXIO);
+ err = pcm_sanity_check(substream);
+ if (err < 0)
+ return err;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
- snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- snd_assert(substream->ffile != NULL, return -ENXIO);
- nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
- if (substream->oss.oss) {
- snd_pcm_oss_setup_t *setup = substream->oss.setup;
- if (setup != NULL) {
- if (setup->nonblock)
- nonblock = 1;
- else if (setup->block)
- nonblock = 0;
- }
- }
-#endif
-
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
}
+EXPORT_SYMBOL(snd_pcm_lib_readv);
+
/*
- * Exported symbols
+ * standard channel mapping helpers
*/
-EXPORT_SYMBOL(snd_interval_refine);
-EXPORT_SYMBOL(snd_interval_list);
-EXPORT_SYMBOL(snd_interval_ratnum);
-EXPORT_SYMBOL(_snd_pcm_hw_params_any);
-EXPORT_SYMBOL(_snd_pcm_hw_param_min);
-EXPORT_SYMBOL(_snd_pcm_hw_param_set);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_min);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_max);
-EXPORT_SYMBOL(snd_pcm_hw_param_mask);
-EXPORT_SYMBOL(snd_pcm_hw_param_first);
-EXPORT_SYMBOL(snd_pcm_hw_param_last);
-EXPORT_SYMBOL(snd_pcm_hw_param_near);
-EXPORT_SYMBOL(snd_pcm_hw_param_set);
-EXPORT_SYMBOL(snd_pcm_hw_refine);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
-EXPORT_SYMBOL(snd_pcm_hw_rule_add);
-EXPORT_SYMBOL(snd_pcm_set_ops);
-EXPORT_SYMBOL(snd_pcm_set_sync);
-EXPORT_SYMBOL(snd_pcm_lib_ioctl);
-EXPORT_SYMBOL(snd_pcm_stop);
-EXPORT_SYMBOL(snd_pcm_period_elapsed);
-EXPORT_SYMBOL(snd_pcm_lib_write);
-EXPORT_SYMBOL(snd_pcm_lib_read);
-EXPORT_SYMBOL(snd_pcm_lib_writev);
-EXPORT_SYMBOL(snd_pcm_lib_readv);
-EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes);
-EXPORT_SYMBOL(snd_pcm_lib_period_bytes);
-/* pcm_memory.c */
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
-EXPORT_SYMBOL(snd_pcm_lib_free_pages);
+/* default channel maps for multi-channel playbacks, up to 8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
+
+/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_MONO } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
+
+static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
+{
+ if (ch > info->max_channels)
+ return false;
+ return !info->channel_mask || (info->channel_mask & (1U << ch));
+}
+
+static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 0;
+ uinfo->count = info->max_channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+ return 0;
+}
+
+/* get callback for channel map ctl element
+ * stores the channel position firstly matching with the current channels
+ */
+static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ const struct snd_pcm_chmap_elem *map;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+ for (map = info->chmap; map->channels; map++) {
+ int i;
+ if (map->channels == substream->runtime->channels &&
+ valid_chmap_channels(info, map->channels)) {
+ for (i = 0; i < map->channels; i++)
+ ucontrol->value.integer.value[i] = map->map[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/* tlv callback for channel map ctl element
+ * expands the pre-defined channel maps in a form of TLV
+ */
+static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ const struct snd_pcm_chmap_elem *map;
+ unsigned int __user *dst;
+ int c, count = 0;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+ return -EFAULT;
+ size -= 8;
+ dst = tlv + 2;
+ for (map = info->chmap; map->channels; map++) {
+ int chs_bytes = map->channels * 4;
+ if (!valid_chmap_channels(info, map->channels))
+ continue;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+ put_user(chs_bytes, dst + 1))
+ return -EFAULT;
+ dst += 2;
+ size -= 8;
+ count += 8;
+ if (size < chs_bytes)
+ return -ENOMEM;
+ size -= chs_bytes;
+ count += chs_bytes;
+ for (c = 0; c < map->channels; c++) {
+ if (put_user(map->map[c], dst))
+ return -EFAULT;
+ dst++;
+ }
+ }
+ if (put_user(count, tlv + 1))
+ return -EFAULT;
+ return 0;
+}
+
+static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ info->pcm->streams[info->stream].chmap_kctl = NULL;
+ kfree(info);
+}
+
+/**
+ * snd_pcm_add_chmap_ctls - create channel-mapping control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @chmap: channel map elements (for query)
+ * @max_channels: the max number of channels for the stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_chmap instance if non-NULL
+ *
+ * Create channel-mapping control elements assigned to the given PCM stream(s).
+ * Return: Zero if successful, or a negative error value.
+ */
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_chmap_elem *chmap,
+ int max_channels,
+ unsigned long private_value,
+ struct snd_pcm_chmap **info_ret)
+{
+ struct snd_pcm_chmap *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = pcm_chmap_ctl_info,
+ .get = pcm_chmap_ctl_get,
+ .tlv.c = pcm_chmap_ctl_tlv,
+ };
+ int err;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->stream = stream;
+ info->chmap = chmap;
+ info->max_channels = max_channels;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ knew.name = "Playback Channel Map";
+ else
+ knew.name = "Capture Channel Map";
+ knew.device = pcm->device;
+ knew.count = pcm->streams[stream].substream_count;
+ knew.private_value = private_value;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = pcm_chmap_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0)
+ return err;
+ pcm->streams[stream].chmap_kctl = info->kctl;
+ if (info_ret)
+ *info_ret = info;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index b3f5344f60b..54debc07f5c 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,11 +19,13 @@
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
@@ -46,22 +48,12 @@ static const size_t snd_minimum_buffer = 16384;
*
* the minimum size is snd_minimum_buffer. it should be power of 2.
*/
-static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size)
+static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
{
struct snd_dma_buffer *dmab = &substream->dma_buffer;
+ size_t orig_size = size;
int err;
- snd_assert(size > 0, return -EINVAL);
-
- /* already reserved? */
- if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
- if (dmab->bytes >= size)
- return 0; /* yes */
- /* no, free the reserved block */
- snd_dma_free_pages(dmab);
- dmab->bytes = 0;
- }
-
do {
if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
size, dmab)) < 0) {
@@ -72,20 +64,21 @@ static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size)
size >>= 1;
} while (size >= snd_minimum_buffer);
dmab->bytes = 0; /* tell error */
+ pr_warn("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
+ substream->pcm->card->number, substream->pcm->device,
+ substream->stream ? 'c' : 'p', substream->number,
+ substream->pcm->name, orig_size);
return 0;
}
/*
* release the preallocated buffer if not yet done.
*/
-static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
+static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream)
{
if (substream->dma_buffer.area == NULL)
return;
- if (substream->dma_buf_id)
- snd_dma_reserve_buf(&substream->dma_buffer, substream->dma_buf_id);
- else
- snd_dma_free_pages(&substream->dma_buffer);
+ snd_dma_free_pages(&substream->dma_buffer);
substream->dma_buffer.area = NULL;
}
@@ -95,15 +88,17 @@ static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
*
* Releases the pre-allocated buffer of the given substream.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream)
+int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_preallocate_dma_free(substream);
- if (substream->proc_prealloc_entry) {
- snd_info_unregister(substream->proc_prealloc_entry);
- substream->proc_prealloc_entry = NULL;
- }
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+ snd_info_free_entry(substream->proc_prealloc_max_entry);
+ substream->proc_prealloc_max_entry = NULL;
+ snd_info_free_entry(substream->proc_prealloc_entry);
+ substream->proc_prealloc_entry = NULL;
+#endif
return 0;
}
@@ -113,11 +108,11 @@ int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream)
*
* Releases all the pre-allocated buffers on the given pcm.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm)
+int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int stream;
for (stream = 0; stream < 2; stream++)
@@ -126,27 +121,42 @@ int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm)
return 0;
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
+
+#ifdef CONFIG_SND_VERBOSE_PROCFS
/*
* read callback for prealloc proc file
*
* prints the current allocated size in kB.
*/
-static void snd_pcm_lib_preallocate_proc_read(snd_info_entry_t *entry,
- snd_info_buffer_t *buffer)
+static void snd_pcm_lib_preallocate_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
+ struct snd_pcm_substream *substream = entry->private_data;
snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024);
}
/*
+ * read callback for prealloc_max proc file
+ *
+ * prints the maximum allowed size in kB.
+ */
+static void snd_pcm_lib_preallocate_max_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_pcm_substream *substream = entry->private_data;
+ snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_max / 1024);
+}
+
+/*
* write callback for prealloc proc file
*
* accepts the preallocation size in kB.
*/
-static void snd_pcm_lib_preallocate_proc_write(snd_info_entry_t *entry,
- snd_info_buffer_t *buffer)
+static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
+ struct snd_pcm_substream *substream = entry->private_data;
char line[64], str[64];
size_t size;
struct snd_dma_buffer new_dmab;
@@ -185,24 +195,12 @@ static void snd_pcm_lib_preallocate_proc_write(snd_info_entry_t *entry,
}
}
-/*
- * pre-allocate the buffer and create a proc file for the substream
- */
-static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream,
- size_t size, size_t max)
+static inline void preallocate_info_init(struct snd_pcm_substream *substream)
{
- snd_info_entry_t *entry;
-
- if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
- preallocate_pcm_pages(substream, size);
+ struct snd_info_entry *entry;
- if (substream->dma_buffer.bytes > 0)
- substream->buffer_bytes_max = substream->dma_buffer.bytes;
- substream->dma_max = max;
if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {
- entry->c.text.read_size = 64;
entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
- entry->c.text.write_size = 64;
entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
entry->mode |= S_IWUSR;
entry->private_data = substream;
@@ -212,6 +210,35 @@ static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream,
}
}
substream->proc_prealloc_entry = entry;
+ if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {
+ entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;
+ entry->private_data = substream;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ }
+ substream->proc_prealloc_max_entry = entry;
+}
+
+#else /* !CONFIG_SND_VERBOSE_PROCFS */
+#define preallocate_info_init(s)
+#endif /* CONFIG_SND_VERBOSE_PROCFS */
+
+/*
+ * pre-allocate the buffer and create a proc file for the substream
+ */
+static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
+ size_t size, size_t max)
+{
+
+ if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
+ preallocate_pcm_pages(substream, size);
+
+ if (substream->dma_buffer.bytes > 0)
+ substream->buffer_bytes_max = substream->dma_buffer.bytes;
+ substream->dma_max = max;
+ preallocate_info_init(substream);
return 0;
}
@@ -220,20 +247,15 @@ static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream,
* snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type
* @substream: the pcm substream instance
* @type: DMA type (SNDRV_DMA_TYPE_*)
- * @data: DMA type dependant data
+ * @data: DMA type dependent data
* @size: the requested pre-allocation size in bytes
* @max: the max. allowed pre-allocation size
*
* Do pre-allocation for the given DMA buffer type.
*
- * When substream->dma_buf_id is set, the function tries to look for
- * the reserved buffer, and the buffer is not freed but reserved at
- * destruction time. The dma_buf_id must be unique for all systems
- * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
- *
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
+int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
int type, struct device *data,
size_t size, size_t max)
{
@@ -242,24 +264,26 @@ int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
+
/**
- * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
+ * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continuous memory type (all substreams)
* @pcm: the pcm instance
* @type: DMA type (SNDRV_DMA_TYPE_*)
- * @data: DMA type dependant data
+ * @data: DMA type dependent data
* @size: the requested pre-allocation size in bytes
* @max: the max. allowed pre-allocation size
*
* Do pre-allocation to all substreams of the given pcm for the
* specified DMA type.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm,
+int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
int type, void *data,
size_t size, size_t max)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int stream, err;
for (stream = 0; stream < 2; stream++)
@@ -269,15 +293,19 @@ int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm,
return 0;
}
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
+
+#ifdef CONFIG_SND_DMA_SGBUF
/**
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
* @offset: the buffer offset
*
- * Returns the page struct at the given buffer offset.
* Used as the page callback of PCM ops.
+ *
+ * Return: The page struct at the given buffer offset. %NULL on failure.
*/
-struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
@@ -287,6 +315,9 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon
return sgbuf->page_table[idx];
}
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
+#endif /* CONFIG_SND_DMA_SGBUF */
+
/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
* @substream: the substream to allocate the DMA buffer to
@@ -295,18 +326,20 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon
* Allocates the DMA buffer on the BUS type given earlier to
* snd_pcm_lib_preallocate_xxx_pages().
*
- * Returns 1 if the buffer is changed, 0 if not changed, or a negative
+ * Return: 1 if the buffer is changed, 0 if not changed, or a negative
* code on failure.
*/
-int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
+int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
struct snd_dma_buffer *dmab = NULL;
- snd_assert(substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL);
- snd_assert(substream != NULL, return -EINVAL);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -EINVAL;
+ if (snd_BUG_ON(substream->dma_buffer.dev.type ==
+ SNDRV_DMA_TYPE_UNKNOWN))
+ return -EINVAL;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -EINVAL);
if (runtime->dma_buffer_p) {
/* perphaps, we might free the large DMA memory region
@@ -318,7 +351,8 @@ int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
}
snd_pcm_lib_free_pages(substream);
}
- if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
+ if (substream->dma_buffer.area != NULL &&
+ substream->dma_buffer.bytes >= size) {
dmab = &substream->dma_buffer; /* use the pre-allocated buffer */
} else {
dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);
@@ -337,21 +371,23 @@ int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
return 1; /* area was changed */
}
+EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
+
/**
* snd_pcm_lib_free_pages - release the allocated DMA buffer.
* @substream: the substream to release the DMA buffer
*
* Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages().
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream)
+int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
- snd_assert(substream != NULL, return -EINVAL);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -EINVAL;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -EINVAL);
if (runtime->dma_area == NULL)
return 0;
if (runtime->dma_buffer_p != &substream->dma_buffer) {
@@ -362,3 +398,63 @@ int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream)
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
+
+EXPORT_SYMBOL(snd_pcm_lib_free_pages);
+
+int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
+ size_t size, gfp_t gfp_flags)
+{
+ struct snd_pcm_runtime *runtime;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -EINVAL;
+ runtime = substream->runtime;
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes >= size)
+ return 0; /* already large enough */
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+ runtime->dma_bytes = size;
+ return 1;
+}
+EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
+
+/**
+ * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
+ * @substream: the substream with a buffer allocated by
+ * snd_pcm_lib_alloc_vmalloc_buffer()
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+
+ if (PCM_RUNTIME_CHECK(substream))
+ return -EINVAL;
+ runtime = substream->runtime;
+ vfree(runtime->dma_area);
+ runtime->dma_area = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
+
+/**
+ * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
+ * @substream: the substream with a buffer allocated by
+ * snd_pcm_lib_alloc_vmalloc_buffer()
+ * @offset: offset in the buffer
+ *
+ * This function is to be used as the page callback in the PCM ops.
+ *
+ * Return: The page struct, or %NULL on failure.
+ */
+struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 1453743e4da..4560ca0e565 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -1,6 +1,6 @@
/*
* PCM Interface - misc routines
- * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz>
*
*
* This library is free software; you can redistribute it and/or modify
@@ -19,8 +19,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
#define SND_PCM_FORMAT_UNKNOWN (-1)
@@ -36,7 +36,10 @@ struct pcm_format_data {
unsigned char silence[8]; /* silence data to fill */
};
-static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
+/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
+#define INT __force int
+
+static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
[SNDRV_PCM_FORMAT_S8] = {
.width = 8, .phys = 8, .le = -1, .signd = 1,
.silence = {},
@@ -75,7 +78,7 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
},
[SNDRV_PCM_FORMAT_U24_BE] = {
.width = 24, .phys = 32, .le = 0, .signd = 0,
- .silence = { 0x80, 0x00, 0x00 },
+ .silence = { 0x00, 0x80, 0x00, 0x00 },
},
[SNDRV_PCM_FORMAT_S32_LE] = {
.width = 32, .phys = 32, .le = 1, .signd = 1,
@@ -129,6 +132,22 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 4, .phys = 4, .le = -1, .signd = -1,
.silence = {},
},
+ [SNDRV_PCM_FORMAT_G723_24] = {
+ .width = 3, .phys = 3, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40] = {
+ .width = 5, .phys = 5, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_DSD_U8] = {
+ .width = 8, .phys = 8, .le = 1, .signd = 0,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_DSD_U16_LE] = {
+ .width = 16, .phys = 16, .le = 1, .signd = 0,
+ .silence = {},
+ },
/* FIXME: the following three formats are not defined properly yet */
[SNDRV_PCM_FORMAT_MPEG] = {
.le = -1, .signd = -1,
@@ -187,6 +206,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 18, .phys = 24, .le = 0, .signd = 0,
.silence = { 0x02, 0x00, 0x00 },
},
+ [SNDRV_PCM_FORMAT_G723_24_1B] = {
+ .width = 3, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40_1B] = {
+ .width = 5, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
};
@@ -194,24 +221,26 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
* snd_pcm_format_signed - Check the PCM format is signed linear
* @format: the format to check
*
- * Returns 1 if the given PCM format is signed linear, 0 if unsigned
+ * Return: 1 if the given PCM format is signed linear, 0 if unsigned
* linear, and a negative error code for non-linear formats.
*/
int snd_pcm_format_signed(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].signd) < 0)
+ if ((val = pcm_formats[(INT)format].signd) < 0)
return -EINVAL;
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_signed);
+
/**
* snd_pcm_format_unsigned - Check the PCM format is unsigned linear
* @format: the format to check
*
- * Returns 1 if the given PCM format is unsigned linear, 0 if signed
+ * Return: 1 if the given PCM format is unsigned linear, 0 if signed
* linear, and a negative error code for non-linear formats.
*/
int snd_pcm_format_unsigned(snd_pcm_format_t format)
@@ -224,39 +253,45 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format)
return !val;
}
+EXPORT_SYMBOL(snd_pcm_format_unsigned);
+
/**
* snd_pcm_format_linear - Check the PCM format is linear
* @format: the format to check
*
- * Returns 1 if the given PCM format is linear, 0 if not.
+ * Return: 1 if the given PCM format is linear, 0 if not.
*/
int snd_pcm_format_linear(snd_pcm_format_t format)
{
return snd_pcm_format_signed(format) >= 0;
}
+EXPORT_SYMBOL(snd_pcm_format_linear);
+
/**
* snd_pcm_format_little_endian - Check the PCM format is little-endian
* @format: the format to check
*
- * Returns 1 if the given PCM format is little-endian, 0 if
+ * Return: 1 if the given PCM format is little-endian, 0 if
* big-endian, or a negative error code if endian not specified.
*/
int snd_pcm_format_little_endian(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].le) < 0)
+ if ((val = pcm_formats[(INT)format].le) < 0)
return -EINVAL;
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_little_endian);
+
/**
* snd_pcm_format_big_endian - Check the PCM format is big-endian
* @format: the format to check
*
- * Returns 1 if the given PCM format is big-endian, 0 if
+ * Return: 1 if the given PCM format is big-endian, 0 if
* little-endian, or a negative error code if endian not specified.
*/
int snd_pcm_format_big_endian(snd_pcm_format_t format)
@@ -269,45 +304,52 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format)
return !val;
}
+EXPORT_SYMBOL(snd_pcm_format_big_endian);
+
/**
* snd_pcm_format_width - return the bit-width of the format
* @format: the format to check
*
- * Returns the bit-width of the format, or a negative error code
+ * Return: The bit-width of the format, or a negative error code
* if unknown format.
*/
int snd_pcm_format_width(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].width) == 0)
+ if ((val = pcm_formats[(INT)format].width) == 0)
return -EINVAL;
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_width);
+
/**
* snd_pcm_format_physical_width - return the physical bit-width of the format
* @format: the format to check
*
- * Returns the physical bit-width of the format, or a negative error code
+ * Return: The physical bit-width of the format, or a negative error code
* if unknown format.
*/
int snd_pcm_format_physical_width(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].phys) == 0)
+ if ((val = pcm_formats[(INT)format].phys) == 0)
return -EINVAL;
return val;
}
+EXPORT_SYMBOL(snd_pcm_format_physical_width);
+
/**
* snd_pcm_format_size - return the byte size of samples on the given format
* @format: the format to check
+ * @samples: sampling rate
*
- * Returns the byte size of the given samples for the format, or a
+ * Return: The byte size of the given samples for the format, or a
* negative error code if unknown format.
*/
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
@@ -318,21 +360,25 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
return samples * phys_width / 8;
}
+EXPORT_SYMBOL(snd_pcm_format_size);
+
/**
* snd_pcm_format_silence_64 - return the silent data in 8 bytes array
* @format: the format to check
*
- * Returns the format pattern to fill or NULL if error.
+ * Return: The format pattern to fill or %NULL if error.
*/
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
{
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return NULL;
- if (! pcm_formats[format].phys)
+ if (! pcm_formats[(INT)format].phys)
return NULL;
- return pcm_formats[format].silence;
+ return pcm_formats[(INT)format].silence;
}
+EXPORT_SYMBOL(snd_pcm_format_silence_64);
+
/**
* snd_pcm_format_set_silence - set the silence data on the buffer
* @format: the PCM format
@@ -341,23 +387,23 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
*
* Sets the silence data on the buffer for the given samples.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
{
int width;
unsigned char *dst, *pat;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
if (samples == 0)
return 0;
- width = pcm_formats[format].phys; /* physical width */
- pat = pcm_formats[format].silence;
+ width = pcm_formats[(INT)format].phys; /* physical width */
+ pat = pcm_formats[(INT)format].silence;
if (! width)
return -EINVAL;
/* signed or 1 byte data */
- if (pcm_formats[format].signd == 1 || width <= 8) {
+ if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
unsigned int bytes = samples * width / 8;
memset(data, *pat, bytes);
return 0;
@@ -402,35 +448,7 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
return 0;
}
-/* [width][unsigned][bigendian] */
-static int linear_formats[4][2][2] = {
- {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
- { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}},
- {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE},
- {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}},
- {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE},
- {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}},
- {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE},
- {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}}
-};
-
-/**
- * snd_pcm_build_linear_format - return the suitable linear format for the given condition
- * @width: the bit-width
- * @unsignd: 1 if unsigned, 0 if signed.
- * @big_endian: 1 if big-endian, 0 if little-endian
- *
- * Returns the suitable linear format for the given condition.
- */
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
-{
- if (width & 7)
- return SND_PCM_FORMAT_UNKNOWN;
- width = (width / 8) - 1;
- if (width < 0 || width >= 4)
- return SND_PCM_FORMAT_UNKNOWN;
- return linear_formats[width][!!unsignd][!!big_endian];
-}
+EXPORT_SYMBOL(snd_pcm_format_set_silence);
/**
* snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
@@ -439,27 +457,99 @@ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_end
* Determines the rate_min and rate_max fields from the rates bits of
* the given runtime->hw.
*
- * Returns zero if successful.
+ * Return: Zero if successful.
*/
-int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime)
+int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
{
- static unsigned rates[] = {
- /* ATTENTION: these values depend on the definition in pcm.h! */
- 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
- 64000, 88200, 96000, 176400, 192000
- };
int i;
- for (i = 0; i < (int)ARRAY_SIZE(rates); i++) {
+ for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
if (runtime->hw.rates & (1 << i)) {
- runtime->hw.rate_min = rates[i];
+ runtime->hw.rate_min = snd_pcm_known_rates.list[i];
break;
}
}
- for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) {
+ for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
if (runtime->hw.rates & (1 << i)) {
- runtime->hw.rate_max = rates[i];
+ runtime->hw.rate_max = snd_pcm_known_rates.list[i];
break;
}
}
return 0;
}
+
+EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
+
+/**
+ * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
+ * @rate: the sample rate to convert
+ *
+ * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
+ * SNDRV_PCM_RATE_KNOT for an unknown rate.
+ */
+unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < snd_pcm_known_rates.count; i++)
+ if (snd_pcm_known_rates.list[i] == rate)
+ return 1u << i;
+ return SNDRV_PCM_RATE_KNOT;
+}
+EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
+
+/**
+ * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
+ * @rate_bit: the rate bit to convert
+ *
+ * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
+ * or 0 for an unknown rate bit.
+ */
+unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
+{
+ unsigned int i;
+
+ for (i = 0; i < snd_pcm_known_rates.count; i++)
+ if ((1u << i) == rate_bit)
+ return snd_pcm_known_rates.list[i];
+ return 0;
+}
+EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
+
+static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates)
+{
+ if (rates & SNDRV_PCM_RATE_CONTINUOUS)
+ return SNDRV_PCM_RATE_CONTINUOUS;
+ else if (rates & SNDRV_PCM_RATE_KNOT)
+ return SNDRV_PCM_RATE_KNOT;
+ return rates;
+}
+
+/**
+ * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks
+ * @rates_a: The first rate mask
+ * @rates_b: The second rate mask
+ *
+ * This function computes the rates that are supported by both rate masks passed
+ * to the function. It will take care of the special handling of
+ * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT.
+ *
+ * Return: A rate mask containing the rates that are supported by both rates_a
+ * and rates_b.
+ */
+unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
+ unsigned int rates_b)
+{
+ rates_a = snd_pcm_rate_mask_sanitize(rates_a);
+ rates_b = snd_pcm_rate_mask_sanitize(rates_b);
+
+ if (rates_a & SNDRV_PCM_RATE_CONTINUOUS)
+ return rates_b;
+ else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS)
+ return rates_a;
+ else if (rates_a & SNDRV_PCM_RATE_KNOT)
+ return rates_b;
+ else if (rates_b & SNDRV_PCM_RATE_KNOT)
+ return rates_a;
+ return rates_a & rates_b;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index e97b2d162cc..b653ab001fb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,14 @@
*
*/
-#include <sound/driver.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
+#include <linux/module.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
-#include <linux/uio.h>
+#include <linux/pm_qos.h>
+#include <linux/aio.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -34,16 +35,19 @@
#include <sound/timer.h>
#include <sound/minors.h>
#include <asm/io.h>
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+#include <dma-coherence.h>
+#endif
/*
* Compatibility
*/
-struct sndrv_pcm_hw_params_old {
+struct snd_pcm_hw_params_old {
unsigned int flags;
unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
SNDRV_PCM_HW_PARAM_ACCESS + 1];
- struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
unsigned int rmask;
unsigned int cmask;
@@ -51,23 +55,29 @@ struct sndrv_pcm_hw_params_old {
unsigned int msbits;
unsigned int rate_num;
unsigned int rate_den;
- sndrv_pcm_uframes_t fifo_size;
+ snd_pcm_uframes_t fifo_size;
unsigned char reserved[64];
};
-#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
-#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
+#ifdef CONFIG_SND_SUPPORT_OLD_API
+#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old)
+#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old)
-static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams);
-static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams);
+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params_old __user * _oparams);
+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params_old __user * _oparams);
+#endif
+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
/*
*
*/
DEFINE_RWLOCK(snd_pcm_link_rwlock);
-static DECLARE_RWSEM(snd_pcm_link_rwsem);
+EXPORT_SYMBOL(snd_pcm_link_rwlock);
+static DECLARE_RWSEM(snd_pcm_link_rwsem);
static inline mm_segment_t snd_enter_user(void)
{
@@ -83,13 +93,12 @@ static inline void snd_leave_user(mm_segment_t fs)
-int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info)
+int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
{
- snd_pcm_runtime_t * runtime;
- snd_pcm_t *pcm = substream->pcm;
- snd_pcm_str_t *pstr = substream->pstr;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm *pcm = substream->pcm;
+ struct snd_pcm_str *pstr = substream->pstr;
- snd_assert(substream != NULL, return -ENXIO);
memset(info, 0, sizeof(*info));
info->card = pcm->card->number;
info->device = pcm->device;
@@ -111,9 +120,10 @@ int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info)
return 0;
}
-int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _info)
+int snd_pcm_info_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_info __user * _info)
{
- snd_pcm_info_t *info;
+ struct snd_pcm_info *info;
int err;
info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -132,7 +142,7 @@ int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _
#ifdef RULES_DEBUG
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
HW_PARAM(ACCESS),
HW_PARAM(FORMAT),
HW_PARAM(SUBFORMAT),
@@ -151,14 +161,14 @@ char *snd_pcm_hw_param_names[] = {
};
#endif
-int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params)
+int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
unsigned int k;
- snd_pcm_hardware_t *hw;
- snd_interval_t *i = NULL;
- snd_mask_t *m = NULL;
- snd_pcm_hw_constraints_t *constrs = &substream->runtime->hw_constraints;
+ struct snd_pcm_hardware *hw;
+ struct snd_interval *i = NULL;
+ struct snd_mask *m = NULL;
+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
unsigned int rstamps[constrs->rules_num];
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp = 2;
@@ -180,12 +190,12 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk("%s = ", snd_pcm_hw_param_names[k]);
- printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
+ pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
#ifdef RULES_DEBUG
- printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
if (changed)
params->cmask |= 1 << k;
@@ -200,21 +210,21 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk("%s = ", snd_pcm_hw_param_names[k]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
- printk(" -> ");
+ pr_cont(" -> ");
#endif
changed = snd_interval_refine(i, constrs_interval(constrs, k));
#ifdef RULES_DEBUG
if (i->empty)
- printk("empty\n");
+ pr_cont("empty\n");
else
- printk("%c%u %u%c\n",
+ pr_cont("%c%u %u%c\n",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
#endif
@@ -231,7 +241,7 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
do {
again = 0;
for (k = 0; k < constrs->rules_num; k++) {
- snd_pcm_hw_rule_t *r = &constrs->rules[k];
+ struct snd_pcm_hw_rule *r = &constrs->rules[k];
unsigned int d;
int doit = 0;
if (r->cond && !(r->cond & params->flags))
@@ -245,18 +255,18 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
if (!doit)
continue;
#ifdef RULES_DEBUG
- printk("Rule %d [%p]: ", k, r->func);
+ pr_debug("Rule %d [%p]: ", k, r->func);
if (r->var >= 0) {
- printk("%s = ", snd_pcm_hw_param_names[r->var]);
+ pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
if (hw_is_mask(r->var)) {
m = hw_param_mask(params, r->var);
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
} else {
i = hw_param_interval(params, r->var);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
@@ -265,19 +275,19 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
changed = r->func(params, r);
#ifdef RULES_DEBUG
if (r->var >= 0) {
- printk(" -> ");
+ pr_cont(" -> ");
if (hw_is_mask(r->var))
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
else {
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
}
- printk("\n");
+ pr_cont("\n");
#endif
rstamps[k] = stamp;
if (changed && r->var >= 0) {
@@ -306,48 +316,78 @@ int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
hw = &substream->runtime->hw;
if (!params->info)
- params->info = hw->info;
- if (!params->fifo_size)
- params->fifo_size = hw->fifo_size;
+ params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ if (!params->fifo_size) {
+ m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ if (snd_mask_min(m) == snd_mask_max(m) &&
+ snd_interval_min(i) == snd_interval_max(i)) {
+ changed = substream->ops->ioctl(substream,
+ SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
+ if (changed < 0)
+ return changed;
+ }
+ }
params->rmask = 0;
return 0;
}
-static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params)
+EXPORT_SYMBOL(snd_pcm_hw_refine);
+
+static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params __user * _params)
{
- snd_pcm_hw_params_t *params;
+ struct snd_pcm_hw_params *params;
int err;
- params = kmalloc(sizeof(*params), GFP_KERNEL);
- if (!params) {
- err = -ENOMEM;
- goto out;
- }
- if (copy_from_user(params, _params, sizeof(*params))) {
- err = -EFAULT;
- goto out;
- }
+ params = memdup_user(_params, sizeof(*params));
+ if (IS_ERR(params))
+ return PTR_ERR(params);
+
err = snd_pcm_hw_refine(substream, params);
if (copy_to_user(_params, params, sizeof(*params))) {
if (!err)
err = -EFAULT;
}
-out:
+
kfree(params);
return err;
}
-static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
- snd_pcm_hw_params_t *params)
+static int period_to_usecs(struct snd_pcm_runtime *runtime)
{
- snd_pcm_runtime_t *runtime;
- int err;
+ int usecs;
+
+ if (! runtime->rate)
+ return -1; /* invalid */
+
+ /* take 75% of period time as the deadline */
+ usecs = (750000 / runtime->rate) * runtime->period_size;
+ usecs += ((750000 % runtime->rate) * runtime->period_size) /
+ runtime->rate;
+
+ return usecs;
+}
+
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
+{
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
+ substream->runtime->status->state = state;
+ snd_pcm_stream_unlock_irq(substream);
+}
+
+static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime;
+ int err, usecs;
unsigned int bits;
snd_pcm_uframes_t frames;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_OPEN:
@@ -359,10 +399,10 @@ static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
if (!substream->oss.oss)
#endif
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -EBADFD;
params->rmask = ~0U;
@@ -388,10 +428,12 @@ static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
runtime->period_size = params_period_size(params);
runtime->periods = params_periods(params);
runtime->buffer_size = params_buffer_size(params);
- runtime->tick_time = params_tick_time(params);
runtime->info = params->info;
runtime->rate_num = params->rate_num;
runtime->rate_den = params->rate_den;
+ runtime->no_period_wakeup =
+ (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+ (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
bits = snd_pcm_format_physical_width(runtime->format);
runtime->sample_bits = bits;
@@ -408,9 +450,7 @@ static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
/* Default sw params */
runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
runtime->period_step = 1;
- runtime->sleep_min = 0;
runtime->control->avail_min = runtime->period_size;
- runtime->xfer_align = runtime->period_size;
runtime->start_threshold = 1;
runtime->stop_threshold = runtime->buffer_size;
runtime->silence_threshold = 0;
@@ -420,50 +460,52 @@ static int snd_pcm_hw_params(snd_pcm_substream_t *substream,
runtime->boundary *= 2;
snd_pcm_timer_resolution_change(substream);
- runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
+
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ if ((usecs = period_to_usecs(runtime)) >= 0)
+ pm_qos_add_request(&substream->latency_pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, usecs);
return 0;
_error:
- /* hardware might be unuseable from this time,
+ /* hardware might be unusable from this time,
so we force application to retry to set
the correct hardware parameter settings */
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
return err;
}
-static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params)
+static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params __user * _params)
{
- snd_pcm_hw_params_t *params;
+ struct snd_pcm_hw_params *params;
int err;
- params = kmalloc(sizeof(*params), GFP_KERNEL);
- if (!params) {
- err = -ENOMEM;
- goto out;
- }
- if (copy_from_user(params, _params, sizeof(*params))) {
- err = -EFAULT;
- goto out;
- }
+ params = memdup_user(_params, sizeof(*params));
+ if (IS_ERR(params))
+ return PTR_ERR(params);
+
err = snd_pcm_hw_params(substream, params);
if (copy_to_user(_params, params, sizeof(*params))) {
if (!err)
err = -EFAULT;
}
-out:
+
kfree(params);
return err;
}
-static int snd_pcm_hw_free(snd_pcm_substream_t * substream)
+static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
int result = 0;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_SETUP:
@@ -474,21 +516,24 @@ static int snd_pcm_hw_free(snd_pcm_substream_t * substream)
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
- if (atomic_read(&runtime->mmap_count))
+ if (atomic_read(&substream->mmap_count))
return -EBADFD;
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
}
-static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_t *params)
+static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_sw_params *params)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
+ int err;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -ENXIO);
snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
snd_pcm_stream_unlock_irq(substream);
@@ -500,9 +545,6 @@ static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_
return -EINVAL;
if (params->avail_min == 0)
return -EINVAL;
- if (params->xfer_align == 0 ||
- params->xfer_align % runtime->min_align != 0)
- return -EINVAL;
if (params->silence_size >= runtime->boundary) {
if (params->silence_threshold != 0)
return -EINVAL;
@@ -512,34 +554,30 @@ static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_
if (params->silence_threshold > runtime->buffer_size)
return -EINVAL;
}
+ err = 0;
snd_pcm_stream_lock_irq(substream);
runtime->tstamp_mode = params->tstamp_mode;
- runtime->sleep_min = params->sleep_min;
runtime->period_step = params->period_step;
runtime->control->avail_min = params->avail_min;
runtime->start_threshold = params->start_threshold;
runtime->stop_threshold = params->stop_threshold;
runtime->silence_threshold = params->silence_threshold;
runtime->silence_size = params->silence_size;
- runtime->xfer_align = params->xfer_align;
params->boundary = runtime->boundary;
if (snd_pcm_running(substream)) {
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
- else
- snd_pcm_tick_set(substream, 0);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
- wake_up(&runtime->sleep);
+ err = snd_pcm_update_state(substream, runtime);
}
snd_pcm_stream_unlock_irq(substream);
- return 0;
+ return err;
}
-static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_params_t __user * _params)
+static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_sw_params __user * _params)
{
- snd_pcm_sw_params_t params;
+ struct snd_pcm_sw_params params;
int err;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
@@ -549,10 +587,10 @@ static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_pa
return err;
}
-int snd_pcm_status(snd_pcm_substream_t *substream,
- snd_pcm_status_t *status)
+int snd_pcm_status(struct snd_pcm_substream *substream,
+ struct snd_pcm_status *status)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
status->state = runtime->status->state;
@@ -562,25 +600,29 @@ int snd_pcm_status(snd_pcm_substream_t *substream,
status->trigger_tstamp = runtime->trigger_tstamp;
if (snd_pcm_running(substream)) {
snd_pcm_update_hw_ptr(substream);
- if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
status->tstamp = runtime->status->tstamp;
- else
- snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
- } else
- snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
+ status->audio_tstamp =
+ runtime->status->audio_tstamp;
+ goto _tstamp_end;
+ }
+ }
+ snd_pcm_gettime(runtime, &status->tstamp);
+ _tstamp_end:
status->appl_ptr = runtime->control->appl_ptr;
status->hw_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
status->avail = snd_pcm_playback_avail(runtime);
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
- runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+ runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
status->delay = runtime->buffer_size - status->avail;
- else
+ status->delay += runtime->delay;
+ } else
status->delay = 0;
} else {
status->avail = snd_pcm_capture_avail(runtime);
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- status->delay = status->avail;
+ status->delay = status->avail + runtime->delay;
else
status->delay = 0;
}
@@ -593,14 +635,12 @@ int snd_pcm_status(snd_pcm_substream_t *substream,
return 0;
}
-static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t __user * _status)
+static int snd_pcm_status_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_status __user * _status)
{
- snd_pcm_status_t status;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_status status;
int res;
- snd_assert(substream != NULL, return -ENXIO);
- runtime = substream->runtime;
memset(&status, 0, sizeof(status));
res = snd_pcm_status(substream, &status);
if (res < 0)
@@ -610,12 +650,12 @@ static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t
return 0;
}
-static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * info)
+static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
+ struct snd_pcm_channel_info * info)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
unsigned int channel;
- snd_assert(substream != NULL, return -ENXIO);
channel = info->channel;
runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
@@ -631,9 +671,10 @@ static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel
return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
}
-static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
+static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_channel_info __user * _info)
{
- snd_pcm_channel_info_t info;
+ struct snd_pcm_channel_info info;
int res;
if (copy_from_user(&info, _info, sizeof(info)))
@@ -646,13 +687,13 @@ static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_ch
return 0;
}
-static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream)
+static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->trigger_master == NULL)
return;
if (runtime->trigger_master == substream) {
- snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec);
+ snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
} else {
snd_pcm_trigger_tstamp(runtime->trigger_master);
runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -661,10 +702,10 @@ static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream)
}
struct action_ops {
- int (*pre_action)(snd_pcm_substream_t *substream, int state);
- int (*do_action)(snd_pcm_substream_t *substream, int state);
- void (*undo_action)(snd_pcm_substream_t *substream, int state);
- void (*post_action)(snd_pcm_substream_t *substream, int state);
+ int (*pre_action)(struct snd_pcm_substream *substream, int state);
+ int (*do_action)(struct snd_pcm_substream *substream, int state);
+ void (*undo_action)(struct snd_pcm_substream *substream, int state);
+ void (*post_action)(struct snd_pcm_substream *substream, int state);
};
/*
@@ -673,29 +714,26 @@ struct action_ops {
* Note2: call with calling stream lock + link lock
*/
static int snd_pcm_action_group(struct action_ops *ops,
- snd_pcm_substream_t *substream,
+ struct snd_pcm_substream *substream,
int state, int do_lock)
{
- struct list_head *pos;
- snd_pcm_substream_t *s = NULL;
- snd_pcm_substream_t *s1;
+ struct snd_pcm_substream *s = NULL;
+ struct snd_pcm_substream *s1;
int res = 0;
- snd_pcm_group_for_each(pos, substream) {
- s = snd_pcm_group_substream_entry(pos);
+ snd_pcm_group_for_each_entry(s, substream) {
if (do_lock && s != substream)
- spin_lock(&s->self_group.lock);
+ spin_lock_nested(&s->self_group.lock,
+ SINGLE_DEPTH_NESTING);
res = ops->pre_action(s, state);
if (res < 0)
goto _unlock;
}
- snd_pcm_group_for_each(pos, substream) {
- s = snd_pcm_group_substream_entry(pos);
+ snd_pcm_group_for_each_entry(s, substream) {
res = ops->do_action(s, state);
if (res < 0) {
if (ops->undo_action) {
- snd_pcm_group_for_each(pos, substream) {
- s1 = snd_pcm_group_substream_entry(pos);
+ snd_pcm_group_for_each_entry(s1, substream) {
if (s1 == s) /* failed stream */
break;
ops->undo_action(s1, state);
@@ -705,15 +743,13 @@ static int snd_pcm_action_group(struct action_ops *ops,
goto _unlock;
}
}
- snd_pcm_group_for_each(pos, substream) {
- s = snd_pcm_group_substream_entry(pos);
+ snd_pcm_group_for_each_entry(s, substream) {
ops->post_action(s, state);
}
_unlock:
if (do_lock) {
/* unlock streams */
- snd_pcm_group_for_each(pos, substream) {
- s1 = snd_pcm_group_substream_entry(pos);
+ snd_pcm_group_for_each_entry(s1, substream) {
if (s1 != substream)
spin_unlock(&s1->self_group.lock);
if (s1 == s) /* end */
@@ -727,7 +763,7 @@ static int snd_pcm_action_group(struct action_ops *ops,
* Note: call with stream lock
*/
static int snd_pcm_action_single(struct action_ops *ops,
- snd_pcm_substream_t *substream,
+ struct snd_pcm_substream *substream,
int state)
{
int res;
@@ -747,7 +783,7 @@ static int snd_pcm_action_single(struct action_ops *ops,
* Note: call with stream lock
*/
static int snd_pcm_action(struct action_ops *ops,
- snd_pcm_substream_t *substream,
+ struct snd_pcm_substream *substream,
int state)
{
int res;
@@ -770,7 +806,7 @@ static int snd_pcm_action(struct action_ops *ops,
* Note: don't use any locks before
*/
static int snd_pcm_action_lock_irq(struct action_ops *ops,
- snd_pcm_substream_t *substream,
+ struct snd_pcm_substream *substream,
int state)
{
int res;
@@ -794,7 +830,7 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
/*
*/
static int snd_pcm_action_nonatomic(struct action_ops *ops,
- snd_pcm_substream_t *substream,
+ struct snd_pcm_substream *substream,
int state)
{
int res;
@@ -811,9 +847,9 @@ static int snd_pcm_action_nonatomic(struct action_ops *ops,
/*
* start callbacks
*/
-static int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
return -EBADFD;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -823,31 +859,33 @@ static int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state)
return 0;
}
-static int snd_pcm_do_start(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state)
{
if (substream->runtime->trigger_master != substream)
return 0;
return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
}
-static void snd_pcm_undo_start(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state)
{
if (substream->runtime->trigger_master == substream)
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
}
-static void snd_pcm_post_start(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->hw_ptr_jiffies = jiffies;
+ runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
+ runtime->rate;
runtime->status->state = state;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,
+ &runtime->trigger_tstamp);
}
static struct action_ops snd_pcm_action_start = {
@@ -858,29 +896,30 @@ static struct action_ops snd_pcm_action_start = {
};
/**
- * snd_pcm_start
+ * snd_pcm_start - start all linked streams
* @substream: the PCM substream instance
*
- * Start all linked streams.
+ * Return: Zero if successful, or a negative error code.
*/
-int snd_pcm_start(snd_pcm_substream_t *substream)
+int snd_pcm_start(struct snd_pcm_substream *substream)
{
- return snd_pcm_action(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
+ return snd_pcm_action(&snd_pcm_action_start, substream,
+ SNDRV_PCM_STATE_RUNNING);
}
/*
* stop callbacks
*/
-static int snd_pcm_pre_stop(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
runtime->trigger_master = substream;
return 0;
}
-static int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state)
{
if (substream->runtime->trigger_master == substream &&
snd_pcm_running(substream))
@@ -888,17 +927,18 @@ static int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state)
return 0; /* unconditonally stop all substreams */
}
-static void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state != state) {
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
+ &runtime->trigger_tstamp);
runtime->status->state = state;
- snd_pcm_tick_set(substream, 0);
}
wake_up(&runtime->sleep);
+ wake_up(&runtime->tsleep);
}
static struct action_ops snd_pcm_action_stop = {
@@ -908,37 +948,42 @@ static struct action_ops snd_pcm_action_stop = {
};
/**
- * snd_pcm_stop
+ * snd_pcm_stop - try to stop all running streams in the substream group
* @substream: the PCM substream instance
* @state: PCM state after stopping the stream
*
- * Try to stop all running streams in the substream group.
- * The state of each stream is changed to the given value after that unconditionally.
+ * The state of each stream is then changed to the given state unconditionally.
+ *
+ * Return: Zero if successful, or a negative error code.
*/
-int snd_pcm_stop(snd_pcm_substream_t *substream, int state)
+int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}
+EXPORT_SYMBOL(snd_pcm_stop);
+
/**
- * snd_pcm_drain_done
+ * snd_pcm_drain_done - stop the DMA only when the given stream is playback
* @substream: the PCM substream
*
- * Stop the DMA only when the given stream is playback.
- * The state is changed to SETUP.
+ * After stopping, the state is changed to SETUP.
* Unlike snd_pcm_stop(), this affects only the given stream.
+ *
+ * Return: Zero if succesful, or a negative error code.
*/
-int snd_pcm_drain_done(snd_pcm_substream_t *substream)
+int snd_pcm_drain_done(struct snd_pcm_substream *substream)
{
- return snd_pcm_action_single(&snd_pcm_action_stop, substream, SNDRV_PCM_STATE_SETUP);
+ return snd_pcm_action_single(&snd_pcm_action_stop, substream,
+ SNDRV_PCM_STATE_SETUP);
}
/*
* pause callbacks
*/
-static int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push)
+static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (!(runtime->info & SNDRV_PCM_INFO_PAUSE))
return -ENOSYS;
if (push) {
@@ -950,16 +995,25 @@ static int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push)
return 0;
}
-static int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push)
+static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
{
if (substream->runtime->trigger_master != substream)
return 0;
+ /* some drivers might use hw_ptr to recover from the pause -
+ update the hw_ptr now */
+ if (push)
+ snd_pcm_update_hw_ptr(substream);
+ /* The jiffies check in snd_pcm_update_hw_ptr*() is done by
+ * a delta between the current jiffies, this gives a large enough
+ * delta, effectively to skip the check once.
+ */
+ substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
return substream->ops->trigger(substream,
push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
}
-static void snd_pcm_undo_pause(snd_pcm_substream_t *substream, int push)
+static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push)
{
if (substream->runtime->trigger_master == substream)
substream->ops->trigger(substream,
@@ -967,22 +1021,24 @@ static void snd_pcm_undo_pause(snd_pcm_substream_t *substream, int push)
SNDRV_PCM_TRIGGER_PAUSE_PUSH);
}
-static void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push)
+static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (push) {
runtime->status->state = SNDRV_PCM_STATE_PAUSED;
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
- snd_pcm_tick_set(substream, 0);
+ snd_timer_notify(substream->timer,
+ SNDRV_TIMER_EVENT_MPAUSE,
+ &runtime->trigger_tstamp);
wake_up(&runtime->sleep);
+ wake_up(&runtime->tsleep);
} else {
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer,
+ SNDRV_TIMER_EVENT_MCONTINUE,
+ &runtime->trigger_tstamp);
}
}
@@ -996,7 +1052,7 @@ static struct action_ops snd_pcm_action_pause = {
/*
* Push/release the pause for all linked streams.
*/
-static int snd_pcm_pause(snd_pcm_substream_t *substream, int push)
+static int snd_pcm_pause(struct snd_pcm_substream *substream, int push)
{
return snd_pcm_action(&snd_pcm_action_pause, substream, push);
}
@@ -1004,18 +1060,18 @@ static int snd_pcm_pause(snd_pcm_substream_t *substream, int push)
#ifdef CONFIG_PM
/* suspend */
-static int snd_pcm_pre_suspend(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
return -EBUSY;
runtime->trigger_master = substream;
return 0;
}
-static int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->trigger_master != substream)
return 0;
if (! snd_pcm_running(substream))
@@ -1024,16 +1080,17 @@ static int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state)
return 0; /* suspend unconditionally */
}
-static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
+ &runtime->trigger_tstamp);
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
- snd_pcm_tick_set(substream, 0);
wake_up(&runtime->sleep);
+ wake_up(&runtime->tsleep);
}
static struct action_ops snd_pcm_action_suspend = {
@@ -1043,37 +1100,49 @@ static struct action_ops snd_pcm_action_suspend = {
};
/**
- * snd_pcm_suspend
+ * snd_pcm_suspend - trigger SUSPEND to all linked streams
* @substream: the PCM substream
*
- * Trigger SUSPEND to all linked streams.
* After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @substream is %NULL), or a negative error
+ * code.
*/
-int snd_pcm_suspend(snd_pcm_substream_t *substream)
+int snd_pcm_suspend(struct snd_pcm_substream *substream)
{
int err;
unsigned long flags;
+ if (! substream)
+ return 0;
+
snd_pcm_stream_lock_irqsave(substream, flags);
err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
snd_pcm_stream_unlock_irqrestore(substream, flags);
return err;
}
+EXPORT_SYMBOL(snd_pcm_suspend);
+
/**
- * snd_pcm_suspend_all
+ * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm
* @pcm: the PCM instance
*
- * Trigger SUSPEND to all substreams in the given pcm.
* After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
*/
-int snd_pcm_suspend_all(snd_pcm_t *pcm)
+int snd_pcm_suspend_all(struct snd_pcm *pcm)
{
- snd_pcm_substream_t *substream;
+ struct snd_pcm_substream *substream;
int stream, err = 0;
+ if (! pcm)
+ return 0;
+
for (stream = 0; stream < 2; stream++) {
- for (substream = pcm->streams[stream].substream; substream; substream = substream->next) {
+ for (substream = pcm->streams[stream].substream;
+ substream; substream = substream->next) {
/* FIXME: the open/close code should lock this as well */
if (substream->runtime == NULL)
continue;
@@ -1085,20 +1154,22 @@ int snd_pcm_suspend_all(snd_pcm_t *pcm)
return 0;
}
+EXPORT_SYMBOL(snd_pcm_suspend_all);
+
/* resume */
-static int snd_pcm_pre_resume(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (!(runtime->info & SNDRV_PCM_INFO_RESUME))
return -ENOSYS;
runtime->trigger_master = substream;
return 0;
}
-static int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state)
+static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->trigger_master != substream)
return 0;
/* DMA not running previously? */
@@ -1109,22 +1180,21 @@ static int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state)
return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME);
}
-static void snd_pcm_undo_resume(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state)
{
if (substream->runtime->trigger_master == substream &&
snd_pcm_running(substream))
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
}
-static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
+static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
+ &runtime->trigger_tstamp);
runtime->status->state = runtime->status->suspended_state;
- if (runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
}
static struct action_ops snd_pcm_action_resume = {
@@ -1134,13 +1204,13 @@ static struct action_ops snd_pcm_action_resume = {
.post_action = snd_pcm_post_resume
};
-static int snd_pcm_resume(snd_pcm_substream_t *substream)
+static int snd_pcm_resume(struct snd_pcm_substream *substream)
{
- snd_card_t *card = substream->pcm->card;
+ struct snd_card *card = substream->pcm->card;
int res;
snd_power_lock(card);
- if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
snd_power_unlock(card);
return res;
@@ -1148,7 +1218,7 @@ static int snd_pcm_resume(snd_pcm_substream_t *substream)
#else
-static int snd_pcm_resume(snd_pcm_substream_t *substream)
+static int snd_pcm_resume(struct snd_pcm_substream *substream)
{
return -ENOSYS;
}
@@ -1160,15 +1230,15 @@ static int snd_pcm_resume(snd_pcm_substream_t *substream)
*
* Change the RUNNING stream(s) to XRUN state.
*/
-static int snd_pcm_xrun(snd_pcm_substream_t *substream)
+static int snd_pcm_xrun(struct snd_pcm_substream *substream)
{
- snd_card_t *card = substream->pcm->card;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_card *card = substream->pcm->card;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int result;
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto _unlock;
}
@@ -1193,9 +1263,9 @@ static int snd_pcm_xrun(snd_pcm_substream_t *substream)
/*
* reset ioctl
*/
-static int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state)
+static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
switch (runtime->status->state) {
case SNDRV_PCM_STATE_RUNNING:
case SNDRV_PCM_STATE_PREPARED:
@@ -1207,23 +1277,23 @@ static int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state)
}
}
-static int snd_pcm_do_reset(snd_pcm_substream_t * substream, int state)
+static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
if (err < 0)
return err;
- // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, );
runtime->hw_ptr_base = 0;
- runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size;
+ runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
+ runtime->status->hw_ptr % runtime->period_size;
runtime->silence_start = runtime->status->hw_ptr;
runtime->silence_filled = 0;
return 0;
}
-static void snd_pcm_post_reset(snd_pcm_substream_t * substream, int state)
+static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
runtime->control->appl_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
@@ -1236,7 +1306,7 @@ static struct action_ops snd_pcm_action_reset = {
.post_action = snd_pcm_post_reset
};
-static int snd_pcm_reset(snd_pcm_substream_t *substream)
+static int snd_pcm_reset(struct snd_pcm_substream *substream)
{
return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0);
}
@@ -1244,17 +1314,21 @@ static int snd_pcm_reset(snd_pcm_substream_t *substream)
/*
* prepare ioctl
*/
-static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state)
+/* we use the second argument for updating f_flags */
+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
+ int f_flags)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (snd_pcm_running(substream))
return -EBUSY;
+ substream->f_flags = f_flags;
return 0;
}
-static int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state)
+static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state)
{
int err;
err = substream->ops->prepare(substream);
@@ -1263,11 +1337,11 @@ static int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state)
return snd_pcm_do_reset(substream, 0);
}
-static void snd_pcm_post_prepare(snd_pcm_substream_t * substream, int state)
+static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
runtime->control->appl_ptr = runtime->status->hw_ptr;
- runtime->status->state = SNDRV_PCM_STATE_PREPARED;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
}
static struct action_ops snd_pcm_action_prepare = {
@@ -1277,19 +1351,28 @@ static struct action_ops snd_pcm_action_prepare = {
};
/**
- * snd_pcm_prepare
+ * snd_pcm_prepare - prepare the PCM substream to be triggerable
* @substream: the PCM substream instance
+ * @file: file to refer f_flags
*
- * Prepare the PCM substream to be triggerable.
+ * Return: Zero if successful, or a negative error code.
*/
-int snd_pcm_prepare(snd_pcm_substream_t *substream)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream,
+ struct file *file)
{
int res;
- snd_card_t *card = substream->pcm->card;
+ struct snd_card *card = substream->pcm->card;
+ int f_flags;
+
+ if (file)
+ f_flags = file->f_flags;
+ else
+ f_flags = substream->f_flags;
snd_power_lock(card);
- if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
- res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
+ res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
+ substream, f_flags);
snd_power_unlock(card);
return res;
}
@@ -1298,17 +1381,22 @@ int snd_pcm_prepare(snd_pcm_substream_t *substream)
* drain ioctl
*/
-static int snd_pcm_pre_drain_init(snd_pcm_substream_t * substream, int state)
+static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
{
- if (substream->ffile->f_flags & O_NONBLOCK)
- return -EAGAIN;
- substream->runtime->trigger_master = substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ switch (runtime->status->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_DISCONNECTED:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ return -EBADFD;
+ }
+ runtime->trigger_master = substream;
return 0;
}
-static int snd_pcm_do_drain_init(snd_pcm_substream_t * substream, int state)
+static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
@@ -1321,22 +1409,25 @@ static int snd_pcm_do_drain_init(snd_pcm_substream_t * substream, int state)
case SNDRV_PCM_STATE_RUNNING:
runtime->status->state = SNDRV_PCM_STATE_DRAINING;
break;
+ case SNDRV_PCM_STATE_XRUN:
+ runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ break;
default:
break;
}
} else {
/* stop running stream */
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
- int state = snd_pcm_capture_avail(runtime) > 0 ?
+ int new_state = snd_pcm_capture_avail(runtime) > 0 ?
SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP;
- snd_pcm_do_stop(substream, state);
- snd_pcm_post_stop(substream, state);
+ snd_pcm_do_stop(substream, new_state);
+ snd_pcm_post_stop(substream, new_state);
}
}
return 0;
}
-static void snd_pcm_post_drain_init(snd_pcm_substream_t * substream, int state)
+static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state)
{
}
@@ -1346,13 +1437,7 @@ static struct action_ops snd_pcm_action_drain_init = {
.post_action = snd_pcm_post_drain_init
};
-struct drain_rec {
- snd_pcm_substream_t *substream;
- wait_queue_t wait;
- snd_pcm_uframes_t stop_threshold;
-};
-
-static int snd_pcm_drop(snd_pcm_substream_t *substream);
+static int snd_pcm_drop(struct snd_pcm_substream *substream);
/*
* Drain the stream(s).
@@ -1361,16 +1446,16 @@ static int snd_pcm_drop(snd_pcm_substream_t *substream);
* After this call, all streams are supposed to be either SETUP or DRAINING
* (capture only) state.
*/
-static int snd_pcm_drain(snd_pcm_substream_t *substream)
+static int snd_pcm_drain(struct snd_pcm_substream *substream,
+ struct file *file)
{
- snd_card_t *card;
- snd_pcm_runtime_t *runtime;
- struct list_head *pos;
+ struct snd_card *card;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *s;
+ wait_queue_t wait;
int result = 0;
- int i, num_drecs;
- struct drain_rec *drec, drec_tmp, *d;
+ int nonblock = 0;
- snd_assert(substream != NULL, return -ENXIO);
card = substream->pcm->card;
runtime = substream->runtime;
@@ -1379,47 +1464,20 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream)
snd_power_lock(card);
if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0) {
snd_power_unlock(card);
return result;
}
}
- /* allocate temporary record for drain sync */
- down_read(&snd_pcm_link_rwsem);
- if (snd_pcm_stream_linked(substream)) {
- drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL);
- if (! drec) {
- up_read(&snd_pcm_link_rwsem);
- snd_power_unlock(card);
- return -ENOMEM;
- }
- } else
- drec = &drec_tmp;
-
- /* count only playback streams */
- num_drecs = 0;
- snd_pcm_group_for_each(pos, substream) {
- snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos);
- runtime = s->runtime;
- if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- d = &drec[num_drecs++];
- d->substream = s;
- init_waitqueue_entry(&d->wait, current);
- add_wait_queue(&runtime->sleep, &d->wait);
- /* stop_threshold fixup to avoid endless loop when
- * stop_threshold > buffer_size
- */
- d->stop_threshold = runtime->stop_threshold;
- if (runtime->stop_threshold > runtime->buffer_size)
- runtime->stop_threshold = runtime->buffer_size;
- }
- }
- up_read(&snd_pcm_link_rwsem);
- if (! num_drecs)
- goto _error;
+ if (file) {
+ if (file->f_flags & O_NONBLOCK)
+ nonblock = 1;
+ } else if (substream->f_flags & O_NONBLOCK)
+ nonblock = 1;
+ down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream);
/* resume pause */
if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
@@ -1427,37 +1485,64 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream)
/* pre-start/stop - all running streams are changed to DRAINING state */
result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
- if (result < 0) {
- snd_pcm_stream_unlock_irq(substream);
- goto _error;
+ if (result < 0)
+ goto unlock;
+ /* in non-blocking, we don't wait in ioctl but let caller poll */
+ if (nonblock) {
+ result = -EAGAIN;
+ goto unlock;
}
for (;;) {
long tout;
+ struct snd_pcm_runtime *to_check;
if (signal_pending(current)) {
result = -ERESTARTSYS;
break;
}
- /* all finished? */
- for (i = 0; i < num_drecs; i++) {
- runtime = drec[i].substream->runtime;
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+ /* find a substream to drain */
+ to_check = NULL;
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ continue;
+ runtime = s->runtime;
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+ to_check = runtime;
break;
+ }
}
- if (i == num_drecs)
- break; /* yes, all drained */
-
- set_current_state(TASK_INTERRUPTIBLE);
+ if (!to_check)
+ break; /* all drained */
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
+ up_read(&snd_pcm_link_rwsem);
snd_power_unlock(card);
- tout = schedule_timeout(10 * HZ);
+ if (runtime->no_period_wakeup)
+ tout = MAX_SCHEDULE_TIMEOUT;
+ else {
+ tout = 10;
+ if (runtime->rate) {
+ long t = runtime->period_size * 2 / runtime->rate;
+ tout = max(t, tout);
+ }
+ tout = msecs_to_jiffies(tout * 1000);
+ }
+ tout = schedule_timeout_interruptible(tout);
snd_power_lock(card);
+ down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream);
+ remove_wait_queue(&to_check->sleep, &wait);
+ if (card->shutdown) {
+ result = -ENODEV;
+ break;
+ }
if (tout == 0) {
if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
result = -ESTRPIPE;
else {
- snd_printd("playback drain error (DMA or IRQ trouble?)\n");
+ dev_dbg(substream->pcm->card->dev,
+ "playback drain error (DMA or IRQ trouble?)\n");
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
result = -EIO;
}
@@ -1465,18 +1550,9 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream)
}
}
+ unlock:
snd_pcm_stream_unlock_irq(substream);
-
- _error:
- for (i = 0; i < num_drecs; i++) {
- d = &drec[i];
- runtime = d->substream->runtime;
- remove_wait_queue(&runtime->sleep, &d->wait);
- runtime->stop_threshold = d->stop_threshold;
- }
-
- if (drec != &drec_tmp)
- kfree(drec);
+ up_read(&snd_pcm_link_rwsem);
snd_power_unlock(card);
return result;
@@ -1487,26 +1563,20 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream)
*
* Immediately put all linked substreams into SETUP state.
*/
-static int snd_pcm_drop(snd_pcm_substream_t *substream)
+static int snd_pcm_drop(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime;
- snd_card_t *card;
+ struct snd_pcm_runtime *runtime;
int result = 0;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- card = substream->pcm->card;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
+ runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
return -EBADFD;
- snd_power_lock(card);
- if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
- result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
- if (result < 0)
- goto _unlock;
- }
-
snd_pcm_stream_lock_irq(substream);
/* resume pause */
if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
@@ -1515,52 +1585,47 @@ static int snd_pcm_drop(snd_pcm_substream_t *substream)
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
snd_pcm_stream_unlock_irq(substream);
- _unlock:
- snd_power_unlock(card);
+
return result;
}
-/* WARNING: Don't forget to fput back the file */
-extern int snd_major;
-static struct file *snd_pcm_file_fd(int fd)
+static bool is_pcm_file(struct file *file)
{
- struct file *file;
- struct inode *inode;
- unsigned short minor;
- file = fget(fd);
- if (!file)
- return NULL;
- inode = file->f_dentry->d_inode;
- if (!S_ISCHR(inode->i_mode) ||
- imajor(inode) != snd_major) {
- fput(file);
- return NULL;
- }
+ struct inode *inode = file_inode(file);
+ unsigned int minor;
+
+ if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
+ return false;
minor = iminor(inode);
- if (minor >= 256 ||
- minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) {
- fput(file);
- return NULL;
- }
- return file;
+ return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
+ snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
}
/*
* PCM link handling
*/
-static int snd_pcm_link(snd_pcm_substream_t *substream, int fd)
+static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
int res = 0;
- struct file *file;
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream1;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream1;
+ struct snd_pcm_group *group;
+ struct fd f = fdget(fd);
- file = snd_pcm_file_fd(fd);
- if (!file)
+ if (!f.file)
return -EBADFD;
- pcm_file = file->private_data;
+ if (!is_pcm_file(f.file)) {
+ res = -EBADFD;
+ goto _badf;
+ }
+ pcm_file = f.file->private_data;
substream1 = pcm_file->substream;
+ group = kmalloc(sizeof(*group), GFP_KERNEL);
+ if (!group) {
+ res = -ENOMEM;
+ goto _nolock;
+ }
down_write(&snd_pcm_link_rwsem);
write_lock_irq(&snd_pcm_link_rwlock);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
@@ -1573,11 +1638,8 @@ static int snd_pcm_link(snd_pcm_substream_t *substream, int fd)
goto _end;
}
if (!snd_pcm_stream_linked(substream)) {
- substream->group = kmalloc(sizeof(snd_pcm_group_t), GFP_ATOMIC);
- if (substream->group == NULL) {
- res = -ENOMEM;
- goto _end;
- }
+ substream->group = group;
+ group = NULL;
spin_lock_init(&substream->group->lock);
INIT_LIST_HEAD(&substream->group->substreams);
list_add_tail(&substream->link_list, &substream->group->substreams);
@@ -1589,20 +1651,24 @@ static int snd_pcm_link(snd_pcm_substream_t *substream, int fd)
_end:
write_unlock_irq(&snd_pcm_link_rwlock);
up_write(&snd_pcm_link_rwsem);
- fput(file);
+ _nolock:
+ snd_card_unref(substream1->pcm->card);
+ kfree(group);
+ _badf:
+ fdput(f);
return res;
}
-static void relink_to_local(snd_pcm_substream_t *substream)
+static void relink_to_local(struct snd_pcm_substream *substream)
{
substream->group = &substream->self_group;
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
}
-static int snd_pcm_unlink(snd_pcm_substream_t *substream)
+static int snd_pcm_unlink(struct snd_pcm_substream *substream)
{
- struct list_head *pos;
+ struct snd_pcm_substream *s;
int res = 0;
down_write(&snd_pcm_link_rwsem);
@@ -1614,8 +1680,8 @@ static int snd_pcm_unlink(snd_pcm_substream_t *substream)
list_del(&substream->link_list);
substream->group->count--;
if (substream->group->count == 1) { /* detach the last stream, too */
- snd_pcm_group_for_each(pos, substream) {
- relink_to_local(snd_pcm_group_substream_entry(pos));
+ snd_pcm_group_for_each_entry(s, substream) {
+ relink_to_local(s);
break;
}
kfree(substream->group);
@@ -1630,51 +1696,51 @@ static int snd_pcm_unlink(snd_pcm_substream_t *substream)
/*
* hw configurator
*/
-static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
+ struct snd_interval t;
snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
+ struct snd_interval t;
snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
+ struct snd_interval t;
snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
hw_param_interval_c(params, rule->deps[1]),
(unsigned long) rule->private, &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
+ struct snd_interval t;
snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
(unsigned long) rule->private,
hw_param_interval_c(params, rule->deps[1]), &t);
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
unsigned int k;
- snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
- snd_mask_t m;
- snd_mask_t *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ struct snd_interval *i = hw_param_interval(params, rule->deps[0]);
+ struct snd_mask m;
+ struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_any(&m);
for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
int bits;
@@ -1689,10 +1755,10 @@ static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
return snd_mask_refine(mask, &m);
}
-static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
+ struct snd_interval t;
unsigned int k;
t.min = UINT_MAX;
t.max = 0;
@@ -1721,19 +1787,25 @@ static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
48000, 64000, 88200, 96000, 176400, 192000 };
-static int snd_pcm_hw_rule_rate(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+};
+
+static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_pcm_hardware_t *hw = rule->private;
+ struct snd_pcm_hardware *hw = rule->private;
return snd_interval_list(hw_param_interval(params, rule->var),
- ARRAY_SIZE(rates), rates, hw->rates);
+ snd_pcm_known_rates.count,
+ snd_pcm_known_rates.list, hw->rates);
}
-static int snd_pcm_hw_rule_buffer_bytes_max(snd_pcm_hw_params_t *params,
- snd_pcm_hw_rule_t *rule)
+static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
- snd_interval_t t;
- snd_pcm_substream_t *substream = rule->private;
+ struct snd_interval t;
+ struct snd_pcm_substream *substream = rule->private;
t.min = 0;
t.max = substream->buffer_bytes_max;
t.openmin = 0;
@@ -1742,10 +1814,10 @@ static int snd_pcm_hw_rule_buffer_bytes_max(snd_pcm_hw_params_t *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream)
+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
int k, err;
for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
@@ -1866,10 +1938,10 @@ int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream)
return 0;
}
-int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- snd_pcm_hardware_t *hw = &runtime->hw;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hardware *hw = &runtime->hw;
int err;
unsigned int mask = 0;
@@ -1886,33 +1958,41 @@ int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;
}
err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
hw->channels_min, hw->channels_max);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
hw->rate_min, hw->rate_max);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
hw->period_bytes_min, hw->period_bytes_max);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
hw->periods_min, hw->periods_max);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
hw->period_bytes_min, hw->buffer_bytes_max);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
snd_pcm_hw_rule_buffer_bytes_max, substream,
@@ -1923,7 +2003,8 @@ int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
/* FIXME: remove */
if (runtime->dma_bytes) {
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
- snd_assert(err >= 0, return -EINVAL);
+ if (err < 0)
+ return err;
}
if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
@@ -1935,126 +2016,142 @@ int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
}
/* FIXME: this belong to lowlevel */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME,
- 1000000 / HZ, 1000000 / HZ);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return 0;
}
-static void snd_pcm_add_file(snd_pcm_str_t *str,
- snd_pcm_file_t *pcm_file)
+static void pcm_release_private(struct snd_pcm_substream *substream)
{
- pcm_file->next = str->files;
- str->files = pcm_file;
-}
-
-static void snd_pcm_remove_file(snd_pcm_str_t *str,
- snd_pcm_file_t *pcm_file)
-{
- snd_pcm_file_t * pcm_file1;
- if (str->files == pcm_file) {
- str->files = pcm_file->next;
- } else {
- pcm_file1 = str->files;
- while (pcm_file1 && pcm_file1->next != pcm_file)
- pcm_file1 = pcm_file1->next;
- if (pcm_file1 != NULL)
- pcm_file1->next = pcm_file->next;
- }
+ snd_pcm_unlink(substream);
}
-static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
+void snd_pcm_release_substream(struct snd_pcm_substream *substream)
{
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
- snd_pcm_str_t * str;
+ substream->ref_count--;
+ if (substream->ref_count > 0)
+ return;
- snd_assert(pcm_file != NULL, return -ENXIO);
- substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
- runtime = substream->runtime;
- str = substream->pstr;
- snd_pcm_unlink(substream);
- if (substream->ffile != NULL) {
+ snd_pcm_drop(substream);
+ if (substream->hw_opened) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
- substream->ffile = NULL;
+ substream->hw_opened = 0;
}
- snd_pcm_remove_file(str, pcm_file);
- snd_pcm_release_substream(substream);
- kfree(pcm_file);
- return 0;
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+ if (substream->pcm_release) {
+ substream->pcm_release(substream);
+ substream->pcm_release = NULL;
+ }
+ snd_pcm_detach_substream(substream);
}
-static int snd_pcm_open_file(struct file *file,
- snd_pcm_t *pcm,
- int stream,
- snd_pcm_file_t **rpcm_file)
-{
- int err = 0;
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_str_t *str;
+EXPORT_SYMBOL(snd_pcm_release_substream);
- snd_assert(rpcm_file != NULL, return -EINVAL);
- *rpcm_file = NULL;
-
- pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
- if (pcm_file == NULL) {
- return -ENOMEM;
- }
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
+ struct file *file,
+ struct snd_pcm_substream **rsubstream)
+{
+ struct snd_pcm_substream *substream;
+ int err;
- if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
- kfree(pcm_file);
+ err = snd_pcm_attach_substream(pcm, stream, file, &substream);
+ if (err < 0)
return err;
+ if (substream->ref_count > 1) {
+ *rsubstream = substream;
+ return 0;
}
- str = substream->pstr;
- substream->file = pcm_file;
- substream->no_mmap_ctrl = 0;
-
- pcm_file->substream = substream;
-
- snd_pcm_add_file(str, pcm_file);
-
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_init failed\n");
- snd_pcm_release_file(pcm_file);
- return err;
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_init failed\n");
+ goto error;
}
- if ((err = substream->ops->open(substream)) < 0) {
- snd_pcm_release_file(pcm_file);
- return err;
- }
- substream->ffile = file;
+ if ((err = substream->ops->open(substream)) < 0)
+ goto error;
+
+ substream->hw_opened = 1;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_complete failed\n");
- snd_pcm_release_file(pcm_file);
- return err;
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_complete failed\n");
+ goto error;
}
+ *rsubstream = substream;
+ return 0;
+
+ error:
+ snd_pcm_release_substream(substream);
+ return err;
+}
+
+EXPORT_SYMBOL(snd_pcm_open_substream);
+
+static int snd_pcm_open_file(struct file *file,
+ struct snd_pcm *pcm,
+ int stream)
+{
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ int err;
+
+ err = snd_pcm_open_substream(pcm, stream, file, &substream);
+ if (err < 0)
+ return err;
+
+ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
+ if (pcm_file == NULL) {
+ snd_pcm_release_substream(substream);
+ return -ENOMEM;
+ }
+ pcm_file->substream = substream;
+ if (substream->ref_count == 1) {
+ substream->file = pcm_file;
+ substream->pcm_release = pcm_release_private;
+ }
file->private_data = pcm_file;
- *rpcm_file = pcm_file;
+
return 0;
}
-static int snd_pcm_open(struct inode *inode, struct file *file)
+static int snd_pcm_playback_open(struct inode *inode, struct file *file)
+{
+ struct snd_pcm *pcm;
+ int err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+ pcm = snd_lookup_minor_data(iminor(inode),
+ SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+ if (pcm)
+ snd_card_unref(pcm->card);
+ return err;
+}
+
+static int snd_pcm_capture_open(struct inode *inode, struct file *file)
+{
+ struct snd_pcm *pcm;
+ int err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+ pcm = snd_lookup_minor_data(iminor(inode),
+ SNDRV_DEVICE_TYPE_PCM_CAPTURE);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+ if (pcm)
+ snd_card_unref(pcm->card);
+ return err;
+}
+
+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{
- int cardnum = SNDRV_MINOR_CARD(iminor(inode));
- int device = SNDRV_MINOR_DEVICE(iminor(inode));
int err;
- snd_pcm_t *pcm;
- snd_pcm_file_t *pcm_file;
wait_queue_t wait;
- snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO);
- pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)];
if (pcm == NULL) {
err = -ENODEV;
goto __error1;
@@ -2068,9 +2165,9 @@ static int snd_pcm_open(struct inode *inode, struct file *file)
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait);
- down(&pcm->open_mutex);
+ mutex_lock(&pcm->open_mutex);
while (1) {
- err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file);
+ err = snd_pcm_open_file(file, pcm, stream);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -2081,16 +2178,20 @@ static int snd_pcm_open(struct inode *inode, struct file *file)
} else
break;
set_current_state(TASK_INTERRUPTIBLE);
- up(&pcm->open_mutex);
+ mutex_unlock(&pcm->open_mutex);
schedule();
- down(&pcm->open_mutex);
+ mutex_lock(&pcm->open_mutex);
+ if (pcm->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
}
remove_wait_queue(&pcm->open_wait, &wait);
- up(&pcm->open_mutex);
+ mutex_unlock(&pcm->open_mutex);
if (err < 0)
goto __error;
return err;
@@ -2105,29 +2206,29 @@ static int snd_pcm_open(struct inode *inode, struct file *file)
static int snd_pcm_release(struct inode *inode, struct file *file)
{
- snd_pcm_t *pcm;
- snd_pcm_substream_t *substream;
- snd_pcm_file_t *pcm_file;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_file *pcm_file;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
- snd_assert(!atomic_read(&substream->runtime->mmap_count), );
+ if (snd_BUG_ON(!substream))
+ return -ENXIO;
pcm = substream->pcm;
- snd_pcm_drop(substream);
- fasync_helper(-1, file, 0, &substream->runtime->fasync);
- down(&pcm->open_mutex);
- snd_pcm_release_file(pcm_file);
- up(&pcm->open_mutex);
+ mutex_lock(&pcm->open_mutex);
+ snd_pcm_release_substream(substream);
+ kfree(pcm_file);
+ mutex_unlock(&pcm->open_mutex);
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
snd_card_file_remove(pcm->card, file);
return 0;
}
-static snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t hw_avail;
@@ -2147,6 +2248,9 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream,
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
+ case SNDRV_PCM_STATE_SUSPENDED:
+ ret = -ESTRPIPE;
+ goto __end;
default:
ret = -EBADFD;
goto __end;
@@ -2159,24 +2263,20 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream,
}
if (frames > (snd_pcm_uframes_t)hw_avail)
frames = hw_avail;
- else
- frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr - frames;
if (appl_ptr < 0)
appl_ptr += runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
- runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
ret = frames;
__end:
snd_pcm_stream_unlock_irq(substream);
return ret;
}
-static snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t hw_avail;
@@ -2196,6 +2296,9 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream,
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
+ case SNDRV_PCM_STATE_SUSPENDED:
+ ret = -ESTRPIPE;
+ goto __end;
default:
ret = -EBADFD;
goto __end;
@@ -2208,24 +2311,20 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream,
}
if (frames > (snd_pcm_uframes_t)hw_avail)
frames = hw_avail;
- else
- frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr - frames;
if (appl_ptr < 0)
appl_ptr += runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
- runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
ret = frames;
__end:
snd_pcm_stream_unlock_irq(substream);
return ret;
}
-static snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
@@ -2246,6 +2345,9 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
+ case SNDRV_PCM_STATE_SUSPENDED:
+ ret = -ESTRPIPE;
+ goto __end;
default:
ret = -EBADFD;
goto __end;
@@ -2258,24 +2360,20 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
- else
- frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
- runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
ret = frames;
__end:
snd_pcm_stream_unlock_irq(substream);
return ret;
}
-static snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
+static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t frames)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
@@ -2296,6 +2394,9 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream,
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
+ case SNDRV_PCM_STATE_SUSPENDED:
+ ret = -ESTRPIPE;
+ goto __end;
default:
ret = -EBADFD;
goto __end;
@@ -2308,24 +2409,19 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream,
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
- else
- frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
- runtime->sleep_min)
- snd_pcm_tick_prepare(substream);
ret = frames;
__end:
snd_pcm_stream_unlock_irq(substream);
return ret;
}
-static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
+static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
snd_pcm_stream_lock_irq(substream);
@@ -2333,6 +2429,7 @@ static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -2353,9 +2450,10 @@ static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
return err;
}
-static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res)
+static int snd_pcm_delay(struct snd_pcm_substream *substream,
+ snd_pcm_sframes_t __user *res)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
snd_pcm_sframes_t n = 0;
@@ -2364,6 +2462,7 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __use
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -2375,6 +2474,7 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __use
n = snd_pcm_playback_hw_avail(runtime);
else
n = snd_pcm_capture_avail(runtime);
+ n += runtime->delay;
break;
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
@@ -2391,18 +2491,19 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __use
return err;
}
-static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr __user *_sync_ptr)
+static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
+ struct snd_pcm_sync_ptr __user *_sync_ptr)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- struct sndrv_pcm_sync_ptr sync_ptr;
- volatile struct sndrv_pcm_mmap_status *status;
- volatile struct sndrv_pcm_mmap_control *control;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_sync_ptr sync_ptr;
+ volatile struct snd_pcm_mmap_status *status;
+ volatile struct snd_pcm_mmap_control *control;
int err;
memset(&sync_ptr, 0, sizeof(sync_ptr));
if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
return -EFAULT;
- if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct sndrv_pcm_mmap_control)))
+ if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control)))
return -EFAULT;
status = runtime->status;
control = runtime->control;
@@ -2429,30 +2530,35 @@ static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_syn
return -EFAULT;
return 0;
}
-
-static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
- unsigned int cmd, void __user *arg);
-static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
- unsigned int cmd, void __user *arg);
-static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
+static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int arg;
+
+ if (get_user(arg, _arg))
+ return -EFAULT;
+ if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
+ return -EINVAL;
+ runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
+ if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+ runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
+ return 0;
+}
+
+static int snd_pcm_common_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
- snd_assert(substream != NULL, return -ENXIO);
-
switch (cmd) {
case SNDRV_PCM_IOCTL_PVERSION:
return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
case SNDRV_PCM_IOCTL_INFO:
return snd_pcm_info_user(substream, arg);
- case SNDRV_PCM_IOCTL_TSTAMP:
- {
- int xarg;
- if (get_user(xarg, (int __user *)arg))
- return -EFAULT;
- substream->runtime->tstamp_timespec = xarg ? 1 : 0;
+ case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */
return 0;
- }
+ case SNDRV_PCM_IOCTL_TTSTAMP:
+ return snd_pcm_tstamp(substream, arg);
case SNDRV_PCM_IOCTL_HW_REFINE:
return snd_pcm_hw_refine_user(substream, arg);
case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -2466,7 +2572,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
case SNDRV_PCM_IOCTL_CHANNEL_INFO:
return snd_pcm_channel_info_user(substream, arg);
case SNDRV_PCM_IOCTL_PREPARE:
- return snd_pcm_prepare(substream);
+ return snd_pcm_prepare(substream, file);
case SNDRV_PCM_IOCTL_RESET:
return snd_pcm_reset(substream);
case SNDRV_PCM_IOCTL_START:
@@ -2485,30 +2591,43 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
return snd_pcm_delay(substream, arg);
case SNDRV_PCM_IOCTL_SYNC_PTR:
return snd_pcm_sync_ptr(substream, arg);
+#ifdef CONFIG_SND_SUPPORT_OLD_API
case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
return snd_pcm_hw_refine_old_user(substream, arg);
case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
return snd_pcm_hw_params_old_user(substream, arg);
+#endif
case SNDRV_PCM_IOCTL_DRAIN:
- return snd_pcm_drain(substream);
+ return snd_pcm_drain(substream, file);
case SNDRV_PCM_IOCTL_DROP:
return snd_pcm_drop(substream);
+ case SNDRV_PCM_IOCTL_PAUSE:
+ {
+ int res;
+ snd_pcm_stream_lock_irq(substream);
+ res = snd_pcm_pause(substream, (int)(unsigned long)arg);
+ snd_pcm_stream_unlock_irq(substream);
+ return res;
+ }
}
- snd_printd("unknown ioctl = 0x%x\n", cmd);
+ pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
-static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
+static int snd_pcm_playback_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
- snd_assert(substream != NULL, return -ENXIO);
- snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL);
+ if (snd_BUG_ON(!substream))
+ return -ENXIO;
+ if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
+ return -EINVAL;
switch (cmd) {
case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
{
- snd_xferi_t xferi;
- snd_xferi_t __user *_xferi = arg;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_xferi xferi;
+ struct snd_xferi __user *_xferi = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t result;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
@@ -2522,9 +2641,9 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
}
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
{
- snd_xfern_t xfern;
- snd_xfern_t __user *_xfern = arg;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_xfern xfern;
+ struct snd_xfern __user *_xfern = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
void __user **bufs;
snd_pcm_sframes_t result;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
@@ -2535,13 +2654,11 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
return -EFAULT;
if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
return -EFAULT;
- bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
- if (bufs == NULL)
- return -ENOMEM;
- if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
- kfree(bufs);
- return -EFAULT;
- }
+
+ bufs = memdup_user(xfern.bufs,
+ sizeof(void *) * runtime->channels);
+ if (IS_ERR(bufs))
+ return PTR_ERR(bufs);
result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
kfree(bufs);
__put_user(result, &_xfern->result);
@@ -2573,29 +2690,24 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames);
return result < 0 ? result : 0;
}
- case SNDRV_PCM_IOCTL_PAUSE:
- {
- int res;
- snd_pcm_stream_lock_irq(substream);
- res = snd_pcm_pause(substream, (int)(unsigned long)arg);
- snd_pcm_stream_unlock_irq(substream);
- return res;
- }
}
- return snd_pcm_common_ioctl1(substream, cmd, arg);
+ return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}
-static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
+static int snd_pcm_capture_ioctl1(struct file *file,
+ struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{
- snd_assert(substream != NULL, return -ENXIO);
- snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL);
+ if (snd_BUG_ON(!substream))
+ return -ENXIO;
+ if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
+ return -EINVAL;
switch (cmd) {
case SNDRV_PCM_IOCTL_READI_FRAMES:
{
- snd_xferi_t xferi;
- snd_xferi_t __user *_xferi = arg;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_xferi xferi;
+ struct snd_xferi __user *_xferi = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t result;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
@@ -2609,9 +2721,9 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
}
case SNDRV_PCM_IOCTL_READN_FRAMES:
{
- snd_xfern_t xfern;
- snd_xfern_t __user *_xfern = arg;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_xfern xfern;
+ struct snd_xfern __user *_xfern = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
void *bufs;
snd_pcm_sframes_t result;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
@@ -2622,13 +2734,11 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
return -EFAULT;
if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
return -EFAULT;
- bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
- if (bufs == NULL)
- return -ENOMEM;
- if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
- kfree(bufs);
- return -EFAULT;
- }
+
+ bufs = memdup_user(xfern.bufs,
+ sizeof(void *) * runtime->channels);
+ if (IS_ERR(bufs))
+ return PTR_ERR(bufs);
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
kfree(bufs);
__put_user(result, &_xfern->result);
@@ -2661,80 +2771,75 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
return result < 0 ? result : 0;
}
}
- return snd_pcm_common_ioctl1(substream, cmd, arg);
+ return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}
-static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- snd_pcm_file_t *pcm_file;
+ struct snd_pcm_file *pcm_file;
pcm_file = file->private_data;
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+ return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
+ (void __user *)arg);
}
-static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- snd_pcm_file_t *pcm_file;
+ struct snd_pcm_file *pcm_file;
pcm_file = file->private_data;
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
- return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+ return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
+ (void __user *)arg);
}
-int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream,
- unsigned int cmd, void *arg)
-{
- mm_segment_t fs;
- int result;
-
- fs = snd_enter_user();
- result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg);
- snd_leave_user(fs);
- return result;
-}
-
-int snd_pcm_kernel_capture_ioctl(snd_pcm_substream_t *substream,
- unsigned int cmd, void *arg)
+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
{
mm_segment_t fs;
int result;
fs = snd_enter_user();
- result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg);
- snd_leave_user(fs);
- return result;
-}
-
-int snd_pcm_kernel_ioctl(snd_pcm_substream_t *substream,
- unsigned int cmd, void *arg)
-{
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
- return snd_pcm_kernel_playback_ioctl(substream, cmd, arg);
+ result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
+ (void __user *)arg);
+ break;
case SNDRV_PCM_STREAM_CAPTURE:
- return snd_pcm_kernel_capture_ioctl(substream, cmd, arg);
+ result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
+ (void __user *)arg);
+ break;
default:
- return -EINVAL;
+ result = -EINVAL;
+ break;
}
+ snd_leave_user(fs);
+ return result;
}
-static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t * offset)
+EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
+
+static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
+ loff_t * offset)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
@@ -2747,61 +2852,59 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, l
return result;
}
-static ssize_t snd_pcm_write(struct file *file, const char __user *buf, size_t count, loff_t * offset)
+static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
+ size_t count, loff_t * offset)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, result = -ENXIO; goto end);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- result = -EBADFD;
- goto end;
- }
- if (!frame_aligned(runtime, count)) {
- result = -EINVAL;
- goto end;
- }
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ if (!frame_aligned(runtime, count))
+ return -EINVAL;
count = bytes_to_frames(runtime, count);
result = snd_pcm_lib_write(substream, buf, count);
if (result > 0)
result = frames_to_bytes(runtime, result);
- end:
return result;
}
-static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
- unsigned long count, loff_t * offset)
+static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
void __user **bufs;
snd_pcm_uframes_t frames;
- pcm_file = file->private_data;
+ pcm_file = iocb->ki_filp->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- if (count > 1024 || count != runtime->channels)
+ if (nr_segs > 1024 || nr_segs != runtime->channels)
return -EINVAL;
- if (!frame_aligned(runtime, _vector->iov_len))
+ if (!frame_aligned(runtime, iov->iov_len))
return -EINVAL;
- frames = bytes_to_samples(runtime, _vector->iov_len);
- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+ frames = bytes_to_samples(runtime, iov->iov_len);
+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
if (bufs == NULL)
return -ENOMEM;
- for (i = 0; i < count; ++i)
- bufs[i] = _vector[i].iov_base;
+ for (i = 0; i < nr_segs; ++i)
+ bufs[i] = iov[i].iov_base;
result = snd_pcm_lib_readv(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
@@ -2809,56 +2912,53 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
return result;
}
-static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
- unsigned long count, loff_t * offset)
+static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
void __user **bufs;
snd_pcm_uframes_t frames;
- pcm_file = file->private_data;
+ pcm_file = iocb->ki_filp->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, result = -ENXIO; goto end);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
- if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
- result = -EBADFD;
- goto end;
- }
- if (count > 128 || count != runtime->channels ||
- !frame_aligned(runtime, _vector->iov_len)) {
- result = -EINVAL;
- goto end;
- }
- frames = bytes_to_samples(runtime, _vector->iov_len);
- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ if (nr_segs > 128 || nr_segs != runtime->channels ||
+ !frame_aligned(runtime, iov->iov_len))
+ return -EINVAL;
+ frames = bytes_to_samples(runtime, iov->iov_len);
+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
if (bufs == NULL)
return -ENOMEM;
- for (i = 0; i < count; ++i)
- bufs[i] = _vector[i].iov_base;
+ for (i = 0; i < nr_segs; ++i)
+ bufs[i] = iov[i].iov_base;
result = snd_pcm_lib_writev(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
kfree(bufs);
- end:
return result;
}
static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
unsigned int mask;
snd_pcm_uframes_t avail;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
poll_wait(file, &runtime->sleep, wait);
@@ -2887,16 +2987,17 @@ static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
{
- snd_pcm_file_t *pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_file *pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
unsigned int mask;
snd_pcm_uframes_t avail;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
poll_wait(file, &runtime->sleep, wait);
@@ -2939,198 +3040,222 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
/*
* mmap status record
*/
-static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+static int snd_pcm_mmap_status_fault(struct vm_area_struct *area,
+ struct vm_fault *vmf)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
- snd_pcm_runtime_t *runtime;
- struct page * page;
+ struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
runtime = substream->runtime;
- page = virt_to_page(runtime->status);
- get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = virt_to_page(runtime->status);
+ get_page(vmf->page);
+ return 0;
}
-static struct vm_operations_struct snd_pcm_vm_ops_status =
+static const struct vm_operations_struct snd_pcm_vm_ops_status =
{
- .nopage = snd_pcm_mmap_status_nopage,
+ .fault = snd_pcm_mmap_status_fault,
};
-static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
- snd_pcm_runtime_t *runtime;
long size;
if (!(area->vm_flags & VM_READ))
return -EINVAL;
- runtime = substream->runtime;
- snd_assert(runtime != NULL, return -EAGAIN);
size = area->vm_end - area->vm_start;
- if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)))
+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_status;
area->vm_private_data = substream;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
return 0;
}
/*
* mmap control record
*/
-static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+static int snd_pcm_mmap_control_fault(struct vm_area_struct *area,
+ struct vm_fault *vmf)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
- snd_pcm_runtime_t *runtime;
- struct page * page;
+ struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_runtime *runtime;
if (substream == NULL)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
runtime = substream->runtime;
- page = virt_to_page(runtime->control);
- get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = virt_to_page(runtime->control);
+ get_page(vmf->page);
+ return 0;
}
-static struct vm_operations_struct snd_pcm_vm_ops_control =
+static const struct vm_operations_struct snd_pcm_vm_ops_control =
{
- .nopage = snd_pcm_mmap_control_nopage,
+ .fault = snd_pcm_mmap_control_fault,
};
-static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file,
+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
- snd_pcm_runtime_t *runtime;
long size;
if (!(area->vm_flags & VM_READ))
return -EINVAL;
- runtime = substream->runtime;
- snd_assert(runtime != NULL, return -EAGAIN);
size = area->vm_end - area->vm_start;
- if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)))
+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_control;
area->vm_private_data = substream;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
return 0;
}
#else /* ! coherent mmap */
/*
* don't support mmap for status and control records.
*/
-static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
return -ENXIO;
}
-static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file,
+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
return -ENXIO;
}
#endif /* coherent mmap */
+static inline struct page *
+snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
+{
+ void *vaddr = substream->runtime->dma_area + ofs;
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+ return virt_to_page(CAC_ADDR(vaddr));
+#endif
+#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE)
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) {
+ dma_addr_t addr = substream->runtime->dma_addr + ofs;
+ addr -= get_dma_offset(substream->dma_buffer.dev.dev);
+ /* assume dma_handle set via pfn_to_phys() in
+ * mm/dma-noncoherent.c
+ */
+ return pfn_to_page(addr >> PAGE_SHIFT);
+ }
+#endif
+ return virt_to_page(vaddr);
+}
+
/*
- * nopage callback for mmapping a RAM page
+ * fault callback for mmapping a RAM page
*/
-static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
+ struct vm_fault *vmf)
{
- snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_runtime *runtime;
unsigned long offset;
struct page * page;
- void *vaddr;
size_t dma_bytes;
if (substream == NULL)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
runtime = substream->runtime;
- offset = area->vm_pgoff << PAGE_SHIFT;
- offset += address - area->vm_start;
- snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
+ offset = vmf->pgoff << PAGE_SHIFT;
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if (offset > dma_bytes - PAGE_SIZE)
- return NOPAGE_SIGBUS;
- if (substream->ops->page) {
+ return VM_FAULT_SIGBUS;
+ if (substream->ops->page)
page = substream->ops->page(substream, offset);
- if (! page)
- return NOPAGE_OOM;
- } else {
- vaddr = runtime->dma_area + offset;
- page = virt_to_page(vaddr);
- }
+ else
+ page = snd_pcm_default_page_ops(substream, offset);
+ if (!page)
+ return VM_FAULT_SIGBUS;
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
-static struct vm_operations_struct snd_pcm_vm_ops_data =
-{
+static const struct vm_operations_struct snd_pcm_vm_ops_data = {
.open = snd_pcm_mmap_data_open,
.close = snd_pcm_mmap_data_close,
- .nopage = snd_pcm_mmap_data_nopage,
};
+static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
+ .open = snd_pcm_mmap_data_open,
+ .close = snd_pcm_mmap_data_close,
+ .fault = snd_pcm_mmap_data_fault,
+};
+
+#ifndef ARCH_HAS_DMA_MMAP_COHERENT
+/* This should be defined / handled globally! */
+#ifdef CONFIG_ARM
+#define ARCH_HAS_DMA_MMAP_COHERENT
+#endif
+#endif
+
/*
* mmap the DMA buffer on RAM
*/
-static int snd_pcm_default_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *area)
-{
- area->vm_ops = &snd_pcm_vm_ops_data;
- area->vm_private_data = substream;
- area->vm_flags |= VM_RESERVED;
- atomic_inc(&substream->runtime->mmap_count);
+int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+ return remap_pfn_range(area, area->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ area->vm_end - area->vm_start, area->vm_page_prot);
+ }
+#endif /* CONFIG_GENERIC_ALLOCATOR */
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+ if (!substream->ops->page &&
+ substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+ return dma_mmap_coherent(substream->dma_buffer.dev.dev,
+ area,
+ substream->runtime->dma_area,
+ substream->runtime->dma_addr,
+ area->vm_end - area->vm_start);
+#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
+ !plat_device_is_coherent(substream->dma_buffer.dev.dev))
+ area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
+#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
+ /* mmap with fault handler */
+ area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
/*
* mmap the DMA buffer on I/O memory area
*/
#if SNDRV_PCM_INFO_MMAP_IOMEM
-static struct vm_operations_struct snd_pcm_vm_ops_data_mmio =
+int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
{
- .open = snd_pcm_mmap_data_open,
- .close = snd_pcm_mmap_data_close,
-};
+ struct snd_pcm_runtime *runtime = substream->runtime;;
-int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct *area)
-{
- long size;
- unsigned long offset;
-
-#ifdef pgprot_noncached
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif
- area->vm_ops = &snd_pcm_vm_ops_data_mmio;
- area->vm_private_data = substream;
- area->vm_flags |= VM_IO;
- size = area->vm_end - area->vm_start;
- offset = area->vm_pgoff << PAGE_SHIFT;
- if (io_remap_pfn_range(area, area->vm_start,
- (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
- size, area->vm_page_prot))
- return -EAGAIN;
- atomic_inc(&substream->runtime->mmap_count);
- return 0;
+ return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
}
+
+EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
#endif /* SNDRV_PCM_INFO_MMAP */
/*
* mmap DMA buffer
*/
-int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
+int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
- snd_pcm_runtime_t *runtime;
+ struct snd_pcm_runtime *runtime;
long size;
unsigned long offset;
size_t dma_bytes;
+ int err;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (!(area->vm_flags & (VM_WRITE|VM_READ)))
@@ -3140,7 +3265,6 @@ int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
return -EINVAL;
}
runtime = substream->runtime;
- snd_assert(runtime != NULL, return -EAGAIN);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
@@ -3156,30 +3280,38 @@ int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
if (offset > dma_bytes - size)
return -EINVAL;
+ area->vm_ops = &snd_pcm_vm_ops_data;
+ area->vm_private_data = substream;
if (substream->ops->mmap)
- return substream->ops->mmap(substream, area);
+ err = substream->ops->mmap(substream, area);
else
- return snd_pcm_default_mmap(substream, area);
+ err = snd_pcm_lib_default_mmap(substream, area);
+ if (!err)
+ atomic_inc(&substream->mmap_count);
+ return err;
}
+EXPORT_SYMBOL(snd_pcm_mmap_data);
+
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{
- snd_pcm_file_t * pcm_file;
- snd_pcm_substream_t *substream;
+ struct snd_pcm_file * pcm_file;
+ struct snd_pcm_substream *substream;
unsigned long offset;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS:
- if (substream->no_mmap_ctrl)
+ if (pcm_file->no_compat_mmap)
return -ENXIO;
return snd_pcm_mmap_status(substream, file, area);
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
- if (substream->no_mmap_ctrl)
+ if (pcm_file->no_compat_mmap)
return -ENXIO;
return snd_pcm_mmap_control(substream, file, area);
default:
@@ -3190,20 +3322,16 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
static int snd_pcm_fasync(int fd, struct file * file, int on)
{
- snd_pcm_file_t * pcm_file;
- snd_pcm_substream_t *substream;
- snd_pcm_runtime_t *runtime;
- int err;
+ struct snd_pcm_file * pcm_file;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
pcm_file = file->private_data;
substream = pcm_file->substream;
- snd_assert(substream != NULL, return -ENXIO);
+ if (PCM_RUNTIME_CHECK(substream))
+ return -ENXIO;
runtime = substream->runtime;
-
- err = fasync_helper(fd, file, on, &runtime->fasync);
- if (err < 0)
- return err;
- return 0;
+ return fasync_helper(fd, file, on, &runtime->fasync);
}
/*
@@ -3219,10 +3347,12 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
* To be removed helpers to keep binary compatibility
*/
+#ifdef CONFIG_SND_SUPPORT_OLD_API
#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
-static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old *oparams)
+static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_params_old *oparams)
{
unsigned int i;
@@ -3240,7 +3370,8 @@ static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, stru
params->fifo_size = oparams->fifo_size;
}
-static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, snd_pcm_hw_params_t *params)
+static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *oparams,
+ struct snd_pcm_hw_params *params)
{
unsigned int i;
@@ -3258,25 +3389,20 @@ static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *opa
oparams->fifo_size = params->fifo_size;
}
-static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params_old __user * _oparams)
{
- snd_pcm_hw_params_t *params;
- struct sndrv_pcm_hw_params_old *oparams = NULL;
+ struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params_old *oparams = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
- if (!params) {
- err = -ENOMEM;
- goto out;
- }
- oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
- if (!oparams) {
- err = -ENOMEM;
- goto out;
- }
+ if (!params)
+ return -ENOMEM;
- if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
- err = -EFAULT;
+ oparams = memdup_user(_oparams, sizeof(*oparams));
+ if (IS_ERR(oparams)) {
+ err = PTR_ERR(oparams);
goto out;
}
snd_pcm_hw_convert_from_old_params(params, oparams);
@@ -3286,30 +3412,27 @@ static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sn
if (!err)
err = -EFAULT;
}
+
+ kfree(oparams);
out:
kfree(params);
- kfree(oparams);
return err;
}
-static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params_old __user * _oparams)
{
- snd_pcm_hw_params_t *params;
- struct sndrv_pcm_hw_params_old *oparams = NULL;
+ struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params_old *oparams = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
- if (!params) {
- err = -ENOMEM;
- goto out;
- }
- oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
- if (!oparams) {
- err = -ENOMEM;
- goto out;
- }
- if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
- err = -EFAULT;
+ if (!params)
+ return -ENOMEM;
+
+ oparams = memdup_user(_oparams, sizeof(*oparams));
+ if (IS_ERR(oparams)) {
+ err = PTR_ERR(oparams);
goto out;
}
snd_pcm_hw_convert_from_old_params(params, oparams);
@@ -3319,50 +3442,70 @@ static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sn
if (!err)
err = -EFAULT;
}
+
+ kfree(oparams);
out:
kfree(params);
- kfree(oparams);
return err;
}
+#endif /* CONFIG_SND_SUPPORT_OLD_API */
+
+#ifndef CONFIG_MMU
+static unsigned long snd_pcm_get_unmapped_area(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ struct snd_pcm_file *pcm_file = file->private_data;
+ struct snd_pcm_substream *substream = pcm_file->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long offset = pgoff << PAGE_SHIFT;
+
+ switch (offset) {
+ case SNDRV_PCM_MMAP_OFFSET_STATUS:
+ return (unsigned long)runtime->status;
+ case SNDRV_PCM_MMAP_OFFSET_CONTROL:
+ return (unsigned long)runtime->control;
+ default:
+ return (unsigned long)runtime->dma_area + offset;
+ }
+}
+#else
+# define snd_pcm_get_unmapped_area NULL
+#endif
/*
* Register section
*/
-static struct file_operations snd_pcm_f_ops_playback = {
- .owner = THIS_MODULE,
- .write = snd_pcm_write,
- .writev = snd_pcm_writev,
- .open = snd_pcm_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_playback_poll,
- .unlocked_ioctl = snd_pcm_playback_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
-};
-
-static struct file_operations snd_pcm_f_ops_capture = {
- .owner = THIS_MODULE,
- .read = snd_pcm_read,
- .readv = snd_pcm_readv,
- .open = snd_pcm_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_capture_poll,
- .unlocked_ioctl = snd_pcm_capture_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
-};
-
-snd_minor_t snd_pcm_reg[2] =
-{
+const struct file_operations snd_pcm_f_ops[2] = {
{
- .comment = "digital audio playback",
- .f_ops = &snd_pcm_f_ops_playback,
+ .owner = THIS_MODULE,
+ .write = snd_pcm_write,
+ .aio_write = snd_pcm_aio_write,
+ .open = snd_pcm_playback_open,
+ .release = snd_pcm_release,
+ .llseek = no_llseek,
+ .poll = snd_pcm_playback_poll,
+ .unlocked_ioctl = snd_pcm_playback_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
- .comment = "digital audio capture",
- .f_ops = &snd_pcm_f_ops_capture,
+ .owner = THIS_MODULE,
+ .read = snd_pcm_read,
+ .aio_read = snd_pcm_aio_read,
+ .open = snd_pcm_capture_open,
+ .release = snd_pcm_release,
+ .llseek = no_llseek,
+ .poll = snd_pcm_capture_poll,
+ .unlocked_ioctl = snd_pcm_capture_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
}
};
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index 884eaea31fe..20ecd8f1808 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -1,6 +1,6 @@
/*
* Digital Audio (PCM) abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,8 +19,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
+#include <linux/gcd.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/timer.h>
@@ -29,35 +29,21 @@
* Timer functions
*/
-/* Greatest common divisor */
-static unsigned long gcd(unsigned long a, unsigned long b)
-{
- unsigned long r;
- if (a < b) {
- r = a;
- a = b;
- b = r;
- }
- while ((r = a % b) != 0) {
- a = b;
- b = r;
- }
- return b;
-}
-
-void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
+void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
{
unsigned long rate, mult, fsize, l, post;
- snd_pcm_runtime_t *runtime = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
mult = 1000000000;
rate = runtime->rate;
- snd_assert(rate != 0, return);
+ if (snd_BUG_ON(!rate))
+ return;
l = gcd(mult, rate);
mult /= l;
rate /= l;
fsize = runtime->period_size;
- snd_assert(fsize != 0, return);
+ if (snd_BUG_ON(!fsize))
+ return;
l = gcd(rate, fsize);
rate /= l;
fsize /= l;
@@ -67,46 +53,42 @@ void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
post *= 2;
}
if (rate == 0) {
- snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
+ pcm_err(substream->pcm,
+ "pcm timer resolution out of range (rate = %u, period_size = %lu)\n",
+ runtime->rate, runtime->period_size);
runtime->timer_resolution = -1;
return;
}
runtime->timer_resolution = (mult * fsize / rate) * post;
}
-static unsigned long snd_pcm_timer_resolution(snd_timer_t * timer)
+static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
{
- snd_pcm_substream_t * substream;
+ struct snd_pcm_substream *substream;
substream = timer->private_data;
return substream->runtime ? substream->runtime->timer_resolution : 0;
}
-static int snd_pcm_timer_start(snd_timer_t * timer)
+static int snd_pcm_timer_start(struct snd_timer * timer)
{
- unsigned long flags;
- snd_pcm_substream_t * substream;
+ struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
- spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 1;
- spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}
-static int snd_pcm_timer_stop(snd_timer_t * timer)
+static int snd_pcm_timer_stop(struct snd_timer * timer)
{
- unsigned long flags;
- snd_pcm_substream_t * substream;
+ struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
- spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 0;
- spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}
-static struct _snd_timer_hardware snd_pcm_timer =
+static struct snd_timer_hardware snd_pcm_timer =
{
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE,
.resolution = 0,
@@ -120,16 +102,16 @@ static struct _snd_timer_hardware snd_pcm_timer =
* Init functions
*/
-static void snd_pcm_timer_free(snd_timer_t *timer)
+static void snd_pcm_timer_free(struct snd_timer *timer)
{
- snd_pcm_substream_t *substream = timer->private_data;
+ struct snd_pcm_substream *substream = timer->private_data;
substream->timer = NULL;
}
-void snd_pcm_timer_init(snd_pcm_substream_t *substream)
+void snd_pcm_timer_init(struct snd_pcm_substream *substream)
{
- snd_timer_id_t tid;
- snd_timer_t *timer;
+ struct snd_timer_id tid;
+ struct snd_timer *timer;
tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
tid.dev_class = SNDRV_TIMER_CLASS_PCM;
@@ -152,7 +134,7 @@ void snd_pcm_timer_init(snd_pcm_substream_t *substream)
substream->timer = timer;
}
-void snd_pcm_timer_done(snd_pcm_substream_t *substream)
+void snd_pcm_timer_done(struct snd_pcm_substream *substream)
{
if (substream->timer) {
snd_device_free(substream->pcm->card, substream->timer);
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 7c20eafecb8..6fc71a4c8a5 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1,6 +1,6 @@
/*
* Abstract layer for MIDI v1.0 stream
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,30 +19,28 @@
*
*/
-#include <sound/driver.h>
#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/wait.h>
#include <sound/rawmidi.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");
#ifdef CONFIG_SND_OSSEMUL
-static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int midi_map[SNDRV_CARDS];
static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
@@ -50,15 +48,30 @@ module_param_array(amidi_map, int, NULL, 0444);
MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
#endif /* CONFIG_SND_OSSEMUL */
-static int snd_rawmidi_free(snd_rawmidi_t *rawmidi);
-static int snd_rawmidi_dev_free(snd_device_t *device);
-static int snd_rawmidi_dev_register(snd_device_t *device);
-static int snd_rawmidi_dev_disconnect(snd_device_t *device);
-static int snd_rawmidi_dev_unregister(snd_device_t *device);
+static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
+static int snd_rawmidi_dev_free(struct snd_device *device);
+static int snd_rawmidi_dev_register(struct snd_device *device);
+static int snd_rawmidi_dev_disconnect(struct snd_device *device);
+
+static LIST_HEAD(snd_rawmidi_devices);
+static DEFINE_MUTEX(register_mutex);
-static snd_rawmidi_t *snd_rawmidi_devices[SNDRV_CARDS * SNDRV_RAWMIDI_DEVICES];
+#define rmidi_err(rmidi, fmt, args...) \
+ dev_err((rmidi)->card->dev, fmt, ##args)
+#define rmidi_warn(rmidi, fmt, args...) \
+ dev_warn((rmidi)->card->dev, fmt, ##args)
+#define rmidi_dbg(rmidi, fmt, args...) \
+ dev_dbg((rmidi)->card->dev, fmt, ##args)
+
+static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
+{
+ struct snd_rawmidi *rawmidi;
-static DECLARE_MUTEX(register_mutex);
+ list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
+ if (rawmidi->card == card && rawmidi->device == device)
+ return rawmidi;
+ return NULL;
+}
static inline unsigned short snd_rawmidi_file_flags(struct file *file)
{
@@ -72,47 +85,38 @@ static inline unsigned short snd_rawmidi_file_flags(struct file *file)
}
}
-static inline int snd_rawmidi_ready(snd_rawmidi_substream_t * substream)
+static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
return runtime->avail >= runtime->avail_min;
}
-static inline int snd_rawmidi_ready_append(snd_rawmidi_substream_t * substream, size_t count)
+static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
+ size_t count)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
return runtime->avail >= runtime->avail_min &&
(!substream->append || runtime->avail >= count);
}
-static void snd_rawmidi_input_event_tasklet(unsigned long data)
-{
- snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
- substream->runtime->event(substream);
-}
-
-static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
+static void snd_rawmidi_input_event_work(struct work_struct *work)
{
- snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
- substream->ops->trigger(substream, 1);
+ struct snd_rawmidi_runtime *runtime =
+ container_of(work, struct snd_rawmidi_runtime, event_work);
+ if (runtime->event)
+ runtime->event(runtime->substream);
}
-static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream)
+static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
{
- snd_rawmidi_runtime_t *runtime;
+ struct snd_rawmidi_runtime *runtime;
if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL)
return -ENOMEM;
+ runtime->substream = substream;
spin_lock_init(&runtime->lock);
init_waitqueue_head(&runtime->sleep);
- if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
- tasklet_init(&runtime->tasklet,
- snd_rawmidi_input_event_tasklet,
- (unsigned long)substream);
- else
- tasklet_init(&runtime->tasklet,
- snd_rawmidi_output_trigger_tasklet,
- (unsigned long)substream);
+ INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
runtime->event = NULL;
runtime->buffer_size = PAGE_SIZE;
runtime->avail_min = 1;
@@ -129,9 +133,9 @@ static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream)
return 0;
}
-static int snd_rawmidi_runtime_free(snd_rawmidi_substream_t * substream)
+static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
kfree(runtime->buffer);
kfree(runtime);
@@ -139,27 +143,26 @@ static int snd_rawmidi_runtime_free(snd_rawmidi_substream_t * substream)
return 0;
}
-static inline void snd_rawmidi_output_trigger(snd_rawmidi_substream_t * substream, int up)
+static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up)
{
- if (up) {
- tasklet_hi_schedule(&substream->runtime->tasklet);
- } else {
- tasklet_kill(&substream->runtime->tasklet);
- substream->ops->trigger(substream, 0);
- }
+ if (!substream->opened)
+ return;
+ substream->ops->trigger(substream, up);
}
-static void snd_rawmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
+ if (!substream->opened)
+ return;
substream->ops->trigger(substream, up);
- if (!up && substream->runtime->event)
- tasklet_kill(&substream->runtime->tasklet);
+ if (!up)
+ cancel_work_sync(&substream->runtime->event_work);
}
-int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream)
+int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
snd_rawmidi_output_trigger(substream, 0);
runtime->drain = 0;
@@ -169,12 +172,13 @@ int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_drop_output);
-int snd_rawmidi_drain_output(snd_rawmidi_substream_t * substream)
+int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
{
int err;
long timeout;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
err = 0;
runtime->drain = 1;
@@ -184,7 +188,9 @@ int snd_rawmidi_drain_output(snd_rawmidi_substream_t * substream)
if (signal_pending(current))
err = -ERESTARTSYS;
if (runtime->avail < runtime->buffer_size && !timeout) {
- snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
+ rmidi_warn(substream->rmidi,
+ "rawmidi drain error (avail = %li, buffer_size = %li)\n",
+ (long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
}
runtime->drain = 0;
@@ -198,11 +204,12 @@ int snd_rawmidi_drain_output(snd_rawmidi_substream_t * substream)
}
return err;
}
+EXPORT_SYMBOL(snd_rawmidi_drain_output);
-int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream)
+int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
{
unsigned long flags;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
snd_rawmidi_input_trigger(substream, 0);
runtime->drain = 0;
@@ -212,228 +219,211 @@ int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_drain_input);
-int snd_rawmidi_kernel_open(int cardnum, int device, int subdevice,
- int mode, snd_rawmidi_file_t * rfile)
+/* look for an available substream for the given stream direction;
+ * if a specific subdevice is given, try to assign it
+ */
+static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
+ int stream, int mode,
+ struct snd_rawmidi_substream **sub_ret)
{
- snd_rawmidi_t *rmidi;
- struct list_head *list1, *list2;
- snd_rawmidi_substream_t *sinput = NULL, *soutput = NULL;
- snd_rawmidi_runtime_t *input = NULL, *output = NULL;
- int err;
+ struct snd_rawmidi_substream *substream;
+ struct snd_rawmidi_str *s = &rmidi->streams[stream];
+ static unsigned int info_flags[2] = {
+ [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
+ [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
+ };
- if (rfile)
- rfile->input = rfile->output = NULL;
- rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
- if (rmidi == NULL) {
- err = -ENODEV;
- goto __error1;
- }
- if (!try_module_get(rmidi->card->module)) {
- err = -EFAULT;
- goto __error1;
- }
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- down(&rmidi->open_mutex);
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
- err = -ENXIO;
- goto __error;
- }
- if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
- err = -ENODEV;
- goto __error;
- }
- if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >=
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
- err = -EAGAIN;
- goto __error;
- }
- }
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) {
- err = -ENXIO;
- goto __error;
- }
- if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
- err = -ENODEV;
- goto __error;
+ if (!(rmidi->info_flags & info_flags[stream]))
+ return -ENXIO;
+ if (subdevice >= 0 && subdevice >= s->substream_count)
+ return -ENODEV;
+
+ list_for_each_entry(substream, &s->substreams, list) {
+ if (substream->opened) {
+ if (stream == SNDRV_RAWMIDI_STREAM_INPUT ||
+ !(mode & SNDRV_RAWMIDI_LFLG_APPEND) ||
+ !substream->append)
+ continue;
}
- if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >=
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
- err = -EAGAIN;
- goto __error;
+ if (subdevice < 0 || subdevice == substream->number) {
+ *sub_ret = substream;
+ return 0;
}
}
- list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next;
- while (1) {
- if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
- sinput = NULL;
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- err = -EAGAIN;
- goto __error;
- }
- break;
- }
- sinput = list_entry(list1, snd_rawmidi_substream_t, list);
- if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened)
- goto __nexti;
- if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number))
- break;
- __nexti:
- list1 = list1->next;
- }
- list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next;
- while (1) {
- if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
- soutput = NULL;
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- err = -EAGAIN;
- goto __error;
- }
- break;
- }
- soutput = list_entry(list2, snd_rawmidi_substream_t, list);
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (mode & SNDRV_RAWMIDI_LFLG_APPEND) {
- if (soutput->opened && !soutput->append)
- goto __nexto;
- } else {
- if (soutput->opened)
- goto __nexto;
- }
+ return -EAGAIN;
+}
+
+/* open and do ref-counting for the given substream */
+static int open_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int mode)
+{
+ int err;
+
+ if (substream->use_count == 0) {
+ err = snd_rawmidi_runtime_create(substream);
+ if (err < 0)
+ return err;
+ err = substream->ops->open(substream);
+ if (err < 0) {
+ snd_rawmidi_runtime_free(substream);
+ return err;
}
- if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number))
- break;
- __nexto:
- list2 = list2->next;
+ substream->opened = 1;
+ substream->active_sensing = 0;
+ if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
+ substream->append = 1;
+ substream->pid = get_pid(task_pid(current));
+ rmidi->streams[substream->stream].substream_opened++;
}
+ substream->use_count++;
+ return 0;
+}
+
+static void close_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int cleanup);
+
+static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
+ struct snd_rawmidi_file *rfile)
+{
+ struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
+ int err;
+
+ rfile->input = rfile->output = NULL;
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
- goto __error;
- input = sinput->runtime;
- if ((err = sinput->ops->open(sinput)) < 0)
- goto __error;
- sinput->opened = 1;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
- } else {
- sinput = NULL;
+ err = assign_substream(rmidi, subdevice,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ mode, &sinput);
+ if (err < 0)
+ return err;
}
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (soutput->opened)
- goto __skip_output;
- if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
- sinput->ops->close(sinput);
- goto __error;
- }
- output = soutput->runtime;
- if ((err = soutput->ops->open(soutput)) < 0) {
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
- sinput->ops->close(sinput);
- goto __error;
- }
- __skip_output:
- soutput->opened = 1;
- if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
- soutput->append = 1;
- if (soutput->use_count++ == 0)
- soutput->active_sensing = 1;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++;
- } else {
- soutput = NULL;
+ err = assign_substream(rmidi, subdevice,
+ SNDRV_RAWMIDI_STREAM_OUTPUT,
+ mode, &soutput);
+ if (err < 0)
+ return err;
}
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- up(&rmidi->open_mutex);
- if (rfile) {
- rfile->rmidi = rmidi;
- rfile->input = sinput;
- rfile->output = soutput;
+
+ if (sinput) {
+ err = open_substream(rmidi, sinput, mode);
+ if (err < 0)
+ return err;
}
+ if (soutput) {
+ err = open_substream(rmidi, soutput, mode);
+ if (err < 0) {
+ if (sinput)
+ close_substream(rmidi, sinput, 0);
+ return err;
+ }
+ }
+
+ rfile->rmidi = rmidi;
+ rfile->input = sinput;
+ rfile->output = soutput;
return 0;
+}
- __error:
- if (input != NULL)
- snd_rawmidi_runtime_free(sinput);
- if (output != NULL)
- snd_rawmidi_runtime_free(soutput);
- module_put(rmidi->card->module);
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- up(&rmidi->open_mutex);
- __error1:
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
+ int mode, struct snd_rawmidi_file * rfile)
+{
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ if (snd_BUG_ON(!rfile))
+ return -EINVAL;
+
+ mutex_lock(&register_mutex);
+ rmidi = snd_rawmidi_search(card, device);
+ if (rmidi == NULL) {
+ mutex_unlock(&register_mutex);
+ return -ENODEV;
+ }
+ if (!try_module_get(rmidi->card->module)) {
+ mutex_unlock(&register_mutex);
+ return -ENXIO;
+ }
+ mutex_unlock(&register_mutex);
+
+ mutex_lock(&rmidi->open_mutex);
+ err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
+ mutex_unlock(&rmidi->open_mutex);
+ if (err < 0)
+ module_put(rmidi->card->module);
return err;
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_open);
static int snd_rawmidi_open(struct inode *inode, struct file *file)
{
int maj = imajor(inode);
- int cardnum;
- snd_card_t *card;
- int device, subdevice;
+ struct snd_card *card;
+ int subdevice;
unsigned short fflags;
int err;
- snd_rawmidi_t *rmidi;
- snd_rawmidi_file_t *rawmidi_file;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_file *rawmidi_file = NULL;
wait_queue_t wait;
- struct list_head *list;
- snd_ctl_file_t *kctl;
-
- switch (maj) {
- case CONFIG_SND_MAJOR:
- cardnum = SNDRV_MINOR_CARD(iminor(inode));
- cardnum %= SNDRV_CARDS;
- device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_RAWMIDI;
- device %= SNDRV_MINOR_RAWMIDIS;
- break;
+ struct snd_ctl_file *kctl;
+
+ if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
+ return -EINVAL; /* invalid combination */
+
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+
+ if (maj == snd_major) {
+ rmidi = snd_lookup_minor_data(iminor(inode),
+ SNDRV_DEVICE_TYPE_RAWMIDI);
#ifdef CONFIG_SND_OSSEMUL
- case SOUND_MAJOR:
- cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
- cardnum %= SNDRV_CARDS;
- device = SNDRV_MINOR_OSS_DEVICE(iminor(inode)) == SNDRV_MINOR_OSS_MIDI ?
- midi_map[cardnum] : amidi_map[cardnum];
- break;
+ } else if (maj == SOUND_MAJOR) {
+ rmidi = snd_lookup_oss_minor_data(iminor(inode),
+ SNDRV_OSS_DEVICE_TYPE_MIDI);
#endif
- default:
+ } else
return -ENXIO;
- }
- rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
if (rmidi == NULL)
return -ENODEV;
-#ifdef CONFIG_SND_OSSEMUL
- if (maj == SOUND_MAJOR && !rmidi->ossreg)
+
+ if (!try_module_get(rmidi->card->module)) {
+ snd_card_unref(rmidi->card);
return -ENXIO;
-#endif
- if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
- return -EINVAL; /* invalid combination */
+ }
+
+ mutex_lock(&rmidi->open_mutex);
card = rmidi->card;
err = snd_card_file_add(card, file);
if (err < 0)
- return -ENODEV;
+ goto __error_card;
fflags = snd_rawmidi_file_flags(file);
- if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
+ if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */
fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
- fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
if (rawmidi_file == NULL) {
- snd_card_file_remove(card, file);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto __error;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait);
- down(&rmidi->open_mutex);
while (1) {
subdevice = -1;
- down_read(&card->controls_rwsem);
- list_for_each(list, &card->ctl_files) {
- kctl = snd_ctl_file(list);
- if (kctl->pid == current->pid) {
+ read_lock(&card->ctl_files_rwlock);
+ list_for_each_entry(kctl, &card->ctl_files, list) {
+ if (kctl->pid == task_pid(current)) {
subdevice = kctl->prefer_rawmidi_subdevice;
- break;
+ if (subdevice != -1)
+ break;
}
}
- up_read(&card->controls_rwsem);
- err = snd_rawmidi_kernel_open(cardnum, device, subdevice, fflags, rawmidi_file);
+ read_unlock(&card->ctl_files_rwlock);
+ err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -444,97 +434,130 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
} else
break;
set_current_state(TASK_INTERRUPTIBLE);
- up(&rmidi->open_mutex);
+ mutex_unlock(&rmidi->open_mutex);
schedule();
- down(&rmidi->open_mutex);
+ mutex_lock(&rmidi->open_mutex);
+ if (rmidi->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
}
+ remove_wait_queue(&rmidi->open_wait, &wait);
+ if (err < 0) {
+ kfree(rawmidi_file);
+ goto __error;
+ }
#ifdef CONFIG_SND_OSSEMUL
if (rawmidi_file->input && rawmidi_file->input->runtime)
rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
if (rawmidi_file->output && rawmidi_file->output->runtime)
rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
#endif
- remove_wait_queue(&rmidi->open_wait, &wait);
- if (err >= 0) {
- file->private_data = rawmidi_file;
- } else {
- snd_card_file_remove(card, file);
- kfree(rawmidi_file);
- }
- up(&rmidi->open_mutex);
+ file->private_data = rawmidi_file;
+ mutex_unlock(&rmidi->open_mutex);
+ snd_card_unref(rmidi->card);
+ return 0;
+
+ __error:
+ snd_card_file_remove(card, file);
+ __error_card:
+ mutex_unlock(&rmidi->open_mutex);
+ module_put(rmidi->card->module);
+ snd_card_unref(rmidi->card);
return err;
}
-int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile)
+static void close_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int cleanup)
{
- snd_rawmidi_t *rmidi;
- snd_rawmidi_substream_t *substream;
- snd_rawmidi_runtime_t *runtime;
+ if (--substream->use_count)
+ return;
- snd_assert(rfile != NULL, return -ENXIO);
- snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
- rmidi = rfile->rmidi;
- down(&rmidi->open_mutex);
- if (rfile->input != NULL) {
- substream = rfile->input;
- rfile->input = NULL;
- runtime = substream->runtime;
- snd_rawmidi_input_trigger(substream, 0);
- substream->ops->close(substream);
- if (runtime->private_free != NULL)
- runtime->private_free(substream);
- snd_rawmidi_runtime_free(substream);
- substream->opened = 0;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
- }
- if (rfile->output != NULL) {
- substream = rfile->output;
- rfile->output = NULL;
- if (--substream->use_count == 0) {
- runtime = substream->runtime;
+ if (cleanup) {
+ if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
+ snd_rawmidi_input_trigger(substream, 0);
+ else {
if (substream->active_sensing) {
unsigned char buf = 0xfe;
- /* sending single active sensing message to shut the device up */
+ /* sending single active sensing message
+ * to shut the device up
+ */
snd_rawmidi_kernel_write(substream, &buf, 1);
}
if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
snd_rawmidi_output_trigger(substream, 0);
- substream->ops->close(substream);
- if (runtime->private_free != NULL)
- runtime->private_free(substream);
- snd_rawmidi_runtime_free(substream);
- substream->opened = 0;
- substream->append = 0;
}
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
}
- up(&rmidi->open_mutex);
+ substream->ops->close(substream);
+ if (substream->runtime->private_free)
+ substream->runtime->private_free(substream);
+ snd_rawmidi_runtime_free(substream);
+ substream->opened = 0;
+ substream->append = 0;
+ put_pid(substream->pid);
+ substream->pid = NULL;
+ rmidi->streams[substream->stream].substream_opened--;
+}
+
+static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
+{
+ struct snd_rawmidi *rmidi;
+
+ rmidi = rfile->rmidi;
+ mutex_lock(&rmidi->open_mutex);
+ if (rfile->input) {
+ close_substream(rmidi, rfile->input, 1);
+ rfile->input = NULL;
+ }
+ if (rfile->output) {
+ close_substream(rmidi, rfile->output, 1);
+ rfile->output = NULL;
+ }
+ rfile->rmidi = NULL;
+ mutex_unlock(&rmidi->open_mutex);
+ wake_up(&rmidi->open_wait);
+}
+
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
+{
+ struct snd_rawmidi *rmidi;
+
+ if (snd_BUG_ON(!rfile))
+ return -ENXIO;
+
+ rmidi = rfile->rmidi;
+ rawmidi_release_priv(rfile);
module_put(rmidi->card->module);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_release);
static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
- snd_rawmidi_file_t *rfile;
- snd_rawmidi_t *rmidi;
- int err;
+ struct snd_rawmidi_file *rfile;
+ struct snd_rawmidi *rmidi;
+ struct module *module;
rfile = file->private_data;
- err = snd_rawmidi_kernel_release(rfile);
rmidi = rfile->rmidi;
- wake_up(&rmidi->open_wait);
+ rawmidi_release_priv(rfile);
kfree(rfile);
+ module = rmidi->card->module;
snd_card_file_remove(rmidi->card, file);
- return err;
+ module_put(module);
+ return 0;
}
-int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *info)
+static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_info *info)
{
- snd_rawmidi_t *rmidi;
+ struct snd_rawmidi *rmidi;
if (substream == NULL)
return -ENODEV;
@@ -554,26 +577,29 @@ int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *inf
return 0;
}
-static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t __user * _info)
+static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_info __user * _info)
{
- snd_rawmidi_info_t info;
+ struct snd_rawmidi_info info;
int err;
if ((err = snd_rawmidi_info(substream, &info)) < 0)
return err;
- if (copy_to_user(_info, &info, sizeof(snd_rawmidi_info_t)))
+ if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
return -EFAULT;
return 0;
}
-int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info)
+int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
{
- snd_rawmidi_t *rmidi;
- snd_rawmidi_str_t *pstr;
- snd_rawmidi_substream_t *substream;
- struct list_head *list;
- if (info->device >= SNDRV_RAWMIDI_DEVICES)
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *pstr;
+ struct snd_rawmidi_substream *substream;
+
+ mutex_lock(&register_mutex);
+ rmidi = snd_rawmidi_search(card, info->device);
+ mutex_unlock(&register_mutex);
+ if (!rmidi)
return -ENXIO;
- rmidi = snd_rawmidi_devices[card->number * SNDRV_RAWMIDI_DEVICES + info->device];
if (info->stream < 0 || info->stream > 1)
return -EINVAL;
pstr = &rmidi->streams[info->stream];
@@ -581,19 +607,19 @@ int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info)
return -ENOENT;
if (info->subdevice >= pstr->substream_count)
return -ENXIO;
- list_for_each(list, &pstr->substreams) {
- substream = list_entry(list, snd_rawmidi_substream_t, list);
+ list_for_each_entry(substream, &pstr->substreams, list) {
if ((unsigned int)substream->number == info->subdevice)
return snd_rawmidi_info(substream, info);
}
return -ENXIO;
}
+EXPORT_SYMBOL(snd_rawmidi_info_select);
-static int snd_rawmidi_info_select_user(snd_card_t *card,
- snd_rawmidi_info_t __user *_info)
+static int snd_rawmidi_info_select_user(struct snd_card *card,
+ struct snd_rawmidi_info __user *_info)
{
int err;
- snd_rawmidi_info_t info;
+ struct snd_rawmidi_info info;
if (get_user(info.device, &_info->device))
return -EFAULT;
if (get_user(info.stream, &_info->stream))
@@ -602,16 +628,16 @@ static int snd_rawmidi_info_select_user(snd_card_t *card,
return -EFAULT;
if ((err = snd_rawmidi_info_select(card, &info)) < 0)
return err;
- if (copy_to_user(_info, &info, sizeof(snd_rawmidi_info_t)))
+ if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
return -EFAULT;
return 0;
}
-int snd_rawmidi_output_params(snd_rawmidi_substream_t * substream,
- snd_rawmidi_params_t * params)
+int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params)
{
char *newbuf;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
if (substream->append && substream->use_count > 1)
return -EBUSY;
@@ -623,22 +649,25 @@ int snd_rawmidi_output_params(snd_rawmidi_substream_t * substream,
return -EINVAL;
}
if (params->buffer_size != runtime->buffer_size) {
- if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
+ newbuf = krealloc(runtime->buffer, params->buffer_size,
+ GFP_KERNEL);
+ if (!newbuf)
return -ENOMEM;
- kfree(runtime->buffer);
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
+ runtime->avail = runtime->buffer_size;
}
runtime->avail_min = params->avail_min;
substream->active_sensing = !params->no_active_sensing;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_output_params);
-int snd_rawmidi_input_params(snd_rawmidi_substream_t * substream,
- snd_rawmidi_params_t * params)
+int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params * params)
{
char *newbuf;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
snd_rawmidi_drain_input(substream);
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
@@ -648,20 +677,22 @@ int snd_rawmidi_input_params(snd_rawmidi_substream_t * substream,
return -EINVAL;
}
if (params->buffer_size != runtime->buffer_size) {
- if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
+ newbuf = krealloc(runtime->buffer, params->buffer_size,
+ GFP_KERNEL);
+ if (!newbuf)
return -ENOMEM;
- kfree(runtime->buffer);
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
}
runtime->avail_min = params->avail_min;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_input_params);
-static int snd_rawmidi_output_status(snd_rawmidi_substream_t * substream,
- snd_rawmidi_status_t * status)
+static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_status * status)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
@@ -671,10 +702,10 @@ static int snd_rawmidi_output_status(snd_rawmidi_substream_t * substream,
return 0;
}
-static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
- snd_rawmidi_status_t * status)
+static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_status * status)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
@@ -688,7 +719,7 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_rawmidi_file_t *rfile;
+ struct snd_rawmidi_file *rfile;
void __user *argp = (void __user *)arg;
rfile = file->private_data;
@@ -699,8 +730,8 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0;
case SNDRV_RAWMIDI_IOCTL_INFO:
{
- snd_rawmidi_stream_t stream;
- snd_rawmidi_info_t __user *info = argp;
+ int stream;
+ struct snd_rawmidi_info __user *info = argp;
if (get_user(stream, &info->stream))
return -EFAULT;
switch (stream) {
@@ -714,8 +745,8 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
}
case SNDRV_RAWMIDI_IOCTL_PARAMS:
{
- snd_rawmidi_params_t params;
- if (copy_from_user(&params, argp, sizeof(snd_rawmidi_params_t)))
+ struct snd_rawmidi_params params;
+ if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
return -EFAULT;
switch (params.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -733,8 +764,8 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDRV_RAWMIDI_IOCTL_STATUS:
{
int err = 0;
- snd_rawmidi_status_t status;
- if (copy_from_user(&status, argp, sizeof(snd_rawmidi_status_t)))
+ struct snd_rawmidi_status status;
+ if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -752,7 +783,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
}
if (err < 0)
return err;
- if (copy_to_user(argp, &status, sizeof(snd_rawmidi_status_t)))
+ if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
return 0;
}
@@ -788,23 +819,20 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
return -EINVAL;
}
}
-#ifdef CONFIG_SND_DEBUG
default:
- snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd);
-#endif
+ rmidi_dbg(rfile->rmidi,
+ "rawmidi: unknown command = 0x%x\n", cmd);
}
return -ENOTTY;
}
-static int snd_rawmidi_control_ioctl(snd_card_t * card,
- snd_ctl_file_t * control,
+static int snd_rawmidi_control_ioctl(struct snd_card *card,
+ struct snd_ctl_file *control,
unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
- unsigned int tmp;
- tmp = card->number * SNDRV_RAWMIDI_DEVICES;
switch (cmd) {
case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
{
@@ -812,14 +840,18 @@ static int snd_rawmidi_control_ioctl(snd_card_t * card,
if (get_user(device, (int __user *)argp))
return -EFAULT;
+ if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
+ device = SNDRV_RAWMIDI_DEVICES - 1;
+ mutex_lock(&register_mutex);
device = device < 0 ? 0 : device + 1;
while (device < SNDRV_RAWMIDI_DEVICES) {
- if (snd_rawmidi_devices[tmp + device])
+ if (snd_rawmidi_search(card, device))
break;
device++;
}
if (device == SNDRV_RAWMIDI_DEVICES)
device = -1;
+ mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)argp))
return -EFAULT;
return 0;
@@ -847,16 +879,20 @@ static int snd_rawmidi_control_ioctl(snd_card_t * card,
*
* Reads the data from the internal buffer.
*
- * Returns the size of read data, or a negative error code on failure.
+ * Return: The size of read data, or a negative error code on failure.
*/
-int snd_rawmidi_receive(snd_rawmidi_substream_t * substream, const unsigned char *buffer, int count)
+int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
+ const unsigned char *buffer, int count)
{
unsigned long flags;
int result = 0, count1;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+ if (!substream->opened)
+ return -EBADFD;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_receive: input is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_receive: input is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -900,20 +936,22 @@ int snd_rawmidi_receive(snd_rawmidi_substream_t * substream, const unsigned char
}
if (result > 0) {
if (runtime->event)
- tasklet_hi_schedule(&runtime->tasklet);
+ schedule_work(&runtime->event_work);
else if (snd_rawmidi_ready(substream))
wake_up(&runtime->sleep);
}
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_receive);
-static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream,
- unsigned char *buf, long count, int kernel)
+static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
+ unsigned char __user *userbuf,
+ unsigned char *kernelbuf, long count)
{
unsigned long flags;
long result = 0, count1;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
while (count > 0 && runtime->avail) {
count1 = runtime->buffer_size - runtime->appl_ptr;
@@ -922,11 +960,11 @@ static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream,
spin_lock_irqsave(&runtime->lock, flags);
if (count1 > (int)runtime->avail)
count1 = runtime->avail;
- if (kernel) {
- memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1);
- } else {
+ if (kernelbuf)
+ memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1);
+ if (userbuf) {
spin_unlock_irqrestore(&runtime->lock, flags);
- if (copy_to_user((char __user *)buf + result,
+ if (copy_to_user(userbuf + result,
runtime->buffer + runtime->appl_ptr, count1)) {
return result > 0 ? result : -EFAULT;
}
@@ -942,19 +980,22 @@ static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream,
return result;
}
-long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *buf, long count)
+long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
+ unsigned char *buf, long count)
{
snd_rawmidi_input_trigger(substream, 1);
- return snd_rawmidi_kernel_read1(substream, buf, count, 1);
+ return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count);
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_read);
-static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count,
+ loff_t *offset)
{
long result;
int count1;
- snd_rawmidi_file_t *rfile;
- snd_rawmidi_substream_t *substream;
- snd_rawmidi_runtime_t *runtime;
+ struct snd_rawmidi_file *rfile;
+ struct snd_rawmidi_substream *substream;
+ struct snd_rawmidi_runtime *runtime;
rfile = file->private_data;
substream = rfile->input;
@@ -977,6 +1018,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
spin_unlock_irq(&runtime->lock);
schedule();
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail)
@@ -985,8 +1028,9 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
}
spin_unlock_irq(&runtime->lock);
count1 = snd_rawmidi_kernel_read1(substream,
- (unsigned char __force *)buf,
- count, 0);
+ (unsigned char __user *)buf,
+ NULL/*kernelbuf*/,
+ count);
if (count1 < 0)
return result > 0 ? result : count1;
result += count1;
@@ -999,17 +1043,18 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
/**
* snd_rawmidi_transmit_empty - check whether the output buffer is empty
* @substream: the rawmidi substream
- *
- * Returns 1 if the internal output buffer is empty, 0 if not.
+ *
+ * Return: 1 if the internal output buffer is empty, 0 if not.
*/
-int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream)
+int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
{
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
int result;
unsigned long flags;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_empty: output is not active!!!\n");
return 1;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -1017,6 +1062,7 @@ int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
/**
* snd_rawmidi_transmit_peek - copy data from the internal buffer
@@ -1030,16 +1076,18 @@ int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream)
* and call snd_rawmidi_transmit_ack() after the transmission is
* finished.
*
- * Returns the size of copied data, or a negative error code on failure.
+ * Return: The size of copied data, or a negative error code on failure.
*/
-int snd_rawmidi_transmit_peek(snd_rawmidi_substream_t * substream, unsigned char *buffer, int count)
+int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+ unsigned char *buffer, int count)
{
unsigned long flags;
int result, count1;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_peek: output is not active!!!\n");
return -EINVAL;
}
result = 0;
@@ -1071,29 +1119,31 @@ int snd_rawmidi_transmit_peek(snd_rawmidi_substream_t * substream, unsigned char
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
/**
* snd_rawmidi_transmit_ack - acknowledge the transmission
* @substream: the rawmidi substream
- * @count: the tranferred count
+ * @count: the transferred count
*
* Advances the hardware pointer for the internal output buffer with
* the given size and updates the condition.
* Call after the transmission is finished.
*
- * Returns the advanced size if successful, or a negative error code on failure.
+ * Return: The advanced size if successful, or a negative error code on failure.
*/
-int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count)
+int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
{
unsigned long flags;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_ack: output is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
- snd_assert(runtime->avail + count <= runtime->buffer_size, );
+ snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
runtime->hw_ptr += count;
runtime->hw_ptr %= runtime->buffer_size;
runtime->avail += count;
@@ -1105,6 +1155,7 @@ int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count)
spin_unlock_irqrestore(&runtime->lock, flags);
return count;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
/**
* snd_rawmidi_transmit - copy from the buffer to the device
@@ -1114,24 +1165,33 @@ int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count)
*
* Copies data from the buffer to the device and advances the pointer.
*
- * Returns the copied size if successful, or a negative error code on failure.
+ * Return: The copied size if successful, or a negative error code on failure.
*/
-int snd_rawmidi_transmit(snd_rawmidi_substream_t * substream, unsigned char *buffer, int count)
+int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
+ unsigned char *buffer, int count)
{
+ if (!substream->opened)
+ return -EBADFD;
count = snd_rawmidi_transmit_peek(substream, buffer, count);
if (count < 0)
return count;
return snd_rawmidi_transmit_ack(substream, count);
}
+EXPORT_SYMBOL(snd_rawmidi_transmit);
-static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const unsigned char *buf, long count, int kernel)
+static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
+ const unsigned char __user *userbuf,
+ const unsigned char *kernelbuf,
+ long count)
{
unsigned long flags;
long count1, result;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
- snd_assert(buf != NULL, return -EINVAL);
- snd_assert(runtime->buffer != NULL, return -EINVAL);
+ if (snd_BUG_ON(!kernelbuf && !userbuf))
+ return -EINVAL;
+ if (snd_BUG_ON(!runtime->buffer))
+ return -EINVAL;
result = 0;
spin_lock_irqsave(&runtime->lock, flags);
@@ -1147,12 +1207,13 @@ static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const
count1 = count;
if (count1 > (long)runtime->avail)
count1 = runtime->avail;
- if (kernel) {
- memcpy(runtime->buffer + runtime->appl_ptr, buf, count1);
- } else {
+ if (kernelbuf)
+ memcpy(runtime->buffer + runtime->appl_ptr,
+ kernelbuf + result, count1);
+ else if (userbuf) {
spin_unlock_irqrestore(&runtime->lock, flags);
if (copy_from_user(runtime->buffer + runtime->appl_ptr,
- (char __user *)buf, count1)) {
+ userbuf + result, count1)) {
spin_lock_irqsave(&runtime->lock, flags);
result = result > 0 ? result : -EFAULT;
goto __end;
@@ -1163,7 +1224,6 @@ static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const
runtime->appl_ptr %= runtime->buffer_size;
runtime->avail -= count1;
result += count1;
- buf += count1;
count -= count1;
}
__end:
@@ -1174,18 +1234,21 @@ static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const
return result;
}
-long snd_rawmidi_kernel_write(snd_rawmidi_substream_t * substream, const unsigned char *buf, long count)
+long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
+ const unsigned char *buf, long count)
{
- return snd_rawmidi_kernel_write1(substream, buf, count, 1);
+ return snd_rawmidi_kernel_write1(substream, NULL, buf, count);
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_write);
-static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
{
long result, timeout;
int count1;
- snd_rawmidi_file_t *rfile;
- snd_rawmidi_runtime_t *runtime;
- snd_rawmidi_substream_t *substream;
+ struct snd_rawmidi_file *rfile;
+ struct snd_rawmidi_runtime *runtime;
+ struct snd_rawmidi_substream *substream;
rfile = file->private_data;
substream = rfile->output;
@@ -1208,6 +1271,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size
spin_unlock_irq(&runtime->lock);
timeout = schedule_timeout(30 * HZ);
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail && !timeout)
@@ -1215,9 +1280,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size
spin_lock_irq(&runtime->lock);
}
spin_unlock_irq(&runtime->lock);
- count1 = snd_rawmidi_kernel_write1(substream,
- (unsigned char __force *)buf,
- count, 0);
+ count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count);
if (count1 < 0)
return result > 0 ? result : count1;
result += count1;
@@ -1226,7 +1289,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size
break;
count -= count1;
}
- if (file->f_flags & O_SYNC) {
+ if (file->f_flags & O_DSYNC) {
spin_lock_irq(&runtime->lock);
while (runtime->avail != runtime->buffer_size) {
wait_queue_t wait;
@@ -1250,8 +1313,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size
static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
{
- snd_rawmidi_file_t *rfile;
- snd_rawmidi_runtime_t *runtime;
+ struct snd_rawmidi_file *rfile;
+ struct snd_rawmidi_runtime *runtime;
unsigned int mask;
rfile = file->private_data;
@@ -1288,26 +1351,29 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
*/
-static void snd_rawmidi_proc_info_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- snd_rawmidi_t *rmidi;
- snd_rawmidi_substream_t *substream;
- snd_rawmidi_runtime_t *runtime;
- struct list_head *list;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *substream;
+ struct snd_rawmidi_runtime *runtime;
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
- down(&rmidi->open_mutex);
+ mutex_lock(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
- list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
- substream = list_entry(list, snd_rawmidi_substream_t, list);
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
+ list) {
snd_iprintf(buffer,
"Output %d\n"
" Tx bytes : %lu\n",
substream->number,
(unsigned long) substream->bytes);
if (substream->opened) {
+ snd_iprintf(buffer,
+ " Owner PID : %d\n",
+ pid_vnr(substream->pid));
runtime = substream->runtime;
snd_iprintf(buffer,
" Mode : %s\n"
@@ -1320,14 +1386,18 @@ static void snd_rawmidi_proc_info_read(snd_info_entry_t *entry,
}
}
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
- list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
- substream = list_entry(list, snd_rawmidi_substream_t, list);
+ list_for_each_entry(substream,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
+ list) {
snd_iprintf(buffer,
"Input %d\n"
" Rx bytes : %lu\n",
substream->number,
(unsigned long) substream->bytes);
if (substream->opened) {
+ snd_iprintf(buffer,
+ " Owner PID : %d\n",
+ pid_vnr(substream->pid));
runtime = substream->runtime;
snd_iprintf(buffer,
" Buffer size : %lu\n"
@@ -1339,44 +1409,40 @@ static void snd_rawmidi_proc_info_read(snd_info_entry_t *entry,
}
}
}
- up(&rmidi->open_mutex);
+ mutex_unlock(&rmidi->open_mutex);
}
/*
* Register functions
*/
-static struct file_operations snd_rawmidi_f_ops =
+static const struct file_operations snd_rawmidi_f_ops =
{
.owner = THIS_MODULE,
.read = snd_rawmidi_read,
.write = snd_rawmidi_write,
.open = snd_rawmidi_open,
.release = snd_rawmidi_release,
+ .llseek = no_llseek,
.poll = snd_rawmidi_poll,
.unlocked_ioctl = snd_rawmidi_ioctl,
.compat_ioctl = snd_rawmidi_ioctl_compat,
};
-static snd_minor_t snd_rawmidi_reg =
-{
- .comment = "raw midi",
- .f_ops = &snd_rawmidi_f_ops,
-};
-
-static int snd_rawmidi_alloc_substreams(snd_rawmidi_t *rmidi,
- snd_rawmidi_str_t *stream,
+static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_str *stream,
int direction,
int count)
{
- snd_rawmidi_substream_t *substream;
+ struct snd_rawmidi_substream *substream;
int idx;
- INIT_LIST_HEAD(&stream->substreams);
for (idx = 0; idx < count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);
- if (substream == NULL)
+ if (substream == NULL) {
+ rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
return -ENOMEM;
+ }
substream->stream = direction;
substream->number = idx;
substream->rmidi = rmidi;
@@ -1399,38 +1465,49 @@ static int snd_rawmidi_alloc_substreams(snd_rawmidi_t *rmidi,
* Creates a new rawmidi instance.
* Use snd_rawmidi_set_ops() to set the operators to the new instance.
*
- * Returns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_rawmidi_new(snd_card_t * card, char *id, int device,
+int snd_rawmidi_new(struct snd_card *card, char *id, int device,
int output_count, int input_count,
- snd_rawmidi_t ** rrawmidi)
+ struct snd_rawmidi ** rrawmidi)
{
- snd_rawmidi_t *rmidi;
+ struct snd_rawmidi *rmidi;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
- .dev_unregister = snd_rawmidi_dev_unregister
};
- snd_assert(rrawmidi != NULL, return -EINVAL);
- *rrawmidi = NULL;
- snd_assert(card != NULL, return -ENXIO);
+ if (snd_BUG_ON(!card))
+ return -ENXIO;
+ if (rrawmidi)
+ *rrawmidi = NULL;
rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
- if (rmidi == NULL)
+ if (rmidi == NULL) {
+ dev_err(card->dev, "rawmidi: cannot allocate\n");
return -ENOMEM;
+ }
rmidi->card = card;
rmidi->device = device;
- init_MUTEX(&rmidi->open_mutex);
+ mutex_init(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
+ INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
+ INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
+
if (id != NULL)
strlcpy(rmidi->id, id, sizeof(rmidi->id));
- if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) {
+ if ((err = snd_rawmidi_alloc_substreams(rmidi,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ input_count)) < 0) {
snd_rawmidi_free(rmidi);
return err;
}
- if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], SNDRV_RAWMIDI_STREAM_OUTPUT, output_count)) < 0) {
+ if ((err = snd_rawmidi_alloc_substreams(rmidi,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
+ SNDRV_RAWMIDI_STREAM_OUTPUT,
+ output_count)) < 0) {
snd_rawmidi_free(rmidi);
return err;
}
@@ -1438,24 +1515,35 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device,
snd_rawmidi_free(rmidi);
return err;
}
- *rrawmidi = rmidi;
+ if (rrawmidi)
+ *rrawmidi = rmidi;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_new);
-static void snd_rawmidi_free_substreams(snd_rawmidi_str_t *stream)
+static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
{
- snd_rawmidi_substream_t *substream;
+ struct snd_rawmidi_substream *substream;
while (!list_empty(&stream->substreams)) {
- substream = list_entry(stream->substreams.next, snd_rawmidi_substream_t, list);
+ substream = list_entry(stream->substreams.next, struct snd_rawmidi_substream, list);
list_del(&substream->list);
kfree(substream);
}
}
-static int snd_rawmidi_free(snd_rawmidi_t *rmidi)
+static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
{
- snd_assert(rmidi != NULL, return -ENXIO);
+ if (!rmidi)
+ return 0;
+
+ snd_info_free_entry(rmidi->proc_entry);
+ rmidi->proc_entry = NULL;
+ mutex_lock(&register_mutex);
+ if (rmidi->ops && rmidi->ops->dev_unregister)
+ rmidi->ops->dev_unregister(rmidi);
+ mutex_unlock(&register_mutex);
+
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
if (rmidi->private_free)
@@ -1464,58 +1552,61 @@ static int snd_rawmidi_free(snd_rawmidi_t *rmidi)
return 0;
}
-static int snd_rawmidi_dev_free(snd_device_t *device)
+static int snd_rawmidi_dev_free(struct snd_device *device)
{
- snd_rawmidi_t *rmidi = device->device_data;
+ struct snd_rawmidi *rmidi = device->device_data;
return snd_rawmidi_free(rmidi);
}
#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-static void snd_rawmidi_dev_seq_free(snd_seq_device_t *device)
+static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)
{
- snd_rawmidi_t *rmidi = device->private_data;
+ struct snd_rawmidi *rmidi = device->private_data;
rmidi->seq_dev = NULL;
}
#endif
-static int snd_rawmidi_dev_register(snd_device_t *device)
+static int snd_rawmidi_dev_register(struct snd_device *device)
{
- int idx, err;
- snd_info_entry_t *entry;
+ int err;
+ struct snd_info_entry *entry;
char name[16];
- snd_rawmidi_t *rmidi = device->device_data;
+ struct snd_rawmidi *rmidi = device->device_data;
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
return -ENOMEM;
- down(&register_mutex);
- idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
- if (snd_rawmidi_devices[idx] != NULL) {
- up(&register_mutex);
+ mutex_lock(&register_mutex);
+ if (snd_rawmidi_search(rmidi->card, rmidi->device)) {
+ mutex_unlock(&register_mutex);
return -EBUSY;
}
- snd_rawmidi_devices[idx] = rmidi;
+ list_add_tail(&rmidi->list, &snd_rawmidi_devices);
sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device);
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
rmidi->card, rmidi->device,
- &snd_rawmidi_reg, name)) < 0) {
- snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
- snd_rawmidi_devices[idx] = NULL;
- up(&register_mutex);
+ &snd_rawmidi_f_ops, rmidi, name)) < 0) {
+ rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
+ rmidi->card->number, rmidi->device);
+ list_del(&rmidi->list);
+ mutex_unlock(&register_mutex);
return err;
}
if (rmidi->ops && rmidi->ops->dev_register &&
(err = rmidi->ops->dev_register(rmidi)) < 0) {
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
- snd_rawmidi_devices[idx] = NULL;
- up(&register_mutex);
+ list_del(&rmidi->list);
+ mutex_unlock(&register_mutex);
return err;
}
#ifdef CONFIG_SND_OSSEMUL
rmidi->ossreg = 0;
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
- rmidi->card, 0, &snd_rawmidi_reg, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0);
+ rmidi->card, 0, &snd_rawmidi_f_ops,
+ rmidi) < 0) {
+ rmidi_err(rmidi,
+ "unable to register OSS rawmidi device %i:%i\n",
+ rmidi->card->number, 0);
} else {
rmidi->ossreg++;
#ifdef SNDRV_OSS_INFO_DEV_MIDI
@@ -1525,19 +1616,21 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
}
if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
- rmidi->card, 1, &snd_rawmidi_reg, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1);
+ rmidi->card, 1, &snd_rawmidi_f_ops,
+ rmidi) < 0) {
+ rmidi_err(rmidi,
+ "unable to register OSS rawmidi device %i:%i\n",
+ rmidi->card->number, 1);
} else {
rmidi->ossreg++;
}
}
#endif /* CONFIG_SND_OSSEMUL */
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
sprintf(name, "midi%d", rmidi->device);
entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
if (entry) {
entry->private_data = rmidi;
- entry->c.text.read_size = 1024;
entry->c.text.read = snd_rawmidi_proc_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -1558,31 +1651,23 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
return 0;
}
-static int snd_rawmidi_dev_disconnect(snd_device_t *device)
-{
- snd_rawmidi_t *rmidi = device->device_data;
- int idx;
-
- down(&register_mutex);
- idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
- snd_rawmidi_devices[idx] = NULL;
- up(&register_mutex);
- return 0;
-}
-
-static int snd_rawmidi_dev_unregister(snd_device_t *device)
+static int snd_rawmidi_dev_disconnect(struct snd_device *device)
{
- int idx;
- snd_rawmidi_t *rmidi = device->device_data;
+ struct snd_rawmidi *rmidi = device->device_data;
+ int dir;
- snd_assert(rmidi != NULL, return -ENXIO);
- down(&register_mutex);
- idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
- snd_rawmidi_devices[idx] = NULL;
- if (rmidi->proc_entry) {
- snd_info_unregister(rmidi->proc_entry);
- rmidi->proc_entry = NULL;
+ mutex_lock(&register_mutex);
+ mutex_lock(&rmidi->open_mutex);
+ wake_up(&rmidi->open_wait);
+ list_del_init(&rmidi->list);
+ for (dir = 0; dir < 2; dir++) {
+ struct snd_rawmidi_substream *s;
+ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
+ if (s->runtime)
+ wake_up(&s->runtime->sleep);
+ }
}
+
#ifdef CONFIG_SND_OSSEMUL
if (rmidi->ossreg) {
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1596,17 +1681,10 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
rmidi->ossreg = 0;
}
#endif /* CONFIG_SND_OSSEMUL */
- if (rmidi->ops && rmidi->ops->dev_unregister)
- rmidi->ops->dev_unregister(rmidi);
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
- up(&register_mutex);
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
- if (rmidi->seq_dev) {
- snd_device_free(rmidi->card, rmidi->seq_dev);
- rmidi->seq_dev = NULL;
- }
-#endif
- return snd_rawmidi_free(rmidi);
+ mutex_unlock(&rmidi->open_mutex);
+ mutex_unlock(&register_mutex);
+ return 0;
}
/**
@@ -1617,16 +1695,15 @@ static int snd_rawmidi_dev_unregister(snd_device_t *device)
*
* Sets the rawmidi operators for the given stream direction.
*/
-void snd_rawmidi_set_ops(snd_rawmidi_t *rmidi, int stream, snd_rawmidi_ops_t *ops)
+void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
+ struct snd_rawmidi_ops *ops)
{
- struct list_head *list;
- snd_rawmidi_substream_t *substream;
+ struct snd_rawmidi_substream *substream;
- list_for_each(list, &rmidi->streams[stream].substreams) {
- substream = list_entry(list, snd_rawmidi_substream_t, list);
+ list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
substream->ops = ops;
- }
}
+EXPORT_SYMBOL(snd_rawmidi_set_ops);
/*
* ENTRY functions
@@ -1642,11 +1719,13 @@ static int __init alsa_rawmidi_init(void)
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
- snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]);
+ pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
+ i, midi_map[i]);
midi_map[i] = 0;
}
if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
- snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]);
+ pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n",
+ i, amidi_map[i]);
amidi_map[i] = 1;
}
}
@@ -1663,22 +1742,3 @@ static void __exit alsa_rawmidi_exit(void)
module_init(alsa_rawmidi_init)
module_exit(alsa_rawmidi_exit)
-
-EXPORT_SYMBOL(snd_rawmidi_output_params);
-EXPORT_SYMBOL(snd_rawmidi_input_params);
-EXPORT_SYMBOL(snd_rawmidi_drop_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_input);
-EXPORT_SYMBOL(snd_rawmidi_receive);
-EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
-EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
-EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
-EXPORT_SYMBOL(snd_rawmidi_transmit);
-EXPORT_SYMBOL(snd_rawmidi_new);
-EXPORT_SYMBOL(snd_rawmidi_set_ops);
-EXPORT_SYMBOL(snd_rawmidi_info);
-EXPORT_SYMBOL(snd_rawmidi_info_select);
-EXPORT_SYMBOL(snd_rawmidi_kernel_open);
-EXPORT_SYMBOL(snd_rawmidi_kernel_release);
-EXPORT_SYMBOL(snd_rawmidi_kernel_read);
-EXPORT_SYMBOL(snd_rawmidi_kernel_write);
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
index d97631c3f3a..5268c1f58c2 100644
--- a/sound/core/rawmidi_compat.c
+++ b/sound/core/rawmidi_compat.c
@@ -22,7 +22,7 @@
#include <linux/compat.h>
-struct sndrv_rawmidi_params32 {
+struct snd_rawmidi_params32 {
s32 stream;
u32 buffer_size;
u32 avail_min;
@@ -30,10 +30,10 @@ struct sndrv_rawmidi_params32 {
unsigned char reserved[16];
} __attribute__((packed));
-static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
- struct sndrv_rawmidi_params32 __user *src)
+static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
+ struct snd_rawmidi_params32 __user *src)
{
- snd_rawmidi_params_t params;
+ struct snd_rawmidi_params params;
unsigned int val;
if (rfile->output == NULL)
@@ -53,7 +53,7 @@ static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
return -EINVAL;
}
-struct sndrv_rawmidi_status32 {
+struct snd_rawmidi_status32 {
s32 stream;
struct compat_timespec tstamp;
u32 avail;
@@ -61,11 +61,11 @@ struct sndrv_rawmidi_status32 {
unsigned char reserved[16];
} __attribute__((packed));
-static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
- struct sndrv_rawmidi_status32 __user *src)
+static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
+ struct snd_rawmidi_status32 __user *src)
{
int err;
- snd_rawmidi_status_t status;
+ struct snd_rawmidi_status status;
if (rfile->output == NULL)
return -EINVAL;
@@ -95,13 +95,13 @@ static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
}
enum {
- SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
- SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
+ SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
+ SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
};
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
- snd_rawmidi_file_t *rfile;
+ struct snd_rawmidi_file *rfile;
void __user *argp = compat_ptr(arg);
rfile = file->private_data;
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index bd5d584d284..f3420d11a12 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -20,17 +20,14 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/threads.h>
#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/log2.h>
#include <sound/core.h>
#include <sound/timer.h>
-#include <sound/info.h>
-#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
+#if IS_ENABLED(CONFIG_RTC)
#include <linux/mc146818rtc.h>
@@ -40,17 +37,19 @@
/*
* prototypes
*/
-static int rtctimer_open(snd_timer_t *t);
-static int rtctimer_close(snd_timer_t *t);
-static int rtctimer_start(snd_timer_t *t);
-static int rtctimer_stop(snd_timer_t *t);
+static int rtctimer_open(struct snd_timer *t);
+static int rtctimer_close(struct snd_timer *t);
+static int rtctimer_start(struct snd_timer *t);
+static int rtctimer_stop(struct snd_timer *t);
/*
* The hardware dependent description for this timer.
*/
-static struct _snd_timer_hardware rtc_hw = {
- .flags = SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
+static struct snd_timer_hardware rtc_hw = {
+ .flags = SNDRV_TIMER_HW_AUTO |
+ SNDRV_TIMER_HW_FIRST |
+ SNDRV_TIMER_HW_TASKLET,
.ticks = 100000000L, /* FIXME: XXX */
.open = rtctimer_open,
.close = rtctimer_close,
@@ -59,13 +58,13 @@ static struct _snd_timer_hardware rtc_hw = {
};
static int rtctimer_freq = RTC_FREQ; /* frequency */
-static snd_timer_t *rtctimer;
-static atomic_t rtc_inc = ATOMIC_INIT(0);
+static struct snd_timer *rtctimer;
+static struct tasklet_struct rtc_tasklet;
static rtc_task_t rtc_task;
static int
-rtctimer_open(snd_timer_t *t)
+rtctimer_open(struct snd_timer *t)
{
int err;
@@ -77,47 +76,49 @@ rtctimer_open(snd_timer_t *t)
}
static int
-rtctimer_close(snd_timer_t *t)
+rtctimer_close(struct snd_timer *t)
{
rtc_task_t *rtc = t->private_data;
if (rtc) {
rtc_unregister(rtc);
+ tasklet_kill(&rtc_tasklet);
t->private_data = NULL;
}
return 0;
}
static int
-rtctimer_start(snd_timer_t *timer)
+rtctimer_start(struct snd_timer *timer)
{
rtc_task_t *rtc = timer->private_data;
- snd_assert(rtc != NULL, return -EINVAL);
+ if (snd_BUG_ON(!rtc))
+ return -EINVAL;
rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
rtc_control(rtc, RTC_PIE_ON, 0);
- atomic_set(&rtc_inc, 0);
return 0;
}
static int
-rtctimer_stop(snd_timer_t *timer)
+rtctimer_stop(struct snd_timer *timer)
{
rtc_task_t *rtc = timer->private_data;
- snd_assert(rtc != NULL, return -EINVAL);
+ if (snd_BUG_ON(!rtc))
+ return -EINVAL;
rtc_control(rtc, RTC_PIE_OFF, 0);
return 0;
}
+static void rtctimer_tasklet(unsigned long data)
+{
+ snd_timer_interrupt((struct snd_timer *)data, 1);
+}
+
/*
* interrupt
*/
static void rtctimer_interrupt(void *private_data)
{
- int ticks;
-
- atomic_inc(&rtc_inc);
- ticks = atomic_read(&rtc_inc);
- snd_timer_interrupt((snd_timer_t*)private_data, ticks);
- atomic_sub(ticks, &rtc_inc);
+ tasklet_schedule(private_data);
}
@@ -126,17 +127,12 @@ static void rtctimer_interrupt(void *private_data)
*/
static int __init rtctimer_init(void)
{
- int order, err;
- snd_timer_t *timer;
+ int err;
+ struct snd_timer *timer;
- if (rtctimer_freq < 2 || rtctimer_freq > 8192) {
- snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq);
- return -EINVAL;
- }
- for (order = 1; rtctimer_freq > order; order <<= 1)
- ;
- if (rtctimer_freq != order) {
- snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq);
+ if (rtctimer_freq < 2 || rtctimer_freq > 8192 ||
+ !is_power_of_2(rtctimer_freq)) {
+ pr_err("ALSA: rtctimer: invalid frequency %d\n", rtctimer_freq);
return -EINVAL;
}
@@ -145,13 +141,16 @@ static int __init rtctimer_init(void)
if (err < 0)
return err;
+ timer->module = THIS_MODULE;
strcpy(timer->name, "RTC timer");
timer->hw = rtc_hw;
timer->hw.resolution = NANO_SEC / rtctimer_freq;
+ tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer);
+
/* set up RTC callback */
rtc_task.func = rtctimer_interrupt;
- rtc_task.private_data = timer;
+ rtc_task.private_data = &rtc_tasklet;
err = snd_timer_global_register(timer);
if (err < 0) {
@@ -166,7 +165,7 @@ static int __init rtctimer_init(void)
static void __exit rtctimer_exit(void)
{
if (rtctimer) {
- snd_timer_global_unregister(rtctimer);
+ snd_timer_global_free(rtctimer);
rtctimer = NULL;
}
}
@@ -185,4 +184,4 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
-#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
+#endif /* IS_ENABLED(CONFIG_RTC) */
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
new file mode 100644
index 00000000000..b851fd890a8
--- /dev/null
+++ b/sound/core/seq/Kconfig
@@ -0,0 +1,16 @@
+# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX)
+
+config SND_RAWMIDI_SEQ
+ def_tristate SND_SEQUENCER && SND_RAWMIDI
+
+config SND_OPL3_LIB_SEQ
+ def_tristate SND_SEQUENCER && SND_OPL3_LIB
+
+config SND_OPL4_LIB_SEQ
+ def_tristate SND_SEQUENCER && SND_OPL4_LIB
+
+config SND_SBAWE_SEQ
+ def_tristate SND_SEQUENCER && SND_SBAWE
+
+config SND_EMU10K1_SEQ
+ def_tristate SND_SEQUENCER && SND_EMU10K1
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 402e2b4a34c..941f64a853e 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -1,13 +1,8 @@
#
# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
-obj-$(CONFIG_SND) += instr/
-ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
- obj-$(CONFIG_SND_SEQUENCER) += oss/
-endif
-
snd-seq-device-objs := seq_device.o
snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
seq_fifo.o seq_prioq.o seq_timer.o \
@@ -15,30 +10,20 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
snd-seq-midi-objs := seq_midi.o
snd-seq-midi-emul-objs := seq_midi_emul.o
snd-seq-midi-event-objs := seq_midi_event.o
-snd-seq-instr-objs := seq_instr.o
snd-seq-dummy-objs := seq_dummy.o
snd-seq-virmidi-objs := seq_virmidi.o
-#
-# this function returns:
-# "m" - CONFIG_SND_SEQUENCER is m
-# <empty string> - CONFIG_SND_SEQUENCER is undefined
-# otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
+ obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
+ obj-$(CONFIG_SND_SEQUENCER) += oss/
endif
obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o
+obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile
deleted file mode 100644
index 69138f30a29..00000000000
--- a/sound/core/seq/instr/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
-#
-
-snd-ainstr-fm-objs := ainstr_fm.o
-snd-ainstr-simple-objs := ainstr_simple.o
-snd-ainstr-gf1-objs := ainstr_gf1.o
-snd-ainstr-iw-objs := ainstr_iw.o
-
-#
-# this function returns:
-# "m" - CONFIG_SND_SEQUENCER is m
-# <empty string> - CONFIG_SND_SEQUENCER is undefined
-# otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
-# Toplevel Module Dependency
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o
-obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c
deleted file mode 100644
index 5c671e69884..00000000000
--- a/sound/core/seq/instr/ainstr_fm.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * FM (OPL2/3) Instrument routines
- * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
- *
- * 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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <sound/core.h>
-#include <sound/ainstr_fm.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support.");
-MODULE_LICENSE("GPL");
-
-static int snd_seq_fm_put(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic, int cmd)
-{
- fm_instrument_t *ip;
- fm_xinstrument_t ix;
- int idx;
-
- if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
- return -EINVAL;
- /* copy instrument data */
- if (len < (long)sizeof(ix))
- return -EINVAL;
- if (copy_from_user(&ix, instr_data, sizeof(ix)))
- return -EFAULT;
- if (ix.stype != FM_STRU_INSTR)
- return -EINVAL;
- ip = (fm_instrument_t *)KINSTR_DATA(instr);
- ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
- ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
- ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
- ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
- ip->type = ix.type;
- for (idx = 0; idx < 4; idx++) {
- ip->op[idx].am_vib = ix.op[idx].am_vib;
- ip->op[idx].ksl_level = ix.op[idx].ksl_level;
- ip->op[idx].attack_decay = ix.op[idx].attack_decay;
- ip->op[idx].sustain_release = ix.op[idx].sustain_release;
- ip->op[idx].wave_select = ix.op[idx].wave_select;
- }
- for (idx = 0; idx < 2; idx++) {
- ip->feedback_connection[idx] = ix.feedback_connection[idx];
- }
- ip->echo_delay = ix.echo_delay;
- ip->echo_atten = ix.echo_atten;
- ip->chorus_spread = ix.chorus_spread;
- ip->trnsps = ix.trnsps;
- ip->fix_dur = ix.fix_dur;
- ip->modes = ix.modes;
- ip->fix_key = ix.fix_key;
- return 0;
-}
-
-static int snd_seq_fm_get(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic,
- int cmd)
-{
- fm_instrument_t *ip;
- fm_xinstrument_t ix;
- int idx;
-
- if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
- return -EINVAL;
- if (len < (long)sizeof(ix))
- return -ENOMEM;
- memset(&ix, 0, sizeof(ix));
- ip = (fm_instrument_t *)KINSTR_DATA(instr);
- ix.stype = FM_STRU_INSTR;
- ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
- ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
- ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
- ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
- ix.type = ip->type;
- for (idx = 0; idx < 4; idx++) {
- ix.op[idx].am_vib = ip->op[idx].am_vib;
- ix.op[idx].ksl_level = ip->op[idx].ksl_level;
- ix.op[idx].attack_decay = ip->op[idx].attack_decay;
- ix.op[idx].sustain_release = ip->op[idx].sustain_release;
- ix.op[idx].wave_select = ip->op[idx].wave_select;
- }
- for (idx = 0; idx < 2; idx++) {
- ix.feedback_connection[idx] = ip->feedback_connection[idx];
- }
- if (copy_to_user(instr_data, &ix, sizeof(ix)))
- return -EFAULT;
- ix.echo_delay = ip->echo_delay;
- ix.echo_atten = ip->echo_atten;
- ix.chorus_spread = ip->chorus_spread;
- ix.trnsps = ip->trnsps;
- ix.fix_dur = ip->fix_dur;
- ix.modes = ip->modes;
- ix.fix_key = ip->fix_key;
- return 0;
-}
-
-static int snd_seq_fm_get_size(void *private_data, snd_seq_kinstr_t *instr,
- long *size)
-{
- *size = sizeof(fm_xinstrument_t);
- return 0;
-}
-
-int snd_seq_fm_init(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_ops_t *next)
-{
- memset(ops, 0, sizeof(*ops));
- // ops->private_data = private_data;
- ops->add_len = sizeof(fm_instrument_t);
- ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3;
- ops->put = snd_seq_fm_put;
- ops->get = snd_seq_fm_get;
- ops->get_size = snd_seq_fm_get_size;
- // ops->remove = snd_seq_fm_remove;
- // ops->notify = snd_seq_fm_notify;
- ops->next = next;
- return 0;
-}
-
-/*
- * Init part
- */
-
-static int __init alsa_ainstr_fm_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ainstr_fm_exit(void)
-{
-}
-
-module_init(alsa_ainstr_fm_init)
-module_exit(alsa_ainstr_fm_exit)
-
-EXPORT_SYMBOL(snd_seq_fm_init);
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
deleted file mode 100644
index 0e4df8826ee..00000000000
--- a/sound/core/seq/instr/ainstr_gf1.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * GF1 (GUS) Patch - Instrument routines
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_gf1.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format)
-{
- unsigned int result = size;
-
- if (format & GF1_WAVE_16BIT)
- result <<= 1;
- if (format & GF1_WAVE_STEREO)
- result <<= 1;
- return format;
-}
-
-static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t *ops,
- gf1_instrument_t *ip,
- char __user **data,
- long *len,
- int atomic)
-{
- gf1_wave_t *wp, *prev;
- gf1_xwave_t xp;
- int err;
- gfp_t gfp_mask;
- unsigned int real_size;
-
- gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
- if (*len < (long)sizeof(xp))
- return -EINVAL;
- if (copy_from_user(&xp, *data, sizeof(xp)))
- return -EFAULT;
- *data += sizeof(xp);
- *len -= sizeof(xp);
- wp = kzalloc(sizeof(*wp), gfp_mask);
- if (wp == NULL)
- return -ENOMEM;
- wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
- wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
- wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
- wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
- wp->format = le32_to_cpu(xp.format);
- wp->size = le32_to_cpu(xp.size);
- wp->start = le32_to_cpu(xp.start);
- wp->loop_start = le32_to_cpu(xp.loop_start);
- wp->loop_end = le32_to_cpu(xp.loop_end);
- wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
- wp->flags = xp.flags;
- wp->sample_rate = le32_to_cpu(xp.sample_rate);
- wp->low_frequency = le32_to_cpu(xp.low_frequency);
- wp->high_frequency = le32_to_cpu(xp.high_frequency);
- wp->root_frequency = le32_to_cpu(xp.root_frequency);
- wp->tune = le16_to_cpu(xp.tune);
- wp->balance = xp.balance;
- memcpy(wp->envelope_rate, xp.envelope_rate, 6);
- memcpy(wp->envelope_offset, xp.envelope_offset, 6);
- wp->tremolo_sweep = xp.tremolo_sweep;
- wp->tremolo_rate = xp.tremolo_rate;
- wp->tremolo_depth = xp.tremolo_depth;
- wp->vibrato_sweep = xp.vibrato_sweep;
- wp->vibrato_rate = xp.vibrato_rate;
- wp->vibrato_depth = xp.vibrato_depth;
- wp->scale_frequency = le16_to_cpu(xp.scale_frequency);
- wp->scale_factor = le16_to_cpu(xp.scale_factor);
- real_size = snd_seq_gf1_size(wp->size, wp->format);
- if ((long)real_size > *len) {
- kfree(wp);
- return -ENOMEM;
- }
- if (ops->put_sample) {
- err = ops->put_sample(ops->private_data, wp,
- *data, real_size, atomic);
- if (err < 0) {
- kfree(wp);
- return err;
- }
- }
- *data += real_size;
- *len -= real_size;
- prev = ip->wave;
- if (prev) {
- while (prev->next) prev = prev->next;
- prev->next = wp;
- } else {
- ip->wave = wp;
- }
- return 0;
-}
-
-static void snd_seq_gf1_wave_free(snd_gf1_ops_t *ops,
- gf1_wave_t *wave,
- int atomic)
-{
- if (ops->remove_sample)
- ops->remove_sample(ops->private_data, wave, atomic);
- kfree(wave);
-}
-
-static void snd_seq_gf1_instr_free(snd_gf1_ops_t *ops,
- gf1_instrument_t *ip,
- int atomic)
-{
- gf1_wave_t *wave;
-
- while ((wave = ip->wave) != NULL) {
- ip->wave = wave->next;
- snd_seq_gf1_wave_free(ops, wave, atomic);
- }
-}
-
-static int snd_seq_gf1_put(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic,
- int cmd)
-{
- snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
- gf1_instrument_t *ip;
- gf1_xinstrument_t ix;
- int err;
- gfp_t gfp_mask;
-
- if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
- return -EINVAL;
- gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
- /* copy instrument data */
- if (len < (long)sizeof(ix))
- return -EINVAL;
- if (copy_from_user(&ix, instr_data, sizeof(ix)))
- return -EFAULT;
- if (ix.stype != GF1_STRU_INSTR)
- return -EINVAL;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- ip = (gf1_instrument_t *)KINSTR_DATA(instr);
- ip->exclusion = le16_to_cpu(ix.exclusion);
- ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
- ip->effect1 = ix.effect1;
- ip->effect1_depth = ix.effect1_depth;
- ip->effect2 = ix.effect2;
- ip->effect2_depth = ix.effect2_depth;
- /* copy layers */
- while (len > (long)sizeof(__u32)) {
- __u32 stype;
-
- if (copy_from_user(&stype, instr_data, sizeof(stype)))
- return -EFAULT;
- if (stype != GF1_STRU_WAVE) {
- snd_seq_gf1_instr_free(ops, ip, atomic);
- return -EINVAL;
- }
- err = snd_seq_gf1_copy_wave_from_stream(ops,
- ip,
- &instr_data,
- &len,
- atomic);
- if (err < 0) {
- snd_seq_gf1_instr_free(ops, ip, atomic);
- return err;
- }
- }
- return 0;
-}
-
-static int snd_seq_gf1_copy_wave_to_stream(snd_gf1_ops_t *ops,
- gf1_instrument_t *ip,
- char __user **data,
- long *len,
- int atomic)
-{
- gf1_wave_t *wp;
- gf1_xwave_t xp;
- int err;
- unsigned int real_size;
-
- for (wp = ip->wave; wp; wp = wp->next) {
- if (*len < (long)sizeof(xp))
- return -ENOMEM;
- memset(&xp, 0, sizeof(xp));
- xp.stype = GF1_STRU_WAVE;
- xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
- xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
- xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
- xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
- xp.format = cpu_to_le32(wp->format);
- xp.size = cpu_to_le32(wp->size);
- xp.start = cpu_to_le32(wp->start);
- xp.loop_start = cpu_to_le32(wp->loop_start);
- xp.loop_end = cpu_to_le32(wp->loop_end);
- xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
- xp.flags = wp->flags;
- xp.sample_rate = cpu_to_le32(wp->sample_rate);
- xp.low_frequency = cpu_to_le32(wp->low_frequency);
- xp.high_frequency = cpu_to_le32(wp->high_frequency);
- xp.root_frequency = cpu_to_le32(wp->root_frequency);
- xp.tune = cpu_to_le16(wp->tune);
- xp.balance = wp->balance;
- memcpy(xp.envelope_rate, wp->envelope_rate, 6);
- memcpy(xp.envelope_offset, wp->envelope_offset, 6);
- xp.tremolo_sweep = wp->tremolo_sweep;
- xp.tremolo_rate = wp->tremolo_rate;
- xp.tremolo_depth = wp->tremolo_depth;
- xp.vibrato_sweep = wp->vibrato_sweep;
- xp.vibrato_rate = wp->vibrato_rate;
- xp.vibrato_depth = wp->vibrato_depth;
- xp.scale_frequency = cpu_to_le16(wp->scale_frequency);
- xp.scale_factor = cpu_to_le16(wp->scale_factor);
- if (copy_to_user(*data, &xp, sizeof(xp)))
- return -EFAULT;
- *data += sizeof(xp);
- *len -= sizeof(xp);
- real_size = snd_seq_gf1_size(wp->size, wp->format);
- if (*len < (long)real_size)
- return -ENOMEM;
- if (ops->get_sample) {
- err = ops->get_sample(ops->private_data, wp,
- *data, real_size, atomic);
- if (err < 0)
- return err;
- }
- *data += wp->size;
- *len -= wp->size;
- }
- return 0;
-}
-
-static int snd_seq_gf1_get(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic,
- int cmd)
-{
- snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
- gf1_instrument_t *ip;
- gf1_xinstrument_t ix;
-
- if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
- return -EINVAL;
- if (len < (long)sizeof(ix))
- return -ENOMEM;
- memset(&ix, 0, sizeof(ix));
- ip = (gf1_instrument_t *)KINSTR_DATA(instr);
- ix.stype = GF1_STRU_INSTR;
- ix.exclusion = cpu_to_le16(ip->exclusion);
- ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
- ix.effect1 = cpu_to_le16(ip->effect1);
- ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
- ix.effect2 = ip->effect2;
- ix.effect2_depth = ip->effect2_depth;
- if (copy_to_user(instr_data, &ix, sizeof(ix)))
- return -EFAULT;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- return snd_seq_gf1_copy_wave_to_stream(ops,
- ip,
- &instr_data,
- &len,
- atomic);
-}
-
-static int snd_seq_gf1_get_size(void *private_data, snd_seq_kinstr_t *instr,
- long *size)
-{
- long result;
- gf1_instrument_t *ip;
- gf1_wave_t *wp;
-
- *size = 0;
- ip = (gf1_instrument_t *)KINSTR_DATA(instr);
- result = sizeof(gf1_xinstrument_t);
- for (wp = ip->wave; wp; wp = wp->next) {
- result += sizeof(gf1_xwave_t);
- result += wp->size;
- }
- *size = result;
- return 0;
-}
-
-static int snd_seq_gf1_remove(void *private_data,
- snd_seq_kinstr_t *instr,
- int atomic)
-{
- snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
- gf1_instrument_t *ip;
-
- ip = (gf1_instrument_t *)KINSTR_DATA(instr);
- snd_seq_gf1_instr_free(ops, ip, atomic);
- return 0;
-}
-
-static void snd_seq_gf1_notify(void *private_data,
- snd_seq_kinstr_t *instr,
- int what)
-{
- snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
-
- if (ops->notify)
- ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_gf1_init(snd_gf1_ops_t *ops,
- void *private_data,
- snd_seq_kinstr_ops_t *next)
-{
- memset(ops, 0, sizeof(*ops));
- ops->private_data = private_data;
- ops->kops.private_data = ops;
- ops->kops.add_len = sizeof(gf1_instrument_t);
- ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH;
- ops->kops.put = snd_seq_gf1_put;
- ops->kops.get = snd_seq_gf1_get;
- ops->kops.get_size = snd_seq_gf1_get_size;
- ops->kops.remove = snd_seq_gf1_remove;
- ops->kops.notify = snd_seq_gf1_notify;
- ops->kops.next = next;
- return 0;
-}
-
-/*
- * Init part
- */
-
-static int __init alsa_ainstr_gf1_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ainstr_gf1_exit(void)
-{
-}
-
-module_init(alsa_ainstr_gf1_init)
-module_exit(alsa_ainstr_gf1_exit)
-
-EXPORT_SYMBOL(snd_seq_gf1_init);
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
deleted file mode 100644
index 7c19fbbc5d0..00000000000
--- a/sound/core/seq/instr/ainstr_iw.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * IWFFFF - AMD InterWave (tm) - Instrument routines
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_iw.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format)
-{
- unsigned int result = size;
-
- if (format & IWFFFF_WAVE_16BIT)
- result <<= 1;
- if (format & IWFFFF_WAVE_STEREO)
- result <<= 1;
- return result;
-}
-
-static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t *fp,
- iwffff_xlfo_t *fx)
-{
- fp->freq = le16_to_cpu(fx->freq);
- fp->depth = le16_to_cpu(fx->depth);
- fp->sweep = le16_to_cpu(fx->sweep);
- fp->shape = fx->shape;
- fp->delay = fx->delay;
-}
-
-static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,
- iwffff_layer_t *lp,
- iwffff_env_t *ep,
- iwffff_xenv_t *ex,
- char __user **data,
- long *len,
- gfp_t gfp_mask)
-{
- __u32 stype;
- iwffff_env_record_t *rp, *rp_last;
- iwffff_xenv_record_t rx;
- iwffff_env_point_t *pp;
- iwffff_xenv_point_t px;
- int points_size, idx;
-
- ep->flags = ex->flags;
- ep->mode = ex->mode;
- ep->index = ex->index;
- rp_last = NULL;
- while (1) {
- if (*len < (long)sizeof(__u32))
- return -EINVAL;
- if (copy_from_user(&stype, *data, sizeof(stype)))
- return -EFAULT;
- if (stype == IWFFFF_STRU_WAVE)
- return 0;
- if (req_stype != stype) {
- if (stype == IWFFFF_STRU_ENV_RECP ||
- stype == IWFFFF_STRU_ENV_RECV)
- return 0;
- }
- if (*len < (long)sizeof(rx))
- return -EINVAL;
- if (copy_from_user(&rx, *data, sizeof(rx)))
- return -EFAULT;
- *data += sizeof(rx);
- *len -= sizeof(rx);
- points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);
- if (points_size > *len)
- return -EINVAL;
- rp = kzalloc(sizeof(*rp) + points_size, gfp_mask);
- if (rp == NULL)
- return -ENOMEM;
- rp->nattack = le16_to_cpu(rx.nattack);
- rp->nrelease = le16_to_cpu(rx.nrelease);
- rp->sustain_offset = le16_to_cpu(rx.sustain_offset);
- rp->sustain_rate = le16_to_cpu(rx.sustain_rate);
- rp->release_rate = le16_to_cpu(rx.release_rate);
- rp->hirange = rx.hirange;
- pp = (iwffff_env_point_t *)(rp + 1);
- for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
- if (copy_from_user(&px, *data, sizeof(px)))
- return -EFAULT;
- *data += sizeof(px);
- *len -= sizeof(px);
- pp->offset = le16_to_cpu(px.offset);
- pp->rate = le16_to_cpu(px.rate);
- }
- if (ep->record == NULL) {
- ep->record = rp;
- } else {
- rp_last = rp;
- }
- rp_last = rp;
- }
- return 0;
-}
-
-static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops,
- iwffff_layer_t *lp,
- char __user **data,
- long *len,
- int atomic)
-{
- iwffff_wave_t *wp, *prev;
- iwffff_xwave_t xp;
- int err;
- gfp_t gfp_mask;
- unsigned int real_size;
-
- gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
- if (*len < (long)sizeof(xp))
- return -EINVAL;
- if (copy_from_user(&xp, *data, sizeof(xp)))
- return -EFAULT;
- *data += sizeof(xp);
- *len -= sizeof(xp);
- wp = kzalloc(sizeof(*wp), gfp_mask);
- if (wp == NULL)
- return -ENOMEM;
- wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
- wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
- wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
- wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
- wp->format = le32_to_cpu(xp.format);
- wp->address.memory = le32_to_cpu(xp.offset);
- wp->size = le32_to_cpu(xp.size);
- wp->start = le32_to_cpu(xp.start);
- wp->loop_start = le32_to_cpu(xp.loop_start);
- wp->loop_end = le32_to_cpu(xp.loop_end);
- wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
- wp->sample_ratio = le32_to_cpu(xp.sample_ratio);
- wp->attenuation = xp.attenuation;
- wp->low_note = xp.low_note;
- wp->high_note = xp.high_note;
- real_size = snd_seq_iwffff_size(wp->size, wp->format);
- if (!(wp->format & IWFFFF_WAVE_ROM)) {
- if ((long)real_size > *len) {
- kfree(wp);
- return -ENOMEM;
- }
- }
- if (ops->put_sample) {
- err = ops->put_sample(ops->private_data, wp,
- *data, real_size, atomic);
- if (err < 0) {
- kfree(wp);
- return err;
- }
- }
- if (!(wp->format & IWFFFF_WAVE_ROM)) {
- *data += real_size;
- *len -= real_size;
- }
- prev = lp->wave;
- if (prev) {
- while (prev->next) prev = prev->next;
- prev->next = wp;
- } else {
- lp->wave = wp;
- }
- return 0;
-}
-
-static void snd_seq_iwffff_env_free(snd_iwffff_ops_t *ops,
- iwffff_env_t *env,
- int atomic)
-{
- iwffff_env_record_t *rec;
-
- while ((rec = env->record) != NULL) {
- env->record = rec->next;
- kfree(rec);
- }
-}
-
-static void snd_seq_iwffff_wave_free(snd_iwffff_ops_t *ops,
- iwffff_wave_t *wave,
- int atomic)
-{
- if (ops->remove_sample)
- ops->remove_sample(ops->private_data, wave, atomic);
- kfree(wave);
-}
-
-static void snd_seq_iwffff_instr_free(snd_iwffff_ops_t *ops,
- iwffff_instrument_t *ip,
- int atomic)
-{
- iwffff_layer_t *layer;
- iwffff_wave_t *wave;
-
- while ((layer = ip->layer) != NULL) {
- ip->layer = layer->next;
- snd_seq_iwffff_env_free(ops, &layer->penv, atomic);
- snd_seq_iwffff_env_free(ops, &layer->venv, atomic);
- while ((wave = layer->wave) != NULL) {
- layer->wave = wave->next;
- snd_seq_iwffff_wave_free(ops, wave, atomic);
- }
- kfree(layer);
- }
-}
-
-static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic,
- int cmd)
-{
- snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
- iwffff_instrument_t *ip;
- iwffff_xinstrument_t ix;
- iwffff_layer_t *lp, *prev_lp;
- iwffff_xlayer_t lx;
- int err;
- gfp_t gfp_mask;
-
- if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
- return -EINVAL;
- gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
- /* copy instrument data */
- if (len < (long)sizeof(ix))
- return -EINVAL;
- if (copy_from_user(&ix, instr_data, sizeof(ix)))
- return -EFAULT;
- if (ix.stype != IWFFFF_STRU_INSTR)
- return -EINVAL;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
- ip->exclusion = le16_to_cpu(ix.exclusion);
- ip->layer_type = le16_to_cpu(ix.layer_type);
- ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
- ip->effect1 = ix.effect1;
- ip->effect1_depth = ix.effect1_depth;
- ip->effect2 = ix.effect2;
- ip->effect2_depth = ix.effect2_depth;
- /* copy layers */
- prev_lp = NULL;
- while (len > 0) {
- if (len < (long)sizeof(iwffff_xlayer_t)) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return -EINVAL;
- }
- if (copy_from_user(&lx, instr_data, sizeof(lx)))
- return -EFAULT;
- instr_data += sizeof(lx);
- len -= sizeof(lx);
- if (lx.stype != IWFFFF_STRU_LAYER) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return -EINVAL;
- }
- lp = kzalloc(sizeof(*lp), gfp_mask);
- if (lp == NULL) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return -ENOMEM;
- }
- if (prev_lp) {
- prev_lp->next = lp;
- } else {
- ip->layer = lp;
- }
- prev_lp = lp;
- lp->flags = lx.flags;
- lp->velocity_mode = lx.velocity_mode;
- lp->layer_event = lx.layer_event;
- lp->low_range = lx.low_range;
- lp->high_range = lx.high_range;
- lp->pan = lx.pan;
- lp->pan_freq_scale = lx.pan_freq_scale;
- lp->attenuation = lx.attenuation;
- snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo);
- snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato);
- lp->freq_scale = le16_to_cpu(lx.freq_scale);
- lp->freq_center = lx.freq_center;
- err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP,
- lp,
- &lp->penv, &lx.penv,
- &instr_data, &len,
- gfp_mask);
- if (err < 0) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return err;
- }
- err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,
- lp,
- &lp->venv, &lx.venv,
- &instr_data, &len,
- gfp_mask);
- if (err < 0) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return err;
- }
- while (len > (long)sizeof(__u32)) {
- __u32 stype;
-
- if (copy_from_user(&stype, instr_data, sizeof(stype)))
- return -EFAULT;
- if (stype != IWFFFF_STRU_WAVE)
- break;
- err = snd_seq_iwffff_copy_wave_from_stream(ops,
- lp,
- &instr_data,
- &len,
- atomic);
- if (err < 0) {
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return err;
- }
- }
- }
- return 0;
-}
-
-static void snd_seq_iwffff_copy_lfo_to_stream(iwffff_xlfo_t *fx,
- iwffff_lfo_t *fp)
-{
- fx->freq = cpu_to_le16(fp->freq);
- fx->depth = cpu_to_le16(fp->depth);
- fx->sweep = cpu_to_le16(fp->sweep);
- fp->shape = fx->shape;
- fp->delay = fx->delay;
-}
-
-static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype,
- iwffff_layer_t *lp,
- iwffff_xenv_t *ex,
- iwffff_env_t *ep,
- char __user **data,
- long *len)
-{
- iwffff_env_record_t *rp;
- iwffff_xenv_record_t rx;
- iwffff_env_point_t *pp;
- iwffff_xenv_point_t px;
- int points_size, idx;
-
- ex->flags = ep->flags;
- ex->mode = ep->mode;
- ex->index = ep->index;
- for (rp = ep->record; rp; rp = rp->next) {
- if (*len < (long)sizeof(rx))
- return -ENOMEM;
- memset(&rx, 0, sizeof(rx));
- rx.stype = req_stype;
- rx.nattack = cpu_to_le16(rp->nattack);
- rx.nrelease = cpu_to_le16(rp->nrelease);
- rx.sustain_offset = cpu_to_le16(rp->sustain_offset);
- rx.sustain_rate = cpu_to_le16(rp->sustain_rate);
- rx.release_rate = cpu_to_le16(rp->release_rate);
- rx.hirange = cpu_to_le16(rp->hirange);
- if (copy_to_user(*data, &rx, sizeof(rx)))
- return -EFAULT;
- *data += sizeof(rx);
- *len -= sizeof(rx);
- points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
- if (*len < points_size)
- return -ENOMEM;
- pp = (iwffff_env_point_t *)(rp + 1);
- for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
- px.offset = cpu_to_le16(pp->offset);
- px.rate = cpu_to_le16(pp->rate);
- if (copy_to_user(*data, &px, sizeof(px)))
- return -EFAULT;
- *data += sizeof(px);
- *len -= sizeof(px);
- }
- }
- return 0;
-}
-
-static int snd_seq_iwffff_copy_wave_to_stream(snd_iwffff_ops_t *ops,
- iwffff_layer_t *lp,
- char __user **data,
- long *len,
- int atomic)
-{
- iwffff_wave_t *wp;
- iwffff_xwave_t xp;
- int err;
- unsigned int real_size;
-
- for (wp = lp->wave; wp; wp = wp->next) {
- if (*len < (long)sizeof(xp))
- return -ENOMEM;
- memset(&xp, 0, sizeof(xp));
- xp.stype = IWFFFF_STRU_WAVE;
- xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
- xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
- xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
- xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
- xp.format = cpu_to_le32(wp->format);
- if (wp->format & IWFFFF_WAVE_ROM)
- xp.offset = cpu_to_le32(wp->address.memory);
- xp.size = cpu_to_le32(wp->size);
- xp.start = cpu_to_le32(wp->start);
- xp.loop_start = cpu_to_le32(wp->loop_start);
- xp.loop_end = cpu_to_le32(wp->loop_end);
- xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
- xp.sample_ratio = cpu_to_le32(wp->sample_ratio);
- xp.attenuation = wp->attenuation;
- xp.low_note = wp->low_note;
- xp.high_note = wp->high_note;
- if (copy_to_user(*data, &xp, sizeof(xp)))
- return -EFAULT;
- *data += sizeof(xp);
- *len -= sizeof(xp);
- real_size = snd_seq_iwffff_size(wp->size, wp->format);
- if (!(wp->format & IWFFFF_WAVE_ROM)) {
- if (*len < (long)real_size)
- return -ENOMEM;
- }
- if (ops->get_sample) {
- err = ops->get_sample(ops->private_data, wp,
- *data, real_size, atomic);
- if (err < 0)
- return err;
- }
- if (!(wp->format & IWFFFF_WAVE_ROM)) {
- *data += real_size;
- *len -= real_size;
- }
- }
- return 0;
-}
-
-static int snd_seq_iwffff_get(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len, int atomic, int cmd)
-{
- snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
- iwffff_instrument_t *ip;
- iwffff_xinstrument_t ix;
- iwffff_layer_t *lp;
- iwffff_xlayer_t lx;
- char __user *layer_instr_data;
- int err;
-
- if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
- return -EINVAL;
- if (len < (long)sizeof(ix))
- return -ENOMEM;
- memset(&ix, 0, sizeof(ix));
- ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
- ix.stype = IWFFFF_STRU_INSTR;
- ix.exclusion = cpu_to_le16(ip->exclusion);
- ix.layer_type = cpu_to_le16(ip->layer_type);
- ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
- ix.effect1 = cpu_to_le16(ip->effect1);
- ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
- ix.effect2 = ip->effect2;
- ix.effect2_depth = ip->effect2_depth;
- if (copy_to_user(instr_data, &ix, sizeof(ix)))
- return -EFAULT;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- for (lp = ip->layer; lp; lp = lp->next) {
- if (len < (long)sizeof(lx))
- return -ENOMEM;
- memset(&lx, 0, sizeof(lx));
- lx.stype = IWFFFF_STRU_LAYER;
- lx.flags = lp->flags;
- lx.velocity_mode = lp->velocity_mode;
- lx.layer_event = lp->layer_event;
- lx.low_range = lp->low_range;
- lx.high_range = lp->high_range;
- lx.pan = lp->pan;
- lx.pan_freq_scale = lp->pan_freq_scale;
- lx.attenuation = lp->attenuation;
- snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo);
- snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato);
- layer_instr_data = instr_data;
- instr_data += sizeof(lx);
- len -= sizeof(lx);
- err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP,
- lp,
- &lx.penv, &lp->penv,
- &instr_data, &len);
- if (err < 0)
- return err;
- err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV,
- lp,
- &lx.venv, &lp->venv,
- &instr_data, &len);
- if (err < 0)
- return err;
- /* layer structure updating is now finished */
- if (copy_to_user(layer_instr_data, &lx, sizeof(lx)))
- return -EFAULT;
- err = snd_seq_iwffff_copy_wave_to_stream(ops,
- lp,
- &instr_data,
- &len,
- atomic);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static long snd_seq_iwffff_env_size_in_stream(iwffff_env_t *ep)
-{
- long result = 0;
- iwffff_env_record_t *rp;
-
- for (rp = ep->record; rp; rp = rp->next) {
- result += sizeof(iwffff_xenv_record_t);
- result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
- }
- return 0;
-}
-
-static long snd_seq_iwffff_wave_size_in_stream(iwffff_layer_t *lp)
-{
- long result = 0;
- iwffff_wave_t *wp;
-
- for (wp = lp->wave; wp; wp = wp->next) {
- result += sizeof(iwffff_xwave_t);
- if (!(wp->format & IWFFFF_WAVE_ROM))
- result += wp->size;
- }
- return result;
-}
-
-static int snd_seq_iwffff_get_size(void *private_data, snd_seq_kinstr_t *instr,
- long *size)
-{
- long result;
- iwffff_instrument_t *ip;
- iwffff_layer_t *lp;
-
- *size = 0;
- ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
- result = sizeof(iwffff_xinstrument_t);
- for (lp = ip->layer; lp; lp = lp->next) {
- result += sizeof(iwffff_xlayer_t);
- result += snd_seq_iwffff_env_size_in_stream(&lp->penv);
- result += snd_seq_iwffff_env_size_in_stream(&lp->venv);
- result += snd_seq_iwffff_wave_size_in_stream(lp);
- }
- *size = result;
- return 0;
-}
-
-static int snd_seq_iwffff_remove(void *private_data,
- snd_seq_kinstr_t *instr,
- int atomic)
-{
- snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
- iwffff_instrument_t *ip;
-
- ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
- snd_seq_iwffff_instr_free(ops, ip, atomic);
- return 0;
-}
-
-static void snd_seq_iwffff_notify(void *private_data,
- snd_seq_kinstr_t *instr,
- int what)
-{
- snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
-
- if (ops->notify)
- ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_iwffff_init(snd_iwffff_ops_t *ops,
- void *private_data,
- snd_seq_kinstr_ops_t *next)
-{
- memset(ops, 0, sizeof(*ops));
- ops->private_data = private_data;
- ops->kops.private_data = ops;
- ops->kops.add_len = sizeof(iwffff_instrument_t);
- ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE;
- ops->kops.put = snd_seq_iwffff_put;
- ops->kops.get = snd_seq_iwffff_get;
- ops->kops.get_size = snd_seq_iwffff_get_size;
- ops->kops.remove = snd_seq_iwffff_remove;
- ops->kops.notify = snd_seq_iwffff_notify;
- ops->kops.next = next;
- return 0;
-}
-
-/*
- * Init part
- */
-
-static int __init alsa_ainstr_iw_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ainstr_iw_exit(void)
-{
-}
-
-module_init(alsa_ainstr_iw_init)
-module_exit(alsa_ainstr_iw_exit)
-
-EXPORT_SYMBOL(snd_seq_iwffff_init);
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c
deleted file mode 100644
index 17ab94e7607..00000000000
--- a/sound/core/seq/instr/ainstr_simple.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Simple (MOD player) - Instrument routines
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_simple.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format)
-{
- unsigned int result = size;
-
- if (format & SIMPLE_WAVE_16BIT)
- result <<= 1;
- if (format & SIMPLE_WAVE_STEREO)
- result <<= 1;
- return result;
-}
-
-static void snd_seq_simple_instr_free(snd_simple_ops_t *ops,
- simple_instrument_t *ip,
- int atomic)
-{
- if (ops->remove_sample)
- ops->remove_sample(ops->private_data, ip, atomic);
-}
-
-static int snd_seq_simple_put(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len,
- int atomic, int cmd)
-{
- snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
- simple_instrument_t *ip;
- simple_xinstrument_t ix;
- int err;
- gfp_t gfp_mask;
- unsigned int real_size;
-
- if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
- return -EINVAL;
- gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
- /* copy instrument data */
- if (len < (long)sizeof(ix))
- return -EINVAL;
- if (copy_from_user(&ix, instr_data, sizeof(ix)))
- return -EFAULT;
- if (ix.stype != SIMPLE_STRU_INSTR)
- return -EINVAL;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- ip = (simple_instrument_t *)KINSTR_DATA(instr);
- ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
- ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
- ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
- ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
- ip->format = le32_to_cpu(ix.format);
- ip->size = le32_to_cpu(ix.size);
- ip->start = le32_to_cpu(ix.start);
- ip->loop_start = le32_to_cpu(ix.loop_start);
- ip->loop_end = le32_to_cpu(ix.loop_end);
- ip->loop_repeat = le16_to_cpu(ix.loop_repeat);
- ip->effect1 = ix.effect1;
- ip->effect1_depth = ix.effect1_depth;
- ip->effect2 = ix.effect2;
- ip->effect2_depth = ix.effect2_depth;
- real_size = snd_seq_simple_size(ip->size, ip->format);
- if (len < (long)real_size)
- return -EINVAL;
- if (ops->put_sample) {
- err = ops->put_sample(ops->private_data, ip,
- instr_data, real_size, atomic);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int snd_seq_simple_get(void *private_data, snd_seq_kinstr_t *instr,
- char __user *instr_data, long len,
- int atomic, int cmd)
-{
- snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
- simple_instrument_t *ip;
- simple_xinstrument_t ix;
- int err;
- unsigned int real_size;
-
- if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
- return -EINVAL;
- if (len < (long)sizeof(ix))
- return -ENOMEM;
- memset(&ix, 0, sizeof(ix));
- ip = (simple_instrument_t *)KINSTR_DATA(instr);
- ix.stype = SIMPLE_STRU_INSTR;
- ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
- ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
- ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
- ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
- ix.format = cpu_to_le32(ip->format);
- ix.size = cpu_to_le32(ip->size);
- ix.start = cpu_to_le32(ip->start);
- ix.loop_start = cpu_to_le32(ip->loop_start);
- ix.loop_end = cpu_to_le32(ip->loop_end);
- ix.loop_repeat = cpu_to_le32(ip->loop_repeat);
- ix.effect1 = cpu_to_le16(ip->effect1);
- ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
- ix.effect2 = ip->effect2;
- ix.effect2_depth = ip->effect2_depth;
- if (copy_to_user(instr_data, &ix, sizeof(ix)))
- return -EFAULT;
- instr_data += sizeof(ix);
- len -= sizeof(ix);
- real_size = snd_seq_simple_size(ip->size, ip->format);
- if (len < (long)real_size)
- return -ENOMEM;
- if (ops->get_sample) {
- err = ops->get_sample(ops->private_data, ip,
- instr_data, real_size, atomic);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int snd_seq_simple_get_size(void *private_data, snd_seq_kinstr_t *instr,
- long *size)
-{
- simple_instrument_t *ip;
-
- ip = (simple_instrument_t *)KINSTR_DATA(instr);
- *size = sizeof(simple_xinstrument_t) + snd_seq_simple_size(ip->size, ip->format);
- return 0;
-}
-
-static int snd_seq_simple_remove(void *private_data,
- snd_seq_kinstr_t *instr,
- int atomic)
-{
- snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
- simple_instrument_t *ip;
-
- ip = (simple_instrument_t *)KINSTR_DATA(instr);
- snd_seq_simple_instr_free(ops, ip, atomic);
- return 0;
-}
-
-static void snd_seq_simple_notify(void *private_data,
- snd_seq_kinstr_t *instr,
- int what)
-{
- snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
-
- if (ops->notify)
- ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_simple_init(snd_simple_ops_t *ops,
- void *private_data,
- snd_seq_kinstr_ops_t *next)
-{
- memset(ops, 0, sizeof(*ops));
- ops->private_data = private_data;
- ops->kops.private_data = ops;
- ops->kops.add_len = sizeof(simple_instrument_t);
- ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE;
- ops->kops.put = snd_seq_simple_put;
- ops->kops.get = snd_seq_simple_get;
- ops->kops.get_size = snd_seq_simple_get_size;
- ops->kops.remove = snd_seq_simple_remove;
- ops->kops.notify = snd_seq_simple_notify;
- ops->kops.next = next;
- return 0;
-}
-
-/*
- * Init part
- */
-
-static int __init alsa_ainstr_simple_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ainstr_simple_exit(void)
-{
-}
-
-module_init(alsa_ainstr_simple_init)
-module_exit(alsa_ainstr_simple_exit)
-
-EXPORT_SYMBOL(snd_seq_simple_init);
diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
index a37ddedf710..b38406b8463 100644
--- a/sound/core/seq/oss/Makefile
+++ b/sound/core/seq/oss/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 4c0558c0a8b..16d42679e43 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -20,10 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/initval.h>
@@ -40,20 +39,19 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
-#ifdef SNDRV_SEQ_OSS_DEBUG
-module_param(seq_oss_debug, int, 0644);
-MODULE_PARM_DESC(seq_oss_debug, "debug option");
-int seq_oss_debug = 0;
-#endif
-
/*
* prototypes
*/
static int register_device(void);
static void unregister_device(void);
+#ifdef CONFIG_PROC_FS
static int register_proc(void);
static void unregister_proc(void);
+#else
+static inline int register_proc(void) { return 0; }
+static inline void unregister_proc(void) {}
+#endif
static int odev_open(struct inode *inode, struct file *file);
static int odev_release(struct inode *inode, struct file *file);
@@ -61,9 +59,6 @@ static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff
static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static unsigned int odev_poll(struct file *file, poll_table * wait);
-#ifdef CONFIG_PROC_FS
-static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
-#endif
/*
@@ -73,7 +68,7 @@ static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
static int __init alsa_seq_oss_init(void)
{
int rc;
- static snd_seq_dev_ops_t ops = {
+ static struct snd_seq_dev_ops ops = {
snd_seq_oss_synth_register,
snd_seq_oss_synth_unregister,
};
@@ -92,7 +87,7 @@ static int __init alsa_seq_oss_init(void)
}
if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
- sizeof(snd_seq_oss_reg_t))) < 0) {
+ sizeof(struct snd_seq_oss_reg))) < 0) {
snd_seq_oss_delete_client();
unregister_proc();
unregister_device();
@@ -122,7 +117,7 @@ module_exit(alsa_seq_oss_exit)
* ALSA minor device interface
*/
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
static int
odev_open(struct inode *inode, struct file *file)
@@ -134,9 +129,9 @@ odev_open(struct inode *inode, struct file *file)
else
level = SNDRV_SEQ_OSS_MODE_SYNTH;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
rc = snd_seq_oss_open(file, level);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return rc;
}
@@ -144,16 +139,16 @@ odev_open(struct inode *inode, struct file *file)
static int
odev_release(struct inode *inode, struct file *file)
{
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
if ((dp = file->private_data) == NULL)
return 0;
snd_seq_oss_drain_write(dp);
- down(&register_mutex);
+ mutex_lock(&register_mutex);
snd_seq_oss_release(dp);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
@@ -161,9 +156,10 @@ odev_release(struct inode *inode, struct file *file)
static ssize_t
odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
dp = file->private_data;
- snd_assert(dp != NULL, return -EIO);
+ if (snd_BUG_ON(!dp))
+ return -ENXIO;
return snd_seq_oss_read(dp, buf, count);
}
@@ -171,18 +167,20 @@ odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
static ssize_t
odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
dp = file->private_data;
- snd_assert(dp != NULL, return -EIO);
+ if (snd_BUG_ON(!dp))
+ return -ENXIO;
return snd_seq_oss_write(dp, buf, count, file);
}
static long
odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
dp = file->private_data;
- snd_assert(dp != NULL, return -EIO);
+ if (snd_BUG_ON(!dp))
+ return -ENXIO;
return snd_seq_oss_ioctl(dp, cmd, arg);
}
@@ -195,9 +193,10 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static unsigned int
odev_poll(struct file *file, poll_table * wait)
{
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
dp = file->private_data;
- snd_assert(dp != NULL, return 0);
+ if (snd_BUG_ON(!dp))
+ return -ENXIO;
return snd_seq_oss_poll(dp, file, wait);
}
@@ -205,7 +204,7 @@ odev_poll(struct file *file, poll_table * wait)
* registration of sequencer minor device
*/
-static struct file_operations seq_oss_f_ops =
+static const struct file_operations seq_oss_f_ops =
{
.owner = THIS_MODULE,
.read = odev_read,
@@ -215,11 +214,7 @@ static struct file_operations seq_oss_f_ops =
.poll = odev_poll,
.unlocked_ioctl = odev_ioctl,
.compat_ioctl = odev_ioctl_compat,
-};
-
-static snd_minor_t seq_oss_reg = {
- .comment = "sequencer",
- .f_ops = &seq_oss_f_ops,
+ .llseek = noop_llseek,
};
static int __init
@@ -227,39 +222,35 @@ register_device(void)
{
int rc;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
- &seq_oss_reg,
- SNDRV_SEQ_OSS_DEVNAME)) < 0) {
- snd_printk(KERN_ERR "can't register device seq\n");
- up(&register_mutex);
+ &seq_oss_f_ops, NULL)) < 0) {
+ pr_err("ALSA: seq_oss: can't register device seq\n");
+ mutex_unlock(&register_mutex);
return rc;
}
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
- &seq_oss_reg,
- SNDRV_SEQ_OSS_DEVNAME)) < 0) {
- snd_printk(KERN_ERR "can't register device music\n");
+ &seq_oss_f_ops, NULL)) < 0) {
+ pr_err("ALSA: seq_oss: can't register device music\n");
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return rc;
}
- debug_printk(("device registered\n"));
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
static void
unregister_device(void)
{
- down(&register_mutex);
- debug_printk(("device unregistered\n"));
+ mutex_lock(&register_mutex);
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)
- snd_printk(KERN_ERR "error unregister device music\n");
+ pr_err("ALSA: seq_oss: error unregister device music\n");
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
- snd_printk(KERN_ERR "error unregister device seq\n");
- up(&register_mutex);
+ pr_err("ALSA: seq_oss: error unregister device seq\n");
+ mutex_unlock(&register_mutex);
}
/*
@@ -268,26 +259,24 @@ unregister_device(void)
#ifdef CONFIG_PROC_FS
-static snd_info_entry_t *info_entry;
+static struct snd_info_entry *info_entry;
static void
-info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf)
+info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
{
- down(&register_mutex);
+ mutex_lock(&register_mutex);
snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
snd_seq_oss_system_info_read(buf);
snd_seq_oss_synth_info_read(buf);
snd_seq_oss_midi_info_read(buf);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
}
-#endif /* CONFIG_PROC_FS */
static int __init
register_proc(void)
{
-#ifdef CONFIG_PROC_FS
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root);
if (entry == NULL)
@@ -295,23 +284,19 @@ register_proc(void)
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->private_data = NULL;
- entry->c.text.read_size = 1024;
entry->c.text.read = info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
return -ENOMEM;
}
info_entry = entry;
-#endif
return 0;
}
static void
unregister_proc(void)
{
-#ifdef CONFIG_PROC_FS
- if (info_entry)
- snd_info_unregister(info_entry);
+ snd_info_free_entry(info_entry);
info_entry = NULL;
-#endif
}
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index 973786758c5..b4392432524 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -21,7 +21,6 @@
#ifndef __SEQ_OSS_DEVICE_H
#define __SEQ_OSS_DEVICE_H
-#include <sound/driver.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/slab.h>
@@ -32,9 +31,6 @@
#include <sound/seq_kernel.h>
#include <sound/info.h>
-/* enable debug print */
-#define SNDRV_SEQ_OSS_DEBUG
-
/* max. applications */
#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
#define SNDRV_SEQ_OSS_MAX_SYNTH_DEVS 16
@@ -47,7 +43,6 @@
#define SNDRV_SEQ_OSS_VERSION_STR "0.1.8"
/* device and proc interface name */
-#define SNDRV_SEQ_OSS_DEVNAME "seq_oss"
#define SNDRV_SEQ_OSS_PROCNAME "oss"
@@ -55,32 +50,24 @@
* type definitions
*/
-typedef struct seq_oss_devinfo_t seq_oss_devinfo_t;
-typedef struct seq_oss_writeq_t seq_oss_writeq_t;
-typedef struct seq_oss_readq_t seq_oss_readq_t;
-typedef struct seq_oss_timer_t seq_oss_timer_t;
-typedef struct seq_oss_synthinfo_t seq_oss_synthinfo_t;
-typedef struct seq_oss_synth_sysex_t seq_oss_synth_sysex_t;
-typedef struct seq_oss_chinfo_t seq_oss_chinfo_t;
typedef unsigned int reltime_t;
typedef unsigned int abstime_t;
-typedef union evrec_t evrec_t;
/*
* synthesizer channel information
*/
-struct seq_oss_chinfo_t {
+struct seq_oss_chinfo {
int note, vel;
};
/*
* synthesizer information
*/
-struct seq_oss_synthinfo_t {
- snd_seq_oss_arg_t arg;
- seq_oss_chinfo_t *ch;
- seq_oss_synth_sysex_t *sysex;
+struct seq_oss_synthinfo {
+ struct snd_seq_oss_arg arg;
+ struct seq_oss_chinfo *ch;
+ struct seq_oss_synth_sysex *sysex;
int nr_voices;
int opened;
int is_midi;
@@ -92,14 +79,14 @@ struct seq_oss_synthinfo_t {
* sequencer client information
*/
-struct seq_oss_devinfo_t {
+struct seq_oss_devinfo {
int index; /* application index */
int cseq; /* sequencer client number */
int port; /* sequencer port number */
int queue; /* sequencer queue number */
- snd_seq_addr_t addr; /* address of this device */
+ struct snd_seq_addr addr; /* address of this device */
int seq_mode; /* sequencer mode */
int file_mode; /* file access */
@@ -109,17 +96,17 @@ struct seq_oss_devinfo_t {
/* synth device table */
int max_synthdev;
- seq_oss_synthinfo_t synths[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
+ struct seq_oss_synthinfo synths[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
int synth_opened;
/* output queue */
- seq_oss_writeq_t *writeq;
+ struct seq_oss_writeq *writeq;
/* midi input queue */
- seq_oss_readq_t *readq;
+ struct seq_oss_readq *readq;
/* timer */
- seq_oss_timer_t *timer;
+ struct seq_oss_timer *timer;
};
@@ -133,24 +120,24 @@ int snd_seq_oss_delete_client(void);
/* device file interface */
int snd_seq_oss_open(struct file *file, int level);
-void snd_seq_oss_release(seq_oss_devinfo_t *dp);
-int snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long arg);
-int snd_seq_oss_read(seq_oss_devinfo_t *dev, char __user *buf, int count);
-int snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt);
-unsigned int snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait);
+void snd_seq_oss_release(struct seq_oss_devinfo *dp);
+int snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long arg);
+int snd_seq_oss_read(struct seq_oss_devinfo *dev, char __user *buf, int count);
+int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, struct file *opt);
+unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait);
-void snd_seq_oss_reset(seq_oss_devinfo_t *dp);
-void snd_seq_oss_drain_write(seq_oss_devinfo_t *dp);
+void snd_seq_oss_reset(struct seq_oss_devinfo *dp);
+void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp);
/* */
-void snd_seq_oss_process_queue(seq_oss_devinfo_t *dp, abstime_t time);
+void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time);
/* proc interface */
-void snd_seq_oss_system_info_read(snd_info_buffer_t *buf);
-void snd_seq_oss_midi_info_read(snd_info_buffer_t *buf);
-void snd_seq_oss_synth_info_read(snd_info_buffer_t *buf);
-void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf);
+void snd_seq_oss_system_info_read(struct snd_info_buffer *buf);
+void snd_seq_oss_midi_info_read(struct snd_info_buffer *buf);
+void snd_seq_oss_synth_info_read(struct snd_info_buffer *buf);
+void snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf);
/* file mode macros */
#define is_read_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_READ)
@@ -159,21 +146,21 @@ void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf);
/* dispatch event */
static inline int
-snd_seq_oss_dispatch(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int atomic, int hop)
+snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int atomic, int hop)
{
return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
}
/* ioctl */
static inline int
-snd_seq_oss_control(seq_oss_devinfo_t *dp, unsigned int type, void *arg)
+snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
{
return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
}
/* fill the addresses in header */
static inline void
-snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev,
+snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
int dest_client, int dest_port)
{
ev->queue = dp->queue;
@@ -186,13 +173,4 @@ snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev,
/* misc. functions for proc interface */
char *enabled_str(int bool);
-
-/* for debug */
-#ifdef SNDRV_SEQ_OSS_DEBUG
-extern int seq_oss_debug;
-#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0)
-#else
-#define debug_printk(x) /**/
-#endif
-
#endif /* __SEQ_OSS_DEVICE_H */
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
index 58e52ddd292..c3908862bc8 100644
--- a/sound/core/seq/oss/seq_oss_event.c
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -31,17 +31,17 @@
/*
* prototypes
*/
-static int extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
-static int chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
-static int chn_common_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
-static int timing_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
-static int local_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
-static int old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
-static int note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
-static int note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
-static int set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev);
-static int set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev);
-static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev);
+static int extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
+static int chn_voice_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
+static int chn_common_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
+static int timing_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
+static int local_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
+static int old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
+static int note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
+static int note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
+static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev);
+static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev);
+static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev);
/*
@@ -51,7 +51,7 @@ static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *
*/
int
-snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
switch (q->s.code) {
case SEQ_EXTENDED:
@@ -104,7 +104,7 @@ snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev
/* old type events: mode1 only */
static int
-old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
switch (q->s.code) {
case SEQ_NOTEOFF:
@@ -130,7 +130,7 @@ old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
/* 8bytes extended event: mode1 only */
static int
-extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
int val;
@@ -184,7 +184,7 @@ extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
/* channel voice events: mode1 and 2 */
static int
-chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+chn_voice_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
if (q->v.chn >= 32)
return -EINVAL;
@@ -205,7 +205,7 @@ chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
/* channel common events: mode1 and 2 */
static int
-chn_common_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+chn_common_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
if (q->l.chn >= 32)
return -EINVAL;
@@ -232,14 +232,14 @@ chn_common_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
/* timer events: mode1 and mode2 */
static int
-timing_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+timing_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
switch (q->t.cmd) {
case TMR_ECHO:
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
return set_echo_event(dp, q, ev);
else {
- evrec_t tmp;
+ union evrec tmp;
memset(&tmp, 0, sizeof(tmp));
/* XXX: only for little-endian! */
tmp.echo = (q->t.time << 8) | SEQ_ECHO;
@@ -267,7 +267,7 @@ timing_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
/* local events: mode1 and 2 */
static int
-local_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+local_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
{
return -EINVAL;
}
@@ -283,9 +283,14 @@ local_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
* Use key-pressure if note >= 128
*/
static int
-note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
+note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
{
- seq_oss_synthinfo_t *info = &dp->synths[dev];
+ struct seq_oss_synthinfo *info;
+
+ if (!snd_seq_oss_synth_is_valid(dp, dev))
+ return -ENXIO;
+
+ info = &dp->synths[dev];
switch (info->arg.event_passing) {
case SNDRV_SEQ_OSS_PROCESS_EVENTS:
if (! info->ch || ch < 0 || ch >= info->nr_voices) {
@@ -338,9 +343,14 @@ note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq
* process note-off event for OSS synth
*/
static int
-note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
+note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
{
- seq_oss_synthinfo_t *info = &dp->synths[dev];
+ struct seq_oss_synthinfo *info;
+
+ if (!snd_seq_oss_synth_is_valid(dp, dev))
+ return -ENXIO;
+
+ info = &dp->synths[dev];
switch (info->arg.event_passing) {
case SNDRV_SEQ_OSS_PROCESS_EVENTS:
if (! info->ch || ch < 0 || ch >= info->nr_voices) {
@@ -369,7 +379,7 @@ note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_se
* create a note event
*/
static int
-set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev)
+set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev)
{
if (! snd_seq_oss_synth_is_valid(dp, dev))
return -ENXIO;
@@ -387,7 +397,7 @@ set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int v
* create a control event
*/
static int
-set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev)
+set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev)
{
if (! snd_seq_oss_synth_is_valid(dp, dev))
return -ENXIO;
@@ -405,7 +415,7 @@ set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, i
* create an echo event
*/
static int
-set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev)
+set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev)
{
ev->type = SNDRV_SEQ_EVENT_ECHO;
/* echo back to itself */
@@ -419,11 +429,11 @@ set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev)
* the echo event is processed here.
*/
int
-snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data,
+snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data,
int atomic, int hop)
{
- seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data;
- evrec_t *rec;
+ struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
+ union evrec *rec;
if (ev->type != SNDRV_SEQ_EVENT_ECHO)
return snd_seq_oss_midi_input(ev, direct, private_data);
@@ -431,7 +441,7 @@ snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data,
if (ev->source.client != dp->cseq)
return 0; /* ignored */
- rec = (evrec_t*)&ev->data;
+ rec = (union evrec*)&ev->data;
if (rec->s.code == SEQ_SYNCTIMER) {
/* sync echo back */
snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time);
diff --git a/sound/core/seq/oss/seq_oss_event.h b/sound/core/seq/oss/seq_oss_event.h
index bf1d4d3f53c..9a4d9adb7b8 100644
--- a/sound/core/seq/oss/seq_oss_event.h
+++ b/sound/core/seq/oss/seq_oss_event.h
@@ -29,74 +29,74 @@
#define LONG_EVENT_SIZE 8
/* short event (4bytes) */
-typedef struct evrec_short_t {
+struct evrec_short {
unsigned char code;
unsigned char parm1;
unsigned char dev;
unsigned char parm2;
-} evrec_short_t;
+};
/* short note events (4bytes) */
-typedef struct evrec_note_t {
+struct evrec_note {
unsigned char code;
unsigned char chn;
unsigned char note;
unsigned char vel;
-} evrec_note_t;
+};
/* long timer events (8bytes) */
-typedef struct evrec_timer_t {
+struct evrec_timer {
unsigned char code;
unsigned char cmd;
unsigned char dummy1, dummy2;
unsigned int time;
-} evrec_timer_t;
+};
/* long extended events (8bytes) */
-typedef struct evrec_extended_t {
+struct evrec_extended {
unsigned char code;
unsigned char cmd;
unsigned char dev;
unsigned char chn;
unsigned char p1, p2, p3, p4;
-} evrec_extended_t;
+};
/* long channel events (8bytes) */
-typedef struct evrec_long_t {
+struct evrec_long {
unsigned char code;
unsigned char dev;
unsigned char cmd;
unsigned char chn;
unsigned char p1, p2;
unsigned short val;
-} evrec_long_t;
+};
/* channel voice events (8bytes) */
-typedef struct evrec_voice_t {
+struct evrec_voice {
unsigned char code;
unsigned char dev;
unsigned char cmd;
unsigned char chn;
unsigned char note, parm;
unsigned short dummy;
-} evrec_voice_t;
+};
/* sysex events (8bytes) */
-typedef struct evrec_sysex_t {
+struct evrec_sysex {
unsigned char code;
unsigned char dev;
unsigned char buf[6];
-} evrec_sysex_t;
+};
/* event record */
-union evrec_t {
- evrec_short_t s;
- evrec_note_t n;
- evrec_long_t l;
- evrec_voice_t v;
- evrec_timer_t t;
- evrec_extended_t e;
- evrec_sysex_t x;
+union evrec {
+ struct evrec_short s;
+ struct evrec_note n;
+ struct evrec_long l;
+ struct evrec_voice v;
+ struct evrec_timer t;
+ struct evrec_extended e;
+ struct evrec_sysex x;
unsigned int echo;
unsigned char c[LONG_EVENT_SIZE];
};
@@ -104,9 +104,9 @@ union evrec_t {
#define ev_is_long(ev) ((ev)->s.code >= 128)
#define ev_length(ev) ((ev)->s.code >= 128 ? LONG_EVENT_SIZE : SHORT_EVENT_SIZE)
-int snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
-int snd_seq_oss_process_timer_event(seq_oss_timer_t *rec, evrec_t *q);
-int snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop);
+int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
+int snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *q);
+int snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
#endif /* __SEQ_OSS_EVENT_H */
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index 1ab1cf8158c..b9184d20c39 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -28,7 +28,10 @@
#include "seq_oss_timer.h"
#include "seq_oss_event.h"
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
/*
* common variables
@@ -41,23 +44,31 @@ static int system_client = -1; /* ALSA sequencer client number */
static int system_port = -1;
static int num_clients;
-static seq_oss_devinfo_t *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
+static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
/*
* prototypes
*/
-static int receive_announce(snd_seq_event_t *ev, int direct, void *private, int atomic, int hop);
+static int receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop);
static int translate_mode(struct file *file);
-static int create_port(seq_oss_devinfo_t *dp);
-static int delete_port(seq_oss_devinfo_t *dp);
-static int alloc_seq_queue(seq_oss_devinfo_t *dp);
+static int create_port(struct seq_oss_devinfo *dp);
+static int delete_port(struct seq_oss_devinfo *dp);
+static int alloc_seq_queue(struct seq_oss_devinfo *dp);
static int delete_seq_queue(int queue);
static void free_devinfo(void *private);
#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
+/* call snd_seq_oss_midi_lookup_ports() asynchronously */
+static void async_call_lookup_ports(struct work_struct *work)
+{
+ snd_seq_oss_midi_lookup_ports(system_client);
+}
+
+static DECLARE_WORK(async_lookup_work, async_call_lookup_ports);
+
/*
* create sequencer client for OSS sequencer
*/
@@ -65,42 +76,22 @@ int __init
snd_seq_oss_create_client(void)
{
int rc;
- snd_seq_client_callback_t callback;
- snd_seq_client_info_t *info;
- snd_seq_port_info_t *port;
- snd_seq_port_callback_t port_callback;
+ struct snd_seq_port_info *port;
+ struct snd_seq_port_callback port_callback;
- info = kmalloc(sizeof(*info), GFP_KERNEL);
port = kmalloc(sizeof(*port), GFP_KERNEL);
- if (!info || !port) {
+ if (!port) {
rc = -ENOMEM;
goto __error;
}
/* create ALSA client */
- memset(&callback, 0, sizeof(callback));
-
- callback.private_data = NULL;
- callback.allow_input = 1;
- callback.allow_output = 1;
-
- rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, &callback);
+ rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
+ "OSS sequencer");
if (rc < 0)
goto __error;
system_client = rc;
- debug_printk(("new client = %d\n", rc));
-
- /* set client information */
- memset(info, 0, sizeof(*info));
- info->client = system_client;
- info->type = KERNEL_CLIENT;
- strcpy(info->name, "OSS sequencer");
-
- rc = call_ctl(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info);
-
- /* look up midi devices */
- snd_seq_oss_midi_lookup_ports(system_client);
/* create annoucement receiver port */
memset(port, 0, sizeof(*port));
@@ -118,7 +109,7 @@ snd_seq_oss_create_client(void)
call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
if ((system_port = port->addr.port) >= 0) {
- snd_seq_port_subscribe_t subs;
+ struct snd_seq_port_subscribe subs;
memset(&subs, 0, sizeof(subs));
subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
@@ -129,9 +120,11 @@ snd_seq_oss_create_client(void)
}
rc = 0;
+ /* look up midi devices */
+ schedule_work(&async_lookup_work);
+
__error:
kfree(port);
- kfree(info);
return rc;
}
@@ -140,9 +133,9 @@ snd_seq_oss_create_client(void)
* receive annoucement from system port, and check the midi device
*/
static int
-receive_announce(snd_seq_event_t *ev, int direct, void *private, int atomic, int hop)
+receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop)
{
- snd_seq_port_info_t pinfo;
+ struct snd_seq_port_info pinfo;
if (atomic)
return 0; /* it must not happen */
@@ -175,6 +168,7 @@ receive_announce(snd_seq_event_t *ev, int direct, void *private, int atomic, int
int
snd_seq_oss_delete_client(void)
{
+ cancel_work_sync(&async_lookup_work);
if (system_client >= 0)
snd_seq_delete_kernel_client(system_client);
@@ -191,51 +185,50 @@ int
snd_seq_oss_open(struct file *file, int level)
{
int i, rc;
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
- if ((dp = kzalloc(sizeof(*dp), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc device info\n");
+ dp = kzalloc(sizeof(*dp), GFP_KERNEL);
+ if (!dp) {
+ pr_err("ALSA: seq_oss: can't malloc device info\n");
return -ENOMEM;
}
- debug_printk(("oss_open: dp = %p\n", dp));
+
+ dp->cseq = system_client;
+ dp->port = -1;
+ dp->queue = -1;
for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
if (client_table[i] == NULL)
break;
}
- if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
- snd_printk(KERN_ERR "too many applications\n");
- kfree(dp);
- return -ENOMEM;
- }
dp->index = i;
- dp->cseq = system_client;
- dp->port = -1;
- dp->queue = -1;
- dp->readq = NULL;
- dp->writeq = NULL;
+ if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
+ pr_err("ALSA: seq_oss: too many applications\n");
+ rc = -ENOMEM;
+ goto _error;
+ }
/* look up synth and midi devices */
snd_seq_oss_synth_setup(dp);
snd_seq_oss_midi_setup(dp);
if (dp->synth_opened == 0 && dp->max_mididev == 0) {
- /* snd_printk(KERN_ERR "no device found\n"); */
+ /* pr_err("ALSA: seq_oss: no device found\n"); */
rc = -ENODEV;
goto _error;
}
/* create port */
- debug_printk(("create new port\n"));
- if ((rc = create_port(dp)) < 0) {
- snd_printk(KERN_ERR "can't create port\n");
+ rc = create_port(dp);
+ if (rc < 0) {
+ pr_err("ALSA: seq_oss: can't create port\n");
goto _error;
}
/* allocate queue */
- debug_printk(("allocate queue\n"));
- if ((rc = alloc_seq_queue(dp)) < 0)
+ rc = alloc_seq_queue(dp);
+ if (rc < 0)
goto _error;
/* set address */
@@ -250,32 +243,30 @@ snd_seq_oss_open(struct file *file, int level)
dp->file_mode = translate_mode(file);
/* initialize read queue */
- debug_printk(("initialize read queue\n"));
if (is_read_mode(dp->file_mode)) {
- if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) {
+ dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
+ if (!dp->readq) {
rc = -ENOMEM;
goto _error;
}
}
/* initialize write queue */
- debug_printk(("initialize write queue\n"));
if (is_write_mode(dp->file_mode)) {
dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
- if (dp->writeq == NULL) {
+ if (!dp->writeq) {
rc = -ENOMEM;
goto _error;
}
}
/* initialize timer */
- debug_printk(("initialize timer\n"));
- if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) {
- snd_printk(KERN_ERR "can't alloc timer\n");
+ dp->timer = snd_seq_oss_timer_new(dp);
+ if (!dp->timer) {
+ pr_err("ALSA: seq_oss: can't alloc timer\n");
rc = -ENOMEM;
goto _error;
}
- debug_printk(("timer initialized\n"));
/* set private data pointer */
file->private_data = dp;
@@ -289,15 +280,13 @@ snd_seq_oss_open(struct file *file, int level)
client_table[dp->index] = dp;
num_clients++;
- debug_printk(("open done\n"));
return 0;
_error:
snd_seq_oss_synth_cleanup(dp);
snd_seq_oss_midi_cleanup(dp);
- i = dp->queue;
+ delete_seq_queue(dp->queue);
delete_port(dp);
- delete_seq_queue(i);
return rc;
}
@@ -323,11 +312,11 @@ translate_mode(struct file *file)
* create sequencer port
*/
static int
-create_port(seq_oss_devinfo_t *dp)
+create_port(struct seq_oss_devinfo *dp)
{
int rc;
- snd_seq_port_info_t port;
- snd_seq_port_callback_t callback;
+ struct snd_seq_port_info port;
+ struct snd_seq_port_callback callback;
memset(&port, 0, sizeof(port));
port.addr.client = dp->cseq;
@@ -349,7 +338,6 @@ create_port(seq_oss_devinfo_t *dp)
return rc;
dp->port = port.addr.port;
- debug_printk(("new port = %d\n", port.addr.port));
return 0;
}
@@ -358,12 +346,13 @@ create_port(seq_oss_devinfo_t *dp)
* delete ALSA port
*/
static int
-delete_port(seq_oss_devinfo_t *dp)
+delete_port(struct seq_oss_devinfo *dp)
{
- if (dp->port < 0)
+ if (dp->port < 0) {
+ kfree(dp);
return 0;
+ }
- debug_printk(("delete_port %i\n", dp->port));
return snd_seq_event_port_detach(dp->cseq, dp->port);
}
@@ -371,9 +360,9 @@ delete_port(seq_oss_devinfo_t *dp)
* allocate a queue
*/
static int
-alloc_seq_queue(seq_oss_devinfo_t *dp)
+alloc_seq_queue(struct seq_oss_devinfo *dp)
{
- snd_seq_queue_info_t qinfo;
+ struct snd_seq_queue_info qinfo;
int rc;
memset(&qinfo, 0, sizeof(qinfo));
@@ -392,7 +381,7 @@ alloc_seq_queue(seq_oss_devinfo_t *dp)
static int
delete_seq_queue(int queue)
{
- snd_seq_queue_info_t qinfo;
+ struct snd_seq_queue_info qinfo;
int rc;
if (queue < 0)
@@ -401,7 +390,7 @@ delete_seq_queue(int queue)
qinfo.queue = queue;
rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
if (rc < 0)
- printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
+ pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
return rc;
}
@@ -412,7 +401,7 @@ delete_seq_queue(int queue)
static void
free_devinfo(void *private)
{
- seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private;
+ struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
if (dp->timer)
snd_seq_oss_timer_delete(dp->timer);
@@ -431,28 +420,23 @@ free_devinfo(void *private)
* close sequencer device
*/
void
-snd_seq_oss_release(seq_oss_devinfo_t *dp)
+snd_seq_oss_release(struct seq_oss_devinfo *dp)
{
int queue;
client_table[dp->index] = NULL;
num_clients--;
- debug_printk(("resetting..\n"));
snd_seq_oss_reset(dp);
- debug_printk(("cleaning up..\n"));
snd_seq_oss_synth_cleanup(dp);
snd_seq_oss_midi_cleanup(dp);
/* clear slot */
- debug_printk(("releasing resource..\n"));
queue = dp->queue;
if (dp->port >= 0)
delete_port(dp);
delete_seq_queue(queue);
-
- debug_printk(("release done\n"));
}
@@ -460,13 +444,12 @@ snd_seq_oss_release(seq_oss_devinfo_t *dp)
* Wait until the queue is empty (if we don't have nonblock)
*/
void
-snd_seq_oss_drain_write(seq_oss_devinfo_t *dp)
+snd_seq_oss_drain_write(struct seq_oss_devinfo *dp)
{
if (! dp->timer->running)
return;
if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
dp->writeq) {
- debug_printk(("syncing..\n"));
while (snd_seq_oss_writeq_sync(dp->writeq))
;
}
@@ -477,7 +460,7 @@ snd_seq_oss_drain_write(seq_oss_devinfo_t *dp)
* reset sequencer devices
*/
void
-snd_seq_oss_reset(seq_oss_devinfo_t *dp)
+snd_seq_oss_reset(struct seq_oss_devinfo *dp)
{
int i;
@@ -502,6 +485,7 @@ snd_seq_oss_reset(seq_oss_devinfo_t *dp)
}
+#ifdef CONFIG_PROC_FS
/*
* misc. functions for proc interface
*/
@@ -525,10 +509,10 @@ filemode_str(int val)
* proc interface
*/
void
-snd_seq_oss_system_info_read(snd_info_buffer_t *buf)
+snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
{
int i;
- seq_oss_devinfo_t *dp;
+ struct seq_oss_devinfo *dp;
snd_iprintf(buf, "ALSA client number %d\n", system_client);
snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
@@ -552,4 +536,4 @@ snd_seq_oss_system_info_read(snd_info_buffer_t *buf)
snd_seq_oss_readq_info_read(dp->readq, buf);
}
}
-
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
index e86f18d00f3..5b8520177b0 100644
--- a/sound/core/seq/oss/seq_oss_ioctl.c
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -28,7 +28,7 @@
#include "seq_oss_midi.h"
#include "seq_oss_event.h"
-static int snd_seq_oss_synth_info_user(seq_oss_devinfo_t *dp, void __user *arg)
+static int snd_seq_oss_synth_info_user(struct seq_oss_devinfo *dp, void __user *arg)
{
struct synth_info info;
@@ -41,7 +41,7 @@ static int snd_seq_oss_synth_info_user(seq_oss_devinfo_t *dp, void __user *arg)
return 0;
}
-static int snd_seq_oss_midi_info_user(seq_oss_devinfo_t *dp, void __user *arg)
+static int snd_seq_oss_midi_info_user(struct seq_oss_devinfo *dp, void __user *arg)
{
struct midi_info info;
@@ -54,24 +54,24 @@ static int snd_seq_oss_midi_info_user(seq_oss_devinfo_t *dp, void __user *arg)
return 0;
}
-static int snd_seq_oss_oob_user(seq_oss_devinfo_t *dp, void __user *arg)
+static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
{
unsigned char ev[8];
- snd_seq_event_t tmpev;
+ struct snd_seq_event tmpev;
if (copy_from_user(ev, arg, 8))
return -EFAULT;
memset(&tmpev, 0, sizeof(tmpev));
snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
tmpev.time.tick = 0;
- if (! snd_seq_oss_process_event(dp, (evrec_t*)ev, &tmpev)) {
+ if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
}
return 0;
}
int
-snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
+snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg)
{
int dev, val;
void __user *arg = (void __user *)carg;
@@ -90,12 +90,10 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
case SNDCTL_SEQ_PANIC:
- debug_printk(("panic\n"));
snd_seq_oss_reset(dp);
return -EINVAL;
case SNDCTL_SEQ_SYNC:
- debug_printk(("sync\n"));
if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
return 0;
while (snd_seq_oss_writeq_sync(dp->writeq))
@@ -105,55 +103,45 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
return 0;
case SNDCTL_SEQ_RESET:
- debug_printk(("reset\n"));
snd_seq_oss_reset(dp);
return 0;
case SNDCTL_SEQ_TESTMIDI:
- debug_printk(("test midi\n"));
if (get_user(dev, p))
return -EFAULT;
return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
case SNDCTL_SEQ_GETINCOUNT:
- debug_printk(("get in count\n"));
if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
return 0;
return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
case SNDCTL_SEQ_GETOUTCOUNT:
- debug_printk(("get out count\n"));
if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
return 0;
return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
case SNDCTL_SEQ_GETTIME:
- debug_printk(("get time\n"));
return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
case SNDCTL_SEQ_RESETSAMPLES:
- debug_printk(("reset samples\n"));
if (get_user(dev, p))
return -EFAULT;
return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
case SNDCTL_SEQ_NRSYNTHS:
- debug_printk(("nr synths\n"));
return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
case SNDCTL_SEQ_NRMIDIS:
- debug_printk(("nr midis\n"));
return put_user(dp->max_mididev, p) ? -EFAULT : 0;
case SNDCTL_SYNTH_MEMAVL:
- debug_printk(("mem avail\n"));
if (get_user(dev, p))
return -EFAULT;
val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
return put_user(val, p) ? -EFAULT : 0;
case SNDCTL_FM_4OP_ENABLE:
- debug_printk(("4op\n"));
if (get_user(dev, p))
return -EFAULT;
snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
@@ -161,19 +149,15 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
case SNDCTL_SYNTH_INFO:
case SNDCTL_SYNTH_ID:
- debug_printk(("synth info\n"));
return snd_seq_oss_synth_info_user(dp, arg);
case SNDCTL_SEQ_OUTOFBAND:
- debug_printk(("out of band\n"));
return snd_seq_oss_oob_user(dp, arg);
case SNDCTL_MIDI_INFO:
- debug_printk(("midi info\n"));
return snd_seq_oss_midi_info_user(dp, arg);
case SNDCTL_SEQ_THRESHOLD:
- debug_printk(("threshold\n"));
if (! is_write_mode(dp->file_mode))
return 0;
if (get_user(val, p))
@@ -186,7 +170,6 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
return 0;
case SNDCTL_MIDI_PRETIME:
- debug_printk(("pretime\n"));
if (dp->readq == NULL || !is_read_mode(dp->file_mode))
return 0;
if (get_user(val, p))
@@ -199,7 +182,6 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
return put_user(val, p) ? -EFAULT : 0;
default:
- debug_printk(("others\n"));
if (! is_write_mode(dp->file_mode))
return -EIO;
return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index f0e95c8f2ee..3a4569669ef 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <sound/asoundef.h>
#include "seq_oss_midi.h"
#include "seq_oss_readq.h"
#include "seq_oss_timer.h"
@@ -27,6 +28,7 @@
#include <sound/seq_midi_event.h>
#include "../seq_lock.h"
#include <linux/init.h>
+#include <linux/slab.h>
/*
@@ -37,15 +39,15 @@
/*
* definition of midi device record
*/
-struct seq_oss_midi_t {
+struct seq_oss_midi {
int seq_device; /* device number */
int client; /* sequencer client number */
int port; /* sequencer port number */
unsigned int flags; /* port capability */
int opened; /* flag for opening */
unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME];
- snd_midi_event_t *coder; /* MIDI event coder */
- seq_oss_devinfo_t *devinfo; /* assigned OSSseq device */
+ struct snd_midi_event *coder; /* MIDI event coder */
+ struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */
snd_use_lock_t use_lock;
};
@@ -54,27 +56,27 @@ struct seq_oss_midi_t {
* midi device table
*/
static int max_midi_devs;
-static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
+static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
static DEFINE_SPINLOCK(register_lock);
/*
* prototypes
*/
-static seq_oss_midi_t *get_mdev(int dev);
-static seq_oss_midi_t *get_mididev(seq_oss_devinfo_t *dp, int dev);
-static int send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev);
-static int send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev);
+static struct seq_oss_midi *get_mdev(int dev);
+static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev);
+static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev);
+static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev);
/*
* look up the existing ports
* this looks a very exhausting job.
*/
-int __init
+int
snd_seq_oss_midi_lookup_ports(int client)
{
- snd_seq_client_info_t *clinfo;
- snd_seq_port_info_t *pinfo;
+ struct snd_seq_client_info *clinfo;
+ struct snd_seq_port_info *pinfo;
clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
@@ -100,10 +102,10 @@ snd_seq_oss_midi_lookup_ports(int client)
/*
*/
-static seq_oss_midi_t *
+static struct seq_oss_midi *
get_mdev(int dev)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
unsigned long flags;
spin_lock_irqsave(&register_lock, flags);
@@ -117,11 +119,11 @@ get_mdev(int dev)
/*
* look for the identical slot
*/
-static seq_oss_midi_t *
+static struct seq_oss_midi *
find_slot(int client, int port)
{
int i;
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
unsigned long flags;
spin_lock_irqsave(&register_lock, flags);
@@ -145,13 +147,12 @@ find_slot(int client, int port)
* register a new port if it doesn't exist yet
*/
int
-snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
+snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
{
int i;
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
unsigned long flags;
- debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port));
/* the port must include generic midi */
if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
return 0;
@@ -173,7 +174,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
* allocate midi info record
*/
if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc midi info\n");
+ pr_err("ALSA: seq_oss: can't malloc midi info\n");
return -ENOMEM;
}
@@ -189,7 +190,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
/* create MIDI coder */
if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
- snd_printk(KERN_ERR "can't malloc midi coder\n");
+ pr_err("ALSA: seq_oss: can't malloc midi coder\n");
kfree(mdev);
return -ENOMEM;
}
@@ -226,7 +227,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
int
snd_seq_oss_midi_check_exit_port(int client, int port)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
unsigned long flags;
int index;
@@ -258,7 +259,7 @@ void
snd_seq_oss_midi_clear_all(void)
{
int i;
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
unsigned long flags;
spin_lock_irqsave(&register_lock, flags);
@@ -279,7 +280,7 @@ snd_seq_oss_midi_clear_all(void)
* set up midi tables
*/
void
-snd_seq_oss_midi_setup(seq_oss_devinfo_t *dp)
+snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
{
dp->max_mididev = max_midi_devs;
}
@@ -288,7 +289,7 @@ snd_seq_oss_midi_setup(seq_oss_devinfo_t *dp)
* clean up midi tables
*/
void
-snd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp)
+snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp)
{
int i;
for (i = 0; i < dp->max_mididev; i++)
@@ -301,7 +302,7 @@ snd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp)
* open all midi devices. ignore errors.
*/
void
-snd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode)
+snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode)
{
int i;
for (i = 0; i < dp->max_mididev; i++)
@@ -312,8 +313,8 @@ snd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode)
/*
* get the midi device information
*/
-static seq_oss_midi_t *
-get_mididev(seq_oss_devinfo_t *dp, int dev)
+static struct seq_oss_midi *
+get_mididev(struct seq_oss_devinfo *dp, int dev)
{
if (dev < 0 || dev >= dp->max_mididev)
return NULL;
@@ -325,11 +326,11 @@ get_mididev(seq_oss_devinfo_t *dp, int dev)
* open the midi device if not opened yet
*/
int
-snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int fmode)
+snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
{
int perm;
- seq_oss_midi_t *mdev;
- snd_seq_port_subscribe_t subs;
+ struct seq_oss_midi *mdev;
+ struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
return -ENODEV;
@@ -392,10 +393,10 @@ snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int fmode)
* close the midi device if already opened
*/
int
-snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev)
+snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_midi_t *mdev;
- snd_seq_port_subscribe_t subs;
+ struct seq_oss_midi *mdev;
+ struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
return -ENODEV;
@@ -404,7 +405,6 @@ snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev)
return 0;
}
- debug_printk(("closing client %d port %d mode %d\n", mdev->client, mdev->port, mdev->opened));
memset(&subs, 0, sizeof(subs));
if (mdev->opened & PERM_WRITE) {
subs.sender = dp->addr;
@@ -430,9 +430,9 @@ snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev)
* change seq capability flags to file mode flags
*/
int
-snd_seq_oss_midi_filemode(seq_oss_devinfo_t *dp, int dev)
+snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
int mode;
if ((mdev = get_mididev(dp, dev)) == NULL)
@@ -453,9 +453,9 @@ snd_seq_oss_midi_filemode(seq_oss_devinfo_t *dp, int dev)
* so far, only close the device.
*/
void
-snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
+snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
return;
@@ -465,10 +465,9 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
}
if (mdev->opened & PERM_WRITE) {
- snd_seq_event_t ev;
+ struct snd_seq_event ev;
int c;
- debug_printk(("resetting client %d port %d\n", mdev->client, mdev->port));
memset(&ev, 0, sizeof(ev));
ev.dest.client = mdev->client;
ev.dest.port = mdev->port;
@@ -476,19 +475,20 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
ev.source.port = dp->port;
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
ev.type = SNDRV_SEQ_EVENT_SENSING;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
}
for (c = 0; c < 16; c++) {
ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
ev.data.control.channel = c;
- ev.data.control.param = 123;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */
+ ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
- ev.data.control.param = 121;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
+ ev.data.control.param =
+ MIDI_CTL_RESET_CONTROLLERS;
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
ev.data.control.value = 0;
- snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
+ snd_seq_oss_dispatch(dp, &ev, 0, 0);
}
}
}
@@ -501,9 +501,9 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
* get client/port of the specified MIDI device
*/
void
-snd_seq_oss_midi_get_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_addr_t *addr)
+snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
return;
@@ -517,10 +517,10 @@ snd_seq_oss_midi_get_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_addr_t *addr)
* input callback - this can be atomic
*/
int
-snd_seq_oss_midi_input(snd_seq_event_t *ev, int direct, void *private_data)
+snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
{
- seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data;
- seq_oss_midi_t *mdev;
+ struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
+ struct seq_oss_midi *mdev;
int rc;
if (dp->readq == NULL)
@@ -545,9 +545,9 @@ snd_seq_oss_midi_input(snd_seq_event_t *ev, int direct, void *private_data)
* convert ALSA sequencer event to OSS synth event
*/
static int
-send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev)
+send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev)
{
- evrec_t ossev;
+ union evrec ossev;
memset(&ossev, 0, sizeof(ossev));
@@ -606,7 +606,7 @@ send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev)
* decode event and send MIDI bytes to read queue
*/
static int
-send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev)
+send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev)
{
char msg[32];
int len;
@@ -634,9 +634,9 @@ send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev
* non-zero : invalid - ignored
*/
int
-snd_seq_oss_midi_putc(seq_oss_devinfo_t *dp, int dev, unsigned char c, snd_seq_event_t *ev)
+snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
return -ENODEV;
@@ -653,9 +653,9 @@ snd_seq_oss_midi_putc(seq_oss_devinfo_t *dp, int dev, unsigned char c, snd_seq_e
* create OSS compatible midi_info record
*/
int
-snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf)
+snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf)
{
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
return -ENXIO;
@@ -668,6 +668,7 @@ snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf
}
+#ifdef CONFIG_PROC_FS
/*
* proc interface
*/
@@ -686,10 +687,10 @@ capmode_str(int val)
}
void
-snd_seq_oss_midi_info_read(snd_info_buffer_t *buf)
+snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
{
int i;
- seq_oss_midi_t *mdev;
+ struct seq_oss_midi *mdev;
snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
for (i = 0; i < max_midi_devs; i++) {
@@ -707,4 +708,4 @@ snd_seq_oss_midi_info_read(snd_info_buffer_t *buf)
snd_use_lock_free(&mdev->use_lock);
}
}
-
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_midi.h b/sound/core/seq/oss/seq_oss_midi.h
index 462484b2b6f..84eb866ba58 100644
--- a/sound/core/seq/oss/seq_oss_midi.h
+++ b/sound/core/seq/oss/seq_oss_midi.h
@@ -26,24 +26,23 @@
#include "seq_oss_device.h"
#include <sound/seq_oss_legacy.h>
-typedef struct seq_oss_midi_t seq_oss_midi_t;
-
int snd_seq_oss_midi_lookup_ports(int client);
-int snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo);
+int snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo);
int snd_seq_oss_midi_check_exit_port(int client, int port);
void snd_seq_oss_midi_clear_all(void);
-void snd_seq_oss_midi_setup(seq_oss_devinfo_t *dp);
-void snd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp);
+void snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp);
+void snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp);
-int snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int file_mode);
-void snd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode);
-int snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev);
-void snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev);
-int snd_seq_oss_midi_putc(seq_oss_devinfo_t *dp, int dev, unsigned char c, snd_seq_event_t *ev);
-int snd_seq_oss_midi_input(snd_seq_event_t *ev, int direct, void *private);
-int snd_seq_oss_midi_filemode(seq_oss_devinfo_t *dp, int dev);
-int snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf);
-void snd_seq_oss_midi_get_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_addr_t *addr);
+int snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int file_mode);
+void snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode);
+int snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev);
+void snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev);
+int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
+ struct snd_seq_event *ev);
+int snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private);
+int snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev);
+int snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf);
+void snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr);
#endif
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index 55571e15cd3..654d17a5023 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -25,6 +25,7 @@
#include <sound/seq_oss_legacy.h>
#include "../seq_lock.h"
#include <linux/wait.h>
+#include <linux/slab.h>
/*
* constants
@@ -41,18 +42,18 @@
/*
* create a read queue
*/
-seq_oss_readq_t *
-snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen)
+struct seq_oss_readq *
+snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
{
- seq_oss_readq_t *q;
+ struct seq_oss_readq *q;
if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc read queue\n");
+ pr_err("ALSA: seq_oss: can't malloc read queue\n");
return NULL;
}
- if ((q->q = kcalloc(maxlen, sizeof(evrec_t), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc read queue buffer\n");
+ if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
+ pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
kfree(q);
return NULL;
}
@@ -72,7 +73,7 @@ snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen)
* delete the read queue
*/
void
-snd_seq_oss_readq_delete(seq_oss_readq_t *q)
+snd_seq_oss_readq_delete(struct seq_oss_readq *q)
{
if (q) {
kfree(q->q);
@@ -84,7 +85,7 @@ snd_seq_oss_readq_delete(seq_oss_readq_t *q)
* reset the read queue
*/
void
-snd_seq_oss_readq_clear(seq_oss_readq_t *q)
+snd_seq_oss_readq_clear(struct seq_oss_readq *q)
{
if (q->qlen) {
q->qlen = 0;
@@ -100,9 +101,9 @@ snd_seq_oss_readq_clear(seq_oss_readq_t *q)
* put a midi byte
*/
int
-snd_seq_oss_readq_puts(seq_oss_readq_t *q, int dev, unsigned char *data, int len)
+snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, int len)
{
- evrec_t rec;
+ union evrec rec;
int result;
memset(&rec, 0, sizeof(rec));
@@ -123,7 +124,7 @@ snd_seq_oss_readq_puts(seq_oss_readq_t *q, int dev, unsigned char *data, int len
* return zero if enqueued
*/
int
-snd_seq_oss_readq_put_event(seq_oss_readq_t *q, evrec_t *ev)
+snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
{
unsigned long flags;
@@ -152,7 +153,7 @@ snd_seq_oss_readq_put_event(seq_oss_readq_t *q, evrec_t *ev)
* caller must hold lock
*/
int
-snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec)
+snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec)
{
if (q->qlen == 0)
return -EAGAIN;
@@ -164,7 +165,7 @@ snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec)
* sleep until ready
*/
void
-snd_seq_oss_readq_wait(seq_oss_readq_t *q)
+snd_seq_oss_readq_wait(struct seq_oss_readq *q)
{
wait_event_interruptible_timeout(q->midi_sleep,
(q->qlen > 0 || q->head == q->tail),
@@ -176,7 +177,7 @@ snd_seq_oss_readq_wait(seq_oss_readq_t *q)
* caller must hold lock
*/
void
-snd_seq_oss_readq_free(seq_oss_readq_t *q)
+snd_seq_oss_readq_free(struct seq_oss_readq *q)
{
if (q->qlen > 0) {
q->head = (q->head + 1) % q->maxlen;
@@ -189,7 +190,7 @@ snd_seq_oss_readq_free(seq_oss_readq_t *q)
* return non-zero if readq is not empty.
*/
unsigned int
-snd_seq_oss_readq_poll(seq_oss_readq_t *q, struct file *file, poll_table *wait)
+snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wait)
{
poll_wait(file, &q->midi_sleep, wait);
return q->qlen;
@@ -199,10 +200,10 @@ snd_seq_oss_readq_poll(seq_oss_readq_t *q, struct file *file, poll_table *wait)
* put a timestamp
*/
int
-snd_seq_oss_readq_put_timestamp(seq_oss_readq_t *q, unsigned long curt, int seq_mode)
+snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode)
{
if (curt != q->input_time) {
- evrec_t rec;
+ union evrec rec;
memset(&rec, 0, sizeof(rec));
switch (seq_mode) {
case SNDRV_SEQ_OSS_MODE_SYNTH:
@@ -222,13 +223,15 @@ snd_seq_oss_readq_put_timestamp(seq_oss_readq_t *q, unsigned long curt, int seq_
}
+#ifdef CONFIG_PROC_FS
/*
* proc interface
*/
void
-snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf)
+snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf)
{
snd_iprintf(buf, " read queue [%s] length = %d : tick = %ld\n",
(waitqueue_active(&q->midi_sleep) ? "sleeping":"running"),
q->qlen, q->input_time);
}
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_readq.h b/sound/core/seq/oss/seq_oss_readq.h
index 303b9298f20..f1463f1f449 100644
--- a/sound/core/seq/oss/seq_oss_readq.h
+++ b/sound/core/seq/oss/seq_oss_readq.h
@@ -28,8 +28,8 @@
/*
* definition of read queue
*/
-struct seq_oss_readq_t {
- evrec_t *q;
+struct seq_oss_readq {
+ union evrec *q;
int qlen;
int maxlen;
int head, tail;
@@ -39,16 +39,16 @@ struct seq_oss_readq_t {
spinlock_t lock;
};
-seq_oss_readq_t *snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen);
-void snd_seq_oss_readq_delete(seq_oss_readq_t *q);
-void snd_seq_oss_readq_clear(seq_oss_readq_t *readq);
-unsigned int snd_seq_oss_readq_poll(seq_oss_readq_t *readq, struct file *file, poll_table *wait);
-int snd_seq_oss_readq_puts(seq_oss_readq_t *readq, int dev, unsigned char *data, int len);
-int snd_seq_oss_readq_put_event(seq_oss_readq_t *readq, evrec_t *ev);
-int snd_seq_oss_readq_put_timestamp(seq_oss_readq_t *readq, unsigned long curt, int seq_mode);
-int snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec);
-void snd_seq_oss_readq_wait(seq_oss_readq_t *q);
-void snd_seq_oss_readq_free(seq_oss_readq_t *q);
+struct seq_oss_readq *snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen);
+void snd_seq_oss_readq_delete(struct seq_oss_readq *q);
+void snd_seq_oss_readq_clear(struct seq_oss_readq *readq);
+unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait);
+int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len);
+int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev);
+int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode);
+int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec);
+void snd_seq_oss_readq_wait(struct seq_oss_readq *q);
+void snd_seq_oss_readq_free(struct seq_oss_readq *q);
#define snd_seq_oss_readq_lock(q, flags) spin_lock_irqsave(&(q)->lock, flags)
#define snd_seq_oss_readq_unlock(q, flags) spin_unlock_irqrestore(&(q)->lock, flags)
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 1d8fbd22e3e..6a7b6aceeca 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -33,7 +33,7 @@
/*
* protoypes
*/
-static int insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt);
+static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt);
/*
@@ -41,12 +41,12 @@ static int insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt);
*/
int
-snd_seq_oss_read(seq_oss_devinfo_t *dp, char __user *buf, int count)
+snd_seq_oss_read(struct seq_oss_devinfo *dp, char __user *buf, int count)
{
- seq_oss_readq_t *readq = dp->readq;
+ struct seq_oss_readq *readq = dp->readq;
int result = 0, err = 0;
int ev_len;
- evrec_t rec;
+ union evrec rec;
unsigned long flags;
if (readq == NULL || ! is_read_mode(dp->file_mode))
@@ -93,11 +93,11 @@ snd_seq_oss_read(seq_oss_devinfo_t *dp, char __user *buf, int count)
*/
int
-snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt)
+snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, struct file *opt)
{
int result = 0, err = 0;
int ev_size, fmt;
- evrec_t rec;
+ union evrec rec;
if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
return -ENXIO;
@@ -161,10 +161,10 @@ snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, stru
* return: 0 = OK, non-zero = NG
*/
static int
-insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt)
+insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
{
int rc = 0;
- snd_seq_event_t event;
+ struct snd_seq_event event;
/* if this is a timing event, process the current time */
if (snd_seq_oss_process_timer_event(dp->timer, rec))
@@ -197,7 +197,7 @@ insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt)
*/
unsigned int
-snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait)
+snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait)
{
unsigned int mask = 0;
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index 8257fce2ca1..701feb71b70 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -24,6 +24,8 @@
#include "seq_oss_midi.h"
#include "../seq_lock.h"
#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
/*
* constants
@@ -37,14 +39,14 @@
*/
/* sysex buffer */
-struct seq_oss_synth_sysex_t {
+struct seq_oss_synth_sysex {
int len;
int skip;
unsigned char buf[MAX_SYSEX_BUFLEN];
};
/* synth info */
-struct seq_oss_synth_t {
+struct seq_oss_synth {
int seq_device;
/* for synth_info */
@@ -53,7 +55,7 @@ struct seq_oss_synth_t {
int nr_voices;
char name[SNDRV_SEQ_OSS_MAX_SYNTH_NAME];
- snd_seq_oss_callback_t oper;
+ struct snd_seq_oss_callback oper;
int opened;
@@ -66,8 +68,8 @@ struct seq_oss_synth_t {
* device table
*/
static int max_synth_devs;
-static seq_oss_synth_t *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
-static seq_oss_synth_t midi_synth_dev = {
+static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
+static struct seq_oss_synth midi_synth_dev = {
-1, /* seq_device */
SYNTH_TYPE_MIDI, /* synth_type */
0, /* synth_subtype */
@@ -80,8 +82,8 @@ static DEFINE_SPINLOCK(register_lock);
/*
* prototypes
*/
-static seq_oss_synth_t *get_synthdev(seq_oss_devinfo_t *dp, int dev);
-static void reset_channels(seq_oss_synthinfo_t *info);
+static struct seq_oss_synth *get_synthdev(struct seq_oss_devinfo *dp, int dev);
+static void reset_channels(struct seq_oss_synthinfo *info);
/*
* global initialization
@@ -96,15 +98,15 @@ snd_seq_oss_synth_init(void)
* registration of the synth device
*/
int
-snd_seq_oss_synth_register(snd_seq_device_t *dev)
+snd_seq_oss_synth_register(struct snd_seq_device *dev)
{
int i;
- seq_oss_synth_t *rec;
- snd_seq_oss_reg_t *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
+ struct seq_oss_synth *rec;
+ struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
unsigned long flags;
if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc synth info\n");
+ pr_err("ALSA: seq_oss: can't malloc synth info\n");
return -ENOMEM;
}
rec->seq_device = -1;
@@ -128,7 +130,7 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev)
if (i >= max_synth_devs) {
if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
spin_unlock_irqrestore(&register_lock, flags);
- snd_printk(KERN_ERR "no more synth slot\n");
+ pr_err("ALSA: seq_oss: no more synth slot\n");
kfree(rec);
return -ENOMEM;
}
@@ -136,7 +138,6 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev)
}
rec->seq_device = i;
synth_devs[i] = rec;
- debug_printk(("synth %s registered %d\n", rec->name, i));
spin_unlock_irqrestore(&register_lock, flags);
dev->driver_data = rec;
#ifdef SNDRV_OSS_INFO_DEV_SYNTH
@@ -148,10 +149,10 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev)
int
-snd_seq_oss_synth_unregister(snd_seq_device_t *dev)
+snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
{
int index;
- seq_oss_synth_t *rec = dev->driver_data;
+ struct seq_oss_synth *rec = dev->driver_data;
unsigned long flags;
spin_lock_irqsave(&register_lock, flags);
@@ -161,7 +162,7 @@ snd_seq_oss_synth_unregister(snd_seq_device_t *dev)
}
if (index >= max_synth_devs) {
spin_unlock_irqrestore(&register_lock, flags);
- snd_printk(KERN_ERR "can't unregister synth\n");
+ pr_err("ALSA: seq_oss: can't unregister synth\n");
return -EINVAL;
}
synth_devs[index] = NULL;
@@ -187,10 +188,10 @@ snd_seq_oss_synth_unregister(snd_seq_device_t *dev)
/*
*/
-static seq_oss_synth_t *
+static struct seq_oss_synth *
get_sdev(int dev)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
unsigned long flags;
spin_lock_irqsave(&register_lock, flags);
@@ -207,11 +208,11 @@ get_sdev(int dev)
*/
void
-snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp)
+snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
{
int i;
- seq_oss_synth_t *rec;
- seq_oss_synthinfo_t *info;
+ struct seq_oss_synth *rec;
+ struct seq_oss_synthinfo *info;
dp->max_synthdev = max_synth_devs;
dp->synth_opened = 0;
@@ -244,12 +245,16 @@ snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp)
}
info->nr_voices = rec->nr_voices;
if (info->nr_voices > 0) {
- info->ch = kcalloc(info->nr_voices, sizeof(seq_oss_chinfo_t), GFP_KERNEL);
- if (!info->ch)
- BUG();
+ info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
+ if (!info->ch) {
+ pr_err("ALSA: seq_oss: Cannot malloc voices\n");
+ rec->oper.close(&info->arg);
+ module_put(rec->oper.owner);
+ snd_use_lock_free(&rec->use_lock);
+ continue;
+ }
reset_channels(info);
}
- debug_printk(("synth %d assigned\n", i));
info->opened++;
rec->opened++;
dp->synth_opened++;
@@ -263,7 +268,7 @@ snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp)
*/
void
-snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp)
+snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp)
{
int i;
@@ -271,7 +276,7 @@ snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp)
return;
for (i = 0; i < dp->max_mididev; i++) {
- seq_oss_synthinfo_t *info;
+ struct seq_oss_synthinfo *info;
info = &dp->synths[dp->max_synthdev];
if (snd_seq_oss_midi_open(dp, i, dp->file_mode) < 0)
continue;
@@ -297,13 +302,14 @@ snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp)
*/
void
-snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp)
+snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
{
int i;
- seq_oss_synth_t *rec;
- seq_oss_synthinfo_t *info;
+ struct seq_oss_synth *rec;
+ struct seq_oss_synthinfo *info;
- snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
+ if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
+ return;
for (i = 0; i < dp->max_synthdev; i++) {
info = &dp->synths[i];
if (! info->opened)
@@ -318,7 +324,6 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp)
if (rec == NULL)
continue;
if (rec->opened > 0) {
- debug_printk(("synth %d closed\n", i));
rec->oper.close(&info->arg);
module_put(rec->oper.owner);
rec->opened = 0;
@@ -338,7 +343,7 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp)
* check if the specified device is MIDI mapped device
*/
static int
-is_midi_dev(seq_oss_devinfo_t *dp, int dev)
+is_midi_dev(struct seq_oss_devinfo *dp, int dev)
{
if (dev < 0 || dev >= dp->max_synthdev)
return 0;
@@ -350,10 +355,10 @@ is_midi_dev(seq_oss_devinfo_t *dp, int dev)
/*
* return synth device information pointer
*/
-static seq_oss_synth_t *
-get_synthdev(seq_oss_devinfo_t *dp, int dev)
+static struct seq_oss_synth *
+get_synthdev(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
if (dev < 0 || dev >= dp->max_synthdev)
return NULL;
if (! dp->synths[dev].opened)
@@ -374,7 +379,7 @@ get_synthdev(seq_oss_devinfo_t *dp, int dev)
* reset note and velocity on each channel.
*/
static void
-reset_channels(seq_oss_synthinfo_t *info)
+reset_channels(struct seq_oss_synthinfo *info)
{
int i;
if (info->ch == NULL || ! info->nr_voices)
@@ -392,12 +397,13 @@ reset_channels(seq_oss_synthinfo_t *info)
* event to the corresponding port.
*/
void
-snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
+snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_synth_t *rec;
- seq_oss_synthinfo_t *info;
+ struct seq_oss_synth *rec;
+ struct seq_oss_synthinfo *info;
- snd_assert(dev >= 0 && dev < dp->max_synthdev, return);
+ if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev))
+ return;
info = &dp->synths[dev];
if (! info->opened)
return;
@@ -428,7 +434,7 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
if (rec->oper.reset) {
rec->oper.reset(&info->arg);
} else {
- snd_seq_event_t ev;
+ struct snd_seq_event ev;
memset(&ev, 0, sizeof(ev));
snd_seq_oss_fill_addr(dp, &ev, info->arg.addr.client,
info->arg.addr.port);
@@ -444,10 +450,10 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
* call load_patch callback function
*/
int
-snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt,
+snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
const char __user *buf, int p, int c)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
int rc;
if (dev < 0 || dev >= dp->max_synthdev)
@@ -470,9 +476,9 @@ snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt,
* check if the device is valid synth device
*/
int
-snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev)
+snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
rec = get_synthdev(dp, dev);
if (rec) {
snd_use_lock_free(&rec->use_lock);
@@ -488,11 +494,11 @@ snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev)
* (0xff).
*/
int
-snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_seq_event_t *ev)
+snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev)
{
int i, send;
unsigned char *dest;
- seq_oss_synth_sysex_t *sysex;
+ struct seq_oss_synth_sysex *sysex;
if (! snd_seq_oss_synth_is_valid(dp, dev))
return -ENXIO;
@@ -545,7 +551,7 @@ snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_
* fill the event source/destination addresses
*/
int
-snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev)
+snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev)
{
if (! snd_seq_oss_synth_is_valid(dp, dev))
return -EINVAL;
@@ -559,9 +565,9 @@ snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev)
* OSS compatible ioctl
*/
int
-snd_seq_oss_synth_ioctl(seq_oss_devinfo_t *dp, int dev, unsigned int cmd, unsigned long addr)
+snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
int rc;
if (is_midi_dev(dp, dev))
@@ -581,7 +587,7 @@ snd_seq_oss_synth_ioctl(seq_oss_devinfo_t *dp, int dev, unsigned int cmd, unsign
* send OSS raw events - SEQ_PRIVATE and SEQ_VOLUME
*/
int
-snd_seq_oss_synth_raw_event(seq_oss_devinfo_t *dp, int dev, unsigned char *data, snd_seq_event_t *ev)
+snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev)
{
if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev))
return -ENXIO;
@@ -595,9 +601,12 @@ snd_seq_oss_synth_raw_event(seq_oss_devinfo_t *dp, int dev, unsigned char *data,
* create OSS compatible synth_info record
*/
int
-snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *inf)
+snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf)
{
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
+
+ if (dev < 0 || dev >= dp->max_synthdev)
+ return -ENXIO;
if (dp->synths[dev].is_midi) {
struct midi_info minf;
@@ -621,14 +630,15 @@ snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *i
}
+#ifdef CONFIG_PROC_FS
/*
* proc interface
*/
void
-snd_seq_oss_synth_info_read(snd_info_buffer_t *buf)
+snd_seq_oss_synth_info_read(struct snd_info_buffer *buf)
{
int i;
- seq_oss_synth_t *rec;
+ struct seq_oss_synth *rec;
snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs);
for (i = 0; i < max_synth_devs; i++) {
@@ -648,4 +658,4 @@ snd_seq_oss_synth_info_read(snd_info_buffer_t *buf)
snd_use_lock_free(&rec->use_lock);
}
}
-
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h
index 07bc0e2cfb8..dbdfcbb80ea 100644
--- a/sound/core/seq/oss/seq_oss_synth.h
+++ b/sound/core/seq/oss/seq_oss_synth.h
@@ -27,23 +27,25 @@
#include <sound/seq_oss_legacy.h>
#include <sound/seq_device.h>
-typedef struct seq_oss_synth_t seq_oss_synth_t;
-
void snd_seq_oss_synth_init(void);
-int snd_seq_oss_synth_register(snd_seq_device_t *dev);
-int snd_seq_oss_synth_unregister(snd_seq_device_t *dev);
-void snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp);
-void snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp);
-void snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp);
+int snd_seq_oss_synth_register(struct snd_seq_device *dev);
+int snd_seq_oss_synth_unregister(struct snd_seq_device *dev);
+void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp);
+void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp);
+void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp);
-void snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev);
-int snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt, const char __user *buf, int p, int c);
-int snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev);
-int snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_seq_event_t *ev);
-int snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev);
-int snd_seq_oss_synth_ioctl(seq_oss_devinfo_t *dp, int dev, unsigned int cmd, unsigned long addr);
-int snd_seq_oss_synth_raw_event(seq_oss_devinfo_t *dp, int dev, unsigned char *data, snd_seq_event_t *ev);
+void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev);
+int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
+ const char __user *buf, int p, int c);
+int snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev);
+int snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf,
+ struct snd_seq_event *ev);
+int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev);
+int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd,
+ unsigned long addr);
+int snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev,
+ unsigned char *data, struct snd_seq_event *ev);
-int snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *inf);
+int snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf);
#endif
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
index 64d594b3170..4f24ea9fad9 100644
--- a/sound/core/seq/oss/seq_oss_timer.c
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -23,6 +23,7 @@
#include "seq_oss_timer.h"
#include "seq_oss_event.h"
#include <sound/seq_oss_legacy.h>
+#include <linux/slab.h>
/*
*/
@@ -33,18 +34,18 @@
/*
*/
-static void calc_alsa_tempo(seq_oss_timer_t *timer);
-static int send_timer_event(seq_oss_devinfo_t *dp, int type, int value);
+static void calc_alsa_tempo(struct seq_oss_timer *timer);
+static int send_timer_event(struct seq_oss_devinfo *dp, int type, int value);
/*
* create and register a new timer.
* if queue is not started yet, start it.
*/
-seq_oss_timer_t *
-snd_seq_oss_timer_new(seq_oss_devinfo_t *dp)
+struct seq_oss_timer *
+snd_seq_oss_timer_new(struct seq_oss_devinfo *dp)
{
- seq_oss_timer_t *rec;
+ struct seq_oss_timer *rec;
rec = kzalloc(sizeof(*rec), GFP_KERNEL);
if (rec == NULL)
@@ -67,7 +68,7 @@ snd_seq_oss_timer_new(seq_oss_devinfo_t *dp)
* if no more timer exists, stop the queue.
*/
void
-snd_seq_oss_timer_delete(seq_oss_timer_t *rec)
+snd_seq_oss_timer_delete(struct seq_oss_timer *rec)
{
if (rec) {
snd_seq_oss_timer_stop(rec);
@@ -82,7 +83,7 @@ snd_seq_oss_timer_delete(seq_oss_timer_t *rec)
* 0 : not a timer event -- enqueue this event
*/
int
-snd_seq_oss_process_timer_event(seq_oss_timer_t *rec, evrec_t *ev)
+snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
{
abstime_t parm = ev->t.time;
@@ -125,7 +126,7 @@ snd_seq_oss_process_timer_event(seq_oss_timer_t *rec, evrec_t *ev)
* convert tempo units
*/
static void
-calc_alsa_tempo(seq_oss_timer_t *timer)
+calc_alsa_tempo(struct seq_oss_timer *timer)
{
timer->tempo = (60 * 1000000) / timer->oss_tempo;
timer->ppq = timer->oss_timebase;
@@ -136,9 +137,9 @@ calc_alsa_tempo(seq_oss_timer_t *timer)
* dispatch a timer event
*/
static int
-send_timer_event(seq_oss_devinfo_t *dp, int type, int value)
+send_timer_event(struct seq_oss_devinfo *dp, int type, int value)
{
- snd_seq_event_t ev;
+ struct snd_seq_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = type;
@@ -156,10 +157,10 @@ send_timer_event(seq_oss_devinfo_t *dp, int type, int value)
* set queue tempo and start queue
*/
int
-snd_seq_oss_timer_start(seq_oss_timer_t *timer)
+snd_seq_oss_timer_start(struct seq_oss_timer *timer)
{
- seq_oss_devinfo_t *dp = timer->dp;
- snd_seq_queue_tempo_t tmprec;
+ struct seq_oss_devinfo *dp = timer->dp;
+ struct snd_seq_queue_tempo tmprec;
if (timer->running)
snd_seq_oss_timer_stop(timer);
@@ -181,7 +182,7 @@ snd_seq_oss_timer_start(seq_oss_timer_t *timer)
* stop queue
*/
int
-snd_seq_oss_timer_stop(seq_oss_timer_t *timer)
+snd_seq_oss_timer_stop(struct seq_oss_timer *timer)
{
if (! timer->running)
return 0;
@@ -195,7 +196,7 @@ snd_seq_oss_timer_stop(seq_oss_timer_t *timer)
* continue queue
*/
int
-snd_seq_oss_timer_continue(seq_oss_timer_t *timer)
+snd_seq_oss_timer_continue(struct seq_oss_timer *timer)
{
if (timer->running)
return 0;
@@ -209,7 +210,7 @@ snd_seq_oss_timer_continue(seq_oss_timer_t *timer)
* change queue tempo
*/
int
-snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value)
+snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value)
{
if (value < MIN_OSS_TEMPO)
value = MIN_OSS_TEMPO;
@@ -227,12 +228,11 @@ snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value)
* ioctls
*/
int
-snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg)
+snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __user *arg)
{
int value;
if (cmd == SNDCTL_SEQ_CTRLRATE) {
- debug_printk(("ctrl rate\n"));
/* if *arg == 0, just return the current rate */
if (get_user(value, arg))
return -EFAULT;
@@ -247,21 +247,16 @@ snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *ar
switch (cmd) {
case SNDCTL_TMR_START:
- debug_printk(("timer start\n"));
return snd_seq_oss_timer_start(timer);
case SNDCTL_TMR_STOP:
- debug_printk(("timer stop\n"));
return snd_seq_oss_timer_stop(timer);
case SNDCTL_TMR_CONTINUE:
- debug_printk(("timer continue\n"));
return snd_seq_oss_timer_continue(timer);
case SNDCTL_TMR_TEMPO:
- debug_printk(("timer tempo\n"));
if (get_user(value, arg))
return -EFAULT;
return snd_seq_oss_timer_tempo(timer, value);
case SNDCTL_TMR_TIMEBASE:
- debug_printk(("timer timebase\n"));
if (get_user(value, arg))
return -EFAULT;
if (value < MIN_OSS_TIMEBASE)
@@ -275,7 +270,6 @@ snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *ar
case SNDCTL_TMR_METRONOME:
case SNDCTL_TMR_SELECT:
case SNDCTL_TMR_SOURCE:
- debug_printk(("timer XXX\n"));
/* not supported */
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_timer.h b/sound/core/seq/oss/seq_oss_timer.h
index 6e4dbd8504c..b995bd68ad1 100644
--- a/sound/core/seq/oss/seq_oss_timer.h
+++ b/sound/core/seq/oss/seq_oss_timer.h
@@ -27,8 +27,8 @@
/*
* timer information definition
*/
-struct seq_oss_timer_t {
- seq_oss_devinfo_t *dp;
+struct seq_oss_timer {
+ struct seq_oss_devinfo *dp;
reltime_t cur_tick;
int realtime;
int running;
@@ -37,22 +37,22 @@ struct seq_oss_timer_t {
};
-seq_oss_timer_t *snd_seq_oss_timer_new(seq_oss_devinfo_t *dp);
-void snd_seq_oss_timer_delete(seq_oss_timer_t *dp);
+struct seq_oss_timer *snd_seq_oss_timer_new(struct seq_oss_devinfo *dp);
+void snd_seq_oss_timer_delete(struct seq_oss_timer *dp);
-int snd_seq_oss_timer_start(seq_oss_timer_t *timer);
-int snd_seq_oss_timer_stop(seq_oss_timer_t *timer);
-int snd_seq_oss_timer_continue(seq_oss_timer_t *timer);
-int snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value);
+int snd_seq_oss_timer_start(struct seq_oss_timer *timer);
+int snd_seq_oss_timer_stop(struct seq_oss_timer *timer);
+int snd_seq_oss_timer_continue(struct seq_oss_timer *timer);
+int snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value);
#define snd_seq_oss_timer_reset snd_seq_oss_timer_start
-int snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg);
+int snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __user *arg);
/*
* get current processed time
*/
static inline abstime_t
-snd_seq_oss_timer_cur_tick(seq_oss_timer_t *timer)
+snd_seq_oss_timer_cur_tick(struct seq_oss_timer *timer)
{
return timer->cur_tick;
}
@@ -62,7 +62,7 @@ snd_seq_oss_timer_cur_tick(seq_oss_timer_t *timer)
* is realtime event?
*/
static inline int
-snd_seq_oss_timer_is_realtime(seq_oss_timer_t *timer)
+snd_seq_oss_timer_is_realtime(struct seq_oss_timer *timer)
{
return timer->realtime;
}
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
index b2037802454..d50338bbc21 100644
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -27,16 +27,17 @@
#include "../seq_lock.h"
#include "../seq_clientmgr.h"
#include <linux/wait.h>
+#include <linux/slab.h>
/*
* create a write queue record
*/
-seq_oss_writeq_t *
-snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen)
+struct seq_oss_writeq *
+snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
{
- seq_oss_writeq_t *q;
- snd_seq_client_pool_t pool;
+ struct seq_oss_writeq *q;
+ struct snd_seq_client_pool pool;
if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
return NULL;
@@ -61,10 +62,12 @@ snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen)
* delete the write queue
*/
void
-snd_seq_oss_writeq_delete(seq_oss_writeq_t *q)
+snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
{
- snd_seq_oss_writeq_clear(q); /* to be sure */
- kfree(q);
+ if (q) {
+ snd_seq_oss_writeq_clear(q); /* to be sure */
+ kfree(q);
+ }
}
@@ -72,9 +75,9 @@ snd_seq_oss_writeq_delete(seq_oss_writeq_t *q)
* reset the write queue
*/
void
-snd_seq_oss_writeq_clear(seq_oss_writeq_t *q)
+snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
{
- snd_seq_remove_events_t reset;
+ struct snd_seq_remove_events reset;
memset(&reset, 0, sizeof(reset));
reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
@@ -88,9 +91,9 @@ snd_seq_oss_writeq_clear(seq_oss_writeq_t *q)
* wait until the write buffer has enough room
*/
int
-snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
+snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
{
- seq_oss_devinfo_t *dp = q->dp;
+ struct seq_oss_devinfo *dp = q->dp;
abstime_t time;
time = snd_seq_oss_timer_cur_tick(dp->timer);
@@ -98,8 +101,8 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
return 0; /* already finished */
if (! q->sync_event_put) {
- snd_seq_event_t ev;
- evrec_t *rec;
+ struct snd_seq_event ev;
+ union evrec *rec;
/* put echoback event */
memset(&ev, 0, sizeof(ev));
@@ -108,7 +111,7 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
ev.time.tick = time;
/* echo back to itself */
snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
- rec = (evrec_t*)&ev.data;
+ rec = (union evrec *)&ev.data;
rec->t.code = SEQ_SYNCTIMER;
rec->t.time = time;
q->sync_event_put = 1;
@@ -128,7 +131,7 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
* wake up sync - echo event was catched
*/
void
-snd_seq_oss_writeq_wakeup(seq_oss_writeq_t *q, abstime_t time)
+snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
{
unsigned long flags;
@@ -146,9 +149,9 @@ snd_seq_oss_writeq_wakeup(seq_oss_writeq_t *q, abstime_t time)
* return the unused pool size
*/
int
-snd_seq_oss_writeq_get_free_size(seq_oss_writeq_t *q)
+snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
{
- snd_seq_client_pool_t pool;
+ struct snd_seq_client_pool pool;
pool.client = q->dp->cseq;
snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
return pool.output_free;
@@ -159,9 +162,9 @@ snd_seq_oss_writeq_get_free_size(seq_oss_writeq_t *q)
* set output threshold size from ioctl
*/
void
-snd_seq_oss_writeq_set_output(seq_oss_writeq_t *q, int val)
+snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
{
- snd_seq_client_pool_t pool;
+ struct snd_seq_client_pool pool;
pool.client = q->dp->cseq;
snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
pool.output_room = val;
diff --git a/sound/core/seq/oss/seq_oss_writeq.h b/sound/core/seq/oss/seq_oss_writeq.h
index 6a13c85e239..c469d296756 100644
--- a/sound/core/seq/oss/seq_oss_writeq.h
+++ b/sound/core/seq/oss/seq_oss_writeq.h
@@ -25,8 +25,8 @@
#include "seq_oss_device.h"
-struct seq_oss_writeq_t {
- seq_oss_devinfo_t *dp;
+struct seq_oss_writeq {
+ struct seq_oss_devinfo *dp;
int maxlen;
abstime_t sync_time;
int sync_event_put;
@@ -38,13 +38,13 @@ struct seq_oss_writeq_t {
/*
* seq_oss_writeq.c
*/
-seq_oss_writeq_t *snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen);
-void snd_seq_oss_writeq_delete(seq_oss_writeq_t *q);
-void snd_seq_oss_writeq_clear(seq_oss_writeq_t *q);
-int snd_seq_oss_writeq_sync(seq_oss_writeq_t *q);
-void snd_seq_oss_writeq_wakeup(seq_oss_writeq_t *q, abstime_t time);
-int snd_seq_oss_writeq_get_free_size(seq_oss_writeq_t *q);
-void snd_seq_oss_writeq_set_output(seq_oss_writeq_t *q, int size);
+struct seq_oss_writeq *snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen);
+void snd_seq_oss_writeq_delete(struct seq_oss_writeq *q);
+void snd_seq_oss_writeq_clear(struct seq_oss_writeq *q);
+int snd_seq_oss_writeq_sync(struct seq_oss_writeq *q);
+void snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time);
+int snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q);
+void snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int size);
#endif
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 24644150f24..71211056108 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -19,9 +19,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/device.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -33,18 +33,21 @@
#include "seq_timer.h"
#include "seq_system.h"
#include "seq_info.h"
+#include <sound/minors.h>
#include <sound/seq_device.h>
#if defined(CONFIG_SND_SEQ_DUMMY_MODULE)
-int seq_client_load[64] = {[0] = SNDRV_SEQ_CLIENT_DUMMY, [1 ... 63] = -1};
+int seq_client_load[15] = {[0] = SNDRV_SEQ_CLIENT_DUMMY, [1 ... 14] = -1};
#else
-int seq_client_load[64] = {[0 ... 63] = -1};
+int seq_client_load[15] = {[0 ... 14] = -1};
#endif
int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
int seq_default_timer_card = -1;
int seq_default_timer_device =
-#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT
+#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT
+ SNDRV_TIMER_GLOBAL_HRTIMER
+#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT)
SNDRV_TIMER_GLOBAL_RTC
#else
SNDRV_TIMER_GLOBAL_SYSTEM
@@ -53,7 +56,7 @@ int seq_default_timer_device =
int seq_default_timer_subdevice = 0;
int seq_default_timer_resolution = 0; /* Hz */
-MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer.");
MODULE_LICENSE("GPL");
@@ -72,6 +75,9 @@ MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice numbe
module_param(seq_default_timer_resolution, int, 0644);
MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz.");
+MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_SEQUENCER);
+MODULE_ALIAS("devname:snd/seq");
+
/*
* INIT PART
*/
@@ -129,25 +135,3 @@ static void __exit alsa_seq_exit(void)
module_init(alsa_seq_init)
module_exit(alsa_seq_exit)
-
- /* seq_clientmgr.c */
-EXPORT_SYMBOL(snd_seq_create_kernel_client);
-EXPORT_SYMBOL(snd_seq_delete_kernel_client);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
-EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
-EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
-EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
-EXPORT_SYMBOL(snd_seq_set_queue_tempo);
- /* seq_memory.c */
-EXPORT_SYMBOL(snd_seq_expand_var_event);
-EXPORT_SYMBOL(snd_seq_dump_var_event);
- /* seq_ports.c */
-EXPORT_SYMBOL(snd_seq_event_port_attach);
-EXPORT_SYMBOL(snd_seq_event_port_detach);
- /* seq_lock.c */
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-/*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/
-/*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/
-EXPORT_SYMBOL(snd_use_lock_sync_helper);
-#endif
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index a886db94b1f..225c73152ee 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1,7 +1,7 @@
/*
* ALSA sequencer Client Manager
* Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@suse.cz>
+ * Jaroslav Kysela <perex@perex.cz>
* Takashi Iwai <tiwai@suse.de>
*
*
@@ -21,9 +21,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/minors.h>
@@ -47,25 +46,44 @@
*
*/
+/*
+ * There are four ranges of client numbers (last two shared):
+ * 0..15: global clients
+ * 16..127: statically allocated client numbers for cards 0..27
+ * 128..191: dynamically allocated client numbers for cards 28..31
+ * 128..191: dynamically allocated client numbers for applications
+ */
+
+/* number of kernel non-card clients */
+#define SNDRV_SEQ_GLOBAL_CLIENTS 16
+/* clients per cards, for static clients */
+#define SNDRV_SEQ_CLIENTS_PER_CARD 4
+/* dynamically allocated client numbers (both kernel drivers and user space) */
+#define SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN 128
+
#define SNDRV_SEQ_LFLG_INPUT 0x0001
#define SNDRV_SEQ_LFLG_OUTPUT 0x0002
#define SNDRV_SEQ_LFLG_OPEN (SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
static DEFINE_SPINLOCK(clients_lock);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
/*
* client table
*/
static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
-static client_t *clienttab[SNDRV_SEQ_MAX_CLIENTS];
-static usage_t client_usage;
+static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS];
+static struct snd_seq_usage client_usage;
/*
* prototypes
*/
-static int bounce_error_event(client_t *client, snd_seq_event_t *event, int err, int atomic, int hop);
-static int snd_seq_deliver_single_event(client_t *client, snd_seq_event_t *event, int filter, int atomic, int hop);
+static int bounce_error_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int err, int atomic, int hop);
+static int snd_seq_deliver_single_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int filter, int atomic, int hop);
/*
*/
@@ -96,30 +114,30 @@ static inline unsigned short snd_seq_file_flags(struct file *file)
}
}
-static inline int snd_seq_write_pool_allocated(client_t *client)
+static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
{
return snd_seq_total_cells(client->pool) > 0;
}
/* return pointer to client structure for specified id */
-static client_t *clientptr(int clientid)
+static struct snd_seq_client *clientptr(int clientid)
{
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n", clientid);
+ pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
+ clientid);
return NULL;
}
return clienttab[clientid];
}
-extern int seq_client_load[];
-
-client_t *snd_seq_client_use_ptr(int clientid)
+struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
{
unsigned long flags;
- client_t *client;
+ struct snd_seq_client *client;
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n", clientid);
+ pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
+ clientid);
return NULL;
}
spin_lock_irqsave(&clients_lock, flags);
@@ -131,26 +149,28 @@ client_t *snd_seq_client_use_ptr(int clientid)
return NULL;
}
spin_unlock_irqrestore(&clients_lock, flags);
-#ifdef CONFIG_KMOD
- if (!in_interrupt() && current->fs->root) {
- static char client_requested[64];
+#ifdef CONFIG_MODULES
+ if (!in_interrupt()) {
+ static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
static char card_requested[SNDRV_CARDS];
- if (clientid < 64) {
+ if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
int idx;
- if (! client_requested[clientid] && current->fs->root) {
+ if (!client_requested[clientid]) {
client_requested[clientid] = 1;
- for (idx = 0; idx < 64; idx++) {
+ for (idx = 0; idx < 15; idx++) {
if (seq_client_load[idx] < 0)
break;
if (seq_client_load[idx] == clientid) {
- request_module("snd-seq-client-%i", clientid);
+ request_module("snd-seq-client-%i",
+ clientid);
break;
}
}
}
- } else if (clientid >= 64 && clientid < 128) {
- int card = (clientid - 64) / 8;
+ } else if (clientid < SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN) {
+ int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
+ SNDRV_SEQ_CLIENTS_PER_CARD;
if (card < snd_ecards_limit) {
if (! card_requested[card]) {
card_requested[card] = 1;
@@ -174,14 +194,14 @@ client_t *snd_seq_client_use_ptr(int clientid)
return client;
}
-static void usage_alloc(usage_t * res, int num)
+static void usage_alloc(struct snd_seq_usage *res, int num)
{
res->cur += num;
if (res->cur > res->peak)
res->peak = res->cur;
}
-static void usage_free(usage_t * res, int num)
+static void usage_free(struct snd_seq_usage *res, int num)
{
res->cur -= num;
}
@@ -196,11 +216,11 @@ int __init client_init_data(void)
}
-static client_t *seq_create_client1(int client_index, int poolsize)
+static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
{
unsigned long flags;
int c;
- client_t *client;
+ struct snd_seq_client *client;
/* init client data */
client = kzalloc(sizeof(*client), GFP_KERNEL);
@@ -214,13 +234,15 @@ static client_t *seq_create_client1(int client_index, int poolsize)
client->type = NO_CLIENT;
snd_use_lock_init(&client->use_lock);
rwlock_init(&client->ports_lock);
- init_MUTEX(&client->ports_mutex);
+ mutex_init(&client->ports_mutex);
INIT_LIST_HEAD(&client->ports_list_head);
/* find free slot in the client table */
spin_lock_irqsave(&clients_lock, flags);
if (client_index < 0) {
- for (c = 128; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
+ for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
+ c < SNDRV_SEQ_MAX_CLIENTS;
+ c++) {
if (clienttab[c] || clienttablock[c])
continue;
clienttab[client->number = c] = client;
@@ -241,11 +263,12 @@ static client_t *seq_create_client1(int client_index, int poolsize)
}
-static int seq_free_client1(client_t *client)
+static int seq_free_client1(struct snd_seq_client *client)
{
unsigned long flags;
- snd_assert(client != NULL, return -EINVAL);
+ if (!client)
+ return 0;
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
spin_lock_irqsave(&clients_lock, flags);
@@ -263,12 +286,13 @@ static int seq_free_client1(client_t *client)
}
-static void seq_free_client(client_t * client)
+static void seq_free_client(struct snd_seq_client * client)
{
- down(&register_mutex);
+ mutex_lock(&register_mutex);
switch (client->type) {
case NO_CLIENT:
- snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n", client->number);
+ pr_warn("ALSA: seq: Trying to free unused client %d\n",
+ client->number);
break;
case USER_CLIENT:
case KERNEL_CLIENT:
@@ -277,9 +301,10 @@ static void seq_free_client(client_t * client)
break;
default:
- snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n", client->number, client->type);
+ pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
+ client->number, client->type);
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
snd_seq_system_client_ev_client_exit(client->number);
}
@@ -292,14 +317,19 @@ static void seq_free_client(client_t * client)
static int snd_seq_open(struct inode *inode, struct file *file)
{
int c, mode; /* client id */
- client_t *client;
- user_client_t *user;
+ struct snd_seq_client *client;
+ struct snd_seq_user_client *user;
+ int err;
+
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
- if (down_interruptible(&register_mutex))
+ if (mutex_lock_interruptible(&register_mutex))
return -ERESTARTSYS;
client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
if (client == NULL) {
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -ENOMEM; /* failure code */
}
@@ -319,14 +349,14 @@ static int snd_seq_open(struct inode *inode, struct file *file)
if (user->fifo == NULL) {
seq_free_client1(client);
kfree(client);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -ENOMEM;
}
}
usage_alloc(&client_usage, 1);
client->type = USER_CLIENT;
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
c = client->number;
file->private_data = client;
@@ -344,7 +374,7 @@ static int snd_seq_open(struct inode *inode, struct file *file)
/* delete a user client */
static int snd_seq_release(struct inode *inode, struct file *file)
{
- client_t *client = (client_t *) file->private_data;
+ struct snd_seq_client *client = file->private_data;
if (client) {
seq_free_client(client);
@@ -364,13 +394,14 @@ static int snd_seq_release(struct inode *inode, struct file *file)
* -EINVAL no enough user-space buffer to write the whole event
* -EFAULT seg. fault during copy to user space
*/
-static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
+ loff_t *offset)
{
- client_t *client = (client_t *) file->private_data;
- fifo_t *fifo;
+ struct snd_seq_client *client = file->private_data;
+ struct snd_seq_fifo *fifo;
int err;
long result = 0;
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT))
return -ENXIO;
@@ -379,7 +410,8 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, l
return -EFAULT;
/* check client structures are in place */
- snd_assert(client != NULL, return -ENXIO);
+ if (snd_BUG_ON(!client))
+ return -ENXIO;
if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
return -ENXIO;
@@ -396,7 +428,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, l
snd_seq_fifo_lock(fifo);
/* while data available in queue */
- while (count >= sizeof(snd_seq_event_t)) {
+ while (count >= sizeof(struct snd_seq_event)) {
int nonblock;
nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
@@ -404,34 +436,34 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, l
break;
}
if (snd_seq_ev_is_variable(&cell->event)) {
- snd_seq_event_t tmpev;
+ struct snd_seq_event tmpev;
tmpev = cell->event;
tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
- if (copy_to_user(buf, &tmpev, sizeof(snd_seq_event_t))) {
+ if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) {
err = -EFAULT;
break;
}
- count -= sizeof(snd_seq_event_t);
- buf += sizeof(snd_seq_event_t);
+ count -= sizeof(struct snd_seq_event);
+ buf += sizeof(struct snd_seq_event);
err = snd_seq_expand_var_event(&cell->event, count,
(char __force *)buf, 0,
- sizeof(snd_seq_event_t));
+ sizeof(struct snd_seq_event));
if (err < 0)
break;
result += err;
count -= err;
buf += err;
} else {
- if (copy_to_user(buf, &cell->event, sizeof(snd_seq_event_t))) {
+ if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) {
err = -EFAULT;
break;
}
- count -= sizeof(snd_seq_event_t);
- buf += sizeof(snd_seq_event_t);
+ count -= sizeof(struct snd_seq_event);
+ buf += sizeof(struct snd_seq_event);
}
snd_seq_cell_free(cell);
cell = NULL; /* to be sure */
- result += sizeof(snd_seq_event_t);
+ result += sizeof(struct snd_seq_event);
}
if (err < 0) {
@@ -449,7 +481,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, l
/*
* check access permission to the port
*/
-static int check_port_perm(client_port_t *port, unsigned int flags)
+static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags)
{
if ((port->capability & flags) != flags)
return 0;
@@ -460,9 +492,10 @@ static int check_port_perm(client_port_t *port, unsigned int flags)
* check if the destination client is available, and return the pointer
* if filter is non-zero, client filter bitmap is tested.
*/
-static client_t *get_event_dest_client(snd_seq_event_t *event, int filter)
+static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event,
+ int filter)
{
- client_t *dest;
+ struct snd_seq_client *dest;
dest = snd_seq_client_use_ptr(event->dest.client);
if (dest == NULL)
@@ -493,10 +526,11 @@ __not_avail:
* quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra
* kmalloc.
*/
-static int bounce_error_event(client_t *client, snd_seq_event_t *event,
+static int bounce_error_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
int err, int atomic, int hop)
{
- snd_seq_event_t bounce_ev;
+ struct snd_seq_event bounce_ev;
int result;
if (client == NULL ||
@@ -531,9 +565,10 @@ static int bounce_error_event(client_t *client, snd_seq_event_t *event,
* of the given queue.
* return non-zero if updated.
*/
-static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real_time)
+static int update_timestamp_of_queue(struct snd_seq_event *event,
+ int queue, int real_time)
{
- queue_t *q;
+ struct snd_seq_queue *q;
q = queueptr(queue);
if (! q)
@@ -559,12 +594,12 @@ static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real
* RETURN VALUE: 0 : if succeeded
* <0 : error
*/
-static int snd_seq_deliver_single_event(client_t *client,
- snd_seq_event_t *event,
+static int snd_seq_deliver_single_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
int filter, int atomic, int hop)
{
- client_t *dest = NULL;
- client_port_t *dest_port = NULL;
+ struct snd_seq_client *dest = NULL;
+ struct snd_seq_client_port *dest_port = NULL;
int result = -ENOENT;
int direct;
@@ -596,7 +631,9 @@ static int snd_seq_deliver_single_event(client_t *client,
case KERNEL_CLIENT:
if (dest_port->event_input == NULL)
break;
- result = dest_port->event_input(event, direct, dest_port->private_data, atomic, hop);
+ result = dest_port->event_input(event, direct,
+ dest_port->private_data,
+ atomic, hop);
break;
default:
break;
@@ -618,16 +655,15 @@ static int snd_seq_deliver_single_event(client_t *client,
/*
* send the event to all subscribers:
*/
-static int deliver_to_subscribers(client_t *client,
- snd_seq_event_t *event,
+static int deliver_to_subscribers(struct snd_seq_client *client,
+ struct snd_seq_event *event,
int atomic, int hop)
{
- subscribers_t *subs;
- int err = 0, num_ev = 0;
- snd_seq_event_t event_saved;
- client_port_t *src_port;
- struct list_head *p;
- port_subs_info_t *grp;
+ struct snd_seq_subscribers *subs;
+ int err, result = 0, num_ev = 0;
+ struct snd_seq_event event_saved;
+ struct snd_seq_client_port *src_port;
+ struct snd_seq_port_subs_info *grp;
src_port = snd_seq_port_use_ptr(client, event->source.port);
if (src_port == NULL)
@@ -641,8 +677,7 @@ static int deliver_to_subscribers(client_t *client,
read_lock(&grp->list_lock);
else
down_read(&grp->list_mutex);
- list_for_each(p, &grp->list_head) {
- subs = list_entry(p, subscribers_t, src_list);
+ list_for_each_entry(subs, &grp->list_head, src_list) {
event->dest = subs->info.dest;
if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
/* convert time according to flag with subscription */
@@ -650,8 +685,12 @@ static int deliver_to_subscribers(client_t *client,
subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
err = snd_seq_deliver_single_event(client, event,
0, atomic, hop);
- if (err < 0)
- break;
+ if (err < 0) {
+ /* save first error that occurs and continue */
+ if (!result)
+ result = err;
+ continue;
+ }
num_ev++;
/* restore original event record */
*event = event_saved;
@@ -662,7 +701,7 @@ static int deliver_to_subscribers(client_t *client,
up_read(&grp->list_mutex);
*event = event_saved; /* restore */
snd_seq_port_unlock(src_port);
- return (err < 0) ? err : num_ev;
+ return (result < 0) ? result : num_ev;
}
@@ -670,46 +709,49 @@ static int deliver_to_subscribers(client_t *client,
/*
* broadcast to all ports:
*/
-static int port_broadcast_event(client_t *client,
- snd_seq_event_t *event,
+static int port_broadcast_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
int atomic, int hop)
{
- int num_ev = 0, err = 0;
- client_t *dest_client;
- struct list_head *p;
+ int num_ev = 0, err, result = 0;
+ struct snd_seq_client *dest_client;
+ struct snd_seq_client_port *port;
dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
if (dest_client == NULL)
return 0; /* no matching destination */
read_lock(&dest_client->ports_lock);
- list_for_each(p, &dest_client->ports_list_head) {
- client_port_t *port = list_entry(p, client_port_t, list);
+ list_for_each_entry(port, &dest_client->ports_list_head, list) {
event->dest.port = port->addr.port;
/* pass NULL as source client to avoid error bounce */
err = snd_seq_deliver_single_event(NULL, event,
SNDRV_SEQ_FILTER_BROADCAST,
atomic, hop);
- if (err < 0)
- break;
+ if (err < 0) {
+ /* save first error that occurs and continue */
+ if (!result)
+ result = err;
+ continue;
+ }
num_ev++;
}
read_unlock(&dest_client->ports_lock);
snd_seq_client_unlock(dest_client);
event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
- return (err < 0) ? err : num_ev;
+ return (result < 0) ? result : num_ev;
}
/*
* send the event to all clients:
* if destination port is also ADDRESS_BROADCAST, deliver to all ports.
*/
-static int broadcast_event(client_t *client,
- snd_seq_event_t *event, int atomic, int hop)
+static int broadcast_event(struct snd_seq_client *client,
+ struct snd_seq_event *event, int atomic, int hop)
{
- int err = 0, num_ev = 0;
+ int err, result = 0, num_ev = 0;
int dest;
- snd_seq_addr_t addr;
+ struct snd_seq_addr addr;
addr = event->dest; /* save */
@@ -726,20 +768,24 @@ static int broadcast_event(client_t *client,
err = snd_seq_deliver_single_event(NULL, event,
SNDRV_SEQ_FILTER_BROADCAST,
atomic, hop);
- if (err < 0)
- break;
+ if (err < 0) {
+ /* save first error that occurs and continue */
+ if (!result)
+ result = err;
+ continue;
+ }
num_ev += err;
}
event->dest = addr; /* restore */
- return (err < 0) ? err : num_ev;
+ return (result < 0) ? result : num_ev;
}
/* multicast - not supported yet */
-static int multicast_event(client_t *client, snd_seq_event_t *event,
+static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
int atomic, int hop)
{
- snd_printd("seq: multicast not supported yet.\n");
+ pr_debug("ALSA: seq: multicast not supported yet.\n");
return 0; /* ignored */
}
#endif /* SUPPORT_BROADCAST */
@@ -753,14 +799,14 @@ static int multicast_event(client_t *client, snd_seq_event_t *event,
* n == 0 : the event was not passed to any client.
* n < 0 : error - event was not processed.
*/
-static int snd_seq_deliver_event(client_t *client, snd_seq_event_t *event,
+static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_event *event,
int atomic, int hop)
{
int result;
hop++;
if (hop >= SNDRV_SEQ_MAX_HOPS) {
- snd_printd("too long delivery path (%d:%d->%d:%d)\n",
+ pr_debug("ALSA: seq: too long delivery path (%d:%d->%d:%d)\n",
event->source.client, event->source.port,
event->dest.client, event->dest.port);
return -EMLINK;
@@ -794,12 +840,13 @@ static int snd_seq_deliver_event(client_t *client, snd_seq_event_t *event,
* n == 0 : the event was not passed to any client.
* n < 0 : error - event was not processed.
*/
-int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop)
+int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
{
- client_t *client;
+ struct snd_seq_client *client;
int result;
- snd_assert(cell != NULL, return -EINVAL);
+ if (snd_BUG_ON(!cell))
+ return -EINVAL;
client = snd_seq_client_use_ptr(cell->event.source.client);
if (client == NULL) {
@@ -812,7 +859,7 @@ int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop)
* the event cell is re-used as a NOTE-OFF event and
* enqueued again.
*/
- snd_seq_event_t tmpev, *ev;
+ struct snd_seq_event tmpev, *ev;
/* reserve this event to enqueue note-off later */
tmpev = cell->event;
@@ -865,12 +912,12 @@ int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop)
* if pool is empty and blocking is TRUE, sleep until a new cell is
* available.
*/
-static int snd_seq_client_enqueue_event(client_t *client,
- snd_seq_event_t *event,
+static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
struct file *file, int blocking,
int atomic, int hop)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
int err;
/* special queue values - force direct passing */
@@ -886,7 +933,7 @@ static int snd_seq_client_enqueue_event(client_t *client,
#endif
if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
/* check presence of source port */
- client_port_t *src_port = snd_seq_port_use_ptr(client, event->source.port);
+ struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port);
if (src_port == NULL)
return -EINVAL;
snd_seq_port_unlock(src_port);
@@ -924,7 +971,7 @@ static int snd_seq_client_enqueue_event(client_t *client,
* check validity of event type and data length.
* return non-zero if invalid.
*/
-static int check_event_type_and_length(snd_seq_event_t *ev)
+static int check_event_type_and_length(struct snd_seq_event *ev)
{
switch (snd_seq_ev_length_type(ev)) {
case SNDRV_SEQ_EVENT_LENGTH_FIXED:
@@ -937,8 +984,7 @@ static int check_event_type_and_length(snd_seq_event_t *ev)
return -EINVAL;
break;
case SNDRV_SEQ_EVENT_LENGTH_VARUSR:
- if (! snd_seq_ev_is_instr_type(ev) ||
- ! snd_seq_ev_is_direct(ev))
+ if (! snd_seq_ev_is_direct(ev))
return -EINVAL;
break;
}
@@ -957,18 +1003,20 @@ static int check_event_type_and_length(snd_seq_event_t *ev)
* -EMLINK too many hops
* others depends on return value from driver callback
*/
-static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
+static ssize_t snd_seq_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
{
- client_t *client = (client_t *) file->private_data;
+ struct snd_seq_client *client = file->private_data;
int written = 0, len;
int err = -EINVAL;
- snd_seq_event_t event;
+ struct snd_seq_event event;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
return -ENXIO;
/* check client structures are in place */
- snd_assert(client != NULL, return -ENXIO);
+ if (snd_BUG_ON(!client))
+ return -ENXIO;
if (!client->accept_output || client->pool == NULL)
return -ENXIO;
@@ -980,7 +1028,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t c
}
/* only process whole events */
- while (count >= sizeof(snd_seq_event_t)) {
+ while (count >= sizeof(struct snd_seq_event)) {
/* Read in the event header from the user */
len = sizeof(event);
if (copy_from_user(&event, buf, len)) {
@@ -1012,12 +1060,12 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t c
/* set user space pointer */
event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
event.data.ext.ptr = (char __force *)buf
- + sizeof(snd_seq_event_t);
+ + sizeof(struct snd_seq_event);
len += extlen; /* increment data length */
} else {
#ifdef CONFIG_COMPAT
if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
- void *ptr = compat_ptr(event.data.raw32.d[1]);
+ void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]);
event.data.ext.ptr = ptr;
}
#endif
@@ -1046,11 +1094,12 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t c
*/
static unsigned int snd_seq_poll(struct file *file, poll_table * wait)
{
- client_t *client = (client_t *) file->private_data;
+ struct snd_seq_client *client = file->private_data;
unsigned int mask = 0;
/* check client structures are in place */
- snd_assert(client != NULL, return -ENXIO);
+ if (snd_BUG_ON(!client))
+ return -ENXIO;
if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
client->data.user.fifo) {
@@ -1076,9 +1125,9 @@ static unsigned int snd_seq_poll(struct file *file, poll_table * wait)
/* SYSTEM_INFO ioctl() */
-static int snd_seq_ioctl_system_info(client_t *client, void __user *arg)
+static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user *arg)
{
- snd_seq_system_info_t info;
+ struct snd_seq_system_info info;
memset(&info, 0, sizeof(info));
/* fill the info fields */
@@ -1096,10 +1145,10 @@ static int snd_seq_ioctl_system_info(client_t *client, void __user *arg)
/* RUNNING_MODE ioctl() */
-static int snd_seq_ioctl_running_mode(client_t *client, void __user *arg)
+static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void __user *arg)
{
- struct sndrv_seq_running_info info;
- client_t *cptr;
+ struct snd_seq_running_info info;
+ struct snd_seq_client *cptr;
int err = 0;
if (copy_from_user(&info, arg, sizeof(info)))
@@ -1133,7 +1182,8 @@ static int snd_seq_ioctl_running_mode(client_t *client, void __user *arg)
}
/* CLIENT_INFO ioctl() */
-static void get_client_info(client_t *cptr, snd_seq_client_info_t *info)
+static void get_client_info(struct snd_seq_client *cptr,
+ struct snd_seq_client_info *info)
{
info->client = cptr->number;
@@ -1147,10 +1197,11 @@ static void get_client_info(client_t *cptr, snd_seq_client_info_t *info)
memset(info->reserved, 0, sizeof(info->reserved));
}
-static int snd_seq_ioctl_get_client_info(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
+ void __user *arg)
{
- client_t *cptr;
- snd_seq_client_info_t client_info;
+ struct snd_seq_client *cptr;
+ struct snd_seq_client_info client_info;
if (copy_from_user(&client_info, arg, sizeof(client_info)))
return -EFAULT;
@@ -1170,9 +1221,10 @@ static int snd_seq_ioctl_get_client_info(client_t * client, void __user *arg)
/* CLIENT_INFO ioctl() */
-static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg)
+static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_client_info_t client_info;
+ struct snd_seq_client_info client_info;
if (copy_from_user(&client_info, arg, sizeof(client_info)))
return -EFAULT;
@@ -1199,11 +1251,12 @@ static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg)
/*
* CREATE PORT ioctl()
*/
-static int snd_seq_ioctl_create_port(client_t * client, void __user *arg)
+static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
+ void __user *arg)
{
- client_port_t *port;
- snd_seq_port_info_t info;
- snd_seq_port_callback_t *callback;
+ struct snd_seq_client_port *port;
+ struct snd_seq_port_info info;
+ struct snd_seq_port_callback *callback;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1249,9 +1302,10 @@ static int snd_seq_ioctl_create_port(client_t * client, void __user *arg)
/*
* DELETE PORT ioctl()
*/
-static int snd_seq_ioctl_delete_port(client_t * client, void __user *arg)
+static int snd_seq_ioctl_delete_port(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_port_info_t info;
+ struct snd_seq_port_info info;
int err;
/* set passed parameters */
@@ -1272,11 +1326,12 @@ static int snd_seq_ioctl_delete_port(client_t * client, void __user *arg)
/*
* GET_PORT_INFO ioctl() (on any client)
*/
-static int snd_seq_ioctl_get_port_info(client_t *client, void __user *arg)
+static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client,
+ void __user *arg)
{
- client_t *cptr;
- client_port_t *port;
- snd_seq_port_info_t info;
+ struct snd_seq_client *cptr;
+ struct snd_seq_client_port *port;
+ struct snd_seq_port_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1304,10 +1359,11 @@ static int snd_seq_ioctl_get_port_info(client_t *client, void __user *arg)
/*
* SET_PORT_INFO ioctl() (only ports on this/own client)
*/
-static int snd_seq_ioctl_set_port_info(client_t * client, void __user *arg)
+static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client,
+ void __user *arg)
{
- client_port_t *port;
- snd_seq_port_info_t info;
+ struct snd_seq_client_port *port;
+ struct snd_seq_port_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1329,9 +1385,10 @@ static int snd_seq_ioctl_set_port_info(client_t * client, void __user *arg)
#define PERM_RD (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
#define PERM_WR (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
-static int check_subscription_permission(client_t *client, client_port_t *sport,
- client_port_t *dport,
- snd_seq_port_subscribe_t *subs)
+static int check_subscription_permission(struct snd_seq_client *client,
+ struct snd_seq_client_port *sport,
+ struct snd_seq_client_port *dport,
+ struct snd_seq_port_subscribe *subs)
{
if (client->number != subs->sender.client &&
client->number != subs->dest.client) {
@@ -1363,9 +1420,10 @@ static int check_subscription_permission(client_t *client, client_port_t *sport,
* client must be user client.
*/
int snd_seq_client_notify_subscription(int client, int port,
- snd_seq_port_subscribe_t *info, int evtype)
+ struct snd_seq_port_subscribe *info,
+ int evtype)
{
- snd_seq_event_t event;
+ struct snd_seq_event event;
memset(&event, 0, sizeof(event));
event.type = evtype;
@@ -1379,12 +1437,13 @@ int snd_seq_client_notify_subscription(int client, int port,
/*
* add to port's subscription list IOCTL interface
*/
-static int snd_seq_ioctl_subscribe_port(client_t * client, void __user *arg)
+static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
+ void __user *arg)
{
int result = -EINVAL;
- client_t *receiver = NULL, *sender = NULL;
- client_port_t *sport = NULL, *dport = NULL;
- snd_seq_port_subscribe_t subs;
+ struct snd_seq_client *receiver = NULL, *sender = NULL;
+ struct snd_seq_client_port *sport = NULL, *dport = NULL;
+ struct snd_seq_port_subscribe subs;
if (copy_from_user(&subs, arg, sizeof(subs)))
return -EFAULT;
@@ -1423,12 +1482,13 @@ static int snd_seq_ioctl_subscribe_port(client_t * client, void __user *arg)
/*
* remove from port's subscription list
*/
-static int snd_seq_ioctl_unsubscribe_port(client_t * client, void __user *arg)
+static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
+ void __user *arg)
{
int result = -ENXIO;
- client_t *receiver = NULL, *sender = NULL;
- client_port_t *sport = NULL, *dport = NULL;
- snd_seq_port_subscribe_t subs;
+ struct snd_seq_client *receiver = NULL, *sender = NULL;
+ struct snd_seq_client_port *sport = NULL, *dport = NULL;
+ struct snd_seq_port_subscribe subs;
if (copy_from_user(&subs, arg, sizeof(subs)))
return -EFAULT;
@@ -1464,11 +1524,12 @@ static int snd_seq_ioctl_unsubscribe_port(client_t * client, void __user *arg)
/* CREATE_QUEUE ioctl() */
-static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg)
+static int snd_seq_ioctl_create_queue(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_info_t info;
+ struct snd_seq_queue_info info;
int result;
- queue_t *q;
+ struct snd_seq_queue *q;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1498,9 +1559,10 @@ static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg)
}
/* DELETE_QUEUE ioctl() */
-static int snd_seq_ioctl_delete_queue(client_t *client, void __user *arg)
+static int snd_seq_ioctl_delete_queue(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_info_t info;
+ struct snd_seq_queue_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1509,10 +1571,11 @@ static int snd_seq_ioctl_delete_queue(client_t *client, void __user *arg)
}
/* GET_QUEUE_INFO ioctl() */
-static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg)
+static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_info_t info;
- queue_t *q;
+ struct snd_seq_queue_info info;
+ struct snd_seq_queue *q;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1535,10 +1598,11 @@ static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg)
}
/* SET_QUEUE_INFO ioctl() */
-static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg)
+static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_info_t info;
- queue_t *q;
+ struct snd_seq_queue_info info;
+ struct snd_seq_queue *q;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1570,10 +1634,10 @@ static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg)
}
/* GET_NAMED_QUEUE ioctl() */
-static int snd_seq_ioctl_get_named_queue(client_t *client, void __user *arg)
+static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, void __user *arg)
{
- snd_seq_queue_info_t info;
- queue_t *q;
+ struct snd_seq_queue_info info;
+ struct snd_seq_queue *q;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1593,11 +1657,12 @@ static int snd_seq_ioctl_get_named_queue(client_t *client, void __user *arg)
}
/* GET_QUEUE_STATUS ioctl() */
-static int snd_seq_ioctl_get_queue_status(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_status_t status;
- queue_t *queue;
- seq_timer_t *tmr;
+ struct snd_seq_queue_status status;
+ struct snd_seq_queue *queue;
+ struct snd_seq_timer *tmr;
if (copy_from_user(&status, arg, sizeof(status)))
return -EFAULT;
@@ -1626,11 +1691,12 @@ static int snd_seq_ioctl_get_queue_status(client_t * client, void __user *arg)
/* GET_QUEUE_TEMPO ioctl() */
-static int snd_seq_ioctl_get_queue_tempo(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_tempo_t tempo;
- queue_t *queue;
- seq_timer_t *tmr;
+ struct snd_seq_queue_tempo tempo;
+ struct snd_seq_queue *queue;
+ struct snd_seq_timer *tmr;
if (copy_from_user(&tempo, arg, sizeof(tempo)))
return -EFAULT;
@@ -1656,17 +1722,20 @@ static int snd_seq_ioctl_get_queue_tempo(client_t * client, void __user *arg)
/* SET_QUEUE_TEMPO ioctl() */
-int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo)
+int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)
{
if (!snd_seq_queue_check_access(tempo->queue, client))
return -EPERM;
return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
}
-static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
+EXPORT_SYMBOL(snd_seq_set_queue_tempo);
+
+static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
+ void __user *arg)
{
int result;
- snd_seq_queue_tempo_t tempo;
+ struct snd_seq_queue_tempo tempo;
if (copy_from_user(&tempo, arg, sizeof(tempo)))
return -EFAULT;
@@ -1677,11 +1746,12 @@ static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
/* GET_QUEUE_TIMER ioctl() */
-static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_timer_t timer;
- queue_t *queue;
- seq_timer_t *tmr;
+ struct snd_seq_queue_timer timer;
+ struct snd_seq_queue *queue;
+ struct snd_seq_timer *tmr;
if (copy_from_user(&timer, arg, sizeof(timer)))
return -EFAULT;
@@ -1690,7 +1760,7 @@ static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
if (queue == NULL)
return -EINVAL;
- if (down_interruptible(&queue->timer_mutex)) {
+ if (mutex_lock_interruptible(&queue->timer_mutex)) {
queuefree(queue);
return -ERESTARTSYS;
}
@@ -1703,7 +1773,7 @@ static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
timer.u.alsa.id = tmr->alsa_id;
timer.u.alsa.resolution = tmr->preferred_resolution;
}
- up(&queue->timer_mutex);
+ mutex_unlock(&queue->timer_mutex);
queuefree(queue);
if (copy_to_user(arg, &timer, sizeof(timer)))
@@ -1713,10 +1783,11 @@ static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
/* SET_QUEUE_TIMER ioctl() */
-static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
+static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
+ void __user *arg)
{
int result = 0;
- snd_seq_queue_timer_t timer;
+ struct snd_seq_queue_timer timer;
if (copy_from_user(&timer, arg, sizeof(timer)))
return -EFAULT;
@@ -1725,13 +1796,13 @@ static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
return -EINVAL;
if (snd_seq_queue_check_access(timer.queue, client->number)) {
- queue_t *q;
- seq_timer_t *tmr;
+ struct snd_seq_queue *q;
+ struct snd_seq_timer *tmr;
q = queueptr(timer.queue);
if (q == NULL)
return -ENXIO;
- if (down_interruptible(&q->timer_mutex)) {
+ if (mutex_lock_interruptible(&q->timer_mutex)) {
queuefree(q);
return -ERESTARTSYS;
}
@@ -1743,7 +1814,7 @@ static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
tmr->preferred_resolution = timer.u.alsa.resolution;
}
result = snd_seq_queue_timer_open(timer.queue);
- up(&q->timer_mutex);
+ mutex_unlock(&q->timer_mutex);
queuefree(q);
} else {
return -EPERM;
@@ -1754,9 +1825,10 @@ static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
/* GET_QUEUE_CLIENT ioctl() */
-static int snd_seq_ioctl_get_queue_client(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_queue_client(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_queue_client_t info;
+ struct snd_seq_queue_client info;
int used;
if (copy_from_user(&info, arg, sizeof(info)))
@@ -1775,10 +1847,11 @@ static int snd_seq_ioctl_get_queue_client(client_t * client, void __user *arg)
/* SET_QUEUE_CLIENT ioctl() */
-static int snd_seq_ioctl_set_queue_client(client_t * client, void __user *arg)
+static int snd_seq_ioctl_set_queue_client(struct snd_seq_client *client,
+ void __user *arg)
{
int err;
- snd_seq_queue_client_t info;
+ struct snd_seq_queue_client info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1794,10 +1867,11 @@ static int snd_seq_ioctl_set_queue_client(client_t * client, void __user *arg)
/* GET_CLIENT_POOL ioctl() */
-static int snd_seq_ioctl_get_client_pool(client_t * client, void __user *arg)
+static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_client_pool_t info;
- client_t *cptr;
+ struct snd_seq_client_pool info;
+ struct snd_seq_client *cptr;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1809,8 +1883,7 @@ static int snd_seq_ioctl_get_client_pool(client_t * client, void __user *arg)
info.output_pool = cptr->pool->size;
info.output_room = cptr->pool->room;
info.output_free = info.output_pool;
- if (cptr->pool)
- info.output_free = snd_seq_unused_cells(cptr->pool);
+ info.output_free = snd_seq_unused_cells(cptr->pool);
if (cptr->type == USER_CLIENT) {
info.input_pool = cptr->data.user.fifo_pool_size;
info.input_free = info.input_pool;
@@ -1828,9 +1901,10 @@ static int snd_seq_ioctl_get_client_pool(client_t * client, void __user *arg)
}
/* SET_CLIENT_POOL ioctl() */
-static int snd_seq_ioctl_set_client_pool(client_t * client, void __user *arg)
+static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_client_pool_t info;
+ struct snd_seq_client_pool info;
int rc;
if (copy_from_user(&info, arg, sizeof(info)))
@@ -1872,9 +1946,10 @@ static int snd_seq_ioctl_set_client_pool(client_t * client, void __user *arg)
/* REMOVE_EVENTS ioctl() */
-static int snd_seq_ioctl_remove_events(client_t * client, void __user *arg)
+static int snd_seq_ioctl_remove_events(struct snd_seq_client *client,
+ void __user *arg)
{
- snd_seq_remove_events_t info;
+ struct snd_seq_remove_events info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -1901,13 +1976,14 @@ static int snd_seq_ioctl_remove_events(client_t * client, void __user *arg)
/*
* get subscription info
*/
-static int snd_seq_ioctl_get_subscription(client_t *client, void __user *arg)
+static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
+ void __user *arg)
{
int result;
- client_t *sender = NULL;
- client_port_t *sport = NULL;
- snd_seq_port_subscribe_t subs;
- subscribers_t *p;
+ struct snd_seq_client *sender = NULL;
+ struct snd_seq_client_port *sport = NULL;
+ struct snd_seq_port_subscribe subs;
+ struct snd_seq_subscribers *p;
if (copy_from_user(&subs, arg, sizeof(subs)))
return -EFAULT;
@@ -1940,13 +2016,14 @@ static int snd_seq_ioctl_get_subscription(client_t *client, void __user *arg)
/*
* get subscription info - check only its presence
*/
-static int snd_seq_ioctl_query_subs(client_t *client, void __user *arg)
+static int snd_seq_ioctl_query_subs(struct snd_seq_client *client,
+ void __user *arg)
{
int result = -ENXIO;
- client_t *cptr = NULL;
- client_port_t *port = NULL;
- snd_seq_query_subs_t subs;
- port_subs_info_t *group;
+ struct snd_seq_client *cptr = NULL;
+ struct snd_seq_client_port *port = NULL;
+ struct snd_seq_query_subs subs;
+ struct snd_seq_port_subs_info *group;
struct list_head *p;
int i;
@@ -1977,12 +2054,12 @@ static int snd_seq_ioctl_query_subs(client_t *client, void __user *arg)
list_for_each(p, &group->list_head) {
if (i++ == subs.index) {
/* found! */
- subscribers_t *s;
+ struct snd_seq_subscribers *s;
if (subs.type == SNDRV_SEQ_QUERY_SUBS_READ) {
- s = list_entry(p, subscribers_t, src_list);
+ s = list_entry(p, struct snd_seq_subscribers, src_list);
subs.addr = s->info.dest;
} else {
- s = list_entry(p, subscribers_t, dest_list);
+ s = list_entry(p, struct snd_seq_subscribers, dest_list);
subs.addr = s->info.sender;
}
subs.flags = s->info.flags;
@@ -2009,10 +2086,11 @@ static int snd_seq_ioctl_query_subs(client_t *client, void __user *arg)
/*
* query next client
*/
-static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg)
+static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
+ void __user *arg)
{
- client_t *cptr = NULL;
- snd_seq_client_info_t info;
+ struct snd_seq_client *cptr = NULL;
+ struct snd_seq_client_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -2040,11 +2118,12 @@ static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg)
/*
* query next port
*/
-static int snd_seq_ioctl_query_next_port(client_t *client, void __user *arg)
+static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
+ void __user *arg)
{
- client_t *cptr;
- client_port_t *port = NULL;
- snd_seq_port_info_t info;
+ struct snd_seq_client *cptr;
+ struct snd_seq_client_port *port = NULL;
+ struct snd_seq_port_info info;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -2075,7 +2154,7 @@ static int snd_seq_ioctl_query_next_port(client_t *client, void __user *arg)
static struct seq_ioctl_table {
unsigned int cmd;
- int (*func)(client_t *client, void __user * arg);
+ int (*func)(struct snd_seq_client *client, void __user * arg);
} ioctl_tables[] = {
{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
@@ -2109,7 +2188,8 @@ static struct seq_ioctl_table {
{ 0, NULL },
};
-static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg)
+static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
+ void __user *arg)
{
struct seq_ioctl_table *p;
@@ -2128,7 +2208,7 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg
if (p->cmd == cmd)
return p->func(client, arg);
}
- snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
+ pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
return -ENOTTY;
}
@@ -2136,9 +2216,10 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg
static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- client_t *client = (client_t *) file->private_data;
+ struct snd_seq_client *client = file->private_data;
- snd_assert(client != NULL, return -ENXIO);
+ if (snd_BUG_ON(!client))
+ return -ENXIO;
return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
}
@@ -2153,41 +2234,47 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg
/* exported to kernel modules */
-int snd_seq_create_kernel_client(snd_card_t *card, int client_index, snd_seq_client_callback_t * callback)
+int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
+ const char *name_fmt, ...)
{
- client_t *client;
+ struct snd_seq_client *client;
+ va_list args;
- snd_assert(! in_interrupt(), return -EBUSY);
+ if (snd_BUG_ON(in_interrupt()))
+ return -EBUSY;
- if (callback == NULL)
- return -EINVAL;
- if (card && client_index > 7)
+ if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD)
return -EINVAL;
- if (card == NULL && client_index > 63)
+ if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
return -EINVAL;
- if (card)
- client_index += 64 + (card->number << 3);
- if (down_interruptible(&register_mutex))
+ if (mutex_lock_interruptible(&register_mutex))
return -ERESTARTSYS;
+
+ if (card) {
+ client_index += SNDRV_SEQ_GLOBAL_CLIENTS
+ + card->number * SNDRV_SEQ_CLIENTS_PER_CARD;
+ if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN)
+ client_index = -1;
+ }
+
/* empty write queue as default */
client = seq_create_client1(client_index, 0);
if (client == NULL) {
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -EBUSY; /* failure code */
}
usage_alloc(&client_usage, 1);
- client->accept_input = callback->allow_output;
- client->accept_output = callback->allow_input;
+ client->accept_input = 1;
+ client->accept_output = 1;
- /* fill client data */
- client->data.kernel.card = card;
- client->data.kernel.private_data = callback->private_data;
- sprintf(client->name, "Client-%d", client->number);
+ va_start(args, name_fmt);
+ vsnprintf(client->name, sizeof(client->name), name_fmt, args);
+ va_end(args);
client->type = KERNEL_CLIENT;
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
/* make others aware this new client */
snd_seq_system_client_ev_client_start(client->number);
@@ -2196,12 +2283,15 @@ int snd_seq_create_kernel_client(snd_card_t *card, int client_index, snd_seq_cli
return client->number;
}
+EXPORT_SYMBOL(snd_seq_create_kernel_client);
+
/* exported to kernel modules */
int snd_seq_delete_kernel_client(int client)
{
- client_t *ptr;
+ struct snd_seq_client *ptr;
- snd_assert(! in_interrupt(), return -EBUSY);
+ if (snd_BUG_ON(in_interrupt()))
+ return -EBUSY;
ptr = clientptr(client);
if (ptr == NULL)
@@ -2212,18 +2302,20 @@ int snd_seq_delete_kernel_client(int client)
return 0;
}
+EXPORT_SYMBOL(snd_seq_delete_kernel_client);
/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
* and snd_seq_kernel_client_enqueue_blocking
*/
-static int kernel_client_enqueue(int client, snd_seq_event_t *ev,
+static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
struct file *file, int blocking,
int atomic, int hop)
{
- client_t *cptr;
+ struct snd_seq_client *cptr;
int result;
- snd_assert(ev != NULL, return -EINVAL);
+ if (snd_BUG_ON(!ev))
+ return -EINVAL;
if (ev->type == SNDRV_SEQ_EVENT_NONE)
return 0; /* ignore this */
@@ -2254,24 +2346,27 @@ static int kernel_client_enqueue(int client, snd_seq_event_t *ev,
*
* RETURN VALUE: zero if succeed, negative if error
*/
-int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t * ev,
+int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
int atomic, int hop)
{
return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
}
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
+
/*
* exported, called by kernel clients to enqueue events (with blocking)
*
* RETURN VALUE: zero if succeed, negative if error
*/
-int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev,
+int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
struct file *file,
int atomic, int hop)
{
return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
}
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
/*
* exported, called by kernel clients to dispatch events directly to other
@@ -2280,13 +2375,14 @@ int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev,
* RETURN VALUE: negative = delivery failed,
* zero, or positive: the number of delivered events
*/
-int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t * ev,
+int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
int atomic, int hop)
{
- client_t *cptr;
+ struct snd_seq_client *cptr;
int result;
- snd_assert(ev != NULL, return -EINVAL);
+ if (snd_BUG_ON(!ev))
+ return -EINVAL;
/* fill in client number */
ev->queue = SNDRV_SEQ_QUEUE_DIRECT;
@@ -2308,6 +2404,7 @@ int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t * ev,
return result;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
/*
* exported, called by kernel clients to perform same functions as with
@@ -2315,7 +2412,7 @@ int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t * ev,
*/
int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
{
- client_t *client;
+ struct snd_seq_client *client;
mm_segment_t fs;
int result;
@@ -2323,16 +2420,17 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
if (client == NULL)
return -ENXIO;
fs = snd_enter_user();
- result = snd_seq_do_ioctl(client, cmd, (void __user *)arg);
+ result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg);
snd_leave_user(fs);
return result;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
/* exported (for OSS emulator) */
int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
{
- client_t *client;
+ struct snd_seq_client *client;
client = clientptr(clientid);
if (client == NULL)
@@ -2345,15 +2443,20 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
return 0;
}
+EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+
/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_PROC_FS
/*
* /proc interface
*/
-static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_info_t *group, int is_src, char *msg)
+static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
+ struct snd_seq_port_subs_info *group,
+ int is_src, char *msg)
{
struct list_head *p;
- subscribers_t *s;
+ struct snd_seq_subscribers *s;
int count = 0;
down_read(&group->list_mutex);
@@ -2364,9 +2467,9 @@ static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_i
snd_iprintf(buffer, msg);
list_for_each(p, &group->list_head) {
if (is_src)
- s = list_entry(p, subscribers_t, src_list);
+ s = list_entry(p, struct snd_seq_subscribers, src_list);
else
- s = list_entry(p, subscribers_t, dest_list);
+ s = list_entry(p, struct snd_seq_subscribers, dest_list);
if (count++)
snd_iprintf(buffer, ", ");
snd_iprintf(buffer, "%d:%d",
@@ -2387,13 +2490,13 @@ static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_i
#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')
-static void snd_seq_info_dump_ports(snd_info_buffer_t *buffer, client_t *client)
+static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
+ struct snd_seq_client *client)
{
- struct list_head *l;
+ struct snd_seq_client_port *p;
- down(&client->ports_mutex);
- list_for_each(l, &client->ports_list_head) {
- client_port_t *p = list_entry(l, client_port_t, list);
+ mutex_lock(&client->ports_mutex);
+ list_for_each_entry(p, &client->ports_list_head, list) {
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
p->addr.port, p->name,
FLAG_PERM_RD(p->capability),
@@ -2403,17 +2506,16 @@ static void snd_seq_info_dump_ports(snd_info_buffer_t *buffer, client_t *client)
snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
}
- up(&client->ports_mutex);
+ mutex_unlock(&client->ports_mutex);
}
/* exported to seq_info.c */
-void snd_seq_info_clients_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+void snd_seq_info_clients_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- extern void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t * pool, char *space);
int c;
- client_t *client;
+ struct snd_seq_client *client;
snd_iprintf(buffer, "Client info\n");
snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur);
@@ -2447,7 +2549,7 @@ void snd_seq_info_clients_read(snd_info_entry_t *entry,
snd_seq_client_unlock(client);
}
}
-
+#endif /* CONFIG_PROC_FS */
/*---------------------------------------------------------------------------*/
@@ -2456,25 +2558,19 @@ void snd_seq_info_clients_read(snd_info_entry_t *entry,
* REGISTRATION PART
*/
-static struct file_operations snd_seq_f_ops =
+static const struct file_operations snd_seq_f_ops =
{
.owner = THIS_MODULE,
.read = snd_seq_read,
.write = snd_seq_write,
.open = snd_seq_open,
.release = snd_seq_release,
+ .llseek = no_llseek,
.poll = snd_seq_poll,
.unlocked_ioctl = snd_seq_ioctl,
.compat_ioctl = snd_seq_ioctl_compat,
};
-static snd_minor_t snd_seq_reg =
-{
- .comment = "sequencer",
- .f_ops = &snd_seq_f_ops,
-};
-
-
/*
* register sequencer device
*/
@@ -2482,15 +2578,16 @@ int __init snd_sequencer_device_init(void)
{
int err;
- if (down_interruptible(&register_mutex))
+ if (mutex_lock_interruptible(&register_mutex))
return -ERESTARTSYS;
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, &snd_seq_reg, "seq")) < 0) {
- up(&register_mutex);
+ if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
+ &snd_seq_f_ops, NULL, "seq")) < 0) {
+ mutex_unlock(&register_mutex);
return err;
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index 3715c36183d..20f0a725ec7 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -30,24 +30,21 @@
/* client manager */
-struct _snd_seq_user_client {
+struct snd_seq_user_client {
struct file *file; /* file struct of client */
/* ... */
/* fifo */
- fifo_t *fifo; /* queue for incoming events */
+ struct snd_seq_fifo *fifo; /* queue for incoming events */
int fifo_pool_size;
};
-struct _snd_seq_kernel_client {
- snd_card_t *card;
- /* pointer to client functions */
- void *private_data; /* private data for client */
+struct snd_seq_kernel_client {
/* ... */
};
-struct _snd_seq_client {
+struct snd_seq_client {
snd_seq_client_type_t type;
unsigned int accept_input: 1,
accept_output: 1;
@@ -61,44 +58,46 @@ struct _snd_seq_client {
int num_ports; /* number of ports */
struct list_head ports_list_head;
rwlock_t ports_lock;
- struct semaphore ports_mutex;
+ struct mutex ports_mutex;
int convert32; /* convert 32->64bit */
/* output pool */
- pool_t *pool; /* memory pool for this client */
+ struct snd_seq_pool *pool; /* memory pool for this client */
union {
- user_client_t user;
- kernel_client_t kernel;
+ struct snd_seq_user_client user;
+ struct snd_seq_kernel_client kernel;
} data;
};
/* usage statistics */
-typedef struct {
+struct snd_seq_usage {
int cur;
int peak;
-} usage_t;
+};
-extern int client_init_data(void);
-extern int snd_sequencer_device_init(void);
-extern void snd_sequencer_device_done(void);
+int client_init_data(void);
+int snd_sequencer_device_init(void);
+void snd_sequencer_device_done(void);
/* get locked pointer to client */
-extern client_t *snd_seq_client_use_ptr(int clientid);
+struct snd_seq_client *snd_seq_client_use_ptr(int clientid);
/* unlock pointer to client */
#define snd_seq_client_unlock(client) snd_use_lock_free(&(client)->use_lock)
/* dispatch event to client(s) */
-extern int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop);
+int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
/* exported to other modules */
-extern int snd_seq_register_kernel_client(snd_seq_client_callback_t *callback, void *private_data);
-extern int snd_seq_unregister_kernel_client(int client);
-extern int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t *ev, int atomic, int hop);
-int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev, struct file *file, int atomic, int hop);
+int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop);
+int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
+ struct file *file, int atomic, int hop);
int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait);
-int snd_seq_client_notify_subscription(int client, int port, snd_seq_port_subscribe_t *info, int evtype);
+int snd_seq_client_notify_subscription(int client, int port,
+ struct snd_seq_port_subscribe *info, int evtype);
+
+extern int seq_client_load[15];
#endif
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
index 902ad8b0c35..81f7c109dc4 100644
--- a/sound/core/seq/seq_compat.c
+++ b/sound/core/seq/seq_compat.c
@@ -21,9 +21,10 @@
/* This file included from seq.c */
#include <linux/compat.h>
+#include <linux/slab.h>
-struct sndrv_seq_port_info32 {
- struct sndrv_seq_addr addr; /* client/port numbers */
+struct snd_seq_port_info32 {
+ struct snd_seq_addr addr; /* client/port numbers */
char name[64]; /* port name */
u32 capability; /* port capability bits */
@@ -41,19 +42,18 @@ struct sndrv_seq_port_info32 {
char reserved[59]; /* for future use */
};
-static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
- struct sndrv_seq_port_info32 __user *data32)
+static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
+ struct snd_seq_port_info32 __user *data32)
{
int err = -EFAULT;
- snd_seq_port_info_t *data;
+ struct snd_seq_port_info *data;
mm_segment_t fs;
- data = kmalloc(sizeof(*data), GFP_KERNEL);
- if (! data)
- return -ENOMEM;
+ data = memdup_user(data32, sizeof(*data32));
+ if (IS_ERR(data))
+ return PTR_ERR(data);
- if (copy_from_user(data, data32, sizeof(*data32)) ||
- get_user(data->flags, &data32->flags) ||
+ if (get_user(data->flags, &data32->flags) ||
get_user(data->time_queue, &data32->time_queue))
goto error;
data->kernel = NULL;
@@ -80,19 +80,20 @@ static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
*/
enum {
- SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
- SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
- SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
- SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
- SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
+ SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct snd_seq_port_info32),
+ SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct snd_seq_port_info32),
+ SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct snd_seq_port_info32),
+ SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct snd_seq_port_info32),
+ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct snd_seq_port_info32),
};
static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
- client_t *client = (client_t *) file->private_data;
+ struct snd_seq_client *client = file->private_data;
void __user *argp = compat_ptr(arg);
- snd_assert(client != NULL, return -ENXIO);
+ if (snd_BUG_ON(!client))
+ return -ENXIO;
switch (cmd) {
case SNDRV_SEQ_IOCTL_PVERSION:
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 252b5273100..91a786a783e 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -36,8 +36,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/seq_device.h>
@@ -45,16 +45,12 @@
#include <sound/initval.h>
#include <linux/kmod.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA sequencer device management");
MODULE_LICENSE("GPL");
-/*
- * driver list
- */
-typedef struct ops_list ops_list_t;
-
/* driver state */
#define DRIVER_EMPTY 0
#define DRIVER_LOADED (1<<0)
@@ -68,13 +64,13 @@ struct ops_list {
int argsize; /* argument size */
/* operators */
- snd_seq_dev_ops_t ops;
+ struct snd_seq_dev_ops ops;
- /* registred devices */
+ /* registered devices */
struct list_head dev_list; /* list of devices */
int num_devices; /* number of associated devices */
int num_init_devices; /* number of initialized devices */
- struct semaphore reg_mutex;
+ struct mutex reg_mutex;
struct list_head list; /* next driver */
};
@@ -82,36 +78,38 @@ struct ops_list {
static LIST_HEAD(opslist);
static int num_ops;
-static DECLARE_MUTEX(ops_mutex);
-static snd_info_entry_t *info_entry = NULL;
+static DEFINE_MUTEX(ops_mutex);
+#ifdef CONFIG_PROC_FS
+static struct snd_info_entry *info_entry;
+#endif
/*
* prototypes
*/
-static int snd_seq_device_free(snd_seq_device_t *dev);
-static int snd_seq_device_dev_free(snd_device_t *device);
-static int snd_seq_device_dev_register(snd_device_t *device);
-static int snd_seq_device_dev_disconnect(snd_device_t *device);
-static int snd_seq_device_dev_unregister(snd_device_t *device);
-
-static int init_device(snd_seq_device_t *dev, ops_list_t *ops);
-static int free_device(snd_seq_device_t *dev, ops_list_t *ops);
-static ops_list_t *find_driver(char *id, int create_if_empty);
-static ops_list_t *create_driver(char *id);
-static void unlock_driver(ops_list_t *ops);
+static int snd_seq_device_free(struct snd_seq_device *dev);
+static int snd_seq_device_dev_free(struct snd_device *device);
+static int snd_seq_device_dev_register(struct snd_device *device);
+static int snd_seq_device_dev_disconnect(struct snd_device *device);
+
+static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
+static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
+static struct ops_list *find_driver(char *id, int create_if_empty);
+static struct ops_list *create_driver(char *id);
+static void unlock_driver(struct ops_list *ops);
static void remove_drivers(void);
/*
* show all drivers and their status
*/
-static void snd_seq_device_info(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+#ifdef CONFIG_PROC_FS
+static void snd_seq_device_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- struct list_head *head;
+ struct ops_list *ops;
- down(&ops_mutex);
- list_for_each(head, &opslist) {
- ops_list_t *ops = list_entry(head, ops_list_t, list);
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
ops->id,
ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
@@ -119,14 +117,15 @@ static void snd_seq_device_info(snd_info_entry_t *entry, snd_info_buffer_t * buf
ops->driver & DRIVER_LOCKED ? ",locked" : "",
ops->num_devices);
}
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
}
+#endif
/*
* load all registered drivers (called from seq_clientmgr.c)
*/
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */
static int snd_seq_in_init;
void snd_seq_autoload_lock(void)
@@ -142,8 +141,8 @@ void snd_seq_autoload_unlock(void)
void snd_seq_device_load_drivers(void)
{
-#ifdef CONFIG_KMOD
- struct list_head *head;
+#ifdef CONFIG_MODULES
+ struct ops_list *ops;
/* Calling request_module during module_init()
* may cause blocking.
@@ -151,50 +150,46 @@ void snd_seq_device_load_drivers(void)
if (snd_seq_in_init)
return;
- if (! current->fs->root)
- return;
-
- down(&ops_mutex);
- list_for_each(head, &opslist) {
- ops_list_t *ops = list_entry(head, ops_list_t, list);
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
if (! (ops->driver & DRIVER_LOADED) &&
! (ops->driver & DRIVER_REQUESTED)) {
ops->used++;
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
ops->driver |= DRIVER_REQUESTED;
request_module("snd-%s", ops->id);
- down(&ops_mutex);
+ mutex_lock(&ops_mutex);
ops->used--;
}
}
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
#endif
}
/*
* register a sequencer device
- * card = card info (NULL allowed)
+ * card = card info
* device = device number (if any)
* id = id of driver
* result = return pointer (NULL allowed if unnecessary)
*/
-int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
- snd_seq_device_t **result)
+int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
+ struct snd_seq_device **result)
{
- snd_seq_device_t *dev;
- ops_list_t *ops;
+ struct snd_seq_device *dev;
+ struct ops_list *ops;
int err;
- static snd_device_ops_t dops = {
+ static struct snd_device_ops dops = {
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
- .dev_unregister = snd_seq_device_dev_unregister
};
if (result)
*result = NULL;
- snd_assert(id != NULL, return -EINVAL);
+ if (snd_BUG_ON(!id))
+ return -EINVAL;
ops = find_driver(id, 1);
if (ops == NULL)
@@ -214,10 +209,10 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
dev->status = SNDRV_SEQ_DEVICE_FREE;
/* add this device to the list */
- down(&ops->reg_mutex);
+ mutex_lock(&ops->reg_mutex);
list_add_tail(&dev->list, &ops->dev_list);
ops->num_devices++;
- up(&ops->reg_mutex);
+ mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
@@ -235,21 +230,22 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
/*
* free the existing device
*/
-static int snd_seq_device_free(snd_seq_device_t *dev)
+static int snd_seq_device_free(struct snd_seq_device *dev)
{
- ops_list_t *ops;
+ struct ops_list *ops;
- snd_assert(dev != NULL, return -EINVAL);
+ if (snd_BUG_ON(!dev))
+ return -EINVAL;
ops = find_driver(dev->id, 0);
if (ops == NULL)
return -ENXIO;
/* remove the device from the list */
- down(&ops->reg_mutex);
+ mutex_lock(&ops->reg_mutex);
list_del(&dev->list);
ops->num_devices--;
- up(&ops->reg_mutex);
+ mutex_unlock(&ops->reg_mutex);
free_device(dev, ops);
if (dev->private_free)
@@ -261,19 +257,19 @@ static int snd_seq_device_free(snd_seq_device_t *dev)
return 0;
}
-static int snd_seq_device_dev_free(snd_device_t *device)
+static int snd_seq_device_dev_free(struct snd_device *device)
{
- snd_seq_device_t *dev = device->device_data;
+ struct snd_seq_device *dev = device->device_data;
return snd_seq_device_free(dev);
}
/*
* register the device
*/
-static int snd_seq_device_dev_register(snd_device_t *device)
+static int snd_seq_device_dev_register(struct snd_device *device)
{
- snd_seq_device_t *dev = device->device_data;
- ops_list_t *ops;
+ struct snd_seq_device *dev = device->device_data;
+ struct ops_list *ops;
ops = find_driver(dev->id, 0);
if (ops == NULL)
@@ -292,10 +288,10 @@ static int snd_seq_device_dev_register(snd_device_t *device)
/*
* disconnect the device
*/
-static int snd_seq_device_dev_disconnect(snd_device_t *device)
+static int snd_seq_device_dev_disconnect(struct snd_device *device)
{
- snd_seq_device_t *dev = device->device_data;
- ops_list_t *ops;
+ struct snd_seq_device *dev = device->device_data;
+ struct ops_list *ops;
ops = find_driver(dev->id, 0);
if (ops == NULL)
@@ -308,23 +304,15 @@ static int snd_seq_device_dev_disconnect(snd_device_t *device)
}
/*
- * unregister the existing device
- */
-static int snd_seq_device_dev_unregister(snd_device_t *device)
-{
- snd_seq_device_t *dev = device->device_data;
- return snd_seq_device_free(dev);
-}
-
-/*
* register device driver
* id = driver id
* entry = driver operators - duplicated to each instance
*/
-int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsize)
+int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
+ int argsize)
{
- struct list_head *head;
- ops_list_t *ops;
+ struct ops_list *ops;
+ struct snd_seq_device *dev;
if (id == NULL || entry == NULL ||
entry->init_device == NULL || entry->free_device == NULL)
@@ -337,24 +325,23 @@ int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsi
return -ENOMEM;
}
if (ops->driver & DRIVER_LOADED) {
- snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
+ pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
snd_seq_autoload_unlock();
return -EBUSY;
}
- down(&ops->reg_mutex);
+ mutex_lock(&ops->reg_mutex);
/* copy driver operators */
ops->ops = *entry;
ops->driver |= DRIVER_LOADED;
ops->argsize = argsize;
/* initialize existing devices if necessary */
- list_for_each(head, &ops->dev_list) {
- snd_seq_device_t *dev = list_entry(head, snd_seq_device_t, list);
+ list_for_each_entry(dev, &ops->dev_list, list) {
init_device(dev, ops);
}
- up(&ops->reg_mutex);
+ mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
snd_seq_autoload_unlock();
@@ -366,28 +353,33 @@ int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsi
/*
* create driver record
*/
-static ops_list_t * create_driver(char *id)
+static struct ops_list * create_driver(char *id)
{
- ops_list_t *ops;
+ struct ops_list *ops;
- ops = kmalloc(sizeof(*ops), GFP_KERNEL);
+ ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (ops == NULL)
return ops;
- memset(ops, 0, sizeof(*ops));
/* set up driver entry */
strlcpy(ops->id, id, sizeof(ops->id));
- init_MUTEX(&ops->reg_mutex);
+ mutex_init(&ops->reg_mutex);
+ /*
+ * The ->reg_mutex locking rules are per-driver, so we create
+ * separate per-driver lock classes:
+ */
+ lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
+
ops->driver = DRIVER_EMPTY;
INIT_LIST_HEAD(&ops->dev_list);
/* lock this instance */
ops->used = 1;
/* register driver entry */
- down(&ops_mutex);
+ mutex_lock(&ops_mutex);
list_add_tail(&ops->list, &opslist);
num_ops++;
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
return ops;
}
@@ -398,31 +390,32 @@ static ops_list_t * create_driver(char *id)
*/
int snd_seq_device_unregister_driver(char *id)
{
- struct list_head *head;
- ops_list_t *ops;
+ struct ops_list *ops;
+ struct snd_seq_device *dev;
ops = find_driver(id, 0);
if (ops == NULL)
return -ENXIO;
if (! (ops->driver & DRIVER_LOADED) ||
(ops->driver & DRIVER_LOCKED)) {
- snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n", id, ops->driver);
+ pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
+ id, ops->driver);
unlock_driver(ops);
return -EBUSY;
}
/* close and release all devices associated with this driver */
- down(&ops->reg_mutex);
+ mutex_lock(&ops->reg_mutex);
ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
- list_for_each(head, &ops->dev_list) {
- snd_seq_device_t *dev = list_entry(head, snd_seq_device_t, list);
+ list_for_each_entry(dev, &ops->dev_list, list) {
free_device(dev, ops);
}
ops->driver = 0;
if (ops->num_init_devices > 0)
- snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n", ops->num_init_devices);
- up(&ops->reg_mutex);
+ pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
+ ops->num_init_devices);
+ mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
@@ -440,10 +433,10 @@ static void remove_drivers(void)
{
struct list_head *head;
- down(&ops_mutex);
+ mutex_lock(&ops_mutex);
head = opslist.next;
while (head != &opslist) {
- ops_list_t *ops = list_entry(head, ops_list_t, list);
+ struct ops_list *ops = list_entry(head, struct ops_list, list);
if (! (ops->driver & DRIVER_LOADED) &&
ops->used == 0 && ops->num_devices == 0) {
head = head->next;
@@ -453,27 +446,29 @@ static void remove_drivers(void)
} else
head = head->next;
}
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
}
/*
* initialize the device - call init_device operator
*/
-static int init_device(snd_seq_device_t *dev, ops_list_t *ops)
+static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
{
if (! (ops->driver & DRIVER_LOADED))
return 0; /* driver is not loaded yet */
if (dev->status != SNDRV_SEQ_DEVICE_FREE)
return 0; /* already initialized */
if (ops->argsize != dev->argsize) {
- snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize);
+ pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
+ dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL;
}
if (ops->ops.init_device(dev) >= 0) {
dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
ops->num_init_devices++;
} else {
- snd_printk(KERN_ERR "init_device failed: %s: %s\n", dev->name, dev->id);
+ pr_err("ALSA: seq: init_device failed: %s: %s\n",
+ dev->name, dev->id);
}
return 0;
@@ -482,7 +477,7 @@ static int init_device(snd_seq_device_t *dev, ops_list_t *ops)
/*
* release the device - call free_device operator
*/
-static int free_device(snd_seq_device_t *dev, ops_list_t *ops)
+static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
{
int result;
@@ -491,7 +486,8 @@ static int free_device(snd_seq_device_t *dev, ops_list_t *ops)
if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
return 0; /* not registered */
if (ops->argsize != dev->argsize) {
- snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize);
+ pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
+ dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL;
}
if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
@@ -499,7 +495,8 @@ static int free_device(snd_seq_device_t *dev, ops_list_t *ops)
dev->driver_data = NULL;
ops->num_init_devices--;
} else {
- snd_printk(KERN_ERR "free_device failed: %s: %s\n", dev->name, dev->id);
+ pr_err("ALSA: seq: free_device failed: %s: %s\n",
+ dev->name, dev->id);
}
return 0;
@@ -508,30 +505,29 @@ static int free_device(snd_seq_device_t *dev, ops_list_t *ops)
/*
* find the matching driver with given id
*/
-static ops_list_t * find_driver(char *id, int create_if_empty)
+static struct ops_list * find_driver(char *id, int create_if_empty)
{
- struct list_head *head;
+ struct ops_list *ops;
- down(&ops_mutex);
- list_for_each(head, &opslist) {
- ops_list_t *ops = list_entry(head, ops_list_t, list);
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
if (strcmp(ops->id, id) == 0) {
ops->used++;
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
return ops;
}
}
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
if (create_if_empty)
return create_driver(id);
return NULL;
}
-static void unlock_driver(ops_list_t *ops)
+static void unlock_driver(struct ops_list *ops)
{
- down(&ops_mutex);
+ mutex_lock(&ops_mutex);
ops->used--;
- up(&ops_mutex);
+ mutex_unlock(&ops_mutex);
}
@@ -541,25 +537,29 @@ static void unlock_driver(ops_list_t *ops)
static int __init alsa_seq_device_init(void)
{
- info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", snd_seq_root);
+#ifdef CONFIG_PROC_FS
+ info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
+ snd_seq_root);
if (info_entry == NULL)
return -ENOMEM;
info_entry->content = SNDRV_INFO_CONTENT_TEXT;
- info_entry->c.text.read_size = 2048;
info_entry->c.text.read = snd_seq_device_info;
if (snd_info_register(info_entry) < 0) {
snd_info_free_entry(info_entry);
return -ENOMEM;
}
+#endif
return 0;
}
static void __exit alsa_seq_device_exit(void)
{
remove_drivers();
- snd_info_unregister(info_entry);
+#ifdef CONFIG_PROC_FS
+ snd_info_free_entry(info_entry);
+#endif
if (num_ops)
- snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
+ pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
}
module_init(alsa_seq_device_init)
@@ -569,7 +569,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);
EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index 5dd0e6a19e5..ec667f158f1 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -18,10 +18,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "seq_clientmgr.h"
#include <sound/initval.h>
@@ -47,11 +46,11 @@
The number of ports to be created can be specified via the module
parameter "ports". For example, to create four ports, add the
- following option in /etc/modprobe.conf:
+ following option in a configuration file under /etc/modprobe.d/:
option snd-seq-dummy ports=4
- The modle option "duplex=1" enables duplex operation to the port.
+ The model option "duplex=1" enables duplex operation to the port.
In duplex mode, a pair of ports are created instead of single port,
and events are tunneled between pair-ports. For example, input to
port A is sent to output port of another port B and vice versa.
@@ -66,19 +65,19 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
static int ports = 1;
-static int duplex = 0;
+static bool duplex;
module_param(ports, int, 0444);
MODULE_PARM_DESC(ports, "number of ports to be created");
module_param(duplex, bool, 0444);
MODULE_PARM_DESC(duplex, "create DUPLEX ports");
-typedef struct snd_seq_dummy_port {
+struct snd_seq_dummy_port {
int client;
int port;
int duplex;
int connect;
-} snd_seq_dummy_port_t;
+};
static int my_client = -1;
@@ -88,11 +87,11 @@ static int my_client = -1;
* Note: this callback is called only after all subscribers are removed.
*/
static int
-dummy_unuse(void *private_data, snd_seq_port_subscribe_t *info)
+dummy_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
- snd_seq_dummy_port_t *p;
+ struct snd_seq_dummy_port *p;
int i;
- snd_seq_event_t ev;
+ struct snd_seq_event ev;
p = private_data;
memset(&ev, 0, sizeof(ev));
@@ -116,10 +115,11 @@ dummy_unuse(void *private_data, snd_seq_port_subscribe_t *info)
* event input callback - just redirect events to subscribers
*/
static int
-dummy_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop)
+dummy_input(struct snd_seq_event *ev, int direct, void *private_data,
+ int atomic, int hop)
{
- snd_seq_dummy_port_t *p;
- snd_seq_event_t tmpev;
+ struct snd_seq_dummy_port *p;
+ struct snd_seq_event tmpev;
p = private_data;
if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM ||
@@ -146,12 +146,12 @@ dummy_free(void *private_data)
/*
* create a port
*/
-static snd_seq_dummy_port_t __init *
+static struct snd_seq_dummy_port __init *
create_port(int idx, int type)
{
- snd_seq_port_info_t pinfo;
- snd_seq_port_callback_t pcb;
- snd_seq_dummy_port_t *rec;
+ struct snd_seq_port_info pinfo;
+ struct snd_seq_port_callback pcb;
+ struct snd_seq_dummy_port *rec;
if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL)
return NULL;
@@ -170,7 +170,9 @@ create_port(int idx, int type)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
if (duplex)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
memset(&pcb, 0, sizeof(pcb));
pcb.owner = THIS_MODULE;
pcb.unuse = dummy_unuse;
@@ -192,31 +194,20 @@ create_port(int idx, int type)
static int __init
register_client(void)
{
- snd_seq_client_callback_t cb;
- snd_seq_client_info_t cinfo;
- snd_seq_dummy_port_t *rec1, *rec2;
+ struct snd_seq_dummy_port *rec1, *rec2;
int i;
if (ports < 1) {
- snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
+ pr_err("ALSA: seq_dummy: invalid number of ports %d\n", ports);
return -EINVAL;
}
/* create client */
- memset(&cb, 0, sizeof(cb));
- cb.allow_input = 1;
- cb.allow_output = 1;
- my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY, &cb);
+ my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY,
+ "Midi Through");
if (my_client < 0)
return my_client;
- /* set client name */
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.client = my_client;
- cinfo.type = KERNEL_CLIENT;
- strcpy(cinfo.name, "Midi Through");
- snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
-
/* create ports */
for (i = 0; i < ports; i++) {
rec1 = create_port(i, 0);
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 4767cfdc361..53a403e17c5 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <sound/core.h>
#include <linux/slab.h>
#include "seq_fifo.h"
@@ -29,13 +28,13 @@
/* FIFO */
/* create new fifo */
-fifo_t *snd_seq_fifo_new(int poolsize)
+struct snd_seq_fifo *snd_seq_fifo_new(int poolsize)
{
- fifo_t *f;
+ struct snd_seq_fifo *f;
f = kzalloc(sizeof(*f), GFP_KERNEL);
if (f == NULL) {
- snd_printd("malloc failed for snd_seq_fifo_new() \n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
return NULL;
}
@@ -62,13 +61,15 @@ fifo_t *snd_seq_fifo_new(int poolsize)
return f;
}
-void snd_seq_fifo_delete(fifo_t **fifo)
+void snd_seq_fifo_delete(struct snd_seq_fifo **fifo)
{
- fifo_t *f;
+ struct snd_seq_fifo *f;
- snd_assert(fifo != NULL, return);
+ if (snd_BUG_ON(!fifo))
+ return;
f = *fifo;
- snd_assert(f != NULL, return);
+ if (snd_BUG_ON(!f))
+ return;
*fifo = NULL;
snd_seq_fifo_clear(f);
@@ -88,12 +89,12 @@ void snd_seq_fifo_delete(fifo_t **fifo)
kfree(f);
}
-static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f);
+static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f);
/* clear queue */
-void snd_seq_fifo_clear(fifo_t *f)
+void snd_seq_fifo_clear(struct snd_seq_fifo *f)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
unsigned long flags;
/* clear overflow flag */
@@ -110,18 +111,20 @@ void snd_seq_fifo_clear(fifo_t *f)
/* enqueue event to fifo */
-int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event)
+int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
+ struct snd_seq_event *event)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
unsigned long flags;
int err;
- snd_assert(f != NULL, return -EINVAL);
+ if (snd_BUG_ON(!f))
+ return -EINVAL;
snd_use_lock_use(&f->use_lock);
err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
if (err < 0) {
- if (err == -ENOMEM)
+ if ((err == -ENOMEM) || (err == -EAGAIN))
atomic_inc(&f->overflow);
snd_use_lock_free(&f->use_lock);
return err;
@@ -148,9 +151,9 @@ int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event)
}
/* dequeue cell from fifo */
-static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f)
+static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
if ((cell = f->head) != NULL) {
f->head = cell->next;
@@ -167,13 +170,15 @@ static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f)
}
/* dequeue cell from fifo and copy on user space */
-int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
+int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
+ struct snd_seq_event_cell **cellp, int nonblock)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
unsigned long flags;
wait_queue_t wait;
- snd_assert(f != NULL, return -EINVAL);
+ if (snd_BUG_ON(!f))
+ return -EINVAL;
*cellp = NULL;
init_waitqueue_entry(&wait, current);
@@ -202,7 +207,8 @@ int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
}
-void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell)
+void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
+ struct snd_seq_event_cell *cell)
{
unsigned long flags;
@@ -217,20 +223,22 @@ void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell)
/* polling; return non-zero if queue is available */
-int snd_seq_fifo_poll_wait(fifo_t *f, struct file *file, poll_table *wait)
+int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file,
+ poll_table *wait)
{
poll_wait(file, &f->input_sleep, wait);
return (f->cells > 0);
}
/* change the size of pool; all old events are removed */
-int snd_seq_fifo_resize(fifo_t *f, int poolsize)
+int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
{
unsigned long flags;
- pool_t *newpool, *oldpool;
- snd_seq_event_cell_t *cell, *next, *oldhead;
+ struct snd_seq_pool *newpool, *oldpool;
+ struct snd_seq_event_cell *cell, *next, *oldhead;
- snd_assert(f != NULL && f->pool != NULL, return -EINVAL);
+ if (snd_BUG_ON(!f || !f->pool))
+ return -EINVAL;
/* allocate new pool */
newpool = snd_seq_pool_new(poolsize);
diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h
index d677c261b0a..062c446e786 100644
--- a/sound/core/seq/seq_fifo.h
+++ b/sound/core/seq/seq_fifo.h
@@ -27,46 +27,46 @@
/* === FIFO === */
-typedef struct {
- pool_t *pool; /* FIFO pool */
- snd_seq_event_cell_t* head; /* pointer to head of fifo */
- snd_seq_event_cell_t* tail; /* pointer to tail of fifo */
+struct snd_seq_fifo {
+ struct snd_seq_pool *pool; /* FIFO pool */
+ struct snd_seq_event_cell *head; /* pointer to head of fifo */
+ struct snd_seq_event_cell *tail; /* pointer to tail of fifo */
int cells;
spinlock_t lock;
snd_use_lock_t use_lock;
wait_queue_head_t input_sleep;
atomic_t overflow;
-} fifo_t;
+};
/* create new fifo (constructor) */
-extern fifo_t *snd_seq_fifo_new(int poolsize);
+struct snd_seq_fifo *snd_seq_fifo_new(int poolsize);
/* delete fifo (destructor) */
-extern void snd_seq_fifo_delete(fifo_t **f);
+void snd_seq_fifo_delete(struct snd_seq_fifo **f);
/* enqueue event to fifo */
-extern int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event);
+int snd_seq_fifo_event_in(struct snd_seq_fifo *f, struct snd_seq_event *event);
/* lock fifo from release */
#define snd_seq_fifo_lock(fifo) snd_use_lock_use(&(fifo)->use_lock)
#define snd_seq_fifo_unlock(fifo) snd_use_lock_free(&(fifo)->use_lock)
/* get a cell from fifo - fifo should be locked */
-int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock);
+int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, struct snd_seq_event_cell **cellp, int nonblock);
/* free dequeued cell - fifo should be locked */
-extern void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell);
+void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, struct snd_seq_event_cell *cell);
/* clean up queue */
-extern void snd_seq_fifo_clear(fifo_t *f);
+void snd_seq_fifo_clear(struct snd_seq_fifo *f);
/* polling */
-extern int snd_seq_fifo_poll_wait(fifo_t *f, struct file *file, poll_table *wait);
+int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file, poll_table *wait);
/* resize pool in fifo */
-int snd_seq_fifo_resize(fifo_t *f, int poolsize);
+int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize);
#endif
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
index b50b695c41c..acf7769419f 100644
--- a/sound/core/seq/seq_info.c
+++ b/sound/core/seq/seq_info.c
@@ -19,30 +19,30 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "seq_info.h"
#include "seq_clientmgr.h"
#include "seq_timer.h"
+#ifdef CONFIG_PROC_FS
+static struct snd_info_entry *queues_entry;
+static struct snd_info_entry *clients_entry;
+static struct snd_info_entry *timer_entry;
-static snd_info_entry_t *queues_entry;
-static snd_info_entry_t *clients_entry;
-static snd_info_entry_t *timer_entry;
-
-static snd_info_entry_t * __init
-create_info_entry(char *name, int size, void (*read)(snd_info_entry_t *, snd_info_buffer_t *))
+static struct snd_info_entry * __init
+create_info_entry(char *name, void (*read)(struct snd_info_entry *,
+ struct snd_info_buffer *))
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, name, snd_seq_root);
if (entry == NULL)
return NULL;
entry->content = SNDRV_INFO_CONTENT_TEXT;
- entry->c.text.read_size = size;
entry->c.text.read = read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -51,25 +51,22 @@ create_info_entry(char *name, int size, void (*read)(snd_info_entry_t *, snd_inf
return entry;
}
-
/* create all our /proc entries */
int __init snd_seq_info_init(void)
{
- queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES),
+ queues_entry = create_info_entry("queues",
snd_seq_info_queues_read);
- clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS),
+ clients_entry = create_info_entry("clients",
snd_seq_info_clients_read);
- timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read);
+ timer_entry = create_info_entry("timer", snd_seq_info_timer_read);
return 0;
}
int __exit snd_seq_info_done(void)
{
- if (queues_entry)
- snd_info_unregister(queues_entry);
- if (clients_entry)
- snd_info_unregister(clients_entry);
- if (timer_entry)
- snd_info_unregister(timer_entry);
+ snd_info_free_entry(queues_entry);
+ snd_info_free_entry(clients_entry);
+ snd_info_free_entry(timer_entry);
return 0;
}
+#endif
diff --git a/sound/core/seq/seq_info.h b/sound/core/seq/seq_info.h
index efd099a858e..4892a7f35c0 100644
--- a/sound/core/seq/seq_info.h
+++ b/sound/core/seq/seq_info.h
@@ -24,13 +24,17 @@
#include <sound/info.h>
#include <sound/seq_kernel.h>
-void snd_seq_info_clients_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
-void snd_seq_info_timer_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
-void snd_seq_info_queues_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
+void snd_seq_info_clients_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer);
+void snd_seq_info_timer_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer);
+void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer);
+#ifdef CONFIG_PROC_FS
int snd_seq_info_init( void );
int snd_seq_info_done( void );
-
+#else
+static inline int snd_seq_info_init(void) { return 0; }
+static inline int snd_seq_info_done(void) { return 0; }
+#endif
#endif
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
deleted file mode 100644
index 019d43a462d..00000000000
--- a/sound/core/seq/seq_instr.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Generic Instrument routines for ALSA sequencer
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "seq_clientmgr.h"
-#include <sound/seq_instr.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library.");
-MODULE_LICENSE("GPL");
-
-
-static void snd_instr_lock_ops(snd_seq_kinstr_list_t *list)
-{
- if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
- spin_lock_irqsave(&list->ops_lock, list->ops_flags);
- } else {
- down(&list->ops_mutex);
- }
-}
-
-static void snd_instr_unlock_ops(snd_seq_kinstr_list_t *list)
-{
- if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
- spin_unlock_irqrestore(&list->ops_lock, list->ops_flags);
- } else {
- up(&list->ops_mutex);
- }
-}
-
-static snd_seq_kinstr_t *snd_seq_instr_new(int add_len, int atomic)
-{
- snd_seq_kinstr_t *instr;
-
- instr = kzalloc(sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL);
- if (instr == NULL)
- return NULL;
- instr->add_len = add_len;
- return instr;
-}
-
-static int snd_seq_instr_free(snd_seq_kinstr_t *instr, int atomic)
-{
- int result = 0;
-
- if (instr == NULL)
- return -EINVAL;
- if (instr->ops && instr->ops->remove)
- result = instr->ops->remove(instr->ops->private_data, instr, 1);
- if (!result)
- kfree(instr);
- return result;
-}
-
-snd_seq_kinstr_list_t *snd_seq_instr_list_new(void)
-{
- snd_seq_kinstr_list_t *list;
-
- list = kzalloc(sizeof(snd_seq_kinstr_list_t), GFP_KERNEL);
- if (list == NULL)
- return NULL;
- spin_lock_init(&list->lock);
- spin_lock_init(&list->ops_lock);
- init_MUTEX(&list->ops_mutex);
- list->owner = -1;
- return list;
-}
-
-void snd_seq_instr_list_free(snd_seq_kinstr_list_t **list_ptr)
-{
- snd_seq_kinstr_list_t *list;
- snd_seq_kinstr_t *instr;
- snd_seq_kcluster_t *cluster;
- int idx;
- unsigned long flags;
-
- if (list_ptr == NULL)
- return;
- list = *list_ptr;
- *list_ptr = NULL;
- if (list == NULL)
- return;
-
- for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {
- while ((instr = list->hash[idx]) != NULL) {
- list->hash[idx] = instr->next;
- list->count--;
- spin_lock_irqsave(&list->lock, flags);
- while (instr->use) {
- spin_unlock_irqrestore(&list->lock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- spin_lock_irqsave(&list->lock, flags);
- }
- spin_unlock_irqrestore(&list->lock, flags);
- if (snd_seq_instr_free(instr, 0)<0)
- snd_printk(KERN_WARNING "instrument free problem\n");
- }
- while ((cluster = list->chash[idx]) != NULL) {
- list->chash[idx] = cluster->next;
- list->ccount--;
- kfree(cluster);
- }
- }
- kfree(list);
-}
-
-static int instr_free_compare(snd_seq_kinstr_t *instr,
- snd_seq_instr_header_t *ifree,
- unsigned int client)
-{
- switch (ifree->cmd) {
- case SNDRV_SEQ_INSTR_FREE_CMD_ALL:
- /* all, except private for other clients */
- if ((instr->instr.std & 0xff000000) == 0)
- return 0;
- if (((instr->instr.std >> 24) & 0xff) == client)
- return 0;
- return 1;
- case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE:
- /* all my private instruments */
- if ((instr->instr.std & 0xff000000) == 0)
- return 1;
- if (((instr->instr.std >> 24) & 0xff) == client)
- return 0;
- return 1;
- case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER:
- /* all my private instruments */
- if ((instr->instr.std & 0xff000000) == 0) {
- if (instr->instr.cluster == ifree->id.cluster)
- return 0;
- return 1;
- }
- if (((instr->instr.std >> 24) & 0xff) == client) {
- if (instr->instr.cluster == ifree->id.cluster)
- return 0;
- }
- return 1;
- }
- return 1;
-}
-
-int snd_seq_instr_list_free_cond(snd_seq_kinstr_list_t *list,
- snd_seq_instr_header_t *ifree,
- int client,
- int atomic)
-{
- snd_seq_kinstr_t *instr, *prev, *next, *flist;
- int idx;
- unsigned long flags;
-
- snd_instr_lock_ops(list);
- for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {
- spin_lock_irqsave(&list->lock, flags);
- instr = list->hash[idx];
- prev = flist = NULL;
- while (instr) {
- while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) {
- prev = instr;
- instr = instr->next;
- }
- if (instr == NULL)
- continue;
- if (instr->ops && instr->ops->notify)
- instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
- next = instr->next;
- if (prev == NULL) {
- list->hash[idx] = next;
- } else {
- prev->next = next;
- }
- list->count--;
- instr->next = flist;
- flist = instr;
- instr = next;
- }
- spin_unlock_irqrestore(&list->lock, flags);
- while (flist) {
- instr = flist;
- flist = instr->next;
- while (instr->use) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
- if (snd_seq_instr_free(instr, atomic)<0)
- snd_printk(KERN_WARNING "instrument free problem\n");
- instr = next;
- }
- }
- snd_instr_unlock_ops(list);
- return 0;
-}
-
-static int compute_hash_instr_key(snd_seq_instr_t *instr)
-{
- int result;
-
- result = instr->bank | (instr->prg << 16);
- result += result >> 24;
- result += result >> 16;
- result += result >> 8;
- return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
-}
-
-#if 0
-static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster)
-{
- int result;
-
- result = cluster;
- result += result >> 24;
- result += result >> 16;
- result += result >> 8;
- return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
-}
-#endif
-
-static int compare_instr(snd_seq_instr_t *i1, snd_seq_instr_t *i2, int exact)
-{
- if (exact) {
- if (i1->cluster != i2->cluster ||
- i1->bank != i2->bank ||
- i1->prg != i2->prg)
- return 1;
- if ((i1->std & 0xff000000) != (i2->std & 0xff000000))
- return 1;
- if (!(i1->std & i2->std))
- return 1;
- return 0;
- } else {
- unsigned int client_check;
-
- if (i2->cluster && i1->cluster != i2->cluster)
- return 1;
- client_check = i2->std & 0xff000000;
- if (client_check) {
- if ((i1->std & 0xff000000) != client_check)
- return 1;
- } else {
- if ((i1->std & i2->std) != i2->std)
- return 1;
- }
- return i1->bank != i2->bank || i1->prg != i2->prg;
- }
-}
-
-snd_seq_kinstr_t *snd_seq_instr_find(snd_seq_kinstr_list_t *list,
- snd_seq_instr_t *instr,
- int exact,
- int follow_alias)
-{
- unsigned long flags;
- int depth = 0;
- snd_seq_kinstr_t *result;
-
- if (list == NULL || instr == NULL)
- return NULL;
- spin_lock_irqsave(&list->lock, flags);
- __again:
- result = list->hash[compute_hash_instr_key(instr)];
- while (result) {
- if (!compare_instr(&result->instr, instr, exact)) {
- if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) {
- instr = (snd_seq_instr_t *)KINSTR_DATA(result);
- if (++depth > 10)
- goto __not_found;
- goto __again;
- }
- result->use++;
- spin_unlock_irqrestore(&list->lock, flags);
- return result;
- }
- result = result->next;
- }
- __not_found:
- spin_unlock_irqrestore(&list->lock, flags);
- return NULL;
-}
-
-void snd_seq_instr_free_use(snd_seq_kinstr_list_t *list,
- snd_seq_kinstr_t *instr)
-{
- unsigned long flags;
-
- if (list == NULL || instr == NULL)
- return;
- spin_lock_irqsave(&list->lock, flags);
- if (instr->use <= 0) {
- snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name);
- } else {
- instr->use--;
- }
- spin_unlock_irqrestore(&list->lock, flags);
-}
-
-static snd_seq_kinstr_ops_t *instr_ops(snd_seq_kinstr_ops_t *ops, char *instr_type)
-{
- while (ops) {
- if (!strcmp(ops->instr_type, instr_type))
- return ops;
- ops = ops->next;
- }
- return NULL;
-}
-
-static int instr_result(snd_seq_event_t *ev,
- int type, int result,
- int atomic)
-{
- snd_seq_event_t sev;
-
- memset(&sev, 0, sizeof(sev));
- sev.type = SNDRV_SEQ_EVENT_RESULT;
- sev.flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED |
- SNDRV_SEQ_PRIORITY_NORMAL;
- sev.source = ev->dest;
- sev.dest = ev->source;
- sev.data.result.event = type;
- sev.data.result.result = result;
-#if 0
- printk("instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i\n",
- type, result,
- sev.queue,
- sev.source.client, sev.source.port,
- sev.dest.client, sev.dest.port);
-#endif
- return snd_seq_kernel_client_dispatch(sev.source.client, &sev, atomic, 0);
-}
-
-static int instr_begin(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&list->lock, flags);
- if (list->owner >= 0 && list->owner != ev->source.client) {
- spin_unlock_irqrestore(&list->lock, flags);
- return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, -EBUSY, atomic);
- }
- list->owner = ev->source.client;
- spin_unlock_irqrestore(&list->lock, flags);
- return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, 0, atomic);
-}
-
-static int instr_end(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- unsigned long flags;
-
- /* TODO: timeout handling */
- spin_lock_irqsave(&list->lock, flags);
- if (list->owner == ev->source.client) {
- list->owner = -1;
- spin_unlock_irqrestore(&list->lock, flags);
- return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, 0, atomic);
- }
- spin_unlock_irqrestore(&list->lock, flags);
- return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, -EINVAL, atomic);
-}
-
-static int instr_info(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_format_info(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_reset(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_status(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_put(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- unsigned long flags;
- snd_seq_instr_header_t put;
- snd_seq_kinstr_t *instr;
- int result = -EINVAL, len, key;
-
- if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
- goto __return;
-
- if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
- goto __return;
- if (copy_from_user(&put, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
- result = -EFAULT;
- goto __return;
- }
- snd_instr_lock_ops(list);
- if (put.id.instr.std & 0xff000000) { /* private instrument */
- put.id.instr.std &= 0x00ffffff;
- put.id.instr.std |= (unsigned int)ev->source.client << 24;
- }
- if ((instr = snd_seq_instr_find(list, &put.id.instr, 1, 0))) {
- snd_seq_instr_free_use(list, instr);
- snd_instr_unlock_ops(list);
- result = -EBUSY;
- goto __return;
- }
- ops = instr_ops(ops, put.data.data.format);
- if (ops == NULL) {
- snd_instr_unlock_ops(list);
- goto __return;
- }
- len = ops->add_len;
- if (put.data.type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)
- len = sizeof(snd_seq_instr_t);
- instr = snd_seq_instr_new(len, atomic);
- if (instr == NULL) {
- snd_instr_unlock_ops(list);
- result = -ENOMEM;
- goto __return;
- }
- instr->ops = ops;
- instr->instr = put.id.instr;
- strlcpy(instr->name, put.data.name, sizeof(instr->name));
- instr->type = put.data.type;
- if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) {
- result = ops->put(ops->private_data,
- instr,
- (void __user *)ev->data.ext.ptr + sizeof(snd_seq_instr_header_t),
- ev->data.ext.len - sizeof(snd_seq_instr_header_t),
- atomic,
- put.cmd);
- if (result < 0) {
- snd_seq_instr_free(instr, atomic);
- snd_instr_unlock_ops(list);
- goto __return;
- }
- }
- key = compute_hash_instr_key(&instr->instr);
- spin_lock_irqsave(&list->lock, flags);
- instr->next = list->hash[key];
- list->hash[key] = instr;
- list->count++;
- spin_unlock_irqrestore(&list->lock, flags);
- snd_instr_unlock_ops(list);
- result = 0;
- __return:
- instr_result(ev, SNDRV_SEQ_EVENT_INSTR_PUT, result, atomic);
- return result;
-}
-
-static int instr_get(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_free(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- snd_seq_instr_header_t ifree;
- snd_seq_kinstr_t *instr, *prev;
- int result = -EINVAL;
- unsigned long flags;
- unsigned int hash;
-
- if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
- goto __return;
-
- if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
- goto __return;
- if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
- result = -EFAULT;
- goto __return;
- }
- if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_ALL ||
- ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE ||
- ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER) {
- result = snd_seq_instr_list_free_cond(list, &ifree, ev->dest.client, atomic);
- goto __return;
- }
- if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_SINGLE) {
- if (ifree.id.instr.std & 0xff000000) {
- ifree.id.instr.std &= 0x00ffffff;
- ifree.id.instr.std |= (unsigned int)ev->source.client << 24;
- }
- hash = compute_hash_instr_key(&ifree.id.instr);
- snd_instr_lock_ops(list);
- spin_lock_irqsave(&list->lock, flags);
- instr = list->hash[hash];
- prev = NULL;
- while (instr) {
- if (!compare_instr(&instr->instr, &ifree.id.instr, 1))
- goto __free_single;
- prev = instr;
- instr = instr->next;
- }
- result = -ENOENT;
- spin_unlock_irqrestore(&list->lock, flags);
- snd_instr_unlock_ops(list);
- goto __return;
-
- __free_single:
- if (prev) {
- prev->next = instr->next;
- } else {
- list->hash[hash] = instr->next;
- }
- if (instr->ops && instr->ops->notify)
- instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
- while (instr->use) {
- spin_unlock_irqrestore(&list->lock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- spin_lock_irqsave(&list->lock, flags);
- }
- spin_unlock_irqrestore(&list->lock, flags);
- result = snd_seq_instr_free(instr, atomic);
- snd_instr_unlock_ops(list);
- goto __return;
- }
-
- __return:
- instr_result(ev, SNDRV_SEQ_EVENT_INSTR_FREE, result, atomic);
- return result;
-}
-
-static int instr_list(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-static int instr_cluster(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int atomic, int hop)
-{
- return -ENXIO;
-}
-
-int snd_seq_instr_event(snd_seq_kinstr_ops_t *ops,
- snd_seq_kinstr_list_t *list,
- snd_seq_event_t *ev,
- int client,
- int atomic,
- int hop)
-{
- int direct = 0;
-
- snd_assert(ops != NULL && list != NULL && ev != NULL, return -EINVAL);
- if (snd_seq_ev_is_direct(ev)) {
- direct = 1;
- switch (ev->type) {
- case SNDRV_SEQ_EVENT_INSTR_BEGIN:
- return instr_begin(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_END:
- return instr_end(ops, list, ev, atomic, hop);
- }
- }
- if ((list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT) && !direct)
- return -EINVAL;
- switch (ev->type) {
- case SNDRV_SEQ_EVENT_INSTR_INFO:
- return instr_info(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_FINFO:
- return instr_format_info(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_RESET:
- return instr_reset(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_STATUS:
- return instr_status(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_PUT:
- return instr_put(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_GET:
- return instr_get(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_FREE:
- return instr_free(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_LIST:
- return instr_list(ops, list, ev, atomic, hop);
- case SNDRV_SEQ_EVENT_INSTR_CLUSTER:
- return instr_cluster(ops, list, ev, atomic, hop);
- }
- return -EINVAL;
-}
-
-/*
- * Init part
- */
-
-static int __init alsa_seq_instr_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_seq_instr_exit(void)
-{
-}
-
-module_init(alsa_seq_instr_init)
-module_exit(alsa_seq_instr_exit)
-
-EXPORT_SYMBOL(snd_seq_instr_list_new);
-EXPORT_SYMBOL(snd_seq_instr_list_free);
-EXPORT_SYMBOL(snd_seq_instr_list_free_cond);
-EXPORT_SYMBOL(snd_seq_instr_find);
-EXPORT_SYMBOL(snd_seq_instr_free_use);
-EXPORT_SYMBOL(snd_seq_instr_event);
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index b09cee058fa..3b693e924db 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -19,7 +19,7 @@
*
*/
-#include <sound/driver.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "seq_lock.h"
@@ -31,18 +31,19 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
int max_count = 5 * HZ;
if (atomic_read(lockp) < 0) {
- printk(KERN_WARNING "seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
+ pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
return;
}
while (atomic_read(lockp) > 0) {
if (max_count == 0) {
- snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
+ pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
break;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
max_count--;
}
}
+EXPORT_SYMBOL(snd_use_lock_sync_helper);
+
#endif
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index d4d7d326c4b..1e206de0c2d 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -1,7 +1,7 @@
/*
* ALSA sequencer Memory Manager
* Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@suse.cz>
+ * Jaroslav Kysela <perex@perex.cz>
* 2000 by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -20,8 +20,8 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
@@ -32,16 +32,12 @@
#include "seq_info.h"
#include "seq_lock.h"
-/* semaphore in struct file record */
-#define semaphore_of(fp) ((fp)->f_dentry->d_inode->i_sem)
-
-
-static inline int snd_seq_pool_available(pool_t *pool)
+static inline int snd_seq_pool_available(struct snd_seq_pool *pool)
{
return pool->total_elements - atomic_read(&pool->counter);
}
-static inline int snd_seq_output_ok(pool_t *pool)
+static inline int snd_seq_output_ok(struct snd_seq_pool *pool)
{
return snd_seq_pool_available(pool) >= pool->room;
}
@@ -72,7 +68,7 @@ static inline int snd_seq_output_ok(pool_t *pool)
* call dump function to expand external data.
*/
-static int get_var_len(const snd_seq_event_t *event)
+static int get_var_len(const struct snd_seq_event *event)
{
if ((event->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
return -EINVAL;
@@ -80,17 +76,18 @@ static int get_var_len(const snd_seq_event_t *event)
return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
}
-int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t func, void *private_data)
+int snd_seq_dump_var_event(const struct snd_seq_event *event,
+ snd_seq_dump_func_t func, void *private_data)
{
int len, err;
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
if ((len = get_var_len(event)) <= 0)
return len;
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
char buf[32];
- char __user *curptr = (char __user *)event->data.ext.ptr;
+ char __user *curptr = (char __force __user *)event->data.ext.ptr;
while (len > 0) {
int size = sizeof(buf);
if (len < size)
@@ -108,9 +105,9 @@ int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t fun
return func(private_data, event->data.ext.ptr, len);
}
- cell = (snd_seq_event_cell_t*)event->data.ext.ptr;
+ cell = (struct snd_seq_event_cell *)event->data.ext.ptr;
for (; len > 0 && cell; cell = cell->next) {
- int size = sizeof(snd_seq_event_t);
+ int size = sizeof(struct snd_seq_event);
if (len < size)
size = len;
err = func(private_data, &cell->event, size);
@@ -121,6 +118,8 @@ int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t fun
return 0;
}
+EXPORT_SYMBOL(snd_seq_dump_var_event);
+
/*
* exported:
@@ -142,7 +141,8 @@ static int seq_copy_in_user(char __user **bufptr, const void *src, int size)
return 0;
}
-int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf, int in_kernel, int size_aligned)
+int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf,
+ int in_kernel, int size_aligned)
{
int len, newlen;
int err;
@@ -151,14 +151,14 @@ int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf,
return len;
newlen = len;
if (size_aligned > 0)
- newlen = ((len + size_aligned - 1) / size_aligned) * size_aligned;
+ newlen = roundup(len, size_aligned);
if (count < newlen)
return -EAGAIN;
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
if (! in_kernel)
return -EINVAL;
- if (copy_from_user(buf, (void __user *)event->data.ext.ptr, len))
+ if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len))
return -EFAULT;
return newlen;
}
@@ -169,32 +169,36 @@ int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf,
return err < 0 ? err : newlen;
}
+EXPORT_SYMBOL(snd_seq_expand_var_event);
/*
* release this cell, free extended data if available
*/
-static inline void free_cell(pool_t *pool, snd_seq_event_cell_t *cell)
+static inline void free_cell(struct snd_seq_pool *pool,
+ struct snd_seq_event_cell *cell)
{
cell->next = pool->free;
pool->free = cell;
atomic_dec(&pool->counter);
}
-void snd_seq_cell_free(snd_seq_event_cell_t * cell)
+void snd_seq_cell_free(struct snd_seq_event_cell * cell)
{
unsigned long flags;
- pool_t *pool;
+ struct snd_seq_pool *pool;
- snd_assert(cell != NULL, return);
+ if (snd_BUG_ON(!cell))
+ return;
pool = cell->pool;
- snd_assert(pool != NULL, return);
+ if (snd_BUG_ON(!pool))
+ return;
spin_lock_irqsave(&pool->lock, flags);
free_cell(pool, cell);
if (snd_seq_ev_is_variable(&cell->event)) {
if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
- snd_seq_event_cell_t *curp, *nextptr;
+ struct snd_seq_event_cell *curp, *nextptr;
curp = cell->event.data.ext.ptr;
for (; curp; curp = nextptr) {
nextptr = curp->next;
@@ -215,9 +219,11 @@ void snd_seq_cell_free(snd_seq_event_cell_t * cell)
/*
* allocate an event cell.
*/
-static int snd_seq_cell_alloc(pool_t *pool, snd_seq_event_cell_t **cellp, int nonblock, struct file *file)
+static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
+ struct snd_seq_event_cell **cellp,
+ int nonblock, struct file *file)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
unsigned long flags;
int err = -EAGAIN;
wait_queue_t wait;
@@ -230,7 +236,7 @@ static int snd_seq_cell_alloc(pool_t *pool, snd_seq_event_cell_t **cellp, int no
init_waitqueue_entry(&wait, current);
spin_lock_irqsave(&pool->lock, flags);
if (pool->ptr == NULL) { /* not initialized */
- snd_printd("seq: pool is not initialized\n");
+ pr_debug("ALSA: seq: pool is not initialized\n");
err = -EINVAL;
goto __error;
}
@@ -280,11 +286,13 @@ __error:
* if the event has external data, the data is decomposed to additional
* cells.
*/
-int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t **cellp, int nonblock, struct file *file)
+int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
+ struct snd_seq_event_cell **cellp, int nonblock,
+ struct file *file)
{
int ncells, err;
unsigned int extlen;
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
*cellp = NULL;
@@ -292,7 +300,7 @@ int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t
extlen = 0;
if (snd_seq_ev_is_variable(event)) {
extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
- ncells = (extlen + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
+ ncells = (extlen + sizeof(struct snd_seq_event) - 1) / sizeof(struct snd_seq_event);
}
if (ncells >= pool->total_elements)
return -ENOMEM;
@@ -309,18 +317,18 @@ int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t
int len = extlen;
int is_chained = event->data.ext.len & SNDRV_SEQ_EXT_CHAINED;
int is_usrptr = event->data.ext.len & SNDRV_SEQ_EXT_USRPTR;
- snd_seq_event_cell_t *src, *tmp, *tail;
+ struct snd_seq_event_cell *src, *tmp, *tail;
char *buf;
cell->event.data.ext.len = extlen | SNDRV_SEQ_EXT_CHAINED;
cell->event.data.ext.ptr = NULL;
- src = (snd_seq_event_cell_t*)event->data.ext.ptr;
+ src = (struct snd_seq_event_cell *)event->data.ext.ptr;
buf = (char *)event->data.ext.ptr;
tail = NULL;
while (ncells-- > 0) {
- int size = sizeof(snd_seq_event_t);
+ int size = sizeof(struct snd_seq_event);
if (len < size)
size = len;
err = snd_seq_cell_alloc(pool, &tmp, nonblock, file);
@@ -336,7 +344,7 @@ int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t
tmp->event = src->event;
src = src->next;
} else if (is_usrptr) {
- if (copy_from_user(&tmp->event, (char __user *)buf, size)) {
+ if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) {
err = -EFAULT;
goto __error;
}
@@ -358,7 +366,8 @@ __error:
/* poll wait */
-int snd_seq_pool_poll_wait(pool_t *pool, struct file *file, poll_table *wait)
+int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file,
+ poll_table *wait)
{
poll_wait(file, &pool->output_sleep, wait);
return snd_seq_output_ok(pool);
@@ -366,19 +375,20 @@ int snd_seq_pool_poll_wait(pool_t *pool, struct file *file, poll_table *wait)
/* allocate room specified number of events */
-int snd_seq_pool_init(pool_t *pool)
+int snd_seq_pool_init(struct snd_seq_pool *pool)
{
int cell;
- snd_seq_event_cell_t *cellptr;
+ struct snd_seq_event_cell *cellptr;
unsigned long flags;
- snd_assert(pool != NULL, return -EINVAL);
+ if (snd_BUG_ON(!pool))
+ return -EINVAL;
if (pool->ptr) /* should be atomic? */
return 0;
- pool->ptr = vmalloc(sizeof(snd_seq_event_cell_t) * pool->size);
+ pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
if (pool->ptr == NULL) {
- snd_printd("seq: malloc for sequencer events failed\n");
+ pr_debug("ALSA: seq: malloc for sequencer events failed\n");
return -ENOMEM;
}
@@ -402,13 +412,14 @@ int snd_seq_pool_init(pool_t *pool)
}
/* remove events */
-int snd_seq_pool_done(pool_t *pool)
+int snd_seq_pool_done(struct snd_seq_pool *pool)
{
unsigned long flags;
- snd_seq_event_cell_t *ptr;
+ struct snd_seq_event_cell *ptr;
int max_count = 5 * HZ;
- snd_assert(pool != NULL, return -EINVAL);
+ if (snd_BUG_ON(!pool))
+ return -EINVAL;
/* wait for closing all threads */
spin_lock_irqsave(&pool->lock, flags);
@@ -420,11 +431,10 @@ int snd_seq_pool_done(pool_t *pool)
while (atomic_read(&pool->counter) > 0) {
if (max_count == 0) {
- snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
+ pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
break;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
max_count--;
}
@@ -447,14 +457,14 @@ int snd_seq_pool_done(pool_t *pool)
/* init new memory pool */
-pool_t *snd_seq_pool_new(int poolsize)
+struct snd_seq_pool *snd_seq_pool_new(int poolsize)
{
- pool_t *pool;
+ struct snd_seq_pool *pool;
/* create pool block */
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
if (pool == NULL) {
- snd_printd("seq: malloc failed for pool\n");
+ pr_debug("ALSA: seq: malloc failed for pool\n");
return NULL;
}
spin_lock_init(&pool->lock);
@@ -473,9 +483,9 @@ pool_t *snd_seq_pool_new(int poolsize)
}
/* remove memory pool */
-int snd_seq_pool_delete(pool_t **ppool)
+int snd_seq_pool_delete(struct snd_seq_pool **ppool)
{
- pool_t *pool = *ppool;
+ struct snd_seq_pool *pool = *ppool;
*ppool = NULL;
if (pool == NULL)
@@ -498,7 +508,8 @@ void __exit snd_sequencer_memory_done(void)
/* exported to seq_clientmgr.c */
-void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t *pool, char *space)
+void snd_seq_info_pool(struct snd_info_buffer *buffer,
+ struct snd_seq_pool *pool, char *space)
{
if (pool == NULL)
return;
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 6c4dde5d3d6..4a2ec779b8a 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -24,23 +24,23 @@
#include <sound/seq_kernel.h>
#include <linux/poll.h>
-typedef struct pool pool_t;
+struct snd_info_buffer;
/* container for sequencer event (internal use) */
-typedef struct snd_seq_event_cell_t {
- snd_seq_event_t event;
- pool_t *pool; /* used pool */
- struct snd_seq_event_cell_t *next; /* next cell */
-} snd_seq_event_cell_t;
+struct snd_seq_event_cell {
+ struct snd_seq_event event;
+ struct snd_seq_pool *pool; /* used pool */
+ struct snd_seq_event_cell *next; /* next cell */
+};
-/* design note: the pool is a contigious block of memory, if we dynamicly
+/* design note: the pool is a contiguous block of memory, if we dynamicly
want to add additional cells to the pool be better store this in another
pool as we need to know the base address of the pool when releasing
memory. */
-struct pool {
- snd_seq_event_cell_t *ptr; /* pointer to first event chunk */
- snd_seq_event_cell_t *free; /* pointer to the head of the free list */
+struct snd_seq_pool {
+ struct snd_seq_event_cell *ptr; /* pointer to first event chunk */
+ struct snd_seq_event_cell *free; /* pointer to the head of the free list */
int total_elements; /* pool size actually allocated */
atomic_t counter; /* cells free */
@@ -63,33 +63,34 @@ struct pool {
spinlock_t lock;
};
-extern void snd_seq_cell_free(snd_seq_event_cell_t* cell);
+void snd_seq_cell_free(struct snd_seq_event_cell *cell);
-int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t **cellp, int nonblock, struct file *file);
+int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
+ struct snd_seq_event_cell **cellp, int nonblock, struct file *file);
/* return number of unused (free) cells */
-static inline int snd_seq_unused_cells(pool_t *pool)
+static inline int snd_seq_unused_cells(struct snd_seq_pool *pool)
{
return pool ? pool->total_elements - atomic_read(&pool->counter) : 0;
}
/* return total number of allocated cells */
-static inline int snd_seq_total_cells(pool_t *pool)
+static inline int snd_seq_total_cells(struct snd_seq_pool *pool)
{
return pool ? pool->total_elements : 0;
}
/* init pool - allocate events */
-int snd_seq_pool_init(pool_t *pool);
+int snd_seq_pool_init(struct snd_seq_pool *pool);
/* done pool - free events */
-int snd_seq_pool_done(pool_t *pool);
+int snd_seq_pool_done(struct snd_seq_pool *pool);
/* create pool */
-pool_t *snd_seq_pool_new(int poolsize);
+struct snd_seq_pool *snd_seq_pool_new(int poolsize);
/* remove pool */
-int snd_seq_pool_delete(pool_t **pool);
+int snd_seq_pool_delete(struct snd_seq_pool **pool);
/* init memory */
int snd_sequencer_memory_init(void);
@@ -98,7 +99,9 @@ int snd_sequencer_memory_init(void);
void snd_sequencer_memory_done(void);
/* polling */
-int snd_seq_pool_poll_wait(pool_t *pool, struct file *file, poll_table *wait);
+int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, poll_table *wait);
+void snd_seq_info_pool(struct snd_info_buffer *buffer,
+ struct snd_seq_pool *pool, char *space);
#endif
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index b4674ae3bc3..a1fd77af605 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -1,7 +1,7 @@
/*
* Generic MIDI synth driver for ALSA sequencer
* Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@suse.cz>
+ * 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
@@ -26,13 +26,12 @@ Possible options for midisynth module:
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/seq_kernel.h>
@@ -40,7 +39,7 @@ Possible options for midisynth module:
#include <sound/seq_midi_event.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
MODULE_LICENSE("GPL");
static int output_buffer_size = PAGE_SIZE;
@@ -51,40 +50,40 @@ module_param(input_buffer_size, int, 0644);
MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
/* data for this midi synth driver */
-typedef struct {
- snd_card_t *card;
+struct seq_midisynth {
+ struct snd_card *card;
int device;
int subdevice;
- snd_rawmidi_file_t input_rfile;
- snd_rawmidi_file_t output_rfile;
+ struct snd_rawmidi_file input_rfile;
+ struct snd_rawmidi_file output_rfile;
int seq_client;
int seq_port;
- snd_midi_event_t *parser;
-} seq_midisynth_t;
+ struct snd_midi_event *parser;
+};
-typedef struct {
+struct seq_midisynth_client {
int seq_client;
int num_ports;
int ports_per_device[SNDRV_RAWMIDI_DEVICES];
- seq_midisynth_t *ports[SNDRV_RAWMIDI_DEVICES];
-} seq_midisynth_client_t;
+ struct seq_midisynth *ports[SNDRV_RAWMIDI_DEVICES];
+};
-static seq_midisynth_client_t *synths[SNDRV_CARDS];
-static DECLARE_MUTEX(register_mutex);
+static struct seq_midisynth_client *synths[SNDRV_CARDS];
+static DEFINE_MUTEX(register_mutex);
/* handle rawmidi input event (MIDI v1.0 stream) */
-static void snd_midi_input_event(snd_rawmidi_substream_t * substream)
+static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
{
- snd_rawmidi_runtime_t *runtime;
- seq_midisynth_t *msynth;
- snd_seq_event_t ev;
+ struct snd_rawmidi_runtime *runtime;
+ struct seq_midisynth *msynth;
+ struct snd_seq_event ev;
char buf[16], *pbuf;
long res, count;
if (substream == NULL)
return;
runtime = substream->runtime;
- msynth = (seq_midisynth_t *) runtime->private_data;
+ msynth = runtime->private_data;
if (msynth == NULL)
return;
memset(&ev, 0, sizeof(ev));
@@ -112,15 +111,17 @@ static void snd_midi_input_event(snd_rawmidi_substream_t * substream)
}
}
-static int dump_midi(snd_rawmidi_substream_t *substream, const char *buf, int count)
+static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count)
{
- snd_rawmidi_runtime_t *runtime;
+ struct snd_rawmidi_runtime *runtime;
int tmp;
- snd_assert(substream != NULL || buf != NULL, return -EINVAL);
+ if (snd_BUG_ON(!substream || !buf))
+ return -EINVAL;
runtime = substream->runtime;
if ((tmp = runtime->avail) < count) {
- snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp);
+ if (printk_ratelimit())
+ pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
return -ENOMEM;
}
if (snd_rawmidi_kernel_write(substream, buf, count) < count)
@@ -128,22 +129,23 @@ static int dump_midi(snd_rawmidi_substream_t *substream, const char *buf, int co
return 0;
}
-static int event_process_midi(snd_seq_event_t * ev, int direct,
+static int event_process_midi(struct snd_seq_event *ev, int direct,
void *private_data, int atomic, int hop)
{
- seq_midisynth_t *msynth = (seq_midisynth_t *) private_data;
+ struct seq_midisynth *msynth = private_data;
unsigned char msg[10]; /* buffer for constructing midi messages */
- snd_rawmidi_substream_t *substream;
+ struct snd_rawmidi_substream *substream;
int len;
- snd_assert(msynth != NULL, return -EINVAL);
+ if (snd_BUG_ON(!msynth))
+ return -EINVAL;
substream = msynth->output_rfile.output;
if (substream == NULL)
return -ENODEV;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
/* invalid event */
- snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
+ pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
}
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
@@ -161,8 +163,8 @@ static int event_process_midi(snd_seq_event_t * ev, int direct,
}
-static int snd_seq_midisynth_new(seq_midisynth_t *msynth,
- snd_card_t *card,
+static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
+ struct snd_card *card,
int device,
int subdevice)
{
@@ -175,16 +177,19 @@ static int snd_seq_midisynth_new(seq_midisynth_t *msynth,
}
/* open associated midi device for input */
-static int midisynth_subscribe(void *private_data, snd_seq_port_subscribe_t *info)
+static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe *info)
{
int err;
- seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
- snd_rawmidi_runtime_t *runtime;
- snd_rawmidi_params_t params;
+ struct seq_midisynth *msynth = private_data;
+ struct snd_rawmidi_runtime *runtime;
+ struct snd_rawmidi_params params;
/* open midi port */
- if ((err = snd_rawmidi_kernel_open(msynth->card->number, msynth->device, msynth->subdevice, SNDRV_RAWMIDI_LFLG_INPUT, &msynth->input_rfile)) < 0) {
- snd_printd("midi input open failed!!!\n");
+ if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
+ msynth->subdevice,
+ SNDRV_RAWMIDI_LFLG_INPUT,
+ &msynth->input_rfile)) < 0) {
+ pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
return err;
}
runtime = msynth->input_rfile.input->runtime;
@@ -203,31 +208,36 @@ static int midisynth_subscribe(void *private_data, snd_seq_port_subscribe_t *inf
}
/* close associated midi device for input */
-static int midisynth_unsubscribe(void *private_data, snd_seq_port_subscribe_t *info)
+static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscribe *info)
{
int err;
- seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
+ struct seq_midisynth *msynth = private_data;
- snd_assert(msynth->input_rfile.input != NULL, return -EINVAL);
+ if (snd_BUG_ON(!msynth->input_rfile.input))
+ return -EINVAL;
err = snd_rawmidi_kernel_release(&msynth->input_rfile);
return err;
}
/* open associated midi device for output */
-static int midisynth_use(void *private_data, snd_seq_port_subscribe_t *info)
+static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info)
{
int err;
- seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
- snd_rawmidi_params_t params;
+ struct seq_midisynth *msynth = private_data;
+ struct snd_rawmidi_params params;
/* open midi port */
- if ((err = snd_rawmidi_kernel_open(msynth->card->number, msynth->device, msynth->subdevice, SNDRV_RAWMIDI_LFLG_OUTPUT, &msynth->output_rfile)) < 0) {
- snd_printd("midi output open failed!!!\n");
+ if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
+ msynth->subdevice,
+ SNDRV_RAWMIDI_LFLG_OUTPUT,
+ &msynth->output_rfile)) < 0) {
+ pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
}
memset(&params, 0, sizeof(params));
params.avail_min = 1;
params.buffer_size = output_buffer_size;
+ params.no_active_sensing = 1;
if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
snd_rawmidi_kernel_release(&msynth->output_rfile);
return err;
@@ -237,20 +247,18 @@ static int midisynth_use(void *private_data, snd_seq_port_subscribe_t *info)
}
/* close associated midi device for output */
-static int midisynth_unuse(void *private_data, snd_seq_port_subscribe_t *info)
+static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
- seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
- unsigned char buf = 0xff; /* MIDI reset */
+ struct seq_midisynth *msynth = private_data;
- snd_assert(msynth->output_rfile.output != NULL, return -EINVAL);
- /* sending single MIDI reset message to shut the device up */
- snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1);
+ if (snd_BUG_ON(!msynth->output_rfile.output))
+ return -EINVAL;
snd_rawmidi_drain_output(msynth->output_rfile.output);
return snd_rawmidi_kernel_release(&msynth->output_rfile);
}
/* delete given midi synth port */
-static void snd_seq_midisynth_delete(seq_midisynth_t *msynth)
+static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
{
if (msynth == NULL)
return;
@@ -264,38 +272,24 @@ static void snd_seq_midisynth_delete(seq_midisynth_t *msynth)
snd_midi_event_free(msynth->parser);
}
-/* set our client name */
-static int set_client_name(seq_midisynth_client_t *client, snd_card_t *card,
- snd_rawmidi_info_t *rmidi)
-{
- snd_seq_client_info_t cinfo;
- const char *name;
-
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.client = client->seq_client;
- cinfo.type = KERNEL_CLIENT;
- name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI";
- strlcpy(cinfo.name, name, sizeof(cinfo.name));
- return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
-}
-
/* register new midi synth port */
static int
-snd_seq_midisynth_register_port(snd_seq_device_t *dev)
+snd_seq_midisynth_register_port(struct snd_seq_device *dev)
{
- seq_midisynth_client_t *client;
- seq_midisynth_t *msynth, *ms;
- snd_seq_port_info_t *port;
- snd_rawmidi_info_t *info;
+ struct seq_midisynth_client *client;
+ struct seq_midisynth *msynth, *ms;
+ struct snd_seq_port_info *port;
+ struct snd_rawmidi_info *info;
+ struct snd_rawmidi *rmidi = dev->private_data;
int newclient = 0;
unsigned int p, ports;
- snd_seq_client_callback_t callbacks;
- snd_seq_port_callback_t pcallbacks;
- snd_card_t *card = dev->card;
+ struct snd_seq_port_callback pcallbacks;
+ struct snd_card *card = dev->card;
int device = dev->device;
unsigned int input_count = 0, output_count = 0;
- snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
+ if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
+ return -EINVAL;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (! info)
return -ENOMEM;
@@ -318,31 +312,29 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
ports = 256 / SNDRV_RAWMIDI_DEVICES;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
client = synths[card->number];
if (client == NULL) {
newclient = 1;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL) {
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
kfree(info);
return -ENOMEM;
}
- memset(&callbacks, 0, sizeof(callbacks));
- callbacks.private_data = client;
- callbacks.allow_input = callbacks.allow_output = 1;
- client->seq_client = snd_seq_create_kernel_client(card, 0, &callbacks);
+ client->seq_client =
+ snd_seq_create_kernel_client(
+ card, 0, "%s", card->shortname[0] ?
+ (const char *)card->shortname : "External MIDI");
if (client->seq_client < 0) {
kfree(client);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
kfree(info);
return -ENOMEM;
}
- set_client_name(client, card, info);
- } else if (device == 0)
- set_client_name(client, card, info); /* use the first device's name */
+ }
- msynth = kcalloc(ports, sizeof(seq_midisynth_t), GFP_KERNEL);
+ msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL);
port = kmalloc(sizeof(*port), GFP_KERNEL);
if (msynth == NULL || port == NULL)
goto __nomem;
@@ -370,13 +362,13 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if (! port->name[0]) {
if (info->name[0]) {
if (ports > 1)
- snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
+ snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
else
snprintf(port->name, sizeof(port->name), "%s", info->name);
} else {
/* last resort */
if (ports > 1)
- sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
+ sprintf(port->name, "MIDI %d-%d-%u", card->number, device, p);
else
sprintf(port->name, "MIDI %d-%d", card->number, device);
}
@@ -388,7 +380,9 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_HARDWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
port->midi_channels = 16;
memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE;
@@ -399,6 +393,8 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
pcallbacks.unuse = midisynth_unuse;
pcallbacks.event_input = event_process_midi;
port->kernel = &pcallbacks;
+ if (rmidi->ops && rmidi->ops->get_port_info)
+ rmidi->ops->get_port_info(rmidi, p, port);
if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
goto __nomem;
ms->seq_client = client->seq_client;
@@ -409,7 +405,7 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
client->num_ports++;
if (newclient)
synths[card->number] = client;
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
kfree(info);
kfree(port);
return 0; /* success */
@@ -426,48 +422,46 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
}
kfree(info);
kfree(port);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -ENOMEM;
}
/* release midi synth port */
static int
-snd_seq_midisynth_unregister_port(snd_seq_device_t *dev)
+snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
{
- seq_midisynth_client_t *client;
- seq_midisynth_t *msynth;
- snd_card_t *card = dev->card;
+ struct seq_midisynth_client *client;
+ struct seq_midisynth *msynth;
+ struct snd_card *card = dev->card;
int device = dev->device, p, ports;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
client = synths[card->number];
if (client == NULL || client->ports[device] == NULL) {
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -ENODEV;
}
ports = client->ports_per_device[device];
client->ports_per_device[device] = 0;
msynth = client->ports[device];
client->ports[device] = NULL;
- snd_runtime_check(msynth != NULL || ports <= 0, goto __skip);
for (p = 0; p < ports; p++)
snd_seq_midisynth_delete(&msynth[p]);
kfree(msynth);
- __skip:
client->num_ports--;
if (client->num_ports <= 0) {
snd_seq_delete_kernel_client(client->seq_client);
synths[card->number] = NULL;
kfree(client);
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return 0;
}
static int __init alsa_seq_midi_init(void)
{
- static snd_seq_dev_ops_t ops = {
+ static struct snd_seq_dev_ops ops = {
snd_seq_midisynth_register_port,
snd_seq_midisynth_unregister_port,
};
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 35fe8a7e34b..9b6470cdcf2 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -29,10 +29,10 @@
* code in here. If there is it should be reported as a bug.
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
#include <sound/seq_midi_emul.h>
@@ -44,17 +44,25 @@ MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI emulation."
MODULE_LICENSE("GPL");
/* Prototypes for static functions */
-static void note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int vel);
-static void do_control(snd_midi_op_t *ops, void *private,
- snd_midi_channel_set_t *chset, snd_midi_channel_t *chan,
+static void note_off(struct snd_midi_op *ops, void *drv,
+ struct snd_midi_channel *chan,
+ int note, int vel);
+static void do_control(struct snd_midi_op *ops, void *private,
+ struct snd_midi_channel_set *chset,
+ struct snd_midi_channel *chan,
int control, int value);
-static void rpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset);
-static void nrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset);
-static void sysex(snd_midi_op_t *ops, void *private, unsigned char *sysex, int len, snd_midi_channel_set_t *chset);
-static void all_sounds_off(snd_midi_op_t *ops, void *private, snd_midi_channel_t *chan);
-static void all_notes_off(snd_midi_op_t *ops, void *private, snd_midi_channel_t *chan);
-static void snd_midi_reset_controllers(snd_midi_channel_t *chan);
-static void reset_all_channels(snd_midi_channel_set_t *chset);
+static void rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
+ struct snd_midi_channel_set *chset);
+static void nrpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
+ struct snd_midi_channel_set *chset);
+static void sysex(struct snd_midi_op *ops, void *private, unsigned char *sysex,
+ int len, struct snd_midi_channel_set *chset);
+static void all_sounds_off(struct snd_midi_op *ops, void *private,
+ struct snd_midi_channel *chan);
+static void all_notes_off(struct snd_midi_op *ops, void *private,
+ struct snd_midi_channel *chan);
+static void snd_midi_reset_controllers(struct snd_midi_channel *chan);
+static void reset_all_channels(struct snd_midi_channel_set *chset);
/*
@@ -63,7 +71,7 @@ static void reset_all_channels(snd_midi_channel_set_t *chset);
* such as GM, GS and XG.
* There modes that this module will run in are:
* Generic MIDI - no interpretation at all, it will just save current values
- * of controlers etc.
+ * of controllers etc.
* GM - You can use all gm_ prefixed elements of chan. Controls, RPN, NRPN,
* SysEx will be interpreded as defined in General Midi.
* GS - You can use all gs_ prefixed elements of chan. Codes for GS will be
@@ -72,15 +80,16 @@ static void reset_all_channels(snd_midi_channel_set_t *chset);
* be interpreted.
*/
void
-snd_midi_process_event(snd_midi_op_t *ops,
- snd_seq_event_t *ev, snd_midi_channel_set_t *chanset)
+snd_midi_process_event(struct snd_midi_op *ops,
+ struct snd_seq_event *ev,
+ struct snd_midi_channel_set *chanset)
{
- snd_midi_channel_t *chan;
+ struct snd_midi_channel *chan;
void *drv;
int dest_channel = 0;
if (ev == NULL || chanset == NULL) {
- snd_printd("ev or chanbase NULL (snd_midi_process_event)\n");
+ pr_debug("ALSA: seq_midi_emul: ev or chanbase NULL (snd_midi_process_event)\n");
return;
}
if (chanset->channels == NULL)
@@ -89,7 +98,8 @@ snd_midi_process_event(snd_midi_op_t *ops,
if (snd_seq_ev_is_channel_type(ev)) {
dest_channel = ev->data.note.channel;
if (dest_channel >= chanset->max_channels) {
- snd_printd("dest channel is %d, max is %d\n", dest_channel, chanset->max_channels);
+ pr_debug("ALSA: seq_midi_emul: dest channel is %d, max is %d\n",
+ dest_channel, chanset->max_channels);
return;
}
}
@@ -166,7 +176,7 @@ snd_midi_process_event(snd_midi_op_t *ops,
ev->data.control.value);
break;
case SNDRV_SEQ_EVENT_NONREGPARAM:
- /* Break it back into its controler values */
+ /* Break it back into its controller values */
chan->param_type = SNDRV_MIDI_PARAM_TYPE_NONREGISTERED;
chan->control[MIDI_CTL_MSB_DATA_ENTRY]
= (ev->data.control.value >> 7) & 0x7f;
@@ -179,7 +189,7 @@ snd_midi_process_event(snd_midi_op_t *ops,
nrpn(ops, drv, chan, chanset);
break;
case SNDRV_SEQ_EVENT_REGPARAM:
- /* Break it back into its controler values */
+ /* Break it back into its controller values */
chan->param_type = SNDRV_MIDI_PARAM_TYPE_REGISTERED;
chan->control[MIDI_CTL_MSB_DATA_ENTRY]
= (ev->data.control.value >> 7) & 0x7f;
@@ -219,17 +229,10 @@ snd_midi_process_event(snd_midi_op_t *ops,
case SNDRV_SEQ_EVENT_PORT_START:
case SNDRV_SEQ_EVENT_PORT_EXIT:
case SNDRV_SEQ_EVENT_PORT_CHANGE:
- case SNDRV_SEQ_EVENT_SAMPLE:
- case SNDRV_SEQ_EVENT_SAMPLE_START:
- case SNDRV_SEQ_EVENT_SAMPLE_STOP:
- case SNDRV_SEQ_EVENT_SAMPLE_FREQ:
- case SNDRV_SEQ_EVENT_SAMPLE_VOLUME:
- case SNDRV_SEQ_EVENT_SAMPLE_LOOP:
- case SNDRV_SEQ_EVENT_SAMPLE_POSITION:
case SNDRV_SEQ_EVENT_ECHO:
not_yet:
default:
- /*snd_printd("Unimplemented event %d\n", ev->type);*/
+ /*pr_debug("ALSA: seq_midi_emul: Unimplemented event %d\n", ev->type);*/
break;
}
}
@@ -239,7 +242,8 @@ snd_midi_process_event(snd_midi_op_t *ops,
* release note
*/
static void
-note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int vel)
+note_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
+ int note, int vel)
{
if (chan->gm_hold) {
/* Hold this note until pedal is turned off */
@@ -256,12 +260,12 @@ note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int
}
/*
- * Do all driver independent operations for this controler and pass
+ * Do all driver independent operations for this controller and pass
* events that need to take place immediately to the driver.
*/
static void
-do_control(snd_midi_op_t *ops, void *drv, snd_midi_channel_set_t *chset,
- snd_midi_channel_t *chan, int control, int value)
+do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chset,
+ struct snd_midi_channel *chan, int control, int value)
{
int i;
@@ -376,7 +380,7 @@ do_control(snd_midi_op_t *ops, void *drv, snd_midi_channel_set_t *chset,
* initialize the MIDI status
*/
void
-snd_midi_channel_set_clear(snd_midi_channel_set_t *chset)
+snd_midi_channel_set_clear(struct snd_midi_channel_set *chset)
{
int i;
@@ -384,7 +388,7 @@ snd_midi_channel_set_clear(snd_midi_channel_set_t *chset)
chset->gs_master_volume = 127;
for (i = 0; i < chset->max_channels; i++) {
- snd_midi_channel_t *chan = chset->channels + i;
+ struct snd_midi_channel *chan = chset->channels + i;
memset(chan->note, 0, sizeof(chan->note));
chan->midi_aftertouch = 0;
@@ -407,8 +411,8 @@ snd_midi_channel_set_clear(snd_midi_channel_set_t *chset)
* Process a rpn message.
*/
static void
-rpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan,
- snd_midi_channel_set_t *chset)
+rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
+ struct snd_midi_channel_set *chset)
{
int type;
int val;
@@ -447,8 +451,8 @@ rpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan,
* Process an nrpn message.
*/
static void
-nrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan,
- snd_midi_channel_set_t *chset)
+nrpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan,
+ struct snd_midi_channel_set *chset)
{
/* parse XG NRPNs here if possible */
if (ops->nrpn)
@@ -475,7 +479,8 @@ get_channel(unsigned char cmd)
* Process a sysex message.
*/
static void
-sysex(snd_midi_op_t *ops, void *private, unsigned char *buf, int len, snd_midi_channel_set_t *chset)
+sysex(struct snd_midi_op *ops, void *private, unsigned char *buf, int len,
+ struct snd_midi_channel_set *chset)
{
/* GM on */
static unsigned char gm_on_macro[] = {
@@ -588,7 +593,7 @@ sysex(snd_midi_op_t *ops, void *private, unsigned char *buf, int len, snd_midi_c
* all sound off
*/
static void
-all_sounds_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
+all_sounds_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan)
{
int n;
@@ -606,7 +611,7 @@ all_sounds_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
* all notes off
*/
static void
-all_notes_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
+all_notes_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan)
{
int n;
@@ -621,12 +626,12 @@ all_notes_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
/*
* Initialise a single midi channel control block.
*/
-static void snd_midi_channel_init(snd_midi_channel_t *p, int n)
+static void snd_midi_channel_init(struct snd_midi_channel *p, int n)
{
if (p == NULL)
return;
- memset(p, 0, sizeof(snd_midi_channel_t));
+ memset(p, 0, sizeof(struct snd_midi_channel));
p->private = NULL;
p->number = n;
@@ -642,12 +647,12 @@ static void snd_midi_channel_init(snd_midi_channel_t *p, int n)
/*
* Allocate and initialise a set of midi channel control blocks.
*/
-static snd_midi_channel_t *snd_midi_channel_init_set(int n)
+static struct snd_midi_channel *snd_midi_channel_init_set(int n)
{
- snd_midi_channel_t *chan;
+ struct snd_midi_channel *chan;
int i;
- chan = kmalloc(n * sizeof(snd_midi_channel_t), GFP_KERNEL);
+ chan = kmalloc(n * sizeof(struct snd_midi_channel), GFP_KERNEL);
if (chan) {
for (i = 0; i < n; i++)
snd_midi_channel_init(chan+i, i);
@@ -660,11 +665,11 @@ static snd_midi_channel_t *snd_midi_channel_init_set(int n)
* reset all midi channels
*/
static void
-reset_all_channels(snd_midi_channel_set_t *chset)
+reset_all_channels(struct snd_midi_channel_set *chset)
{
int ch;
for (ch = 0; ch < chset->max_channels; ch++) {
- snd_midi_channel_t *chan = chset->channels + ch;
+ struct snd_midi_channel *chan = chset->channels + ch;
snd_midi_reset_controllers(chan);
chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */
chan->gm_rpn_fine_tuning = 0;
@@ -681,9 +686,9 @@ reset_all_channels(snd_midi_channel_set_t *chset)
/*
* Allocate and initialise a midi channel set.
*/
-snd_midi_channel_set_t *snd_midi_channel_alloc_set(int n)
+struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n)
{
- snd_midi_channel_set_t *chset;
+ struct snd_midi_channel_set *chset;
chset = kmalloc(sizeof(*chset), GFP_KERNEL);
if (chset) {
@@ -697,7 +702,7 @@ snd_midi_channel_set_t *snd_midi_channel_alloc_set(int n)
/*
* Reset the midi controllers on a particular channel to default values.
*/
-static void snd_midi_reset_controllers(snd_midi_channel_t *chan)
+static void snd_midi_reset_controllers(struct snd_midi_channel *chan)
{
memset(chan->control, 0, sizeof(chan->control));
chan->gm_volume = 127;
@@ -709,7 +714,7 @@ static void snd_midi_reset_controllers(snd_midi_channel_t *chan)
/*
* Free a midi channel set.
*/
-void snd_midi_channel_free_set(snd_midi_channel_set_t *chset)
+void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)
{
if (chset == NULL)
return;
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index 2dc1aecfb42..37db7ba492a 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -2,7 +2,7 @@
* MIDI byte <-> sequencer event coder
*
* Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>,
- * Jaroslav Kysela <perex@suse.cz>
+ * 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
@@ -19,90 +19,89 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
#include <sound/seq_midi_event.h>
#include <sound/asoundef.h>
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder");
MODULE_LICENSE("GPL");
-/* queue type */
-/* from 0 to 7 are normal commands (note off, on, etc.) */
-#define ST_NOTEOFF 0
-#define ST_NOTEON 1
+/* event type, index into status_event[] */
+/* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */
+#define ST_INVALID 7
#define ST_SPECIAL 8
#define ST_SYSEX ST_SPECIAL
/* from 8 to 15 are events for 0xf0-0xf7 */
-/* status event types */
-typedef void (*event_encode_t)(snd_midi_event_t *dev, snd_seq_event_t *ev);
-typedef void (*event_decode_t)(snd_seq_event_t *ev, unsigned char *buf);
-
/*
* prototypes
*/
-static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
-static void note_decode(snd_seq_event_t *ev, unsigned char *buf);
-static void one_param_decode(snd_seq_event_t *ev, unsigned char *buf);
-static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf);
-static void two_param_decode(snd_seq_event_t *ev, unsigned char *buf);
-static void songpos_decode(snd_seq_event_t *ev, unsigned char *buf);
+static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
+static void note_decode(struct snd_seq_event *ev, unsigned char *buf);
+static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf);
+static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf);
+static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf);
+static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf);
/*
* event list
*/
-static struct status_event_list_t {
+static struct status_event_list {
int event;
int qlen;
- event_encode_t encode;
- event_decode_t decode;
+ void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev);
+ void (*decode)(struct snd_seq_event *ev, unsigned char *buf);
} status_event[] = {
- /* 0x80 - 0xf0 */
- {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
- {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
- {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
- {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
- {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
- {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode},
- {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode},
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */
+ /* 0x80 - 0xef */
+ {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
+ {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
+ {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
+ {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
+ {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
+ {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode},
+ {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode},
+ /* invalid */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL},
/* 0xf0 - 0xff */
- {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
- {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
- {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
- {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */
- {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */
- {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */
- {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */
- {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */
- {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
- {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */
- {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
- {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
+ {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
+ {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
+ {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
+ {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf4 */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf5 */
+ {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf7 */
+ {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf9 */
+ {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */
+ {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */
+ {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
+ {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xfd */
+ {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
+ {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
};
-static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
-static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev);
+static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len,
+ struct snd_seq_event *ev);
+static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, int count,
+ struct snd_seq_event *ev);
-static struct extra_event_list_t {
+static struct extra_event_list {
int event;
- int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
+ int (*decode)(struct snd_midi_event *dev, unsigned char *buf, int len,
+ struct snd_seq_event *ev);
} extra_event[] = {
{SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
@@ -113,9 +112,9 @@ static struct extra_event_list_t {
* new/delete record
*/
-int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev)
+int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev)
{
- snd_midi_event_t *dev;
+ struct snd_midi_event *dev;
*rdev = NULL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -130,12 +129,13 @@ int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev)
}
dev->bufsize = bufsize;
dev->lastcmd = 0xff;
+ dev->type = ST_INVALID;
spin_lock_init(&dev->lock);
*rdev = dev;
return 0;
}
-void snd_midi_event_free(snd_midi_event_t *dev)
+void snd_midi_event_free(struct snd_midi_event *dev)
{
if (dev != NULL) {
kfree(dev->buf);
@@ -146,14 +146,14 @@ void snd_midi_event_free(snd_midi_event_t *dev)
/*
* initialize record
*/
-static inline void reset_encode(snd_midi_event_t *dev)
+static inline void reset_encode(struct snd_midi_event *dev)
{
dev->read = 0;
dev->qlen = 0;
- dev->type = 0;
+ dev->type = ST_INVALID;
}
-void snd_midi_event_reset_encode(snd_midi_event_t *dev)
+void snd_midi_event_reset_encode(struct snd_midi_event *dev)
{
unsigned long flags;
@@ -162,7 +162,7 @@ void snd_midi_event_reset_encode(snd_midi_event_t *dev)
spin_unlock_irqrestore(&dev->lock, flags);
}
-void snd_midi_event_reset_decode(snd_midi_event_t *dev)
+void snd_midi_event_reset_decode(struct snd_midi_event *dev)
{
unsigned long flags;
@@ -172,14 +172,14 @@ void snd_midi_event_reset_decode(snd_midi_event_t *dev)
}
#if 0
-void snd_midi_event_init(snd_midi_event_t *dev)
+void snd_midi_event_init(struct snd_midi_event *dev)
{
snd_midi_event_reset_encode(dev);
snd_midi_event_reset_decode(dev);
}
#endif /* 0 */
-void snd_midi_event_no_status(snd_midi_event_t *dev, int on)
+void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
{
dev->nostat = on ? 1 : 0;
}
@@ -188,7 +188,7 @@ void snd_midi_event_no_status(snd_midi_event_t *dev, int on)
* resize buffer
*/
#if 0
-int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize)
+int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize)
{
unsigned char *new_buf, *old_buf;
unsigned long flags;
@@ -213,7 +213,8 @@ int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize)
* read bytes and encode to sequencer event if finished
* return the size of encoded bytes
*/
-long snd_midi_event_encode(snd_midi_event_t *dev, unsigned char *buf, long count, snd_seq_event_t *ev)
+long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count,
+ struct snd_seq_event *ev)
{
long result = 0;
int rc;
@@ -238,7 +239,8 @@ long snd_midi_event_encode(snd_midi_event_t *dev, unsigned char *buf, long count
* 0 data is not finished
* negative for error
*/
-int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev)
+int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
+ struct snd_seq_event *ev)
{
int rc = 0;
unsigned long flags;
@@ -250,29 +252,31 @@ int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev
ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
- return 1;
+ return ev->type != SNDRV_SEQ_EVENT_NONE;
}
spin_lock_irqsave(&dev->lock, flags);
- if (dev->qlen > 0) {
- /* rest of command */
- dev->buf[dev->read++] = c;
- if (dev->type != ST_SYSEX)
- dev->qlen--;
- } else {
+ if ((c & 0x80) &&
+ (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
/* new command */
+ dev->buf[0] = c;
+ if ((c & 0xf0) == 0xf0) /* system messages */
+ dev->type = (c & 0x0f) + ST_SPECIAL;
+ else
+ dev->type = (c >> 4) & 0x07;
dev->read = 1;
- if (c & 0x80) {
- dev->buf[0] = c;
- if ((c & 0xf0) == 0xf0) /* special events */
- dev->type = (c & 0x0f) + ST_SPECIAL;
- else
- dev->type = (c >> 4) & 0x07;
- dev->qlen = status_event[dev->type].qlen;
- } else {
- /* process this byte as argument */
+ dev->qlen = status_event[dev->type].qlen;
+ } else {
+ if (dev->qlen > 0) {
+ /* rest of command */
dev->buf[dev->read++] = c;
+ if (dev->type != ST_SYSEX)
+ dev->qlen--;
+ } else {
+ /* running status */
+ dev->buf[1] = c;
dev->qlen = status_event[dev->type].qlen - 1;
+ dev->read = 2;
}
}
if (dev->qlen == 0) {
@@ -281,6 +285,8 @@ int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev
ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
if (status_event[dev->type].encode) /* set data values */
status_event[dev->type].encode(dev, ev);
+ if (dev->type >= ST_SPECIAL)
+ dev->type = ST_INVALID;
rc = 1;
} else if (dev->type == ST_SYSEX) {
if (c == MIDI_CMD_COMMON_SYSEX_END ||
@@ -303,7 +309,7 @@ int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev
}
/* encode note event */
-static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.note.channel = dev->buf[0] & 0x0f;
ev->data.note.note = dev->buf[1];
@@ -311,21 +317,21 @@ static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
}
/* encode one parameter controls */
-static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.control.channel = dev->buf[0] & 0x0f;
ev->data.control.value = dev->buf[1];
}
/* encode pitch wheel change */
-static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.control.channel = dev->buf[0] & 0x0f;
ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
}
/* encode midi control change */
-static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.control.channel = dev->buf[0] & 0x0f;
ev->data.control.param = dev->buf[1];
@@ -333,13 +339,13 @@ static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
}
/* encode one parameter value*/
-static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.control.value = dev->buf[1];
}
/* encode song position */
-static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
+static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
{
ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
}
@@ -348,7 +354,8 @@ static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
* decode from a sequencer event to midi bytes
* return the size of decoded midi events
*/
-long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, snd_seq_event_t *ev)
+long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count,
+ struct snd_seq_event *ev)
{
unsigned int cmd, type;
@@ -404,20 +411,20 @@ long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count
/* decode note event */
-static void note_decode(snd_seq_event_t *ev, unsigned char *buf)
+static void note_decode(struct snd_seq_event *ev, unsigned char *buf)
{
buf[0] = ev->data.note.note & 0x7f;
buf[1] = ev->data.note.velocity & 0x7f;
}
/* decode one parameter controls */
-static void one_param_decode(snd_seq_event_t *ev, unsigned char *buf)
+static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf)
{
buf[0] = ev->data.control.value & 0x7f;
}
/* decode pitch wheel change */
-static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf)
+static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf)
{
int value = ev->data.control.value + 8192;
buf[0] = value & 0x7f;
@@ -425,21 +432,22 @@ static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf)
}
/* decode midi control change */
-static void two_param_decode(snd_seq_event_t *ev, unsigned char *buf)
+static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf)
{
buf[0] = ev->data.control.param & 0x7f;
buf[1] = ev->data.control.value & 0x7f;
}
/* decode song position */
-static void songpos_decode(snd_seq_event_t *ev, unsigned char *buf)
+static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf)
{
buf[0] = ev->data.control.value & 0x7f;
buf[1] = (ev->data.control.value >> 7) & 0x7f;
}
/* decode 14bit control */
-static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev)
+static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf,
+ int count, struct snd_seq_event *ev)
{
unsigned char cmd;
int idx = 0;
@@ -476,7 +484,8 @@ static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int co
}
/* decode reg/nonreg param */
-static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev)
+static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
+ int count, struct snd_seq_event *ev)
{
unsigned char cmd;
char *cbytes;
@@ -496,10 +505,10 @@ static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int coun
if (dev->nostat && count < 12)
return -ENOMEM;
cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
- bytes[0] = ev->data.control.param & 0x007f;
- bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
- bytes[2] = ev->data.control.value & 0x007f;
- bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
+ bytes[0] = (ev->data.control.param & 0x3f80) >> 7;
+ bytes[1] = ev->data.control.param & 0x007f;
+ bytes[2] = (ev->data.control.value & 0x3f80) >> 7;
+ bytes[3] = ev->data.control.value & 0x007f;
if (cmd != dev->lastcmd && !dev->nostat) {
if (count < 9)
return -ENOMEM;
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 57ec31df0d1..794a341bf0e 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -1,7 +1,7 @@
/*
* ALSA sequencer Ports
* Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@suse.cz>
+ * Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,9 @@
*
*/
-#include <sound/driver.h>
#include <sound/core.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include "seq_system.h"
#include "seq_ports.h"
#include "seq_clientmgr.h"
@@ -56,16 +56,15 @@ much elements are in array.
*/
/* return pointer to port structure - port is locked if found */
-client_port_t *snd_seq_port_use_ptr(client_t *client, int num)
+struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
+ int num)
{
- struct list_head *p;
- client_port_t *port;
+ struct snd_seq_client_port *port;
if (client == NULL)
return NULL;
read_lock(&client->ports_lock);
- list_for_each(p, &client->ports_list_head) {
- port = list_entry(p, client_port_t, list);
+ list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
@@ -80,17 +79,16 @@ client_port_t *snd_seq_port_use_ptr(client_t *client, int num)
/* search for the next port - port is locked if found */
-client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t *pinfo)
+struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *client,
+ struct snd_seq_port_info *pinfo)
{
int num;
- struct list_head *p;
- client_port_t *port, *found;
+ struct snd_seq_client_port *port, *found;
num = pinfo->addr.port;
found = NULL;
read_lock(&client->ports_lock);
- list_for_each(p, &client->ports_list_head) {
- port = list_entry(p, client_port_t, list);
+ list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port < num)
continue;
if (port->addr.port == num) {
@@ -111,8 +109,8 @@ client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t
}
-/* initialize port_subs_info_t */
-static void port_subs_info_init(port_subs_info_t *grp)
+/* initialize snd_seq_port_subs_info */
+static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
{
INIT_LIST_HEAD(&grp->list_head);
grp->count = 0;
@@ -125,25 +123,26 @@ static void port_subs_info_init(port_subs_info_t *grp)
/* create a port, port number is returned (-1 on failure) */
-client_port_t *snd_seq_create_port(client_t *client, int port)
+struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
+ int port)
{
unsigned long flags;
- client_port_t *new_port;
- struct list_head *l;
+ struct snd_seq_client_port *new_port, *p;
int num = -1;
/* sanity check */
- snd_assert(client, return NULL);
+ if (snd_BUG_ON(!client))
+ return NULL;
if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
- snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
+ pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
return NULL;
}
/* create a new port */
new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
if (! new_port) {
- snd_printd("malloc failed for registering client port\n");
+ pr_debug("ALSA: seq: malloc failed for registering client port\n");
return NULL; /* failure, out of memory */
}
/* init port data */
@@ -156,38 +155,44 @@ client_port_t *snd_seq_create_port(client_t *client, int port)
port_subs_info_init(&new_port->c_dest);
num = port >= 0 ? port : 0;
- down(&client->ports_mutex);
+ mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
- list_for_each(l, &client->ports_list_head) {
- client_port_t *p = list_entry(l, client_port_t, list);
+ list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port > num)
break;
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
/* insert the new port */
- list_add_tail(&new_port->list, l);
+ list_add_tail(&new_port->list, &p->list);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
write_unlock_irqrestore(&client->ports_lock, flags);
- up(&client->ports_mutex);
+ mutex_unlock(&client->ports_mutex);
sprintf(new_port->name, "port-%d", num);
return new_port;
}
/* */
-enum group_type_t {
+enum group_type {
SRC_LIST, DEST_LIST
};
-static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp, snd_seq_port_subscribe_t *info, int send_ack);
-static int unsubscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp, snd_seq_port_subscribe_t *info, int send_ack);
+static int subscribe_port(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+ struct snd_seq_port_subscribe *info, int send_ack);
+static int unsubscribe_port(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+ struct snd_seq_port_subscribe *info, int send_ack);
-static client_port_t *get_client_port(snd_seq_addr_t *addr, client_t **cp)
+static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
+ struct snd_seq_client **cp)
{
- client_port_t *p;
+ struct snd_seq_client_port *p;
*cp = snd_seq_client_use_ptr(addr->client);
if (*cp) {
p = snd_seq_port_use_ptr(*cp, addr->port);
@@ -204,22 +209,23 @@ static client_port_t *get_client_port(snd_seq_addr_t *addr, client_t **cp)
* remove all subscribers on the list
* this is called from port_delete, for each src and dest list.
*/
-static void clear_subscriber_list(client_t *client, client_port_t *port,
- port_subs_info_t *grp, int grptype)
+static void clear_subscriber_list(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+ int grptype)
{
struct list_head *p, *n;
- down_write(&grp->list_mutex);
list_for_each_safe(p, n, &grp->list_head) {
- subscribers_t *subs;
- client_t *c;
- client_port_t *aport;
+ struct snd_seq_subscribers *subs;
+ struct snd_seq_client *c;
+ struct snd_seq_client_port *aport;
if (grptype == SRC_LIST) {
- subs = list_entry(p, subscribers_t, src_list);
+ subs = list_entry(p, struct snd_seq_subscribers, src_list);
aport = get_client_port(&subs->info.dest, &c);
} else {
- subs = list_entry(p, subscribers_t, dest_list);
+ subs = list_entry(p, struct snd_seq_subscribers, dest_list);
aport = get_client_port(&subs->info.sender, &c);
}
list_del(p);
@@ -233,25 +239,25 @@ static void clear_subscriber_list(client_t *client, client_port_t *port,
kfree(subs);
} else {
/* ok we got the connected port */
- port_subs_info_t *agrp;
+ struct snd_seq_port_subs_info *agrp;
agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src;
down_write(&agrp->list_mutex);
if (grptype == SRC_LIST)
list_del(&subs->dest_list);
else
list_del(&subs->src_list);
+ up_write(&agrp->list_mutex);
unsubscribe_port(c, aport, agrp, &subs->info, 1);
kfree(subs);
- up_write(&agrp->list_mutex);
snd_seq_port_unlock(aport);
snd_seq_client_unlock(c);
}
}
- up_write(&grp->list_mutex);
}
/* delete port data */
-static int port_delete(client_t *client, client_port_t *port)
+static int port_delete(struct snd_seq_client *client,
+ struct snd_seq_client_port *port)
{
/* set closing flag and wait for all port access are gone */
port->closing = 1;
@@ -264,8 +270,8 @@ static int port_delete(client_t *client, client_port_t *port)
if (port->private_free)
port->private_free(port->private_data);
- snd_assert(port->c_src.count == 0,);
- snd_assert(port->c_dest.count == 0,);
+ snd_BUG_ON(port->c_src.count != 0);
+ snd_BUG_ON(port->c_dest.count != 0);
kfree(port);
return 0;
@@ -273,26 +279,24 @@ static int port_delete(client_t *client, client_port_t *port)
/* delete a port with the given port id */
-int snd_seq_delete_port(client_t *client, int port)
+int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
unsigned long flags;
- struct list_head *l;
- client_port_t *found = NULL;
+ struct snd_seq_client_port *found = NULL, *p;
- down(&client->ports_mutex);
+ mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
- list_for_each(l, &client->ports_list_head) {
- client_port_t *p = list_entry(l, client_port_t, list);
+ list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
- list_del(l);
+ list_del(&p->list);
client->num_ports--;
found = p;
break;
}
}
write_unlock_irqrestore(&client->ports_lock, flags);
- up(&client->ports_mutex);
+ mutex_unlock(&client->ports_mutex);
if (found)
return port_delete(client, found);
else
@@ -300,21 +304,20 @@ int snd_seq_delete_port(client_t *client, int port)
}
/* delete the all ports belonging to the given client */
-int snd_seq_delete_all_ports(client_t *client)
+int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
unsigned long flags;
- struct list_head deleted_list, *p, *n;
+ struct list_head deleted_list;
+ struct snd_seq_client_port *port, *tmp;
/* move the port list to deleted_list, and
* clear the port list in the client data.
*/
- down(&client->ports_mutex);
+ mutex_lock(&client->ports_mutex);
write_lock_irqsave(&client->ports_lock, flags);
if (! list_empty(&client->ports_list_head)) {
- __list_add(&deleted_list,
- client->ports_list_head.prev,
- client->ports_list_head.next);
- INIT_LIST_HEAD(&client->ports_list_head);
+ list_add(&deleted_list, &client->ports_list_head);
+ list_del_init(&client->ports_list_head);
} else {
INIT_LIST_HEAD(&deleted_list);
}
@@ -322,20 +325,21 @@ int snd_seq_delete_all_ports(client_t *client)
write_unlock_irqrestore(&client->ports_lock, flags);
/* remove each port in deleted_list */
- list_for_each_safe(p, n, &deleted_list) {
- client_port_t *port = list_entry(p, client_port_t, list);
- list_del(p);
+ list_for_each_entry_safe(port, tmp, &deleted_list, list) {
+ list_del(&port->list);
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
- up(&client->ports_mutex);
+ mutex_unlock(&client->ports_mutex);
return 0;
}
/* set port info fields */
-int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info)
+int snd_seq_set_port_info(struct snd_seq_client_port * port,
+ struct snd_seq_port_info * info)
{
- snd_assert(port && info, return -EINVAL);
+ if (snd_BUG_ON(!port || !info))
+ return -EINVAL;
/* set port name */
if (info->name[0])
@@ -361,9 +365,11 @@ int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info)
}
/* get port info fields */
-int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info)
+int snd_seq_get_port_info(struct snd_seq_client_port * port,
+ struct snd_seq_port_info * info)
{
- snd_assert(port && info, return -EINVAL);
+ if (snd_BUG_ON(!port || !info))
+ return -EINVAL;
/* get port name */
strlcpy(info->name, port->name, sizeof(info->name));
@@ -407,11 +413,14 @@ int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info)
* initialization or termination of devices (see seq_midi.c).
*
* If callback_all option is set, the callback function is invoked
- * at each connnection/disconnection.
+ * at each connection/disconnection.
*/
-static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp,
- snd_seq_port_subscribe_t *info, int send_ack)
+static int subscribe_port(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+ struct snd_seq_port_subscribe *info,
+ int send_ack)
{
int err = 0;
@@ -432,9 +441,11 @@ static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_
return err;
}
-static int unsubscribe_port(client_t *client, client_port_t *port,
- port_subs_info_t *grp,
- snd_seq_port_subscribe_t *info, int send_ack)
+static int unsubscribe_port(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+ struct snd_seq_port_subscribe *info,
+ int send_ack)
{
int err = 0;
@@ -453,15 +464,15 @@ static int unsubscribe_port(client_t *client, client_port_t *port,
/* check if both addresses are identical */
-static inline int addr_match(snd_seq_addr_t *r, snd_seq_addr_t *s)
+static inline int addr_match(struct snd_seq_addr *r, struct snd_seq_addr *s)
{
return (r->client == s->client) && (r->port == s->port);
}
/* check the two subscribe info match */
/* if flags is zero, checks only sender and destination addresses */
-static int match_subs_info(snd_seq_port_subscribe_t *r,
- snd_seq_port_subscribe_t *s)
+static int match_subs_info(struct snd_seq_port_subscribe *r,
+ struct snd_seq_port_subscribe *s)
{
if (addr_match(&r->sender, &s->sender) &&
addr_match(&r->dest, &s->dest)) {
@@ -475,15 +486,16 @@ static int match_subs_info(snd_seq_port_subscribe_t *r,
/* connect two ports */
-int snd_seq_port_connect(client_t *connector,
- client_t *src_client, client_port_t *src_port,
- client_t *dest_client, client_port_t *dest_port,
- snd_seq_port_subscribe_t *info)
+int snd_seq_port_connect(struct snd_seq_client *connector,
+ struct snd_seq_client *src_client,
+ struct snd_seq_client_port *src_port,
+ struct snd_seq_client *dest_client,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_port_subscribe *info)
{
- port_subs_info_t *src = &src_port->c_src;
- port_subs_info_t *dest = &dest_port->c_dest;
- subscribers_t *subs;
- struct list_head *p;
+ struct snd_seq_port_subs_info *src = &src_port->c_src;
+ struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+ struct snd_seq_subscribers *subs, *s;
int err, src_called = 0;
unsigned long flags;
int exclusive;
@@ -496,7 +508,7 @@ int snd_seq_port_connect(client_t *connector,
atomic_set(&subs->ref_count, 2);
down_write(&src->list_mutex);
- down_write(&dest->list_mutex);
+ down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;
err = -EBUSY;
@@ -507,13 +519,11 @@ int snd_seq_port_connect(client_t *connector,
if (src->exclusive || dest->exclusive)
goto __error;
/* check whether already exists */
- list_for_each(p, &src->list_head) {
- subscribers_t *s = list_entry(p, subscribers_t, src_list);
+ list_for_each_entry(s, &src->list_head, src_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
- list_for_each(p, &dest->list_head) {
- subscribers_t *s = list_entry(p, subscribers_t, dest_list);
+ list_for_each_entry(s, &dest->list_head, dest_list) {
if (match_subs_info(info, &s->info))
goto __error;
}
@@ -554,24 +564,24 @@ int snd_seq_port_connect(client_t *connector,
/* remove the connection */
-int snd_seq_port_disconnect(client_t *connector,
- client_t *src_client, client_port_t *src_port,
- client_t *dest_client, client_port_t *dest_port,
- snd_seq_port_subscribe_t *info)
+int snd_seq_port_disconnect(struct snd_seq_client *connector,
+ struct snd_seq_client *src_client,
+ struct snd_seq_client_port *src_port,
+ struct snd_seq_client *dest_client,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_port_subscribe *info)
{
- port_subs_info_t *src = &src_port->c_src;
- port_subs_info_t *dest = &dest_port->c_dest;
- subscribers_t *subs;
- struct list_head *p;
+ struct snd_seq_port_subs_info *src = &src_port->c_src;
+ struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+ struct snd_seq_subscribers *subs;
int err = -ENOENT;
unsigned long flags;
down_write(&src->list_mutex);
- down_write(&dest->list_mutex);
+ down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
/* look for the connection */
- list_for_each(p, &src->list_head) {
- subs = list_entry(p, subscribers_t, src_list);
+ list_for_each_entry(subs, &src->list_head, src_list) {
if (match_subs_info(info, &subs->info)) {
write_lock_irqsave(&src->list_lock, flags);
// write_lock(&dest->list_lock); // no lock yet
@@ -597,15 +607,13 @@ int snd_seq_port_disconnect(client_t *connector,
/* get matched subscriber */
-subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp,
- snd_seq_addr_t *dest_addr)
+struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
+ struct snd_seq_addr *dest_addr)
{
- struct list_head *p;
- subscribers_t *s, *found = NULL;
+ struct snd_seq_subscribers *s, *found = NULL;
down_read(&src_grp->list_mutex);
- list_for_each(p, &src_grp->list_head) {
- s = list_entry(p, subscribers_t, src_list);
+ list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
found = s;
break;
@@ -623,11 +631,11 @@ subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp,
*/
/* exported */
int snd_seq_event_port_attach(int client,
- snd_seq_port_callback_t *pcbp,
+ struct snd_seq_port_callback *pcbp,
int cap, int type, int midi_channels,
int midi_voices, char *portname)
{
- snd_seq_port_info_t portinfo;
+ struct snd_seq_port_info portinfo;
int ret;
/* Set up the port */
@@ -653,6 +661,7 @@ int snd_seq_event_port_attach(int client,
return ret;
}
+EXPORT_SYMBOL(snd_seq_event_port_attach);
/*
* Detach the driver from a port.
@@ -660,7 +669,7 @@ int snd_seq_event_port_attach(int client,
/* exported */
int snd_seq_event_port_detach(int client, int port)
{
- snd_seq_port_info_t portinfo;
+ struct snd_seq_port_info portinfo;
int err;
memset(&portinfo, 0, sizeof(portinfo));
@@ -672,3 +681,5 @@ int snd_seq_event_port_detach(int client, int port)
return err;
}
+
+EXPORT_SYMBOL(snd_seq_event_port_detach);
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index 89fd4416f6f..9d7117118ba 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -40,37 +40,38 @@
*/
-typedef struct subscribers_t {
- snd_seq_port_subscribe_t info; /* additional info */
+struct snd_seq_subscribers {
+ struct snd_seq_port_subscribe info; /* additional info */
struct list_head src_list; /* link of sources */
struct list_head dest_list; /* link of destinations */
atomic_t ref_count;
-} subscribers_t;
+};
-typedef struct port_subs_info_t {
+struct snd_seq_port_subs_info {
struct list_head list_head; /* list of subscribed ports */
unsigned int count; /* count of subscribers */
unsigned int exclusive: 1; /* exclusive mode */
struct rw_semaphore list_mutex;
rwlock_t list_lock;
- snd_seq_kernel_port_open_t *open;
- snd_seq_kernel_port_close_t *close;
-} port_subs_info_t;
+ int (*open)(void *private_data, struct snd_seq_port_subscribe *info);
+ int (*close)(void *private_data, struct snd_seq_port_subscribe *info);
+};
-typedef struct client_port_t {
+struct snd_seq_client_port {
- snd_seq_addr_t addr; /* client/port number */
+ struct snd_seq_addr addr; /* client/port number */
struct module *owner; /* owner of this port */
char name[64]; /* port name */
struct list_head list; /* port list */
snd_use_lock_t use_lock;
/* subscribers */
- port_subs_info_t c_src; /* read (sender) list */
- port_subs_info_t c_dest; /* write (dest) list */
+ struct snd_seq_port_subs_info c_src; /* read (sender) list */
+ struct snd_seq_port_subs_info c_dest; /* write (dest) list */
- snd_seq_kernel_port_input_t *event_input;
- snd_seq_kernel_port_private_free_t *private_free;
+ int (*event_input)(struct snd_seq_event *ev, int direct, void *private_data,
+ int atomic, int hop);
+ void (*private_free)(void *private_data);
void *private_data;
unsigned int callback_all : 1;
unsigned int closing : 1;
@@ -87,42 +88,55 @@ typedef struct client_port_t {
int midi_voices;
int synth_voices;
-} client_port_t;
+};
+
+struct snd_seq_client;
/* return pointer to port structure and lock port */
-client_port_t *snd_seq_port_use_ptr(client_t *client, int num);
+struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, int num);
/* search for next port - port is locked if found */
-client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t *pinfo);
+struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *client,
+ struct snd_seq_port_info *pinfo);
/* unlock the port */
#define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock)
/* create a port, port number is returned (-1 on failure) */
-client_port_t *snd_seq_create_port(client_t *client, int port_index);
+struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port_index);
/* delete a port */
-int snd_seq_delete_port(client_t *client, int port);
+int snd_seq_delete_port(struct snd_seq_client *client, int port);
/* delete all ports */
-int snd_seq_delete_all_ports(client_t *client);
+int snd_seq_delete_all_ports(struct snd_seq_client *client);
/* set port info fields */
-int snd_seq_set_port_info(client_port_t *port, snd_seq_port_info_t *info);
+int snd_seq_set_port_info(struct snd_seq_client_port *port,
+ struct snd_seq_port_info *info);
/* get port info fields */
-int snd_seq_get_port_info(client_port_t *port, snd_seq_port_info_t *info);
+int snd_seq_get_port_info(struct snd_seq_client_port *port,
+ struct snd_seq_port_info *info);
/* add subscriber to subscription list */
-int snd_seq_port_connect(client_t *caller, client_t *s, client_port_t *sp, client_t *d, client_port_t *dp, snd_seq_port_subscribe_t *info);
+int snd_seq_port_connect(struct snd_seq_client *caller,
+ struct snd_seq_client *s, struct snd_seq_client_port *sp,
+ struct snd_seq_client *d, struct snd_seq_client_port *dp,
+ struct snd_seq_port_subscribe *info);
/* remove subscriber from subscription list */
-int snd_seq_port_disconnect(client_t *caller, client_t *s, client_port_t *sp, client_t *d, client_port_t *dp, snd_seq_port_subscribe_t *info);
+int snd_seq_port_disconnect(struct snd_seq_client *caller,
+ struct snd_seq_client *s, struct snd_seq_client_port *sp,
+ struct snd_seq_client *d, struct snd_seq_client_port *dp,
+ struct snd_seq_port_subscribe *info);
/* subscribe port */
-int snd_seq_port_subscribe(client_port_t *port, snd_seq_port_subscribe_t *info);
+int snd_seq_port_subscribe(struct snd_seq_client_port *port,
+ struct snd_seq_port_subscribe *info);
/* get matched subscriber */
-subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp, snd_seq_addr_t *dest_addr);
+struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
+ struct snd_seq_addr *dest_addr);
#endif
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index cd641bca994..021b02bc933 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -19,7 +19,6 @@
*
*/
-#include <sound/driver.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -55,13 +54,13 @@
/* create new prioq (constructor) */
-prioq_t *snd_seq_prioq_new(void)
+struct snd_seq_prioq *snd_seq_prioq_new(void)
{
- prioq_t *f;
+ struct snd_seq_prioq *f;
f = kzalloc(sizeof(*f), GFP_KERNEL);
if (f == NULL) {
- snd_printd("oops: malloc failed for snd_seq_prioq_new()\n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
return NULL;
}
@@ -74,13 +73,13 @@ prioq_t *snd_seq_prioq_new(void)
}
/* delete prioq (destructor) */
-void snd_seq_prioq_delete(prioq_t **fifo)
+void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
{
- prioq_t *f = *fifo;
+ struct snd_seq_prioq *f = *fifo;
*fifo = NULL;
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_delete() called with NULL prioq\n");
return;
}
@@ -101,7 +100,8 @@ void snd_seq_prioq_delete(prioq_t **fifo)
/* compare timestamp between events */
/* return 1 if a >= b; 0 */
-static inline int compare_timestamp(snd_seq_event_t * a, snd_seq_event_t * b)
+static inline int compare_timestamp(struct snd_seq_event *a,
+ struct snd_seq_event *b)
{
if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
/* compare ticks */
@@ -117,7 +117,8 @@ static inline int compare_timestamp(snd_seq_event_t * a, snd_seq_event_t * b)
* zero if a = b;
* positive if a > b;
*/
-static inline int compare_timestamp_rel(snd_seq_event_t *a, snd_seq_event_t *b)
+static inline int compare_timestamp_rel(struct snd_seq_event *a,
+ struct snd_seq_event *b)
{
if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
/* compare ticks */
@@ -144,15 +145,16 @@ static inline int compare_timestamp_rel(snd_seq_event_t *a, snd_seq_event_t *b)
}
/* enqueue cell to prioq */
-int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
+int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
+ struct snd_seq_event_cell * cell)
{
- snd_seq_event_cell_t *cur, *prev;
+ struct snd_seq_event_cell *cur, *prev;
unsigned long flags;
int count;
int prior;
- snd_assert(f, return -EINVAL);
- snd_assert(cell, return -EINVAL);
+ if (snd_BUG_ON(!f || !cell))
+ return -EINVAL;
/* check flags */
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
@@ -195,7 +197,7 @@ int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
cur = cur->next;
if (! --count) {
spin_unlock_irqrestore(&f->lock, flags);
- snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
+ pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
}
@@ -215,13 +217,13 @@ int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
}
/* dequeue cell from prioq */
-snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t * f)
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
{
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
unsigned long flags;
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
spin_lock_irqsave(&f->lock, flags);
@@ -243,10 +245,10 @@ snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t * f)
}
/* return number of events available in prioq */
-int snd_seq_prioq_avail(prioq_t * f)
+int snd_seq_prioq_avail(struct snd_seq_prioq * f)
{
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return 0;
}
return f->cells;
@@ -254,17 +256,18 @@ int snd_seq_prioq_avail(prioq_t * f)
/* peek at cell at the head of the prioq */
-snd_seq_event_cell_t *snd_seq_prioq_cell_peek(prioq_t * f)
+struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
{
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
return f->head;
}
-static inline int prioq_match(snd_seq_event_cell_t *cell, int client, int timestamp)
+static inline int prioq_match(struct snd_seq_event_cell *cell,
+ int client, int timestamp)
{
if (cell->event.source.client == client ||
cell->event.dest.client == client)
@@ -286,12 +289,12 @@ static inline int prioq_match(snd_seq_event_cell_t *cell, int client, int timest
}
/* remove cells for left client */
-void snd_seq_prioq_leave(prioq_t * f, int client, int timestamp)
+void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
{
- register snd_seq_event_cell_t *cell, *next;
+ register struct snd_seq_event_cell *cell, *next;
unsigned long flags;
- snd_seq_event_cell_t *prev = NULL;
- snd_seq_event_cell_t *freefirst = NULL, *freeprev = NULL, *freenext;
+ struct snd_seq_event_cell *prev = NULL;
+ struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
/* collect all removed cells */
spin_lock_irqsave(&f->lock, flags);
@@ -318,7 +321,8 @@ void snd_seq_prioq_leave(prioq_t * f, int client, int timestamp)
freeprev = cell;
} else {
#if 0
- printk("type = %i, source = %i, dest = %i, client = %i\n",
+ pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
+ "client = %i\n",
cell->event.type,
cell->event.source.client,
cell->event.dest.client,
@@ -338,8 +342,8 @@ void snd_seq_prioq_leave(prioq_t * f, int client, int timestamp)
}
}
-static int prioq_remove_match(snd_seq_remove_events_t *info,
- snd_seq_event_t *ev)
+static int prioq_remove_match(struct snd_seq_remove_events *info,
+ struct snd_seq_event *ev)
{
int res;
@@ -394,13 +398,13 @@ static int prioq_remove_match(snd_seq_remove_events_t *info,
}
/* remove cells matching remove criteria */
-void snd_seq_prioq_remove_events(prioq_t * f, int client,
- snd_seq_remove_events_t *info)
+void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
+ struct snd_seq_remove_events *info)
{
- register snd_seq_event_cell_t *cell, *next;
+ struct snd_seq_event_cell *cell, *next;
unsigned long flags;
- snd_seq_event_cell_t *prev = NULL;
- snd_seq_event_cell_t *freefirst = NULL, *freeprev = NULL, *freenext;
+ struct snd_seq_event_cell *prev = NULL;
+ struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
/* collect all removed cells */
spin_lock_irqsave(&f->lock, flags);
diff --git a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h
index f12af79308b..d38bb78d934 100644
--- a/sound/core/seq/seq_prioq.h
+++ b/sound/core/seq/seq_prioq.h
@@ -26,37 +26,37 @@
/* === PRIOQ === */
-typedef struct {
- snd_seq_event_cell_t* head; /* pointer to head of prioq */
- snd_seq_event_cell_t* tail; /* pointer to tail of prioq */
+struct snd_seq_prioq {
+ struct snd_seq_event_cell *head; /* pointer to head of prioq */
+ struct snd_seq_event_cell *tail; /* pointer to tail of prioq */
int cells;
spinlock_t lock;
-} prioq_t;
+};
/* create new prioq (constructor) */
-extern prioq_t *snd_seq_prioq_new(void);
+struct snd_seq_prioq *snd_seq_prioq_new(void);
/* delete prioq (destructor) */
-extern void snd_seq_prioq_delete(prioq_t **fifo);
+void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);
/* enqueue cell to prioq */
-extern int snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
+int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
/* dequeue cell from prioq */
-extern snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t *f);
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f);
/* return number of events available in prioq */
-extern int snd_seq_prioq_avail(prioq_t *f);
+int snd_seq_prioq_avail(struct snd_seq_prioq *f);
/* peek at cell at the head of the prioq */
-extern snd_seq_event_cell_t *snd_seq_prioq_cell_peek(prioq_t *f);
+struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f);
/* client left queue */
-extern void snd_seq_prioq_leave(prioq_t *f, int client, int timestamp);
+void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);
/* Remove events */
-void snd_seq_prioq_remove_events(prioq_t * f, int client,
- snd_seq_remove_events_t *info);
+void snd_seq_prioq_remove_events(struct snd_seq_prioq *f, int client,
+ struct snd_seq_remove_events *info);
#endif
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 5f5c3cb37cb..aad4878cee5 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -29,13 +29,12 @@
* Aug. 30, 2000 Takashi Iwai
* - Queues are managed in static array again, but with better way.
* The API itself is identical.
- * - The queue is locked when queue_t pinter is returned via
+ * - The queue is locked when struct snd_seq_queue pointer is returned via
* queueptr(). This pointer *MUST* be released afterward by
* queuefree(ptr).
* - Addition of experimental sync support.
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -48,7 +47,7 @@
#include "seq_info.h"
/* list of allocated queues */
-static queue_t *queue_list[SNDRV_SEQ_MAX_QUEUES];
+static struct snd_seq_queue *queue_list[SNDRV_SEQ_MAX_QUEUES];
static DEFINE_SPINLOCK(queue_list_lock);
/* number of queues allocated */
static int num_queues;
@@ -61,7 +60,7 @@ int snd_seq_queue_get_cur_queues(void)
/*----------------------------------------------------------------*/
/* assign queue id and insert to list */
-static int queue_list_add(queue_t *q)
+static int queue_list_add(struct snd_seq_queue *q)
{
int i;
unsigned long flags;
@@ -80,9 +79,9 @@ static int queue_list_add(queue_t *q)
return -1;
}
-static queue_t *queue_list_remove(int id, int client)
+static struct snd_seq_queue *queue_list_remove(int id, int client)
{
- queue_t *q;
+ struct snd_seq_queue *q;
unsigned long flags;
spin_lock_irqsave(&queue_list_lock, flags);
@@ -107,19 +106,19 @@ static queue_t *queue_list_remove(int id, int client)
/*----------------------------------------------------------------*/
/* create new queue (constructor) */
-static queue_t *queue_new(int owner, int locked)
+static struct snd_seq_queue *queue_new(int owner, int locked)
{
- queue_t *q;
+ struct snd_seq_queue *q;
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (q == NULL) {
- snd_printd("malloc failed for snd_seq_queue_new()\n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
return NULL;
}
spin_lock_init(&q->owner_lock);
spin_lock_init(&q->check_lock);
- init_MUTEX(&q->timer_mutex);
+ mutex_init(&q->timer_mutex);
snd_use_lock_init(&q->use_lock);
q->queue = -1;
@@ -142,7 +141,7 @@ static queue_t *queue_new(int owner, int locked)
}
/* delete queue (destructor) */
-static void queue_delete(queue_t *q)
+static void queue_delete(struct snd_seq_queue *q)
{
/* stop and release the timer */
snd_seq_timer_stop(q->timer);
@@ -187,7 +186,7 @@ void __exit snd_seq_queues_delete(void)
*/
int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
{
- queue_t *q;
+ struct snd_seq_queue *q;
q = queue_new(client, locked);
if (q == NULL)
@@ -204,7 +203,7 @@ int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
/* delete a queue - queue must be owned by the client */
int snd_seq_queue_delete(int client, int queueid)
{
- queue_t *q;
+ struct snd_seq_queue *q;
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
return -EINVAL;
@@ -218,9 +217,9 @@ int snd_seq_queue_delete(int client, int queueid)
/* return pointer to queue structure for specified id */
-queue_t *queueptr(int queueid)
+struct snd_seq_queue *queueptr(int queueid)
{
- queue_t *q;
+ struct snd_seq_queue *q;
unsigned long flags;
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
@@ -234,10 +233,10 @@ queue_t *queueptr(int queueid)
}
/* return the (first) queue matching with the specified name */
-queue_t *snd_seq_queue_find_name(char *name)
+struct snd_seq_queue *snd_seq_queue_find_name(char *name)
{
int i;
- queue_t *q;
+ struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) != NULL) {
@@ -252,10 +251,10 @@ queue_t *snd_seq_queue_find_name(char *name)
/* -------------------------------------------------------- */
-void snd_seq_check_queue(queue_t *q, int atomic, int hop)
+void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
{
unsigned long flags;
- snd_seq_event_cell_t *cell;
+ struct snd_seq_event_cell *cell;
if (q == NULL)
return;
@@ -273,7 +272,8 @@ void snd_seq_check_queue(queue_t *q, int atomic, int hop)
__again:
/* Process tick queue... */
while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
- if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick, &cell->event.time.tick)) {
+ if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick,
+ &cell->event.time.tick)) {
cell = snd_seq_prioq_cell_out(q->tickq);
if (cell)
snd_seq_dispatch_event(cell, atomic, hop);
@@ -286,7 +286,8 @@ void snd_seq_check_queue(queue_t *q, int atomic, int hop)
/* Process time queue... */
while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
- if (snd_seq_compare_real_time(&q->timer->cur_time, &cell->event.time.time)) {
+ if (snd_seq_compare_real_time(&q->timer->cur_time,
+ &cell->event.time.time)) {
cell = snd_seq_prioq_cell_out(q->timeq);
if (cell)
snd_seq_dispatch_event(cell, atomic, hop);
@@ -309,12 +310,13 @@ void snd_seq_check_queue(queue_t *q, int atomic, int hop)
/* enqueue a event to singe queue */
-int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop)
+int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop)
{
int dest, err;
- queue_t *q;
+ struct snd_seq_queue *q;
- snd_assert(cell != NULL, return -EINVAL);
+ if (snd_BUG_ON(!cell))
+ return -EINVAL;
dest = cell->event.queue; /* destination queue */
q = queueptr(dest);
if (q == NULL)
@@ -327,7 +329,8 @@ int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop)
break;
case SNDRV_SEQ_TIME_STAMP_REAL:
- snd_seq_inc_real_time(&cell->event.time.time, &q->timer->cur_time);
+ snd_seq_inc_real_time(&cell->event.time.time,
+ &q->timer->cur_time);
break;
}
cell->event.flags &= ~SNDRV_SEQ_TIME_MODE_MASK;
@@ -361,7 +364,7 @@ int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop)
/*----------------------------------------------------------------*/
-static inline int check_access(queue_t *q, int client)
+static inline int check_access(struct snd_seq_queue *q, int client)
{
return (q->owner == client) || (!q->locked && !q->klocked);
}
@@ -369,7 +372,7 @@ static inline int check_access(queue_t *q, int client)
/* check if the client has permission to modify queue parameters.
* if it does, lock the queue
*/
-static int queue_access_lock(queue_t *q, int client)
+static int queue_access_lock(struct snd_seq_queue *q, int client)
{
unsigned long flags;
int access_ok;
@@ -383,7 +386,7 @@ static int queue_access_lock(queue_t *q, int client)
}
/* unlock the queue */
-static inline void queue_access_unlock(queue_t *q)
+static inline void queue_access_unlock(struct snd_seq_queue *q)
{
unsigned long flags;
@@ -395,7 +398,7 @@ static inline void queue_access_unlock(queue_t *q)
/* exported - only checking permission */
int snd_seq_queue_check_access(int queueid, int client)
{
- queue_t *q = queueptr(queueid);
+ struct snd_seq_queue *q = queueptr(queueid);
int access_ok;
unsigned long flags;
@@ -415,7 +418,7 @@ int snd_seq_queue_check_access(int queueid, int client)
*/
int snd_seq_queue_set_owner(int queueid, int client, int locked)
{
- queue_t *q = queueptr(queueid);
+ struct snd_seq_queue *q = queueptr(queueid);
if (q == NULL)
return -EINVAL;
@@ -443,8 +446,8 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
int snd_seq_queue_timer_open(int queueid)
{
int result = 0;
- queue_t *queue;
- seq_timer_t *tmr;
+ struct snd_seq_queue *queue;
+ struct snd_seq_timer *tmr;
queue = queueptr(queueid);
if (queue == NULL)
@@ -463,23 +466,22 @@ int snd_seq_queue_timer_open(int queueid)
*/
int snd_seq_queue_timer_close(int queueid)
{
- queue_t *queue;
- seq_timer_t *tmr;
+ struct snd_seq_queue *queue;
int result = 0;
queue = queueptr(queueid);
if (queue == NULL)
return -EINVAL;
- tmr = queue->timer;
snd_seq_timer_close(queue);
queuefree(queue);
return result;
}
/* change queue tempo and ppq */
-int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t *info)
+int snd_seq_queue_timer_set_tempo(int queueid, int client,
+ struct snd_seq_queue_tempo *info)
{
- queue_t *q = queueptr(queueid);
+ struct snd_seq_queue *q = queueptr(queueid);
int result;
if (q == NULL)
@@ -493,7 +495,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t
if (result >= 0)
result = snd_seq_timer_set_ppq(q->timer, info->ppq);
if (result >= 0 && info->skew_base > 0)
- result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base);
+ result = snd_seq_timer_set_skew(q->timer, info->skew_value,
+ info->skew_base);
queue_access_unlock(q);
queuefree(q);
return result;
@@ -506,12 +509,12 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t
*/
int snd_seq_queue_use(int queueid, int client, int use)
{
- queue_t *queue;
+ struct snd_seq_queue *queue;
queue = queueptr(queueid);
if (queue == NULL)
return -EINVAL;
- down(&queue->timer_mutex);
+ mutex_lock(&queue->timer_mutex);
if (use) {
if (!test_and_set_bit(client, queue->clients_bitmap))
queue->clients++;
@@ -526,7 +529,7 @@ int snd_seq_queue_use(int queueid, int client, int use)
} else {
snd_seq_timer_close(queue);
}
- up(&queue->timer_mutex);
+ mutex_unlock(&queue->timer_mutex);
queuefree(queue);
return 0;
}
@@ -538,7 +541,7 @@ int snd_seq_queue_use(int queueid, int client, int use)
*/
int snd_seq_queue_is_used(int queueid, int client)
{
- queue_t *q;
+ struct snd_seq_queue *q;
int result;
q = queueptr(queueid);
@@ -559,7 +562,7 @@ void snd_seq_queue_client_termination(int client)
{
unsigned long flags;
int i;
- queue_t *q;
+ struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
@@ -584,7 +587,7 @@ void snd_seq_queue_client_termination(int client)
void snd_seq_queue_client_leave(int client)
{
int i;
- queue_t *q;
+ struct snd_seq_queue *q;
/* delete own queues from queue list */
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
@@ -615,7 +618,7 @@ void snd_seq_queue_client_leave(int client)
void snd_seq_queue_client_leave_cells(int client)
{
int i;
- queue_t *q;
+ struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
@@ -627,10 +630,10 @@ void snd_seq_queue_client_leave_cells(int client)
}
/* remove cells based on flush criteria */
-void snd_seq_queue_remove_cells(int client, snd_seq_remove_events_t *info)
+void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info)
{
int i;
- queue_t *q;
+ struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
@@ -650,9 +653,10 @@ void snd_seq_queue_remove_cells(int client, snd_seq_remove_events_t *info)
/*
* send events to all subscribed ports
*/
-static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
+static void queue_broadcast_event(struct snd_seq_queue *q, struct snd_seq_event *ev,
+ int atomic, int hop)
{
- snd_seq_event_t sev;
+ struct snd_seq_event sev;
sev = *ev;
@@ -672,7 +676,8 @@ static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, i
* process a received queue-control event.
* this function is exported for seq_sync.c.
*/
-static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev,
+static void snd_seq_queue_process_event(struct snd_seq_queue *q,
+ struct snd_seq_event *ev,
int atomic, int hop)
{
switch (ev->type) {
@@ -724,11 +729,12 @@ static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev,
* Queue control via timer control port:
* this function is exported as a callback of timer port.
*/
-int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop)
+int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop)
{
- queue_t *q;
+ struct snd_seq_queue *q;
- snd_assert(ev != NULL, return -EINVAL);
+ if (snd_BUG_ON(!ev))
+ return -EINVAL;
q = queueptr(ev->data.queue.queue);
if (q == NULL)
@@ -749,13 +755,14 @@ int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop)
/*----------------------------------------------------------------*/
+#ifdef CONFIG_PROC_FS
/* exported to seq_info.c */
-void snd_seq_info_queues_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+void snd_seq_info_queues_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
int i, bpm;
- queue_t *q;
- seq_timer_t *tmr;
+ struct snd_seq_queue *q;
+ struct snd_seq_timer *tmr;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
@@ -782,3 +789,5 @@ void snd_seq_info_queues_read(snd_info_entry_t *entry,
queuefree(q);
}
}
+#endif /* CONFIG_PROC_FS */
+
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index ea3c54216ea..30c8111477f 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -30,15 +30,15 @@
#define SEQ_QUEUE_NO_OWNER (-1)
-struct _snd_seq_queue {
+struct snd_seq_queue {
int queue; /* queue number */
char name[64]; /* name of this queue */
- prioq_t *tickq; /* midi tick event queue */
- prioq_t *timeq; /* real-time event queue */
+ struct snd_seq_prioq *tickq; /* midi tick event queue */
+ struct snd_seq_prioq *timeq; /* real-time event queue */
- seq_timer_t *timer; /* time keeper for this queue */
+ struct snd_seq_timer *timer; /* time keeper for this queue */
int owner; /* client that 'owns' the timer */
unsigned int locked:1, /* timer is only accesibble by owner if set */
klocked:1, /* kernel lock (after START) */
@@ -54,7 +54,7 @@ struct _snd_seq_queue {
/* clients which uses this queue (bitmap) */
DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
unsigned int clients; /* users of this queue */
- struct semaphore timer_mutex;
+ struct mutex timer_mutex;
snd_use_lock_t use_lock;
};
@@ -83,26 +83,26 @@ void snd_seq_queue_client_termination(int client);
void snd_seq_queue_client_leave(int client);
/* enqueue a event received from one the clients */
-int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop);
+int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop);
/* Remove events */
void snd_seq_queue_client_leave_cells(int client);
-void snd_seq_queue_remove_cells(int client, snd_seq_remove_events_t *info);
+void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info);
/* return pointer to queue structure for specified id */
-queue_t *queueptr(int queueid);
+struct snd_seq_queue *queueptr(int queueid);
/* unlock */
#define queuefree(q) snd_use_lock_free(&(q)->use_lock)
/* return the (first) queue matching with the specified name */
-queue_t *snd_seq_queue_find_name(char *name);
+struct snd_seq_queue *snd_seq_queue_find_name(char *name);
/* check single queue and dispatch events */
-void snd_seq_check_queue(queue_t *q, int atomic, int hop);
+void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop);
/* access to queue's parameters */
int snd_seq_queue_check_access(int queueid, int client);
-int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t *info);
+int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info);
int snd_seq_queue_set_owner(int queueid, int client, int locked);
int snd_seq_queue_set_locked(int queueid, int client, int locked);
int snd_seq_queue_timer_open(int queueid);
@@ -110,7 +110,7 @@ int snd_seq_queue_timer_close(int queueid);
int snd_seq_queue_use(int queueid, int client, int use);
int snd_seq_queue_is_used(int queueid, int client);
-int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop);
+int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop);
/*
* 64bit division - for sync stuff..
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
index 0d9eff85ab8..8ce1d0b40dc 100644
--- a/sound/core/seq/seq_system.c
+++ b/sound/core/seq/seq_system.c
@@ -19,8 +19,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include "seq_system.h"
#include "seq_timer.h"
@@ -66,12 +67,12 @@ static int announce_port = -1;
/* fill standard header data, source port & channel are filled in */
-static int setheader(snd_seq_event_t * ev, int client, int port)
+static int setheader(struct snd_seq_event * ev, int client, int port)
{
if (announce_port < 0)
return -ENODEV;
- memset(ev, 0, sizeof(snd_seq_event_t));
+ memset(ev, 0, sizeof(struct snd_seq_event));
ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
@@ -92,7 +93,7 @@ static int setheader(snd_seq_event_t * ev, int client, int port)
/* entry points for broadcasting system events */
void snd_seq_system_broadcast(int client, int port, int type)
{
- snd_seq_event_t ev;
+ struct snd_seq_event ev;
if (setheader(&ev, client, port) < 0)
return;
@@ -101,7 +102,7 @@ void snd_seq_system_broadcast(int client, int port, int type)
}
/* entry points for broadcasting system events */
-int snd_seq_system_notify(int client, int port, snd_seq_event_t *ev)
+int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
{
ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
ev->source.client = sysclient;
@@ -112,7 +113,7 @@ int snd_seq_system_notify(int client, int port, snd_seq_event_t *ev)
}
/* call-back handler for timer events */
-static int event_input_timer(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop)
+static int event_input_timer(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
{
return snd_seq_control_queue(ev, atomic, hop);
}
@@ -120,34 +121,19 @@ static int event_input_timer(snd_seq_event_t * ev, int direct, void *private_dat
/* register our internal client */
int __init snd_seq_system_client_init(void)
{
+ struct snd_seq_port_callback pcallbacks;
+ struct snd_seq_port_info *port;
- snd_seq_client_callback_t callbacks;
- snd_seq_port_callback_t pcallbacks;
- snd_seq_client_info_t *inf;
- snd_seq_port_info_t *port;
-
- inf = kzalloc(sizeof(*inf), GFP_KERNEL);
port = kzalloc(sizeof(*port), GFP_KERNEL);
- if (! inf || ! port) {
- kfree(inf);
- kfree(port);
+ if (!port)
return -ENOMEM;
- }
- memset(&callbacks, 0, sizeof(callbacks));
memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE;
pcallbacks.event_input = event_input_timer;
/* register client */
- callbacks.allow_input = callbacks.allow_output = 1;
- sysclient = snd_seq_create_kernel_client(NULL, 0, &callbacks);
-
- /* set our name */
- inf->client = 0;
- inf->type = KERNEL_CLIENT;
- strcpy(inf->name, "System");
- snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, inf);
+ sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
/* register timer */
strcpy(port->name, "Timer");
@@ -171,7 +157,6 @@ int __init snd_seq_system_client_init(void)
snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
announce_port = port->addr.port;
- kfree(inf);
kfree(port);
return 0;
}
diff --git a/sound/core/seq/seq_system.h b/sound/core/seq/seq_system.h
index 900007255bb..cf2cfa23430 100644
--- a/sound/core/seq/seq_system.h
+++ b/sound/core/seq/seq_system.h
@@ -34,7 +34,7 @@ void snd_seq_system_broadcast(int client, int port, int type);
#define snd_seq_system_client_ev_port_exit(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_EXIT)
#define snd_seq_system_client_ev_port_change(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_CHANGE)
-int snd_seq_system_notify(int client, int port, snd_seq_event_t *ev);
+int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev);
/* register our internal client */
int snd_seq_system_client_init(void);
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index b57a3c07ff6..e73605393ee 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -1,7 +1,7 @@
/*
* ALSA sequencer Timer
* Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@suse.cz>
+ * Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -20,49 +20,44 @@
*
*/
-#include <sound/driver.h>
#include <sound/core.h>
#include <linux/slab.h>
#include "seq_timer.h"
#include "seq_queue.h"
#include "seq_info.h"
-extern int seq_default_timer_class;
-extern int seq_default_timer_sclass;
-extern int seq_default_timer_card;
-extern int seq_default_timer_device;
-extern int seq_default_timer_subdevice;
-extern int seq_default_timer_resolution;
+/* allowed sequencer timer frequencies, in Hz */
+#define MIN_FREQUENCY 10
+#define MAX_FREQUENCY 6250
+#define DEFAULT_FREQUENCY 1000
#define SKEW_BASE 0x10000 /* 16bit shift */
-static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick,
- int tempo, int ppq, int nticks)
+static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
{
- if (tempo < 1000000)
- tick->resolution = (tempo * 1000) / ppq;
+ if (tmr->tempo < 1000000)
+ tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
else {
/* might overflow.. */
unsigned int s;
- s = tempo % ppq;
- s = (s * 1000) / ppq;
- tick->resolution = (tempo / ppq) * 1000;
- tick->resolution += s;
+ s = tmr->tempo % tmr->ppq;
+ s = (s * 1000) / tmr->ppq;
+ tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
+ tmr->tick.resolution += s;
}
- if (tick->resolution <= 0)
- tick->resolution = 1;
- tick->resolution *= nticks;
- snd_seq_timer_update_tick(tick, 0);
+ if (tmr->tick.resolution <= 0)
+ tmr->tick.resolution = 1;
+ snd_seq_timer_update_tick(&tmr->tick, 0);
}
/* create new timer (constructor) */
-seq_timer_t *snd_seq_timer_new(void)
+struct snd_seq_timer *snd_seq_timer_new(void)
{
- seq_timer_t *tmr;
+ struct snd_seq_timer *tmr;
tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
if (tmr == NULL) {
- snd_printd("malloc failed for snd_seq_timer_new() \n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
return NULL;
}
spin_lock_init(&tmr->lock);
@@ -77,13 +72,13 @@ seq_timer_t *snd_seq_timer_new(void)
}
/* delete timer (destructor) */
-void snd_seq_timer_delete(seq_timer_t **tmr)
+void snd_seq_timer_delete(struct snd_seq_timer **tmr)
{
- seq_timer_t *t = *tmr;
+ struct snd_seq_timer *t = *tmr;
*tmr = NULL;
if (t == NULL) {
- snd_printd("oops: snd_seq_timer_delete() called with NULL timer\n");
+ pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
return;
}
t->running = 0;
@@ -95,12 +90,12 @@ void snd_seq_timer_delete(seq_timer_t **tmr)
kfree(t);
}
-void snd_seq_timer_defaults(seq_timer_t * tmr)
+void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
{
/* setup defaults */
tmr->ppq = 96; /* 96 PPQ */
tmr->tempo = 500000; /* 120 BPM */
- snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
+ snd_seq_timer_set_tick_resolution(tmr);
tmr->running = 0;
tmr->type = SNDRV_SEQ_TIMER_ALSA;
@@ -114,7 +109,7 @@ void snd_seq_timer_defaults(seq_timer_t * tmr)
tmr->skew = tmr->skew_base = SKEW_BASE;
}
-void snd_seq_timer_reset(seq_timer_t * tmr)
+void snd_seq_timer_reset(struct snd_seq_timer * tmr)
{
unsigned long flags;
@@ -132,13 +127,13 @@ void snd_seq_timer_reset(seq_timer_t * tmr)
/* called by timer interrupt routine. the period time since previous invocation is passed */
-static void snd_seq_timer_interrupt(snd_timer_instance_t *timeri,
+static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
unsigned long resolution,
unsigned long ticks)
{
unsigned long flags;
- queue_t *q = (queue_t *)timeri->callback_data;
- seq_timer_t *tmr;
+ struct snd_seq_queue *q = timeri->callback_data;
+ struct snd_seq_timer *tmr;
if (q == NULL)
return;
@@ -173,28 +168,30 @@ static void snd_seq_timer_interrupt(snd_timer_instance_t *timeri,
}
/* set current tempo */
-int snd_seq_timer_set_tempo(seq_timer_t * tmr, int tempo)
+int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
{
unsigned long flags;
- snd_assert(tmr, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
if (tempo <= 0)
return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
if ((unsigned int)tempo != tmr->tempo) {
tmr->tempo = tempo;
- snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
+ snd_seq_timer_set_tick_resolution(tmr);
}
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
/* set current ppq */
-int snd_seq_timer_set_ppq(seq_timer_t * tmr, int ppq)
+int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
{
unsigned long flags;
- snd_assert(tmr, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
if (ppq <= 0)
return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
@@ -202,22 +199,24 @@ int snd_seq_timer_set_ppq(seq_timer_t * tmr, int ppq)
/* refuse to change ppq on running timers */
/* because it will upset the song position (ticks) */
spin_unlock_irqrestore(&tmr->lock, flags);
- snd_printd("seq: cannot change ppq of a running timer\n");
+ pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
return -EBUSY;
}
tmr->ppq = ppq;
- snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
+ snd_seq_timer_set_tick_resolution(tmr);
spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
/* set current tick position */
-int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t position)
+int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
+ snd_seq_tick_time_t position)
{
unsigned long flags;
- snd_assert(tmr, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
spin_lock_irqsave(&tmr->lock, flags);
tmr->tick.cur_tick = position;
@@ -227,11 +226,13 @@ int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t positi
}
/* set current real-time position */
-int snd_seq_timer_set_position_time(seq_timer_t *tmr, snd_seq_real_time_t position)
+int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
+ snd_seq_real_time_t position)
{
unsigned long flags;
- snd_assert(tmr, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
snd_seq_sanity_real_time(&position);
spin_lock_irqsave(&tmr->lock, flags);
@@ -241,15 +242,17 @@ int snd_seq_timer_set_position_time(seq_timer_t *tmr, snd_seq_real_time_t positi
}
/* set timer skew */
-int snd_seq_timer_set_skew(seq_timer_t *tmr, unsigned int skew, unsigned int base)
+int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
+ unsigned int base)
{
unsigned long flags;
- snd_assert(tmr, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
/* FIXME */
if (base != SKEW_BASE) {
- snd_printd("invalid skew base 0x%x\n", base);
+ pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
return -EINVAL;
}
spin_lock_irqsave(&tmr->lock, flags);
@@ -258,15 +261,16 @@ int snd_seq_timer_set_skew(seq_timer_t *tmr, unsigned int skew, unsigned int bas
return 0;
}
-int snd_seq_timer_open(queue_t *q)
+int snd_seq_timer_open(struct snd_seq_queue *q)
{
- snd_timer_instance_t *t;
- seq_timer_t *tmr;
+ struct snd_timer_instance *t;
+ struct snd_seq_timer *tmr;
char str[32];
int err;
tmr = q->timer;
- snd_assert(tmr != NULL, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
if (tmr->timeri)
return -EBUSY;
sprintf(str, "sequencer queue %i", q->queue);
@@ -278,7 +282,7 @@ int snd_seq_timer_open(queue_t *q)
if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
- snd_timer_id_t tid;
+ struct snd_timer_id tid;
memset(&tid, 0, sizeof(tid));
tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
@@ -286,10 +290,10 @@ int snd_seq_timer_open(queue_t *q)
tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
err = snd_timer_open(&t, str, &tid, q->queue);
}
- if (err < 0) {
- snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
- return err;
- }
+ }
+ if (err < 0) {
+ pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
+ return err;
}
t->callback = snd_seq_timer_interrupt;
t->callback_data = q;
@@ -298,12 +302,13 @@ int snd_seq_timer_open(queue_t *q)
return 0;
}
-int snd_seq_timer_close(queue_t *q)
+int snd_seq_timer_close(struct snd_seq_queue *q)
{
- seq_timer_t *tmr;
+ struct snd_seq_timer *tmr;
tmr = q->timer;
- snd_assert(tmr != NULL, return -EINVAL);
+ if (snd_BUG_ON(!tmr))
+ return -EINVAL;
if (tmr->timeri) {
snd_timer_stop(tmr->timeri);
snd_timer_close(tmr->timeri);
@@ -312,7 +317,7 @@ int snd_seq_timer_close(queue_t *q)
return 0;
}
-int snd_seq_timer_stop(seq_timer_t * tmr)
+int snd_seq_timer_stop(struct snd_seq_timer * tmr)
{
if (! tmr->timeri)
return -EINVAL;
@@ -323,20 +328,30 @@ int snd_seq_timer_stop(seq_timer_t * tmr)
return 0;
}
-static int initialize_timer(seq_timer_t *tmr)
+static int initialize_timer(struct snd_seq_timer *tmr)
{
- snd_timer_t *t;
+ struct snd_timer *t;
+ unsigned long freq;
+
t = tmr->timeri->timer;
- snd_assert(t, return -EINVAL);
+ if (snd_BUG_ON(!t))
+ return -EINVAL;
+
+ freq = tmr->preferred_resolution;
+ if (!freq)
+ freq = DEFAULT_FREQUENCY;
+ else if (freq < MIN_FREQUENCY)
+ freq = MIN_FREQUENCY;
+ else if (freq > MAX_FREQUENCY)
+ freq = MAX_FREQUENCY;
tmr->ticks = 1;
- if (tmr->preferred_resolution &&
- ! (t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
+ if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
unsigned long r = t->hw.resolution;
if (! r && t->hw.c_resolution)
r = t->hw.c_resolution(t);
if (r) {
- tmr->ticks = (unsigned int)(1000000000uL / (r * tmr->preferred_resolution));
+ tmr->ticks = (unsigned int)(1000000000uL / (r * freq));
if (! tmr->ticks)
tmr->ticks = 1;
}
@@ -345,7 +360,7 @@ static int initialize_timer(seq_timer_t *tmr)
return 0;
}
-int snd_seq_timer_start(seq_timer_t * tmr)
+int snd_seq_timer_start(struct snd_seq_timer * tmr)
{
if (! tmr->timeri)
return -EINVAL;
@@ -360,7 +375,7 @@ int snd_seq_timer_start(seq_timer_t * tmr)
return 0;
}
-int snd_seq_timer_continue(seq_timer_t * tmr)
+int snd_seq_timer_continue(struct snd_seq_timer * tmr)
{
if (! tmr->timeri)
return -EINVAL;
@@ -378,7 +393,7 @@ int snd_seq_timer_continue(seq_timer_t * tmr)
}
/* return current 'real' time. use timeofday() to get better granularity. */
-snd_seq_real_time_t snd_seq_timer_get_cur_time(seq_timer_t *tmr)
+snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
{
snd_seq_real_time_t cur_time;
@@ -403,19 +418,21 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(seq_timer_t *tmr)
/* TODO: use interpolation on tick queue (will only be useful for very
high PPQ values) */
-snd_seq_tick_time_t snd_seq_timer_get_cur_tick(seq_timer_t *tmr)
+snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
{
return tmr->tick.cur_tick;
}
+#ifdef CONFIG_PROC_FS
/* exported to seq_info.c */
-void snd_seq_info_timer_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+void snd_seq_info_timer_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
int idx;
- queue_t *q;
- seq_timer_t *tmr;
- snd_timer_instance_t *ti;
+ struct snd_seq_queue *q;
+ struct snd_seq_timer *tmr;
+ struct snd_timer_instance *ti;
unsigned long resolution;
for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) {
@@ -434,3 +451,5 @@ void snd_seq_info_timer_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer
queuefree(q);
}
}
+#endif /* CONFIG_PROC_FS */
+
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
index 287ed68591d..88dfb71805a 100644
--- a/sound/core/seq/seq_timer.h
+++ b/sound/core/seq/seq_timer.h
@@ -24,13 +24,13 @@
#include <sound/timer.h>
#include <sound/seq_kernel.h>
-typedef struct {
+struct snd_seq_timer_tick {
snd_seq_tick_time_t cur_tick; /* current tick */
unsigned long resolution; /* time per tick in nsec */
unsigned long fraction; /* current time per tick in nsec */
-} seq_timer_tick_t;
+};
-typedef struct {
+struct snd_seq_timer {
/* ... tempo / offset / running state */
unsigned int running:1, /* running state of queue */
@@ -40,12 +40,12 @@ typedef struct {
int ppq; /* time resolution, ticks/quarter */
snd_seq_real_time_t cur_time; /* current time */
- seq_timer_tick_t tick; /* current tick */
+ struct snd_seq_timer_tick tick; /* current tick */
int tick_updated;
int type; /* timer type */
- snd_timer_id_t alsa_id; /* ALSA's timer ID */
- snd_timer_instance_t *timeri; /* timer instance */
+ struct snd_timer_id alsa_id; /* ALSA's timer ID */
+ struct snd_timer_instance *timeri; /* timer instance */
unsigned int ticks;
unsigned long preferred_resolution; /* timer resolution, ticks/sec */
@@ -55,17 +55,18 @@ typedef struct {
struct timeval last_update; /* time of last clock update, used for interpolation */
spinlock_t lock;
-} seq_timer_t;
+};
/* create new timer (constructor) */
-extern seq_timer_t *snd_seq_timer_new(void);
+struct snd_seq_timer *snd_seq_timer_new(void);
/* delete timer (destructor) */
-extern void snd_seq_timer_delete(seq_timer_t **tmr);
+void snd_seq_timer_delete(struct snd_seq_timer **tmr);
/* */
-static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution)
+static inline void snd_seq_timer_update_tick(struct snd_seq_timer_tick *tick,
+ unsigned long resolution)
{
if (tick->resolution > 0) {
tick->fraction += resolution;
@@ -119,21 +120,29 @@ static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long
}
/* called by timer isr */
-int snd_seq_timer_open(queue_t *q);
-int snd_seq_timer_close(queue_t *q);
-int snd_seq_timer_midi_open(queue_t *q);
-int snd_seq_timer_midi_close(queue_t *q);
-void snd_seq_timer_defaults(seq_timer_t *tmr);
-void snd_seq_timer_reset(seq_timer_t *tmr);
-int snd_seq_timer_stop(seq_timer_t *tmr);
-int snd_seq_timer_start(seq_timer_t *tmr);
-int snd_seq_timer_continue(seq_timer_t *tmr);
-int snd_seq_timer_set_tempo(seq_timer_t *tmr, int tempo);
-int snd_seq_timer_set_ppq(seq_timer_t *tmr, int ppq);
-int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t position);
-int snd_seq_timer_set_position_time(seq_timer_t *tmr, snd_seq_real_time_t position);
-int snd_seq_timer_set_skew(seq_timer_t *tmr, unsigned int skew, unsigned int base);
-snd_seq_real_time_t snd_seq_timer_get_cur_time(seq_timer_t *tmr);
-snd_seq_tick_time_t snd_seq_timer_get_cur_tick(seq_timer_t *tmr);
+struct snd_seq_queue;
+int snd_seq_timer_open(struct snd_seq_queue *q);
+int snd_seq_timer_close(struct snd_seq_queue *q);
+int snd_seq_timer_midi_open(struct snd_seq_queue *q);
+int snd_seq_timer_midi_close(struct snd_seq_queue *q);
+void snd_seq_timer_defaults(struct snd_seq_timer *tmr);
+void snd_seq_timer_reset(struct snd_seq_timer *tmr);
+int snd_seq_timer_stop(struct snd_seq_timer *tmr);
+int snd_seq_timer_start(struct snd_seq_timer *tmr);
+int snd_seq_timer_continue(struct snd_seq_timer *tmr);
+int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo);
+int snd_seq_timer_set_ppq(struct snd_seq_timer *tmr, int ppq);
+int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
+int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
+int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
+snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr);
+snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr);
+
+extern int seq_default_timer_class;
+extern int seq_default_timer_sclass;
+extern int seq_default_timer_card;
+extern int seq_default_timer_device;
+extern int seq_default_timer_subdevice;
+extern int seq_default_timer_resolution;
#endif
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index e4f512aa742..56e0f4cd3f8 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -35,10 +35,9 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/wait.h>
-#include <linux/sched.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
@@ -56,7 +55,8 @@ MODULE_LICENSE("GPL");
/*
* initialize an event record
*/
-static void snd_virmidi_init_event(snd_virmidi_t *vmidi, snd_seq_event_t *ev)
+static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
+ struct snd_seq_event *ev)
{
memset(ev, 0, sizeof(*ev));
ev->source.port = vmidi->port;
@@ -76,16 +76,15 @@ static void snd_virmidi_init_event(snd_virmidi_t *vmidi, snd_seq_event_t *ev)
/*
* decode input event and put to read buffer of each opened file
*/
-static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_t *ev)
+static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
+ struct snd_seq_event *ev)
{
- snd_virmidi_t *vmidi;
- struct list_head *list;
+ struct snd_virmidi *vmidi;
unsigned char msg[4];
int len;
read_lock(&rdev->filelist_lock);
- list_for_each(list, &rdev->filelist) {
- vmidi = list_entry(list, snd_virmidi_t, list);
+ list_for_each_entry(vmidi, &rdev->filelist, list) {
if (!vmidi->trigger)
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
@@ -111,9 +110,9 @@ static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_
* SNDRV_VIRMIDI_SEQ_ATTACH.
*/
#if 0
-int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev)
+int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = rmidi->private_data;
return snd_virmidi_dev_receive_event(rdev, ev);
@@ -123,10 +122,10 @@ int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev)
/*
* event handler of virmidi port
*/
-static int snd_virmidi_event_input(snd_seq_event_t *ev, int direct,
+static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
void *private_data, int atomic, int hop)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = private_data;
if (!(rdev->flags & SNDRV_VIRMIDI_USE))
@@ -137,9 +136,9 @@ static int snd_virmidi_event_input(snd_seq_event_t *ev, int direct,
/*
* trigger rawmidi stream for input
*/
-static void snd_virmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- snd_virmidi_t *vmidi = substream->runtime->private_data;
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
if (up) {
vmidi->trigger = 1;
@@ -151,9 +150,9 @@ static void snd_virmidi_input_trigger(snd_rawmidi_substream_t * substream, int u
/*
* trigger rawmidi stream for output
*/
-static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int up)
+static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- snd_virmidi_t *vmidi = substream->runtime->private_data;
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
int count, res;
unsigned char buf[32], *pbuf;
@@ -165,7 +164,7 @@ static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int
return; /* ignored */
}
if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
- if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
+ if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
return;
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
}
@@ -184,7 +183,7 @@ static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int
pbuf += res;
count -= res;
if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
- if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
+ if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
return;
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
}
@@ -198,11 +197,11 @@ static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int
/*
* open rawmidi handle for input
*/
-static int snd_virmidi_input_open(snd_rawmidi_substream_t * substream)
+static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
{
- snd_virmidi_dev_t *rdev = substream->rmidi->private_data;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
- snd_virmidi_t *vmidi;
+ struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+ struct snd_virmidi *vmidi;
unsigned long flags;
vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
@@ -227,11 +226,11 @@ static int snd_virmidi_input_open(snd_rawmidi_substream_t * substream)
/*
* open rawmidi handle for output
*/
-static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream)
+static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream)
{
- snd_virmidi_dev_t *rdev = substream->rmidi->private_data;
- snd_rawmidi_runtime_t *runtime = substream->runtime;
- snd_virmidi_t *vmidi;
+ struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+ struct snd_virmidi *vmidi;
vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
if (vmidi == NULL)
@@ -253,9 +252,9 @@ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream)
/*
* close rawmidi handle for input
*/
-static int snd_virmidi_input_close(snd_rawmidi_substream_t * substream)
+static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
{
- snd_virmidi_t *vmidi = substream->runtime->private_data;
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
snd_midi_event_free(vmidi->parser);
list_del(&vmidi->list);
substream->runtime->private_data = NULL;
@@ -266,9 +265,9 @@ static int snd_virmidi_input_close(snd_rawmidi_substream_t * substream)
/*
* close rawmidi handle for output
*/
-static int snd_virmidi_output_close(snd_rawmidi_substream_t * substream)
+static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream)
{
- snd_virmidi_t *vmidi = substream->runtime->private_data;
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -278,9 +277,10 @@ static int snd_virmidi_output_close(snd_rawmidi_substream_t * substream)
/*
* subscribe callback - allow output to rawmidi device
*/
-static int snd_virmidi_subscribe(void *private_data, snd_seq_port_subscribe_t *info)
+static int snd_virmidi_subscribe(void *private_data,
+ struct snd_seq_port_subscribe *info)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = private_data;
if (!try_module_get(rdev->card->module))
@@ -292,9 +292,10 @@ static int snd_virmidi_subscribe(void *private_data, snd_seq_port_subscribe_t *i
/*
* unsubscribe callback - disallow output to rawmidi device
*/
-static int snd_virmidi_unsubscribe(void *private_data, snd_seq_port_subscribe_t *info)
+static int snd_virmidi_unsubscribe(void *private_data,
+ struct snd_seq_port_subscribe *info)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = private_data;
rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE;
@@ -306,9 +307,10 @@ static int snd_virmidi_unsubscribe(void *private_data, snd_seq_port_subscribe_t
/*
* use callback - allow input to rawmidi device
*/
-static int snd_virmidi_use(void *private_data, snd_seq_port_subscribe_t *info)
+static int snd_virmidi_use(void *private_data,
+ struct snd_seq_port_subscribe *info)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = private_data;
if (!try_module_get(rdev->card->module))
@@ -320,9 +322,10 @@ static int snd_virmidi_use(void *private_data, snd_seq_port_subscribe_t *info)
/*
* unuse callback - disallow input to rawmidi device
*/
-static int snd_virmidi_unuse(void *private_data, snd_seq_port_subscribe_t *info)
+static int snd_virmidi_unuse(void *private_data,
+ struct snd_seq_port_subscribe *info)
{
- snd_virmidi_dev_t *rdev;
+ struct snd_virmidi_dev *rdev;
rdev = private_data;
rdev->flags &= ~SNDRV_VIRMIDI_USE;
@@ -335,13 +338,13 @@ static int snd_virmidi_unuse(void *private_data, snd_seq_port_subscribe_t *info)
* Register functions
*/
-static snd_rawmidi_ops_t snd_virmidi_input_ops = {
+static struct snd_rawmidi_ops snd_virmidi_input_ops = {
.open = snd_virmidi_input_open,
.close = snd_virmidi_input_close,
.trigger = snd_virmidi_input_trigger,
};
-static snd_rawmidi_ops_t snd_virmidi_output_ops = {
+static struct snd_rawmidi_ops snd_virmidi_output_ops = {
.open = snd_virmidi_output_open,
.close = snd_virmidi_output_close,
.trigger = snd_virmidi_output_trigger,
@@ -350,52 +353,42 @@ static snd_rawmidi_ops_t snd_virmidi_output_ops = {
/*
* create a sequencer client and a port
*/
-static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev)
+static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
{
int client;
- snd_seq_client_callback_t callbacks;
- snd_seq_port_callback_t pcallbacks;
- snd_seq_client_info_t *info;
- snd_seq_port_info_t *pinfo;
+ struct snd_seq_port_callback pcallbacks;
+ struct snd_seq_port_info *pinfo;
int err;
if (rdev->client >= 0)
return 0;
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
- if (! info || ! pinfo) {
+ pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+ if (!pinfo) {
err = -ENOMEM;
goto __error;
}
- memset(&callbacks, 0, sizeof(callbacks));
- callbacks.private_data = rdev;
- callbacks.allow_input = 1;
- callbacks.allow_output = 1;
- client = snd_seq_create_kernel_client(rdev->card, rdev->device, &callbacks);
+ client = snd_seq_create_kernel_client(rdev->card, rdev->device,
+ "%s %d-%d", rdev->rmidi->name,
+ rdev->card->number,
+ rdev->device);
if (client < 0) {
err = client;
goto __error;
}
rdev->client = client;
- /* set client name */
- memset(info, 0, sizeof(*info));
- info->client = client;
- info->type = KERNEL_CLIENT;
- sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device);
- snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info);
-
/* create a port */
- memset(pinfo, 0, sizeof(*pinfo));
pinfo->addr.client = client;
sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
/* set all capabilities */
pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
- pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+ pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+ | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+ | SNDRV_SEQ_PORT_TYPE_PORT;
pinfo->midi_channels = 16;
memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE;
@@ -417,7 +410,6 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev)
err = 0; /* success */
__error:
- kfree(info);
kfree(pinfo);
return err;
}
@@ -426,7 +418,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev)
/*
* release the sequencer client
*/
-static void snd_virmidi_dev_detach_seq(snd_virmidi_dev_t *rdev)
+static void snd_virmidi_dev_detach_seq(struct snd_virmidi_dev *rdev)
{
if (rdev->client >= 0) {
snd_seq_delete_kernel_client(rdev->client);
@@ -437,9 +429,9 @@ static void snd_virmidi_dev_detach_seq(snd_virmidi_dev_t *rdev)
/*
* register the device
*/
-static int snd_virmidi_dev_register(snd_rawmidi_t *rmidi)
+static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi)
{
- snd_virmidi_dev_t *rdev = rmidi->private_data;
+ struct snd_virmidi_dev *rdev = rmidi->private_data;
int err;
switch (rdev->seq_mode) {
@@ -454,7 +446,7 @@ static int snd_virmidi_dev_register(snd_rawmidi_t *rmidi)
/* should check presence of port more strictly.. */
break;
default:
- snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode);
+ pr_err("ALSA: seq_virmidi: seq_mode is not set: %d\n", rdev->seq_mode);
return -EINVAL;
}
return 0;
@@ -464,9 +456,9 @@ static int snd_virmidi_dev_register(snd_rawmidi_t *rmidi)
/*
* unregister the device
*/
-static int snd_virmidi_dev_unregister(snd_rawmidi_t *rmidi)
+static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi)
{
- snd_virmidi_dev_t *rdev = rmidi->private_data;
+ struct snd_virmidi_dev *rdev = rmidi->private_data;
if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH)
snd_virmidi_dev_detach_seq(rdev);
@@ -476,7 +468,7 @@ static int snd_virmidi_dev_unregister(snd_rawmidi_t *rmidi)
/*
*
*/
-static snd_rawmidi_global_ops_t snd_virmidi_global_ops = {
+static struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
.dev_register = snd_virmidi_dev_register,
.dev_unregister = snd_virmidi_dev_unregister,
};
@@ -484,9 +476,9 @@ static snd_rawmidi_global_ops_t snd_virmidi_global_ops = {
/*
* free device
*/
-static void snd_virmidi_free(snd_rawmidi_t *rmidi)
+static void snd_virmidi_free(struct snd_rawmidi *rmidi)
{
- snd_virmidi_dev_t *rdev = rmidi->private_data;
+ struct snd_virmidi_dev *rdev = rmidi->private_data;
kfree(rdev);
}
@@ -495,10 +487,10 @@ static void snd_virmidi_free(snd_rawmidi_t *rmidi)
*
*/
/* exported */
-int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi)
+int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmidi)
{
- snd_rawmidi_t *rmidi;
- snd_virmidi_dev_t *rdev;
+ struct snd_rawmidi *rmidi;
+ struct snd_virmidi_dev *rdev;
int err;
*rrmidi = NULL;
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index 74745da9deb..0a418503ec4 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -19,16 +19,16 @@
*
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <linux/export.h>
#include <sound/memalloc.h>
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
-#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
{
@@ -39,17 +39,20 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
if (! sgbuf)
return -EINVAL;
+ if (dmab->area)
+ vunmap(dmab->area);
+ dmab->area = NULL;
+
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
tmpb.dev.dev = sgbuf->dev;
for (i = 0; i < sgbuf->pages; i++) {
+ if (!(sgbuf->table[i].addr & ~PAGE_MASK))
+ continue; /* continuous pages */
tmpb.area = sgbuf->table[i].buf;
- tmpb.addr = sgbuf->table[i].addr;
- tmpb.bytes = PAGE_SIZE;
+ tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
+ tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
snd_dma_free_pages(&tmpb);
}
- if (dmab->area)
- vunmap(dmab->area);
- dmab->area = NULL;
kfree(sgbuf->table);
kfree(sgbuf->page_table);
@@ -59,53 +62,104 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
return 0;
}
+#define MAX_ALLOC_PAGES 32
+
void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size)
{
struct snd_sg_buf *sgbuf;
- unsigned int i, pages;
+ unsigned int i, pages, chunk, maxpages;
struct snd_dma_buffer tmpb;
+ struct snd_sg_page *table;
+ struct page **pgtable;
dmab->area = NULL;
dmab->addr = 0;
- dmab->private_data = sgbuf = kmalloc(sizeof(*sgbuf), GFP_KERNEL);
+ dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (! sgbuf)
return NULL;
- memset(sgbuf, 0, sizeof(*sgbuf));
sgbuf->dev = device;
pages = snd_sgbuf_aligned_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
- sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
- if (! sgbuf->table)
+ table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
+ if (!table)
goto _failed;
- memset(sgbuf->table, 0, sizeof(*sgbuf->table) * sgbuf->tblsize);
- sgbuf->page_table = kmalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, GFP_KERNEL);
- if (! sgbuf->page_table)
+ sgbuf->table = table;
+ pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
+ if (!pgtable)
goto _failed;
- memset(sgbuf->page_table, 0, sizeof(*sgbuf->page_table) * sgbuf->tblsize);
+ sgbuf->page_table = pgtable;
- /* allocate each page */
- for (i = 0; i < pages; i++) {
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) {
- if (res_size == NULL)
+ /* allocate pages */
+ maxpages = MAX_ALLOC_PAGES;
+ while (pages > 0) {
+ chunk = pages;
+ /* don't be too eager to take a huge chunk */
+ if (chunk > maxpages)
+ chunk = maxpages;
+ chunk <<= PAGE_SHIFT;
+ if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
+ chunk, &tmpb) < 0) {
+ if (!sgbuf->pages)
+ goto _failed;
+ if (!res_size)
goto _failed;
- *res_size = size = sgbuf->pages * PAGE_SIZE;
+ size = sgbuf->pages * PAGE_SIZE;
break;
}
- sgbuf->table[i].buf = tmpb.area;
- sgbuf->table[i].addr = tmpb.addr;
- sgbuf->page_table[i] = virt_to_page(tmpb.area);
- sgbuf->pages++;
+ chunk = tmpb.bytes >> PAGE_SHIFT;
+ for (i = 0; i < chunk; i++) {
+ table->buf = tmpb.area;
+ table->addr = tmpb.addr;
+ if (!i)
+ table->addr |= chunk; /* mark head */
+ table++;
+ *pgtable++ = virt_to_page(tmpb.area);
+ tmpb.area += PAGE_SIZE;
+ tmpb.addr += PAGE_SIZE;
+ }
+ sgbuf->pages += chunk;
+ pages -= chunk;
+ if (chunk < maxpages)
+ maxpages = chunk;
}
sgbuf->size = size;
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
if (! dmab->area)
goto _failed;
+ if (res_size)
+ *res_size = sgbuf->size;
return dmab->area;
_failed:
snd_free_sgbuf_pages(dmab); /* free the table */
return NULL;
}
+
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+ unsigned int ofs, unsigned int size)
+{
+ struct snd_sg_buf *sg = dmab->private_data;
+ unsigned int start, end, pg;
+
+ start = ofs >> PAGE_SHIFT;
+ end = (ofs + size - 1) >> PAGE_SHIFT;
+ /* check page continuity */
+ pg = sg->table[start].addr >> PAGE_SHIFT;
+ for (;;) {
+ start++;
+ if (start > end)
+ break;
+ pg++;
+ if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+ return (start << PAGE_SHIFT) - ofs;
+ }
+ /* ok, all on continuous pages */
+ return size;
+}
+EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
diff --git a/sound/core/sound.c b/sound/core/sound.c
index b57519a3e3d..38ad1a0dd3f 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -1,6 +1,6 @@
/*
* Advanced Linux Sound Architecture
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,39 +19,32 @@
*
*/
-#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
-#include <sound/version.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <linux/kmod.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/device.h>
-
-#define SNDRV_OS_MINORS 256
+#include <linux/mutex.h>
static int major = CONFIG_SND_MAJOR;
int snd_major;
+EXPORT_SYMBOL(snd_major);
+
static int cards_limit = 1;
-static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO;
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
MODULE_LICENSE("GPL");
module_param(major, int, 0444);
MODULE_PARM_DESC(major, "Major # for sound driver.");
module_param(cards_limit, int, 0444);
MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
-#ifdef CONFIG_DEVFS_FS
-module_param(device_mode, int, 0444);
-MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs.");
-#endif
MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
/* this one holds the actual max. card number currently available.
@@ -59,45 +52,35 @@ MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
* modules are loaded manually, this limit number increases, too.
*/
int snd_ecards_limit;
+EXPORT_SYMBOL(snd_ecards_limit);
-static struct list_head snd_minors_hash[SNDRV_CARDS];
-
-static DECLARE_MUTEX(sound_mutex);
-
-extern struct class *sound_class;
-
+static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
+static DEFINE_MUTEX(sound_mutex);
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
/**
* snd_request_card - try to load the card module
* @card: the card number
*
* Tries to load the module "snd-card-X" for the given card number
- * via KMOD. Returns immediately if already loaded.
+ * via request_module. Returns immediately if already loaded.
*/
void snd_request_card(int card)
{
- int locked;
-
- if (! current->fs->root)
- return;
- read_lock(&snd_card_rwlock);
- locked = snd_cards_lock & (1 << card);
- read_unlock(&snd_card_rwlock);
- if (locked)
+ if (snd_card_locked(card))
return;
if (card < 0 || card >= cards_limit)
return;
request_module("snd-card-%i", card);
}
+EXPORT_SYMBOL(snd_request_card);
+
static void snd_request_other(int minor)
{
char *str;
- if (! current->fs->root)
- return;
switch (minor) {
case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break;
case SNDRV_MINOR_TIMER: str = "snd-timer"; break;
@@ -106,65 +89,127 @@ static void snd_request_other(int minor)
request_module(str);
}
-#endif /* request_module support */
+#endif /* modular kernel */
-static snd_minor_t *snd_minor_search(int minor)
+/**
+ * snd_lookup_minor_data - get user data of a registered device
+ * @minor: the minor number
+ * @type: device type (SNDRV_DEVICE_TYPE_XXX)
+ *
+ * Checks that a minor device with the specified type is registered, and returns
+ * its user data pointer.
+ *
+ * This function increments the reference counter of the card instance
+ * if an associated instance with the given minor number and type is found.
+ * The caller must call snd_card_unref() appropriately later.
+ *
+ * Return: The user data pointer if the specified device is found. %NULL
+ * otherwise.
+ */
+void *snd_lookup_minor_data(unsigned int minor, int type)
{
- struct list_head *list;
- snd_minor_t *mptr;
+ struct snd_minor *mreg;
+ void *private_data;
+
+ if (minor >= ARRAY_SIZE(snd_minors))
+ return NULL;
+ mutex_lock(&sound_mutex);
+ mreg = snd_minors[minor];
+ if (mreg && mreg->type == type) {
+ private_data = mreg->private_data;
+ if (private_data && mreg->card_ptr)
+ get_device(&mreg->card_ptr->card_dev);
+ } else
+ private_data = NULL;
+ mutex_unlock(&sound_mutex);
+ return private_data;
+}
- list_for_each(list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]) {
- mptr = list_entry(list, snd_minor_t, list);
- if (mptr->number == minor)
- return mptr;
+EXPORT_SYMBOL(snd_lookup_minor_data);
+
+#ifdef CONFIG_MODULES
+static struct snd_minor *autoload_device(unsigned int minor)
+{
+ int dev;
+ mutex_unlock(&sound_mutex); /* release lock temporarily */
+ dev = SNDRV_MINOR_DEVICE(minor);
+ if (dev == SNDRV_MINOR_CONTROL) {
+ /* /dev/aloadC? */
+ int card = SNDRV_MINOR_CARD(minor);
+ if (snd_cards[card] == NULL)
+ snd_request_card(card);
+ } else if (dev == SNDRV_MINOR_GLOBAL) {
+ /* /dev/aloadSEQ */
+ snd_request_other(minor);
}
- return NULL;
+ mutex_lock(&sound_mutex); /* reacuire lock */
+ return snd_minors[minor];
}
+#else /* !CONFIG_MODULES */
+#define autoload_device(minor) NULL
+#endif /* CONFIG_MODULES */
static int snd_open(struct inode *inode, struct file *file)
{
- int minor = iminor(inode);
- int card = SNDRV_MINOR_CARD(minor);
- int dev = SNDRV_MINOR_DEVICE(minor);
- snd_minor_t *mptr = NULL;
- struct file_operations *old_fops;
+ unsigned int minor = iminor(inode);
+ struct snd_minor *mptr = NULL;
+ const struct file_operations *new_fops;
int err = 0;
- if (dev != SNDRV_MINOR_SEQUENCER && dev != SNDRV_MINOR_TIMER) {
- if (snd_cards[card] == NULL) {
-#ifdef CONFIG_KMOD
- snd_request_card(card);
- if (snd_cards[card] == NULL)
-#endif
- return -ENODEV;
+ if (minor >= ARRAY_SIZE(snd_minors))
+ return -ENODEV;
+ mutex_lock(&sound_mutex);
+ mptr = snd_minors[minor];
+ if (mptr == NULL) {
+ mptr = autoload_device(minor);
+ if (!mptr) {
+ mutex_unlock(&sound_mutex);
+ return -ENODEV;
}
- } else {
-#ifdef CONFIG_KMOD
- if ((mptr = snd_minor_search(minor)) == NULL)
- snd_request_other(minor);
-#endif
}
- if (mptr == NULL && (mptr = snd_minor_search(minor)) == NULL)
+ new_fops = fops_get(mptr->f_ops);
+ mutex_unlock(&sound_mutex);
+ if (!new_fops)
return -ENODEV;
- old_fops = file->f_op;
- file->f_op = fops_get(mptr->f_ops);
+ replace_fops(file, new_fops);
+
if (file->f_op->open)
err = file->f_op->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- fops_put(old_fops);
return err;
}
-static struct file_operations snd_fops =
+static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
- .open = snd_open
+ .open = snd_open,
+ .llseek = noop_llseek,
};
-static int snd_kernel_minor(int type, snd_card_t * card, int dev)
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+static int snd_find_free_minor(int type)
+{
+ int minor;
+
+ /* static minors for module auto loading */
+ if (type == SNDRV_DEVICE_TYPE_SEQUENCER)
+ return SNDRV_MINOR_SEQUENCER;
+ if (type == SNDRV_DEVICE_TYPE_TIMER)
+ return SNDRV_MINOR_TIMER;
+
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
+ /* skip static minors still used for module auto loading */
+ if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL)
+ continue;
+ if (minor == SNDRV_MINOR_SEQUENCER ||
+ minor == SNDRV_MINOR_TIMER)
+ continue;
+ if (!snd_minors[minor])
+ return minor;
+ }
+ return -EBUSY;
+}
+#else
+static int snd_kernel_minor(int type, struct snd_card *card, int dev)
{
int minor;
@@ -174,69 +219,110 @@ static int snd_kernel_minor(int type, snd_card_t * card, int dev)
minor = type;
break;
case SNDRV_DEVICE_TYPE_CONTROL:
- snd_assert(card != NULL, return -EINVAL);
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
minor = SNDRV_MINOR(card->number, type);
break;
case SNDRV_DEVICE_TYPE_HWDEP:
case SNDRV_DEVICE_TYPE_RAWMIDI:
case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
- snd_assert(card != NULL, return -EINVAL);
+ case SNDRV_DEVICE_TYPE_COMPRESS:
+ if (snd_BUG_ON(!card))
+ return -EINVAL;
minor = SNDRV_MINOR(card->number, type + dev);
break;
default:
return -EINVAL;
}
- snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
+ if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
+ return -EINVAL;
return minor;
}
+#endif
/**
- * snd_register_device - Register the ALSA device file for the card
+ * snd_register_device_for_dev - Register the ALSA device file for the card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
* @card: the card instance
* @dev: the device index
- * @reg: the snd_minor_t record
+ * @f_ops: the file operations
+ * @private_data: user pointer for f_ops->open()
* @name: the device file name
+ * @device: the &struct device to link this new device to
*
* Registers an ALSA device file for the given card.
* The operators have to be set in reg parameter.
*
- * Retrurns zero if successful, or a negative error code on failure.
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, const char *name)
+int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
+ const struct file_operations *f_ops,
+ void *private_data,
+ const char *name, struct device *device)
{
- int minor = snd_kernel_minor(type, card, dev);
- snd_minor_t *preg;
- struct device *device = NULL;
+ int minor;
+ struct snd_minor *preg;
- if (minor < 0)
- return minor;
- snd_assert(name, return -EINVAL);
- preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t) + strlen(name) + 1, GFP_KERNEL);
+ if (snd_BUG_ON(!name))
+ return -EINVAL;
+ preg = kmalloc(sizeof *preg, GFP_KERNEL);
if (preg == NULL)
return -ENOMEM;
- *preg = *reg;
- preg->number = minor;
+ preg->type = type;
+ preg->card = card ? card->number : -1;
preg->device = dev;
- strcpy(preg->name, name);
- down(&sound_mutex);
- if (snd_minor_search(minor)) {
- up(&sound_mutex);
+ preg->f_ops = f_ops;
+ preg->private_data = private_data;
+ preg->card_ptr = card;
+ mutex_lock(&sound_mutex);
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+ minor = snd_find_free_minor(type);
+#else
+ minor = snd_kernel_minor(type, card, dev);
+ if (minor >= 0 && snd_minors[minor])
+ minor = -EBUSY;
+#endif
+ if (minor < 0) {
+ mutex_unlock(&sound_mutex);
kfree(preg);
- return -EBUSY;
+ return minor;
}
- list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]);
- if (strncmp(name, "controlC", 8) || card->number >= cards_limit)
- devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name);
- if (card)
- device = card->dev;
- class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
-
- up(&sound_mutex);
+ snd_minors[minor] = preg;
+ preg->dev = device_create(sound_class, device, MKDEV(major, minor),
+ private_data, "%s", name);
+ if (IS_ERR(preg->dev)) {
+ snd_minors[minor] = NULL;
+ mutex_unlock(&sound_mutex);
+ minor = PTR_ERR(preg->dev);
+ kfree(preg);
+ return minor;
+ }
+
+ mutex_unlock(&sound_mutex);
return 0;
}
+EXPORT_SYMBOL(snd_register_device_for_dev);
+
+/* find the matching minor record
+ * return the index of snd_minor, or -1 if not found
+ */
+static int find_snd_minor(int type, struct snd_card *card, int dev)
+{
+ int cardnum, minor;
+ struct snd_minor *mptr;
+
+ cardnum = card ? card->number : -1;
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
+ if ((mptr = snd_minors[minor]) != NULL &&
+ mptr->type == type &&
+ mptr->card == cardnum &&
+ mptr->device == dev)
+ return minor;
+ return -1;
+}
+
/**
* snd_unregister_device - unregister the device on the given card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
@@ -246,67 +332,109 @@ int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg,
* Unregisters the device file already registered via
* snd_register_device().
*
- * Returns zero if sucecessful, or a negative error code on failure
+ * Return: Zero if successful, or a negative error code on failure.
*/
-int snd_unregister_device(int type, snd_card_t * card, int dev)
+int snd_unregister_device(int type, struct snd_card *card, int dev)
{
- int minor = snd_kernel_minor(type, card, dev);
- snd_minor_t *mptr;
+ int minor;
- if (minor < 0)
- return minor;
- down(&sound_mutex);
- if ((mptr = snd_minor_search(minor)) == NULL) {
- up(&sound_mutex);
+ mutex_lock(&sound_mutex);
+ minor = find_snd_minor(type, card, dev);
+ if (minor < 0) {
+ mutex_unlock(&sound_mutex);
return -EINVAL;
}
- if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */
- devfs_remove("snd/%s", mptr->name);
- class_device_destroy(sound_class, MKDEV(major, minor));
+ device_destroy(sound_class, MKDEV(major, minor));
- list_del(&mptr->list);
- up(&sound_mutex);
- kfree(mptr);
+ kfree(snd_minors[minor]);
+ snd_minors[minor] = NULL;
+ mutex_unlock(&sound_mutex);
return 0;
}
+EXPORT_SYMBOL(snd_unregister_device);
+
+/* get the assigned device to the given type and device number;
+ * the caller needs to release it via put_device() after using it
+ */
+struct device *snd_get_device(int type, struct snd_card *card, int dev)
+{
+ int minor;
+ struct device *d = NULL;
+
+ mutex_lock(&sound_mutex);
+ minor = find_snd_minor(type, card, dev);
+ if (minor >= 0) {
+ d = snd_minors[minor]->dev;
+ if (d)
+ get_device(d);
+ }
+ mutex_unlock(&sound_mutex);
+ return d;
+}
+EXPORT_SYMBOL(snd_get_device);
+
+#ifdef CONFIG_PROC_FS
/*
* INFO PART
*/
-static snd_info_entry_t *snd_minor_info_entry = NULL;
+static struct snd_info_entry *snd_minor_info_entry;
-static void snd_minor_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static const char *snd_device_type_name(int type)
{
- int card, device;
- struct list_head *list;
- snd_minor_t *mptr;
-
- down(&sound_mutex);
- for (card = 0; card < SNDRV_CARDS; card++) {
- list_for_each(list, &snd_minors_hash[card]) {
- mptr = list_entry(list, snd_minor_t, list);
- if (SNDRV_MINOR_DEVICE(mptr->number) != SNDRV_MINOR_SEQUENCER) {
- if ((device = mptr->device) >= 0)
- snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, device, mptr->comment);
- else
- snd_iprintf(buffer, "%3i: [%i] : %s\n", mptr->number, card, mptr->comment);
- } else {
- snd_iprintf(buffer, "%3i: : %s\n", mptr->number, mptr->comment);
- }
- }
+ switch (type) {
+ case SNDRV_DEVICE_TYPE_CONTROL:
+ return "control";
+ case SNDRV_DEVICE_TYPE_HWDEP:
+ return "hardware dependent";
+ case SNDRV_DEVICE_TYPE_RAWMIDI:
+ return "raw midi";
+ case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
+ return "digital audio playback";
+ case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
+ return "digital audio capture";
+ case SNDRV_DEVICE_TYPE_SEQUENCER:
+ return "sequencer";
+ case SNDRV_DEVICE_TYPE_TIMER:
+ return "timer";
+ default:
+ return "?";
}
- up(&sound_mutex);
+}
+
+static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+{
+ int minor;
+ struct snd_minor *mptr;
+
+ mutex_lock(&sound_mutex);
+ for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
+ if (!(mptr = snd_minors[minor]))
+ continue;
+ if (mptr->card >= 0) {
+ if (mptr->device >= 0)
+ snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n",
+ minor, mptr->card, mptr->device,
+ snd_device_type_name(mptr->type));
+ else
+ snd_iprintf(buffer, "%3i: [%2i] : %s\n",
+ minor, mptr->card,
+ snd_device_type_name(mptr->type));
+ } else
+ snd_iprintf(buffer, "%3i: : %s\n", minor,
+ snd_device_type_name(mptr->type));
+ }
+ mutex_unlock(&sound_mutex);
}
int __init snd_minor_info_init(void)
{
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_minor_info_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -319,185 +447,40 @@ int __init snd_minor_info_init(void)
int __exit snd_minor_info_done(void)
{
- if (snd_minor_info_entry)
- snd_info_unregister(snd_minor_info_entry);
+ snd_info_free_entry(snd_minor_info_entry);
return 0;
}
+#endif /* CONFIG_PROC_FS */
/*
* INIT PART
*/
-#ifdef CONFIG_SND_GENERIC_DRIVER
-extern struct device_driver snd_generic_driver;
-#endif
-
static int __init alsa_sound_init(void)
{
- short controlnum;
- int err;
- int card;
-
snd_major = major;
snd_ecards_limit = cards_limit;
- for (card = 0; card < SNDRV_CARDS; card++)
- INIT_LIST_HEAD(&snd_minors_hash[card]);
- if ((err = snd_oss_init_module()) < 0)
- return err;
- devfs_mk_dir("snd");
if (register_chrdev(major, "alsa", &snd_fops)) {
- snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
- devfs_remove("snd");
+ pr_err("ALSA core: unable to register native major device number %d\n", major);
return -EIO;
}
- snd_memory_init();
if (snd_info_init() < 0) {
- snd_memory_done();
unregister_chrdev(major, "alsa");
- devfs_remove("snd");
return -ENOMEM;
}
snd_info_minor_register();
-#ifdef CONFIG_SND_GENERIC_DRIVER
- driver_register(&snd_generic_driver);
-#endif
- for (controlnum = 0; controlnum < cards_limit; controlnum++)
- devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum);
#ifndef MODULE
- printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
+ pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
#endif
return 0;
}
static void __exit alsa_sound_exit(void)
{
- short controlnum;
-
- for (controlnum = 0; controlnum < cards_limit; controlnum++)
- devfs_remove("snd/controlC%d", controlnum);
-
-#ifdef CONFIG_SND_GENERIC_DRIVER
- driver_unregister(&snd_generic_driver);
-#endif
snd_info_minor_unregister();
snd_info_done();
- snd_memory_done();
- if (unregister_chrdev(major, "alsa") != 0)
- snd_printk(KERN_ERR "unable to unregister major device number %d\n", major);
- devfs_remove("snd");
+ unregister_chrdev(major, "alsa");
}
-module_init(alsa_sound_init)
-module_exit(alsa_sound_exit)
-
- /* sound.c */
-EXPORT_SYMBOL(snd_major);
-EXPORT_SYMBOL(snd_ecards_limit);
-#if defined(CONFIG_KMOD)
-EXPORT_SYMBOL(snd_request_card);
-#endif
-EXPORT_SYMBOL(snd_register_device);
-EXPORT_SYMBOL(snd_unregister_device);
-#if defined(CONFIG_SND_OSSEMUL)
-EXPORT_SYMBOL(snd_register_oss_device);
-EXPORT_SYMBOL(snd_unregister_oss_device);
-#endif
- /* memory.c */
-#ifdef CONFIG_SND_DEBUG_MEMORY
-EXPORT_SYMBOL(snd_hidden_kmalloc);
-EXPORT_SYMBOL(snd_hidden_kcalloc);
-EXPORT_SYMBOL(snd_hidden_kfree);
-EXPORT_SYMBOL(snd_hidden_vmalloc);
-EXPORT_SYMBOL(snd_hidden_vfree);
-EXPORT_SYMBOL(snd_hidden_kstrdup);
-#endif
-EXPORT_SYMBOL(copy_to_user_fromio);
-EXPORT_SYMBOL(copy_from_user_toio);
- /* init.c */
-EXPORT_SYMBOL(snd_cards);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
-#endif
-EXPORT_SYMBOL(snd_card_new);
-EXPORT_SYMBOL(snd_card_disconnect);
-EXPORT_SYMBOL(snd_card_free);
-EXPORT_SYMBOL(snd_card_free_in_thread);
-EXPORT_SYMBOL(snd_card_register);
-EXPORT_SYMBOL(snd_component_add);
-EXPORT_SYMBOL(snd_card_file_add);
-EXPORT_SYMBOL(snd_card_file_remove);
-#ifdef CONFIG_SND_GENERIC_DRIVER
-EXPORT_SYMBOL(snd_card_set_generic_dev);
-#endif
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_power_wait);
-EXPORT_SYMBOL(snd_card_set_pm_callback);
-#ifdef CONFIG_SND_GENERIC_DRIVER
-EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(snd_card_pci_suspend);
-EXPORT_SYMBOL(snd_card_pci_resume);
-#endif
-#endif
- /* device.c */
-EXPORT_SYMBOL(snd_device_new);
-EXPORT_SYMBOL(snd_device_register);
-EXPORT_SYMBOL(snd_device_free);
- /* isadma.c */
-#ifdef CONFIG_ISA_DMA_API
-EXPORT_SYMBOL(snd_dma_program);
-EXPORT_SYMBOL(snd_dma_disable);
-EXPORT_SYMBOL(snd_dma_pointer);
-#endif
- /* info.c */
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(snd_seq_root);
-EXPORT_SYMBOL(snd_iprintf);
-EXPORT_SYMBOL(snd_info_get_line);
-EXPORT_SYMBOL(snd_info_get_str);
-EXPORT_SYMBOL(snd_info_create_module_entry);
-EXPORT_SYMBOL(snd_info_create_card_entry);
-EXPORT_SYMBOL(snd_info_free_entry);
-EXPORT_SYMBOL(snd_info_register);
-EXPORT_SYMBOL(snd_info_unregister);
-EXPORT_SYMBOL(snd_card_proc_new);
-#endif
- /* info_oss.c */
-#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
-EXPORT_SYMBOL(snd_oss_info_register);
-#endif
- /* control.c */
-EXPORT_SYMBOL(snd_ctl_new);
-EXPORT_SYMBOL(snd_ctl_new1);
-EXPORT_SYMBOL(snd_ctl_free_one);
-EXPORT_SYMBOL(snd_ctl_add);
-EXPORT_SYMBOL(snd_ctl_remove);
-EXPORT_SYMBOL(snd_ctl_remove_id);
-EXPORT_SYMBOL(snd_ctl_rename_id);
-EXPORT_SYMBOL(snd_ctl_find_numid);
-EXPORT_SYMBOL(snd_ctl_find_id);
-EXPORT_SYMBOL(snd_ctl_notify);
-EXPORT_SYMBOL(snd_ctl_register_ioctl);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
-#ifdef CONFIG_COMPAT
-EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
-#endif
-EXPORT_SYMBOL(snd_ctl_elem_read);
-EXPORT_SYMBOL(snd_ctl_elem_write);
- /* misc.c */
-EXPORT_SYMBOL(snd_task_name);
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-EXPORT_SYMBOL(snd_verbose_printk);
-#endif
-#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
-EXPORT_SYMBOL(snd_verbose_printd);
-#endif
- /* wrappers */
-#ifdef CONFIG_SND_DEBUG_MEMORY
-EXPORT_SYMBOL(snd_wrapper_kmalloc);
-EXPORT_SYMBOL(snd_wrapper_kfree);
-EXPORT_SYMBOL(snd_wrapper_vmalloc);
-EXPORT_SYMBOL(snd_wrapper_vfree);
-#endif
+subsys_initcall(alsa_sound_init);
+module_exit(alsa_sound_exit);
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index e401c670329..573a65eb2b7 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -1,6 +1,6 @@
/*
* Advanced Linux Sound Architecture
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,48 +19,59 @@
*
*/
-#include <sound/driver.h>
-
#ifdef CONFIG_SND_OSSEMUL
-#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
+#if !IS_ENABLED(CONFIG_SOUND)
#error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
#endif
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
#include <linux/sound.h>
+#include <linux/mutex.h>
-#define SNDRV_OS_MINORS 256
-
-static struct list_head snd_oss_minors_hash[SNDRV_CARDS];
+#define SNDRV_OSS_MINORS 256
-static DECLARE_MUTEX(sound_oss_mutex);
+static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
+static DEFINE_MUTEX(sound_oss_mutex);
-static snd_minor_t *snd_oss_minor_search(int minor)
+/* NOTE: This function increments the refcount of the associated card like
+ * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately
+ */
+void *snd_lookup_oss_minor_data(unsigned int minor, int type)
{
- struct list_head *list;
- snd_minor_t *mptr;
+ struct snd_minor *mreg;
+ void *private_data;
- list_for_each(list, &snd_oss_minors_hash[SNDRV_MINOR_OSS_CARD(minor)]) {
- mptr = list_entry(list, snd_minor_t, list);
- if (mptr->number == minor)
- return mptr;
- }
- return NULL;
+ if (minor >= ARRAY_SIZE(snd_oss_minors))
+ return NULL;
+ mutex_lock(&sound_oss_mutex);
+ mreg = snd_oss_minors[minor];
+ if (mreg && mreg->type == type) {
+ private_data = mreg->private_data;
+ if (private_data && mreg->card_ptr)
+ get_device(&mreg->card_ptr->card_dev);
+ } else
+ private_data = NULL;
+ mutex_unlock(&sound_oss_mutex);
+ return private_data;
}
-static int snd_oss_kernel_minor(int type, snd_card_t * card, int dev)
+EXPORT_SYMBOL(snd_lookup_oss_minor_data);
+
+static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
{
int minor;
switch (type) {
case SNDRV_OSS_DEVICE_TYPE_MIXER:
- snd_assert(card != NULL && dev <= 1, return -EINVAL);
+ if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+ return -EINVAL;
minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER));
break;
case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
@@ -70,11 +81,13 @@ static int snd_oss_kernel_minor(int type, snd_card_t * card, int dev)
minor = SNDRV_MINOR_OSS_MUSIC;
break;
case SNDRV_OSS_DEVICE_TYPE_PCM:
- snd_assert(card != NULL && dev <= 1, return -EINVAL);
+ if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+ return -EINVAL;
minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM));
break;
case SNDRV_OSS_DEVICE_TYPE_MIDI:
- snd_assert(card != NULL && dev <= 1, return -EINVAL);
+ if (snd_BUG_ON(!card || dev < 0 || dev > 1))
+ return -EINVAL;
minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI));
break;
case SNDRV_OSS_DEVICE_TYPE_DMFM:
@@ -86,30 +99,37 @@ static int snd_oss_kernel_minor(int type, snd_card_t * card, int dev)
default:
return -EINVAL;
}
- snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
+ if (minor < 0 || minor >= SNDRV_OSS_MINORS)
+ return -EINVAL;
return minor;
}
-int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, const char *name)
+int snd_register_oss_device(int type, struct snd_card *card, int dev,
+ const struct file_operations *f_ops, void *private_data)
{
int minor = snd_oss_kernel_minor(type, card, dev);
int minor_unit;
- snd_minor_t *preg;
+ struct snd_minor *preg;
int cidx = SNDRV_MINOR_OSS_CARD(minor);
int track2 = -1;
int register1 = -1, register2 = -1;
- struct device *carddev = NULL;
+ struct device *carddev = snd_card_get_device_link(card);
+ if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
+ return 0; /* ignore silently */
if (minor < 0)
return minor;
- preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t), GFP_KERNEL);
+ preg = kmalloc(sizeof(struct snd_minor), GFP_KERNEL);
if (preg == NULL)
return -ENOMEM;
- *preg = *reg;
- preg->number = minor;
+ preg->type = type;
+ preg->card = card ? card->number : -1;
preg->device = dev;
- down(&sound_oss_mutex);
- list_add_tail(&preg->list, &snd_oss_minors_hash[cidx]);
+ preg->f_ops = f_ops;
+ preg->private_data = private_data;
+ preg->card_ptr = card;
+ mutex_lock(&sound_oss_mutex);
+ snd_oss_minors[minor] = preg;
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
switch (minor_unit) {
case SNDRV_MINOR_OSS_PCM:
@@ -122,17 +142,17 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
- if (card)
- carddev = card->dev;
- register1 = register_sound_special_device(reg->f_ops, minor, carddev);
+ register1 = register_sound_special_device(f_ops, minor, carddev);
if (register1 != minor)
goto __end;
if (track2 >= 0) {
- register2 = register_sound_special_device(reg->f_ops, track2, carddev);
+ register2 = register_sound_special_device(f_ops, track2,
+ carddev);
if (register2 != track2)
goto __end;
+ snd_oss_minors[track2] = preg;
}
- up(&sound_oss_mutex);
+ mutex_unlock(&sound_oss_mutex);
return 0;
__end:
@@ -140,25 +160,29 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
unregister_sound_special(register2);
if (register1 >= 0)
unregister_sound_special(register1);
- list_del(&preg->list);
- up(&sound_oss_mutex);
+ snd_oss_minors[minor] = NULL;
+ mutex_unlock(&sound_oss_mutex);
kfree(preg);
return -EBUSY;
}
-int snd_unregister_oss_device(int type, snd_card_t * card, int dev)
+EXPORT_SYMBOL(snd_register_oss_device);
+
+int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
{
int minor = snd_oss_kernel_minor(type, card, dev);
int cidx = SNDRV_MINOR_OSS_CARD(minor);
int track2 = -1;
- snd_minor_t *mptr;
+ struct snd_minor *mptr;
+ if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
+ return 0;
if (minor < 0)
return minor;
- down(&sound_oss_mutex);
- mptr = snd_oss_minor_search(minor);
+ mutex_lock(&sound_oss_mutex);
+ mptr = snd_oss_minors[minor];
if (mptr == NULL) {
- up(&sound_oss_mutex);
+ mutex_unlock(&sound_oss_mutex);
return -ENOENT;
}
unregister_sound_special(minor);
@@ -173,54 +197,73 @@ int snd_unregister_oss_device(int type, snd_card_t * card, int dev)
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
- if (track2 >= 0)
+ if (track2 >= 0) {
unregister_sound_special(track2);
- list_del(&mptr->list);
- up(&sound_oss_mutex);
+ snd_oss_minors[track2] = NULL;
+ }
+ snd_oss_minors[minor] = NULL;
+ mutex_unlock(&sound_oss_mutex);
kfree(mptr);
return 0;
}
+EXPORT_SYMBOL(snd_unregister_oss_device);
+
/*
* INFO PART
*/
#ifdef CONFIG_PROC_FS
-static snd_info_entry_t *snd_minor_info_oss_entry = NULL;
+static struct snd_info_entry *snd_minor_info_oss_entry;
-static void snd_minor_info_oss_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+static const char *snd_oss_device_type_name(int type)
{
- int card, dev;
- struct list_head *list;
- snd_minor_t *mptr;
-
- down(&sound_oss_mutex);
- for (card = 0; card < SNDRV_CARDS; card++) {
- list_for_each(list, &snd_oss_minors_hash[card]) {
- mptr = list_entry(list, snd_minor_t, list);
- dev = SNDRV_MINOR_OSS_DEVICE(mptr->number);
- if (dev != SNDRV_MINOR_OSS_SNDSTAT &&
- dev != SNDRV_MINOR_OSS_SEQUENCER &&
- dev != SNDRV_MINOR_OSS_MUSIC)
- snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, dev, mptr->comment);
- else
- snd_iprintf(buffer, "%3i: : %s\n", mptr->number, mptr->comment);
- }
+ switch (type) {
+ case SNDRV_OSS_DEVICE_TYPE_MIXER:
+ return "mixer";
+ case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
+ case SNDRV_OSS_DEVICE_TYPE_MUSIC:
+ return "sequencer";
+ case SNDRV_OSS_DEVICE_TYPE_PCM:
+ return "digital audio";
+ case SNDRV_OSS_DEVICE_TYPE_MIDI:
+ return "raw midi";
+ case SNDRV_OSS_DEVICE_TYPE_DMFM:
+ return "hardware dependent";
+ default:
+ return "?";
}
- up(&sound_oss_mutex);
}
-#endif /* CONFIG_PROC_FS */
+static void snd_minor_info_oss_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ int minor;
+ struct snd_minor *mptr;
+
+ mutex_lock(&sound_oss_mutex);
+ for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
+ if (!(mptr = snd_oss_minors[minor]))
+ continue;
+ if (mptr->card >= 0)
+ snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor,
+ mptr->card, mptr->device,
+ snd_oss_device_type_name(mptr->type));
+ else
+ snd_iprintf(buffer, "%3i: : %s\n", minor,
+ snd_oss_device_type_name(mptr->type));
+ }
+ mutex_unlock(&sound_oss_mutex);
+}
+
int __init snd_minor_info_oss_init(void)
{
-#ifdef CONFIG_PROC_FS
- snd_info_entry_t *entry;
+ struct snd_info_entry *entry;
entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
if (entry) {
- entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_minor_info_oss_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);
@@ -228,26 +271,14 @@ int __init snd_minor_info_oss_init(void)
}
}
snd_minor_info_oss_entry = entry;
-#endif
return 0;
}
int __exit snd_minor_info_oss_done(void)
{
-#ifdef CONFIG_PROC_FS
- if (snd_minor_info_oss_entry)
- snd_info_unregister(snd_minor_info_oss_entry);
-#endif
- return 0;
-}
-
-int __init snd_oss_init_module(void)
-{
- int card;
-
- for (card = 0; card < SNDRV_CARDS; card++)
- INIT_LIST_HEAD(&snd_oss_minors_hash[card]);
+ snd_info_free_entry(snd_minor_info_oss_entry);
return 0;
}
+#endif /* CONFIG_PROC_FS */
#endif /* CONFIG_SND_OSSEMUL */
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 22b10462408..777a45e08e5 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1,6 +1,6 @@
/*
* Timers abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,13 @@
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/module.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/timer.h>
@@ -34,44 +34,47 @@
#include <sound/minors.h>
#include <sound/initval.h>
#include <linux/kmod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
-#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
-#define DEFAULT_TIMER_LIMIT 3
-#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
+#if IS_ENABLED(CONFIG_SND_HRTIMER)
+#define DEFAULT_TIMER_LIMIT 4
+#elif IS_ENABLED(CONFIG_SND_RTCTIMER)
#define DEFAULT_TIMER_LIMIT 2
#else
#define DEFAULT_TIMER_LIMIT 1
#endif
static int timer_limit = DEFAULT_TIMER_LIMIT;
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
+static int timer_tstamp_monotonic = 1;
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL");
module_param(timer_limit, int, 0444);
MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
+module_param(timer_tstamp_monotonic, int, 0444);
+MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
+
+MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
+MODULE_ALIAS("devname:snd/timer");
-typedef struct {
- snd_timer_instance_t *timeri;
- int tread; /* enhanced read with timestamps and events */
+struct snd_timer_user {
+ struct snd_timer_instance *timeri;
+ int tread; /* enhanced read with timestamps and events */
unsigned long ticks;
unsigned long overrun;
int qhead;
int qtail;
int qused;
int queue_size;
- snd_timer_read_t *queue;
- snd_timer_tread_t *tqueue;
+ struct snd_timer_read *queue;
+ struct snd_timer_tread *tqueue;
spinlock_t qlock;
unsigned long last_resolution;
unsigned int filter;
struct timespec tstamp; /* trigger tstamp */
wait_queue_head_t qchange_sleep;
struct fasync_struct *fasync;
- struct semaphore tread_sem;
-} snd_timer_user_t;
+ struct mutex tread_sem;
+};
/* list of timers */
static LIST_HEAD(snd_timer_list);
@@ -82,22 +85,23 @@ static LIST_HEAD(snd_timer_slave_list);
/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
-static int snd_timer_free(snd_timer_t *timer);
-static int snd_timer_dev_free(snd_device_t *device);
-static int snd_timer_dev_register(snd_device_t *device);
-static int snd_timer_dev_unregister(snd_device_t *device);
+static int snd_timer_free(struct snd_timer *timer);
+static int snd_timer_dev_free(struct snd_device *device);
+static int snd_timer_dev_register(struct snd_device *device);
+static int snd_timer_dev_disconnect(struct snd_device *device);
-static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left);
+static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
/*
* create a timer instance with the given owner string.
* when timer is not NULL, increments the module counter
*/
-static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer)
+static struct snd_timer_instance *snd_timer_instance_new(char *owner,
+ struct snd_timer *timer)
{
- snd_timer_instance_t *timeri;
+ struct snd_timer_instance *timeri;
timeri = kzalloc(sizeof(*timeri), GFP_KERNEL);
if (timeri == NULL)
return NULL;
@@ -113,7 +117,7 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti
INIT_LIST_HEAD(&timeri->slave_active_head);
timeri->timer = timer;
- if (timer && timer->card && !try_module_get(timer->card->module)) {
+ if (timer && !try_module_get(timer->module)) {
kfree(timeri->owner);
kfree(timeri);
return NULL;
@@ -125,14 +129,11 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti
/*
* find a timer instance from the given timer id
*/
-static snd_timer_t *snd_timer_find(snd_timer_id_t *tid)
+static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
{
- snd_timer_t *timer = NULL;
- struct list_head *p;
-
- list_for_each(p, &snd_timer_list) {
- timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
+ struct snd_timer *timer = NULL;
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
if (timer->tmr_class != tid->dev_class)
continue;
if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
@@ -149,12 +150,10 @@ static snd_timer_t *snd_timer_find(snd_timer_id_t *tid)
return NULL;
}
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
-static void snd_timer_request(snd_timer_id_t *tid)
+static void snd_timer_request(struct snd_timer_id *tid)
{
- if (! current->fs->root)
- return;
switch (tid->dev_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
if (tid->device < timer_limit)
@@ -178,21 +177,18 @@ static void snd_timer_request(snd_timer_id_t *tid)
*
* call this with register_mutex down.
*/
-static void snd_timer_check_slave(snd_timer_instance_t *slave)
+static void snd_timer_check_slave(struct snd_timer_instance *slave)
{
- snd_timer_t *timer;
- snd_timer_instance_t *master;
- struct list_head *p, *q;
+ struct snd_timer *timer;
+ struct snd_timer_instance *master;
/* FIXME: it's really dumb to look up all entries.. */
- list_for_each(p, &snd_timer_list) {
- timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
- list_for_each(q, &timer->open_list_head) {
- master = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list);
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
+ list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
- list_del(&slave->open_list);
- list_add_tail(&slave->open_list, &master->slave_list_head);
+ list_move_tail(&slave->open_list,
+ &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
@@ -209,23 +205,21 @@ static void snd_timer_check_slave(snd_timer_instance_t *slave)
*
* call this with register_mutex down.
*/
-static void snd_timer_check_master(snd_timer_instance_t *master)
+static void snd_timer_check_master(struct snd_timer_instance *master)
{
- snd_timer_instance_t *slave;
- struct list_head *p, *n;
+ struct snd_timer_instance *slave, *tmp;
/* check all pending slaves */
- list_for_each_safe(p, n, &snd_timer_slave_list) {
- slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
+ list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
- list_del(p);
- list_add_tail(p, &master->slave_list_head);
+ list_move_tail(&slave->open_list, &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
- list_add_tail(&slave->active_list, &master->slave_active_head);
+ list_add_tail(&slave->active_list,
+ &master->slave_active_head);
spin_unlock_irq(&slave_active_lock);
}
}
@@ -235,81 +229,89 @@ static void snd_timer_check_master(snd_timer_instance_t *master)
* open a timer instance
* when opening a master, the slave id must be here given.
*/
-int snd_timer_open(snd_timer_instance_t **ti,
- char *owner, snd_timer_id_t *tid,
+int snd_timer_open(struct snd_timer_instance **ti,
+ char *owner, struct snd_timer_id *tid,
unsigned int slave_id)
{
- snd_timer_t *timer;
- snd_timer_instance_t *timeri = NULL;
-
+ struct snd_timer *timer;
+ struct snd_timer_instance *timeri = NULL;
+
if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
/* open a slave instance */
if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
- snd_printd("invalid slave class %i\n", tid->dev_sclass);
+ pr_debug("ALSA: timer: invalid slave class %i\n",
+ tid->dev_sclass);
return -EINVAL;
}
- down(&register_mutex);
+ mutex_lock(&register_mutex);
timeri = snd_timer_instance_new(owner, NULL);
+ if (!timeri) {
+ mutex_unlock(&register_mutex);
+ return -ENOMEM;
+ }
timeri->slave_class = tid->dev_sclass;
timeri->slave_id = tid->device;
timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
list_add_tail(&timeri->open_list, &snd_timer_slave_list);
snd_timer_check_slave(timeri);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
*ti = timeri;
return 0;
}
/* open a master instance */
- down(&register_mutex);
+ mutex_lock(&register_mutex);
timer = snd_timer_find(tid);
-#ifdef CONFIG_KMOD
- if (timer == NULL) {
- up(&register_mutex);
+#ifdef CONFIG_MODULES
+ if (!timer) {
+ mutex_unlock(&register_mutex);
snd_timer_request(tid);
- down(&register_mutex);
+ mutex_lock(&register_mutex);
timer = snd_timer_find(tid);
}
#endif
- if (timer) {
- if (!list_empty(&timer->open_list_head)) {
- timeri = (snd_timer_instance_t *)list_entry(timer->open_list_head.next, snd_timer_instance_t, open_list);
- if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
- up(&register_mutex);
- return -EBUSY;
- }
- }
- timeri = snd_timer_instance_new(owner, timer);
- if (timeri) {
- timeri->slave_class = tid->dev_sclass;
- timeri->slave_id = slave_id;
- if (list_empty(&timer->open_list_head) && timer->hw.open)
- timer->hw.open(timer);
- list_add_tail(&timeri->open_list, &timer->open_list_head);
- snd_timer_check_master(timeri);
- }
- } else {
- up(&register_mutex);
+ if (!timer) {
+ mutex_unlock(&register_mutex);
return -ENODEV;
}
- up(&register_mutex);
+ if (!list_empty(&timer->open_list_head)) {
+ timeri = list_entry(timer->open_list_head.next,
+ struct snd_timer_instance, open_list);
+ if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
+ mutex_unlock(&register_mutex);
+ return -EBUSY;
+ }
+ }
+ timeri = snd_timer_instance_new(owner, timer);
+ if (!timeri) {
+ mutex_unlock(&register_mutex);
+ return -ENOMEM;
+ }
+ timeri->slave_class = tid->dev_sclass;
+ timeri->slave_id = slave_id;
+ if (list_empty(&timer->open_list_head) && timer->hw.open)
+ timer->hw.open(timer);
+ list_add_tail(&timeri->open_list, &timer->open_list_head);
+ snd_timer_check_master(timeri);
+ mutex_unlock(&register_mutex);
*ti = timeri;
return 0;
}
-static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event);
+static int _snd_timer_stop(struct snd_timer_instance *timeri,
+ int keep_flag, int event);
/*
* close a timer instance
*/
-int snd_timer_close(snd_timer_instance_t * timeri)
+int snd_timer_close(struct snd_timer_instance *timeri)
{
- snd_timer_t *timer = NULL;
- struct list_head *p, *n;
- snd_timer_instance_t *slave;
+ struct snd_timer *timer = NULL;
+ struct snd_timer_instance *slave, *tmp;
- snd_assert(timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timeri))
+ return -ENXIO;
/* force to stop the timer */
snd_timer_stop(timeri);
@@ -323,11 +325,13 @@ int snd_timer_close(snd_timer_instance_t * timeri)
spin_lock_irq(&slave_active_lock);
}
spin_unlock_irq(&slave_active_lock);
- down(&register_mutex);
+ mutex_lock(&register_mutex);
list_del(&timeri->open_list);
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
} else {
timer = timeri->timer;
+ if (snd_BUG_ON(!timer))
+ goto out;
/* wait, until the active callback is finished */
spin_lock_irq(&timer->lock);
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -336,35 +340,36 @@ int snd_timer_close(snd_timer_instance_t * timeri)
spin_lock_irq(&timer->lock);
}
spin_unlock_irq(&timer->lock);
- down(&register_mutex);
+ mutex_lock(&register_mutex);
list_del(&timeri->open_list);
- if (timer && list_empty(&timer->open_list_head) && timer->hw.close)
+ if (timer && list_empty(&timer->open_list_head) &&
+ timer->hw.close)
timer->hw.close(timer);
/* remove slave links */
- list_for_each_safe(p, n, &timeri->slave_list_head) {
- slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
+ list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
+ open_list) {
spin_lock_irq(&slave_active_lock);
_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
- list_del(p);
- list_add_tail(p, &snd_timer_slave_list);
+ list_move_tail(&slave->open_list, &snd_timer_slave_list);
slave->master = NULL;
slave->timer = NULL;
spin_unlock_irq(&slave_active_lock);
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
}
+ out:
if (timeri->private_free)
timeri->private_free(timeri);
kfree(timeri->owner);
kfree(timeri);
- if (timer && timer->card)
- module_put(timer->card->module);
+ if (timer)
+ module_put(timer->module);
return 0;
}
-unsigned long snd_timer_resolution(snd_timer_instance_t * timeri)
+unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{
- snd_timer_t * timer;
+ struct snd_timer * timer;
if (timeri == NULL)
return 0;
@@ -376,21 +381,26 @@ unsigned long snd_timer_resolution(snd_timer_instance_t * timeri)
return 0;
}
-static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event event)
+static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
unsigned long flags;
unsigned long resolution = 0;
- snd_timer_instance_t *ts;
- struct list_head *n;
+ struct snd_timer_instance *ts;
struct timespec tstamp;
- snd_timestamp_now(&tstamp, 1);
- snd_assert(event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE, return);
- if (event == SNDRV_TIMER_EVENT_START || event == SNDRV_TIMER_EVENT_CONTINUE)
+ if (timer_tstamp_monotonic)
+ ktime_get_ts(&tstamp);
+ else
+ getnstimeofday(&tstamp);
+ if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
+ event > SNDRV_TIMER_EVENT_PAUSE))
+ return;
+ if (event == SNDRV_TIMER_EVENT_START ||
+ event == SNDRV_TIMER_EVENT_CONTINUE)
resolution = snd_timer_resolution(ti);
if (ti->ccallback)
- ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
+ ti->ccallback(ti, event, &tstamp, resolution);
if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
return;
timer = ti->timer;
@@ -399,18 +409,16 @@ static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event e
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
return;
spin_lock_irqsave(&timer->lock, flags);
- list_for_each(n, &ti->slave_active_head) {
- ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ti, event + 100, &tstamp, resolution);
- }
spin_unlock_irqrestore(&timer->lock, flags);
}
-static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, unsigned long sticks)
+static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri,
+ unsigned long sticks)
{
- list_del(&timeri->active_list);
- list_add_tail(&timeri->active_list, &timer->active_list_head);
+ list_move_tail(&timeri->active_list, &timer->active_list_head);
if (timer->running) {
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
goto __start_now;
@@ -427,24 +435,25 @@ static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, un
}
}
-static int snd_timer_start_slave(snd_timer_instance_t *timeri)
+static int snd_timer_start_slave(struct snd_timer_instance *timeri)
{
unsigned long flags;
spin_lock_irqsave(&slave_active_lock, flags);
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
if (timeri->master)
- list_add_tail(&timeri->active_list, &timeri->master->slave_active_head);
+ list_add_tail(&timeri->active_list,
+ &timeri->master->slave_active_head);
spin_unlock_irqrestore(&slave_active_lock, flags);
return 1; /* delayed start */
}
/*
* start the timer instance
- */
-int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks)
+ */
+int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
int result = -EINVAL;
unsigned long flags;
@@ -467,12 +476,14 @@ int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks)
return result;
}
-static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event)
+static int _snd_timer_stop(struct snd_timer_instance * timeri,
+ int keep_flag, int event)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
unsigned long flags;
- snd_assert(timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timeri))
+ return -ENXIO;
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
if (!keep_flag) {
@@ -501,7 +512,8 @@ static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sn
}
}
if (!keep_flag)
- timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START);
+ timeri->flags &=
+ ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
spin_unlock_irqrestore(&timer->lock, flags);
__end:
if (event != SNDRV_TIMER_EVENT_RESOLUTION)
@@ -514,9 +526,9 @@ static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sn
*
* do not call this from the timer callback!
*/
-int snd_timer_stop(snd_timer_instance_t * timeri)
+int snd_timer_stop(struct snd_timer_instance *timeri)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
unsigned long flags;
int err;
@@ -524,6 +536,8 @@ int snd_timer_stop(snd_timer_instance_t * timeri)
if (err < 0)
return err;
timer = timeri->timer;
+ if (!timer)
+ return -EINVAL;
spin_lock_irqsave(&timer->lock, flags);
timeri->cticks = timeri->ticks;
timeri->pticks = 0;
@@ -534,9 +548,9 @@ int snd_timer_stop(snd_timer_instance_t * timeri)
/*
* start again.. the tick is kept.
*/
-int snd_timer_continue(snd_timer_instance_t * timeri)
+int snd_timer_continue(struct snd_timer_instance *timeri)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
int result = -EINVAL;
unsigned long flags;
@@ -560,7 +574,7 @@ int snd_timer_continue(snd_timer_instance_t * timeri)
/*
* pause.. remember the ticks left
*/
-int snd_timer_pause(snd_timer_instance_t * timeri)
+int snd_timer_pause(struct snd_timer_instance * timeri)
{
return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
}
@@ -571,14 +585,12 @@ int snd_timer_pause(snd_timer_instance_t * timeri)
* start pending instances and check the scheduling ticks.
* when the scheduling ticks is changed set CHANGE flag to reprogram the timer.
*/
-static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left)
+static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left)
{
- snd_timer_instance_t *ti;
+ struct snd_timer_instance *ti;
unsigned long ticks = ~0UL;
- struct list_head *p;
- list_for_each(p, &timer->active_list_head) {
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
+ list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->flags & SNDRV_TIMER_IFLG_START) {
ti->flags &= ~SNDRV_TIMER_IFLG_START;
ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
@@ -606,20 +618,21 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left)
*/
static void snd_timer_tasklet(unsigned long arg)
{
- snd_timer_t *timer = (snd_timer_t *) arg;
- snd_timer_instance_t *ti;
+ struct snd_timer *timer = (struct snd_timer *) arg;
+ struct snd_timer_instance *ti;
struct list_head *p;
unsigned long resolution, ticks;
+ unsigned long flags;
- spin_lock(&timer->lock);
+ spin_lock_irqsave(&timer->lock, flags);
/* now process all callbacks */
while (!list_empty(&timer->sack_list_head)) {
p = timer->sack_list_head.next; /* get first item */
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list);
+ ti = list_entry(p, struct snd_timer_instance, ack_list);
/* remove from ack_list and make empty */
list_del_init(p);
-
+
ticks = ti->pticks;
ti->pticks = 0;
resolution = ti->resolution;
@@ -631,7 +644,7 @@ static void snd_timer_tasklet(unsigned long arg)
spin_lock(&timer->lock);
ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
}
- spin_unlock(&timer->lock);
+ spin_unlock_irqrestore(&timer->lock, flags);
}
/*
@@ -640,17 +653,18 @@ static void snd_timer_tasklet(unsigned long arg)
* ticks_left is usually equal to timer->sticks.
*
*/
-void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
+void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
{
- snd_timer_instance_t *ti, *ts;
+ struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution, ticks;
- struct list_head *p, *q, *n;
+ struct list_head *p, *ack_list_head;
+ unsigned long flags;
int use_tasklet = 0;
if (timer == NULL)
return;
- spin_lock(&timer->lock);
+ spin_lock_irqsave(&timer->lock, flags);
/* remember the current resolution */
if (timer->hw.c_resolution)
@@ -659,11 +673,12 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
resolution = timer->hw.resolution;
/* loop for all active instances
- * here we cannot use list_for_each because the active_list of a processed
- * instance is relinked to done_list_head before callback is called.
+ * Here we cannot use list_for_each_entry because the active_list of a
+ * processed instance is relinked to done_list_head before the callback
+ * is called.
*/
- list_for_each_safe(p, n, &timer->active_list_head) {
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
+ list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
+ active_list) {
if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
continue;
ti->pticks += ticks_left;
@@ -679,32 +694,24 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
} else {
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (--timer->running)
- list_del(p);
+ list_del(&ti->active_list);
}
- if (list_empty(&ti->ack_list)) {
- if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
- (ti->flags & SNDRV_TIMER_IFLG_FAST)) {
- list_add_tail(&ti->ack_list, &timer->ack_list_head);
- } else {
- list_add_tail(&ti->ack_list, &timer->sack_list_head);
- }
- }
- list_for_each(q, &ti->slave_active_head) {
- ts = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, active_list);
+ if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
+ (ti->flags & SNDRV_TIMER_IFLG_FAST))
+ ack_list_head = &timer->ack_list_head;
+ else
+ ack_list_head = &timer->sack_list_head;
+ if (list_empty(&ti->ack_list))
+ list_add_tail(&ti->ack_list, ack_list_head);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list) {
ts->pticks = ti->pticks;
ts->resolution = resolution;
- if (list_empty(&ts->ack_list)) {
- if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
- (ti->flags & SNDRV_TIMER_IFLG_FAST)) {
- list_add_tail(&ts->ack_list, &timer->ack_list_head);
- } else {
- list_add_tail(&ts->ack_list, &timer->sack_list_head);
- }
- }
+ if (list_empty(&ts->ack_list))
+ list_add_tail(&ts->ack_list, ack_list_head);
}
}
if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
- snd_timer_reschedule(timer, ticks_left);
+ snd_timer_reschedule(timer, timer->sticks);
if (timer->running) {
if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
timer->hw.stop(timer);
@@ -723,11 +730,11 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
/* now process all fast callbacks */
while (!list_empty(&timer->ack_list_head)) {
p = timer->ack_list_head.next; /* get first item */
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list);
-
+ ti = list_entry(p, struct snd_timer_instance, ack_list);
+
/* remove from ack_list and make empty */
list_del_init(p);
-
+
ticks = ti->pticks;
ti->pticks = 0;
@@ -741,32 +748,36 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
/* do we have any slow callbacks? */
use_tasklet = !list_empty(&timer->sack_list_head);
- spin_unlock(&timer->lock);
+ spin_unlock_irqrestore(&timer->lock, flags);
if (use_tasklet)
- tasklet_hi_schedule(&timer->task_queue);
+ tasklet_schedule(&timer->task_queue);
}
/*
*/
-int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer)
+int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
+ struct snd_timer **rtimer)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
int err;
- static snd_device_ops_t ops = {
+ static struct snd_device_ops ops = {
.dev_free = snd_timer_dev_free,
.dev_register = snd_timer_dev_register,
- .dev_unregister = snd_timer_dev_unregister
+ .dev_disconnect = snd_timer_dev_disconnect,
};
- snd_assert(tid != NULL, return -EINVAL);
- snd_assert(rtimer != NULL, return -EINVAL);
- *rtimer = NULL;
+ if (snd_BUG_ON(!tid))
+ return -EINVAL;
+ if (rtimer)
+ *rtimer = NULL;
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
- if (timer == NULL)
+ if (timer == NULL) {
+ pr_err("ALSA: timer: cannot allocate\n");
return -ENOMEM;
+ }
timer->tmr_class = tid->dev_class;
timer->card = card;
timer->tmr_device = tid->device;
@@ -779,46 +790,65 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t *
INIT_LIST_HEAD(&timer->ack_list_head);
INIT_LIST_HEAD(&timer->sack_list_head);
spin_lock_init(&timer->lock);
- tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer);
+ tasklet_init(&timer->task_queue, snd_timer_tasklet,
+ (unsigned long)timer);
if (card != NULL) {
- if ((err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)) < 0) {
+ timer->module = card->module;
+ err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
+ if (err < 0) {
snd_timer_free(timer);
return err;
}
}
- *rtimer = timer;
+ if (rtimer)
+ *rtimer = timer;
return 0;
}
-static int snd_timer_free(snd_timer_t *timer)
+static int snd_timer_free(struct snd_timer *timer)
{
- snd_assert(timer != NULL, return -ENXIO);
+ if (!timer)
+ return 0;
+
+ mutex_lock(&register_mutex);
+ if (! list_empty(&timer->open_list_head)) {
+ struct list_head *p, *n;
+ struct snd_timer_instance *ti;
+ pr_warn("ALSA: timer %p is busy?\n", timer);
+ list_for_each_safe(p, n, &timer->open_list_head) {
+ list_del_init(p);
+ ti = list_entry(p, struct snd_timer_instance, open_list);
+ ti->timer = NULL;
+ }
+ }
+ list_del(&timer->device_list);
+ mutex_unlock(&register_mutex);
+
if (timer->private_free)
timer->private_free(timer);
kfree(timer);
return 0;
}
-static int snd_timer_dev_free(snd_device_t *device)
+static int snd_timer_dev_free(struct snd_device *device)
{
- snd_timer_t *timer = device->device_data;
+ struct snd_timer *timer = device->device_data;
return snd_timer_free(timer);
}
-static int snd_timer_dev_register(snd_device_t *dev)
+static int snd_timer_dev_register(struct snd_device *dev)
{
- snd_timer_t *timer = dev->device_data;
- snd_timer_t *timer1;
- struct list_head *p;
+ struct snd_timer *timer = dev->device_data;
+ struct snd_timer *timer1;
- snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
+ return -ENXIO;
if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
!timer->hw.resolution && timer->hw.c_resolution == NULL)
return -EINVAL;
- down(&register_mutex);
- list_for_each(p, &snd_timer_list) {
- timer1 = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
+ mutex_lock(&register_mutex);
+ list_for_each_entry(timer1, &snd_timer_list, device_list) {
if (timer1->tmr_class > timer->tmr_class)
break;
if (timer1->tmr_class < timer->tmr_class)
@@ -838,49 +868,34 @@ static int snd_timer_dev_register(snd_device_t *dev)
if (timer1->tmr_subdevice < timer->tmr_subdevice)
continue;
/* conflicts.. */
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
return -EBUSY;
}
- list_add_tail(&timer->device_list, p);
- up(&register_mutex);
+ list_add_tail(&timer->device_list, &timer1->device_list);
+ mutex_unlock(&register_mutex);
return 0;
}
-static int snd_timer_unregister(snd_timer_t *timer)
+static int snd_timer_dev_disconnect(struct snd_device *device)
{
- struct list_head *p, *n;
- snd_timer_instance_t *ti;
-
- snd_assert(timer != NULL, return -ENXIO);
- down(&register_mutex);
- if (! list_empty(&timer->open_list_head)) {
- snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
- list_for_each_safe(p, n, &timer->open_list_head) {
- list_del_init(p);
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
- ti->timer = NULL;
- }
- }
- list_del(&timer->device_list);
- up(&register_mutex);
- return snd_timer_free(timer);
-}
-
-static int snd_timer_dev_unregister(snd_device_t *device)
-{
- snd_timer_t *timer = device->device_data;
- return snd_timer_unregister(timer);
+ struct snd_timer *timer = device->device_data;
+ mutex_lock(&register_mutex);
+ list_del_init(&timer->device_list);
+ mutex_unlock(&register_mutex);
+ return 0;
}
-void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp)
+void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
{
unsigned long flags;
unsigned long resolution = 0;
- snd_timer_instance_t *ti, *ts;
- struct list_head *p, *n;
+ struct snd_timer_instance *ti, *ts;
- snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);
- snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return);
+ if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
+ return;
+ if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
+ event > SNDRV_TIMER_EVENT_MRESUME))
+ return;
spin_lock_irqsave(&timer->lock, flags);
if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
@@ -890,15 +905,12 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
else
resolution = timer->hw.resolution;
}
- list_for_each(p, &timer->active_list_head) {
- ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
+ list_for_each_entry(ti, &timer->active_list_head, active_list) {
if (ti->ccallback)
ti->ccallback(ti, event, tstamp, resolution);
- list_for_each(n, &ti->slave_active_head) {
- ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list)
if (ts->ccallback)
ts->ccallback(ts, event, tstamp, resolution);
- }
}
spin_unlock_irqrestore(&timer->lock, flags);
}
@@ -906,10 +918,10 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
/*
* exported functions for global timers
*/
-int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer)
+int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer)
{
- snd_timer_id_t tid;
-
+ struct snd_timer_id tid;
+
tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
tid.card = -1;
@@ -918,32 +930,26 @@ int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer)
return snd_timer_new(NULL, id, &tid, rtimer);
}
-int snd_timer_global_free(snd_timer_t *timer)
+int snd_timer_global_free(struct snd_timer *timer)
{
return snd_timer_free(timer);
}
-int snd_timer_global_register(snd_timer_t *timer)
+int snd_timer_global_register(struct snd_timer *timer)
{
- snd_device_t dev;
+ struct snd_device dev;
memset(&dev, 0, sizeof(dev));
dev.device_data = timer;
return snd_timer_dev_register(&dev);
}
-int snd_timer_global_unregister(snd_timer_t *timer)
-{
- return snd_timer_unregister(timer);
-}
-
-/*
+/*
* System timer
*/
struct snd_timer_system_private {
struct timer_list tlist;
- struct timer * timer;
unsigned long last_expires;
unsigned long last_jiffies;
unsigned long correction;
@@ -951,15 +957,15 @@ struct snd_timer_system_private {
static void snd_timer_s_function(unsigned long data)
{
- snd_timer_t *timer = (snd_timer_t *)data;
+ struct snd_timer *timer = (struct snd_timer *)data;
struct snd_timer_system_private *priv = timer->private_data;
unsigned long jiff = jiffies;
if (time_after(jiff, priv->last_expires))
- priv->correction = (long)jiff - (long)priv->last_expires;
+ priv->correction += (long)jiff - (long)priv->last_expires;
snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
}
-static int snd_timer_s_start(snd_timer_t * timer)
+static int snd_timer_s_start(struct snd_timer * timer)
{
struct snd_timer_system_private *priv;
unsigned long njiff;
@@ -971,14 +977,14 @@ static int snd_timer_s_start(snd_timer_t * timer)
njiff++;
} else {
njiff += timer->sticks - priv->correction;
- priv->correction -= timer->sticks;
+ priv->correction = 0;
}
priv->last_expires = priv->tlist.expires = njiff;
add_timer(&priv->tlist);
return 0;
}
-static int snd_timer_s_stop(snd_timer_t * timer)
+static int snd_timer_s_stop(struct snd_timer * timer)
{
struct snd_timer_system_private *priv;
unsigned long jiff;
@@ -990,10 +996,11 @@ static int snd_timer_s_stop(snd_timer_t * timer)
timer->sticks = priv->last_expires - jiff;
else
timer->sticks = 1;
+ priv->correction = 0;
return 0;
}
-static struct _snd_timer_hardware snd_timer_system =
+static struct snd_timer_hardware snd_timer_system =
{
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
.resolution = 1000000000L / HZ,
@@ -1002,18 +1009,19 @@ static struct _snd_timer_hardware snd_timer_system =
.stop = snd_timer_s_stop
};
-static void snd_timer_free_system(snd_timer_t *timer)
+static void snd_timer_free_system(struct snd_timer *timer)
{
kfree(timer->private_data);
}
static int snd_timer_register_system(void)
{
- snd_timer_t *timer;
+ struct snd_timer *timer;
struct snd_timer_system_private *priv;
int err;
- if ((err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer)) < 0)
+ err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer);
+ if (err < 0)
return err;
strcpy(timer->name, "system timer");
timer->hw = snd_timer_system;
@@ -1030,65 +1038,93 @@ static int snd_timer_register_system(void)
return snd_timer_global_register(timer);
}
+#ifdef CONFIG_PROC_FS
/*
* Info interface
*/
-static void snd_timer_proc_read(snd_info_entry_t *entry,
- snd_info_buffer_t * buffer)
+static void snd_timer_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
{
- unsigned long flags;
- snd_timer_t *timer;
- snd_timer_instance_t *ti;
- struct list_head *p, *q;
+ struct snd_timer *timer;
+ struct snd_timer_instance *ti;
- down(&register_mutex);
- list_for_each(p, &snd_timer_list) {
- timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
+ mutex_lock(&register_mutex);
+ list_for_each_entry(timer, &snd_timer_list, device_list) {
switch (timer->tmr_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
snd_iprintf(buffer, "G%i: ", timer->tmr_device);
break;
case SNDRV_TIMER_CLASS_CARD:
- snd_iprintf(buffer, "C%i-%i: ", timer->card->number, timer->tmr_device);
+ snd_iprintf(buffer, "C%i-%i: ",
+ timer->card->number, timer->tmr_device);
break;
case SNDRV_TIMER_CLASS_PCM:
- snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, timer->tmr_device, timer->tmr_subdevice);
+ snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number,
+ timer->tmr_device, timer->tmr_subdevice);
break;
default:
- snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, timer->card ? timer->card->number : -1, timer->tmr_device, timer->tmr_subdevice);
+ snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class,
+ timer->card ? timer->card->number : -1,
+ timer->tmr_device, timer->tmr_subdevice);
}
snd_iprintf(buffer, "%s :", timer->name);
if (timer->hw.resolution)
- snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks);
+ snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
+ timer->hw.resolution / 1000,
+ timer->hw.resolution % 1000,
+ timer->hw.ticks);
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
snd_iprintf(buffer, "\n");
- spin_lock_irqsave(&timer->lock, flags);
- list_for_each(q, &timer->open_list_head) {
- ti = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list);
- snd_iprintf(buffer, " Client %s : %s : lost interrupts %li\n",
- ti->owner ? ti->owner : "unknown",
- ti->flags & (SNDRV_TIMER_IFLG_START|SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped",
- ti->lost);
+ list_for_each_entry(ti, &timer->open_list_head, open_list)
+ snd_iprintf(buffer, " Client %s : %s\n",
+ ti->owner ? ti->owner : "unknown",
+ ti->flags & (SNDRV_TIMER_IFLG_START |
+ SNDRV_TIMER_IFLG_RUNNING)
+ ? "running" : "stopped");
+ }
+ mutex_unlock(&register_mutex);
+}
+
+static struct snd_info_entry *snd_timer_proc_entry;
+
+static void __init snd_timer_proc_init(void)
+{
+ struct snd_info_entry *entry;
+
+ entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
+ if (entry != NULL) {
+ entry->c.text.read = snd_timer_proc_read;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
}
- spin_unlock_irqrestore(&timer->lock, flags);
}
- up(&register_mutex);
+ snd_timer_proc_entry = entry;
+}
+
+static void __exit snd_timer_proc_done(void)
+{
+ snd_info_free_entry(snd_timer_proc_entry);
}
+#else /* !CONFIG_PROC_FS */
+#define snd_timer_proc_init()
+#define snd_timer_proc_done()
+#endif
/*
* USER SPACE interface
*/
-static void snd_timer_user_interrupt(snd_timer_instance_t *timeri,
+static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
unsigned long resolution,
unsigned long ticks)
{
- snd_timer_user_t *tu = timeri->callback_data;
- snd_timer_read_t *r;
+ struct snd_timer_user *tu = timeri->callback_data;
+ struct snd_timer_read *r;
int prev;
-
+
spin_lock(&tu->qlock);
if (tu->qused > 0) {
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
@@ -1113,7 +1149,8 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri,
wake_up(&tu->qchange_sleep);
}
-static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_tread_t *tread)
+static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
+ struct snd_timer_tread *tread)
{
if (tu->qused >= tu->queue_size) {
tu->overrun++;
@@ -1124,46 +1161,54 @@ static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_trea
}
}
-static void snd_timer_user_ccallback(snd_timer_instance_t *timeri,
- enum sndrv_timer_event event,
+static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
+ int event,
struct timespec *tstamp,
unsigned long resolution)
{
- snd_timer_user_t *tu = timeri->callback_data;
- snd_timer_tread_t r1;
+ struct snd_timer_user *tu = timeri->callback_data;
+ struct snd_timer_tread r1;
+ unsigned long flags;
- if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE)
+ if (event >= SNDRV_TIMER_EVENT_START &&
+ event <= SNDRV_TIMER_EVENT_PAUSE)
tu->tstamp = *tstamp;
if ((tu->filter & (1 << event)) == 0 || !tu->tread)
return;
r1.event = event;
r1.tstamp = *tstamp;
r1.val = resolution;
- spin_lock(&tu->qlock);
+ spin_lock_irqsave(&tu->qlock, flags);
snd_timer_user_append_to_tqueue(tu, &r1);
- spin_unlock(&tu->qlock);
+ spin_unlock_irqrestore(&tu->qlock, flags);
kill_fasync(&tu->fasync, SIGIO, POLL_IN);
wake_up(&tu->qchange_sleep);
}
-static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
+static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
unsigned long resolution,
unsigned long ticks)
{
- snd_timer_user_t *tu = timeri->callback_data;
- snd_timer_tread_t *r, r1;
+ struct snd_timer_user *tu = timeri->callback_data;
+ struct snd_timer_tread *r, r1;
struct timespec tstamp;
int prev, append = 0;
- snd_timestamp_zero(&tstamp);
+ memset(&tstamp, 0, sizeof(tstamp));
spin_lock(&tu->qlock);
- if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION)|(1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
+ if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
+ (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
spin_unlock(&tu->qlock);
return;
}
- if (tu->last_resolution != resolution || ticks > 0)
- snd_timestamp_now(&tstamp, 1);
- if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) {
+ if (tu->last_resolution != resolution || ticks > 0) {
+ if (timer_tstamp_monotonic)
+ ktime_get_ts(&tstamp);
+ else
+ getnstimeofday(&tstamp);
+ }
+ if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
+ tu->last_resolution != resolution) {
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
r1.tstamp = tstamp;
r1.val = resolution;
@@ -1200,17 +1245,23 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
static int snd_timer_user_open(struct inode *inode, struct file *file)
{
- snd_timer_user_t *tu;
-
+ struct snd_timer_user *tu;
+ int err;
+
+ err = nonseekable_open(inode, file);
+ if (err < 0)
+ return err;
+
tu = kzalloc(sizeof(*tu), GFP_KERNEL);
if (tu == NULL)
return -ENOMEM;
spin_lock_init(&tu->qlock);
init_waitqueue_head(&tu->qchange_sleep);
- init_MUTEX(&tu->tread_sem);
+ mutex_init(&tu->tread_sem);
tu->ticks = 1;
tu->queue_size = 128;
- tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
+ tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
+ GFP_KERNEL);
if (tu->queue == NULL) {
kfree(tu);
return -ENOMEM;
@@ -1221,12 +1272,11 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
static int snd_timer_user_release(struct inode *inode, struct file *file)
{
- snd_timer_user_t *tu;
+ struct snd_timer_user *tu;
if (file->private_data) {
tu = file->private_data;
file->private_data = NULL;
- fasync_helper(-1, file, 0, &tu->fasync);
if (tu->timeri)
snd_timer_close(tu->timeri);
kfree(tu->queue);
@@ -1236,7 +1286,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
return 0;
}
-static void snd_timer_user_zero_id(snd_timer_id_t *id)
+static void snd_timer_user_zero_id(struct snd_timer_id *id)
{
id->dev_class = SNDRV_TIMER_CLASS_NONE;
id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
@@ -1245,7 +1295,7 @@ static void snd_timer_user_zero_id(snd_timer_id_t *id)
id->subdevice = -1;
}
-static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer)
+static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer)
{
id->dev_class = timer->tmr_class;
id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
@@ -1254,20 +1304,21 @@ static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer)
id->subdevice = timer->tmr_subdevice;
}
-static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
+static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
{
- snd_timer_id_t id;
- snd_timer_t *timer;
+ struct snd_timer_id id;
+ struct snd_timer *timer;
struct list_head *p;
-
+
if (copy_from_user(&id, _tid, sizeof(id)))
return -EFAULT;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
if (id.dev_class < 0) { /* first item */
if (list_empty(&snd_timer_list))
snd_timer_user_zero_id(&id);
else {
- timer = (snd_timer_t *)list_entry(snd_timer_list.next, snd_timer_t, device_list);
+ timer = list_entry(snd_timer_list.next,
+ struct snd_timer, device_list);
snd_timer_user_copy_id(&id, timer);
}
} else {
@@ -1275,7 +1326,7 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
case SNDRV_TIMER_CLASS_GLOBAL:
id.device = id.device < 0 ? 0 : id.device + 1;
list_for_each(p, &snd_timer_list) {
- timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
+ timer = list_entry(p, struct snd_timer, device_list);
if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
snd_timer_user_copy_id(&id, timer);
break;
@@ -1299,12 +1350,16 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
if (id.device < 0) {
id.device = 0;
} else {
- id.subdevice = id.subdevice < 0 ? 0 : id.subdevice + 1;
+ if (id.subdevice < 0) {
+ id.subdevice = 0;
+ } else {
+ id.subdevice++;
+ }
}
}
}
list_for_each(p, &snd_timer_list) {
- timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
+ timer = list_entry(p, struct snd_timer, device_list);
if (timer->tmr_class > id.dev_class) {
snd_timer_user_copy_id(&id, timer);
break;
@@ -1339,31 +1394,29 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
snd_timer_user_zero_id(&id);
}
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
if (copy_to_user(_tid, &id, sizeof(*_tid)))
return -EFAULT;
return 0;
-}
+}
-static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo)
+static int snd_timer_user_ginfo(struct file *file,
+ struct snd_timer_ginfo __user *_ginfo)
{
- snd_timer_ginfo_t *ginfo;
- snd_timer_id_t tid;
- snd_timer_t *t;
+ struct snd_timer_ginfo *ginfo;
+ struct snd_timer_id tid;
+ struct snd_timer *t;
struct list_head *p;
int err = 0;
- ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL);
- if (! ginfo)
- return -ENOMEM;
- if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) {
- kfree(ginfo);
- return -EFAULT;
- }
+ ginfo = memdup_user(_ginfo, sizeof(*ginfo));
+ if (IS_ERR(ginfo))
+ return PTR_ERR(ginfo);
+
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
ginfo->card = t->card ? t->card->number : -1;
@@ -1382,44 +1435,48 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_gi
} else {
err = -ENODEV;
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
err = -EFAULT;
kfree(ginfo);
return err;
}
-static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams)
+static int snd_timer_user_gparams(struct file *file,
+ struct snd_timer_gparams __user *_gparams)
{
- snd_timer_gparams_t gparams;
- snd_timer_t *t;
+ struct snd_timer_gparams gparams;
+ struct snd_timer *t;
int err;
if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
return -EFAULT;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
t = snd_timer_find(&gparams.tid);
- if (t != NULL) {
- if (list_empty(&t->open_list_head)) {
- if (t->hw.set_period)
- err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
- else
- err = -ENOSYS;
- } else {
- err = -EBUSY;
- }
- } else {
+ if (!t) {
err = -ENODEV;
+ goto _error;
}
- up(&register_mutex);
+ if (!list_empty(&t->open_list_head)) {
+ err = -EBUSY;
+ goto _error;
+ }
+ if (!t->hw.set_period) {
+ err = -ENOSYS;
+ goto _error;
+ }
+ err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
+_error:
+ mutex_unlock(&register_mutex);
return err;
}
-static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus)
+static int snd_timer_user_gstatus(struct file *file,
+ struct snd_timer_gstatus __user *_gstatus)
{
- snd_timer_gstatus_t gstatus;
- snd_timer_id_t tid;
- snd_timer_t *t;
+ struct snd_timer_gstatus gstatus;
+ struct snd_timer_id tid;
+ struct snd_timer *t;
int err = 0;
if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
@@ -1427,7 +1484,7 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user
tid = gstatus.tid;
memset(&gstatus, 0, sizeof(gstatus));
gstatus.tid = tid;
- down(&register_mutex);
+ mutex_lock(&register_mutex);
t = snd_timer_find(&tid);
if (t != NULL) {
if (t->hw.c_resolution)
@@ -1435,7 +1492,8 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user
else
gstatus.resolution = t->hw.resolution;
if (t->hw.precise_resolution) {
- t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den);
+ t->hw.precise_resolution(t, &gstatus.resolution_num,
+ &gstatus.resolution_den);
} else {
gstatus.resolution_num = gstatus.resolution;
gstatus.resolution_den = 1000000000uL;
@@ -1443,21 +1501,22 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user
} else {
err = -ENODEV;
}
- up(&register_mutex);
+ mutex_unlock(&register_mutex);
if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
err = -EFAULT;
return err;
}
-static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect)
+static int snd_timer_user_tselect(struct file *file,
+ struct snd_timer_select __user *_tselect)
{
- snd_timer_user_t *tu;
- snd_timer_select_t tselect;
+ struct snd_timer_user *tu;
+ struct snd_timer_select tselect;
char str[32];
int err = 0;
-
+
tu = file->private_data;
- down(&tu->tread_sem);
+ mutex_lock(&tu->tread_sem);
if (tu->timeri) {
snd_timer_close(tu->timeri);
tu->timeri = NULL;
@@ -1469,7 +1528,8 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *
sprintf(str, "application %i", current->pid);
if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
- if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
+ err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid);
+ if (err < 0)
goto __err;
kfree(tu->queue);
@@ -1477,41 +1537,47 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *
kfree(tu->tqueue);
tu->tqueue = NULL;
if (tu->tread) {
- tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
+ tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread),
+ GFP_KERNEL);
if (tu->tqueue == NULL)
err = -ENOMEM;
} else {
- tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
+ tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
+ GFP_KERNEL);
if (tu->queue == NULL)
err = -ENOMEM;
}
-
+
if (err < 0) {
snd_timer_close(tu->timeri);
tu->timeri = NULL;
} else {
tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
- tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
+ tu->timeri->callback = tu->tread
+ ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
tu->timeri->ccallback = snd_timer_user_ccallback;
tu->timeri->callback_data = (void *)tu;
}
__err:
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return err;
}
-static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
+static int snd_timer_user_info(struct file *file,
+ struct snd_timer_info __user *_info)
{
- snd_timer_user_t *tu;
- snd_timer_info_t *info;
- snd_timer_t *t;
+ struct snd_timer_user *tu;
+ struct snd_timer_info *info;
+ struct snd_timer *t;
int err = 0;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
@@ -1528,26 +1594,30 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info
return err;
}
-static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params)
+static int snd_timer_user_params(struct file *file,
+ struct snd_timer_params __user *_params)
{
- snd_timer_user_t *tu;
- snd_timer_params_t params;
- snd_timer_t *t;
- snd_timer_read_t *tr;
- snd_timer_tread_t *ttr;
+ struct snd_timer_user *tu;
+ struct snd_timer_params params;
+ struct snd_timer *t;
+ struct snd_timer_read *tr;
+ struct snd_timer_tread *ttr;
int err;
-
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
err = -EINVAL;
goto _end;
}
- if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) {
+ if (params.queue_size > 0 &&
+ (params.queue_size < 32 || params.queue_size > 1024)) {
err = -EINVAL;
goto _end;
}
@@ -1580,16 +1650,19 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
spin_unlock_irq(&t->lock);
- if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) {
+ if (params.queue_size > 0 &&
+ (unsigned int)tu->queue_size != params.queue_size) {
if (tu->tread) {
- ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
+ ttr = kmalloc(params.queue_size * sizeof(*ttr),
+ GFP_KERNEL);
if (ttr) {
kfree(tu->tqueue);
tu->queue_size = params.queue_size;
tu->tqueue = ttr;
}
} else {
- tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
+ tr = kmalloc(params.queue_size * sizeof(*tr),
+ GFP_KERNEL);
if (tr) {
kfree(tu->queue);
tu->queue_size = params.queue_size;
@@ -1600,20 +1673,19 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
tu->qhead = tu->qtail = tu->qused = 0;
if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
if (tu->tread) {
- snd_timer_tread_t tread;
+ struct snd_timer_tread tread;
tread.event = SNDRV_TIMER_EVENT_EARLY;
tread.tstamp.tv_sec = 0;
tread.tstamp.tv_nsec = 0;
tread.val = 0;
snd_timer_user_append_to_tqueue(tu, &tread);
} else {
- snd_timer_read_t *r = &tu->queue[0];
+ struct snd_timer_read *r = &tu->queue[0];
r->resolution = 0;
r->ticks = 0;
tu->qused++;
tu->qtail++;
}
-
}
tu->filter = params.filter;
tu->ticks = params.ticks;
@@ -1624,13 +1696,15 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
return err;
}
-static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status)
+static int snd_timer_user_status(struct file *file,
+ struct snd_timer_status __user *_status)
{
- snd_timer_user_t *tu;
- snd_timer_status_t status;
-
+ struct snd_timer_user *tu;
+ struct snd_timer_status status;
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
@@ -1647,10 +1721,11 @@ static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_
static int snd_timer_user_start(struct file *file)
{
int err;
- snd_timer_user_t *tu;
-
+ struct snd_timer_user *tu;
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
snd_timer_stop(tu->timeri);
tu->timeri->lost = 0;
tu->last_resolution = 0;
@@ -1660,20 +1735,22 @@ static int snd_timer_user_start(struct file *file)
static int snd_timer_user_stop(struct file *file)
{
int err;
- snd_timer_user_t *tu;
-
+ struct snd_timer_user *tu;
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
}
static int snd_timer_user_continue(struct file *file)
{
int err;
- snd_timer_user_t *tu;
-
+ struct snd_timer_user *tu;
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
tu->timeri->lost = 0;
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
@@ -1681,10 +1758,11 @@ static int snd_timer_user_continue(struct file *file)
static int snd_timer_user_pause(struct file *file)
{
int err;
- snd_timer_user_t *tu;
-
+ struct snd_timer_user *tu;
+
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
}
@@ -1695,12 +1773,13 @@ enum {
SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
};
-static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- snd_timer_user_t *tu;
+ struct snd_timer_user *tu;
void __user *argp = (void __user *)arg;
int __user *p = argp;
-
+
tu = file->private_data;
switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION:
@@ -1710,18 +1789,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l
case SNDRV_TIMER_IOCTL_TREAD:
{
int xarg;
-
- down(&tu->tread_sem);
+
+ mutex_lock(&tu->tread_sem);
if (tu->timeri) { /* too late */
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return -EBUSY;
}
if (get_user(xarg, p)) {
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return -EFAULT;
}
tu->tread = xarg ? 1 : 0;
- up(&tu->tread_sem);
+ mutex_unlock(&tu->tread_sem);
return 0;
}
case SNDRV_TIMER_IOCTL_GINFO:
@@ -1756,24 +1835,21 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
- snd_timer_user_t *tu;
- int err;
-
+ struct snd_timer_user *tu;
+
tu = file->private_data;
- err = fasync_helper(fd, file, on, &tu->fasync);
- if (err < 0)
- return err;
- return 0;
+ return fasync_helper(fd, file, on, &tu->fasync);
}
-static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
+static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *offset)
{
- snd_timer_user_t *tu;
+ struct snd_timer_user *tu;
long result = 0, unit;
int err = 0;
-
+
tu = file->private_data;
- unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t);
+ unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read);
spin_lock_irq(&tu->qlock);
while ((long)count - result >= unit) {
while (!tu->qused) {
@@ -1805,12 +1881,14 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_
goto _error;
if (tu->tread) {
- if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) {
+ if (copy_to_user(buffer, &tu->tqueue[tu->qhead++],
+ sizeof(struct snd_timer_tread))) {
err = -EFAULT;
goto _error;
}
} else {
- if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) {
+ if (copy_to_user(buffer, &tu->queue[tu->qhead++],
+ sizeof(struct snd_timer_read))) {
err = -EFAULT;
goto _error;
}
@@ -1832,12 +1910,12 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_
static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
- snd_timer_user_t *tu;
+ struct snd_timer_user *tu;
tu = file->private_data;
poll_wait(file, &tu->qchange_sleep, wait);
-
+
mask = 0;
if (tu->qused)
mask |= POLLIN | POLLRDNORM;
@@ -1851,52 +1929,38 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
#define snd_timer_user_ioctl_compat NULL
#endif
-static struct file_operations snd_timer_f_ops =
+static const struct file_operations snd_timer_f_ops =
{
.owner = THIS_MODULE,
.read = snd_timer_user_read,
.open = snd_timer_user_open,
.release = snd_timer_user_release,
+ .llseek = no_llseek,
.poll = snd_timer_user_poll,
.unlocked_ioctl = snd_timer_user_ioctl,
.compat_ioctl = snd_timer_user_ioctl_compat,
.fasync = snd_timer_user_fasync,
};
-static snd_minor_t snd_timer_reg =
-{
- .comment = "timer",
- .f_ops = &snd_timer_f_ops,
-};
-
/*
* ENTRY functions
*/
-static snd_info_entry_t *snd_timer_proc_entry = NULL;
-
static int __init alsa_timer_init(void)
{
int err;
- snd_info_entry_t *entry;
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
- snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer");
+ snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
+ "system timer");
#endif
- if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) {
- entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128;
- entry->c.text.read = snd_timer_proc_read;
- if (snd_info_register(entry) < 0) {
- snd_info_free_entry(entry);
- entry = NULL;
- }
- }
- snd_timer_proc_entry = entry;
+
if ((err = snd_timer_register_system()) < 0)
- snd_printk(KERN_ERR "unable to register system timer (%i)\n", err);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER,
- NULL, 0, &snd_timer_reg, "timer"))<0)
- snd_printk(KERN_ERR "unable to register timer device (%i)\n", err);
+ pr_err("ALSA: unable to register system timer (%i)\n", err);
+ if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
+ &snd_timer_f_ops, NULL, "timer")) < 0)
+ pr_err("ALSA: unable to register timer device (%i)\n", err);
+ snd_timer_proc_init();
return 0;
}
@@ -1907,13 +1971,10 @@ static void __exit alsa_timer_exit(void)
snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);
/* unregister the system timer */
list_for_each_safe(p, n, &snd_timer_list) {
- snd_timer_t *timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
- snd_timer_unregister(timer);
- }
- if (snd_timer_proc_entry) {
- snd_info_unregister(snd_timer_proc_entry);
- snd_timer_proc_entry = NULL;
+ struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
+ snd_timer_free(timer);
}
+ snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
#endif
@@ -1934,5 +1995,4 @@ EXPORT_SYMBOL(snd_timer_notify);
EXPORT_SYMBOL(snd_timer_global_new);
EXPORT_SYMBOL(snd_timer_global_free);
EXPORT_SYMBOL(snd_timer_global_register);
-EXPORT_SYMBOL(snd_timer_global_unregister);
EXPORT_SYMBOL(snd_timer_interrupt);
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 3de552dfe80..e05802ae6e1 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -22,7 +22,7 @@
#include <linux/compat.h>
-struct sndrv_timer_info32 {
+struct snd_timer_info32 {
u32 flags;
s32 card;
unsigned char id[64];
@@ -33,16 +33,18 @@ struct sndrv_timer_info32 {
};
static int snd_timer_user_info_compat(struct file *file,
- struct sndrv_timer_info32 __user *_info)
+ struct snd_timer_info32 __user *_info)
{
- snd_timer_user_t *tu;
- struct sndrv_timer_info32 info;
- snd_timer_t *t;
+ struct snd_timer_user *tu;
+ struct snd_timer_info32 info;
+ struct snd_timer *t;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!tu->timeri))
+ return -ENXIO;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (snd_BUG_ON(!t))
+ return -ENXIO;
memset(&info, 0, sizeof(info));
info.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
@@ -55,7 +57,7 @@ static int snd_timer_user_info_compat(struct file *file,
return 0;
}
-struct sndrv_timer_status32 {
+struct snd_timer_status32 {
struct compat_timespec tstamp;
u32 resolution;
u32 lost;
@@ -65,13 +67,14 @@ struct sndrv_timer_status32 {
};
static int snd_timer_user_status_compat(struct file *file,
- struct sndrv_timer_status32 __user *_status)
+ struct snd_timer_status32 __user *_status)
{
- snd_timer_user_t *tu;
- snd_timer_status_t status;
+ struct snd_timer_user *tu;
+ struct snd_timer_status status;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!tu->timeri))
+ return -ENXIO;
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
@@ -89,8 +92,8 @@ static int snd_timer_user_status_compat(struct file *file,
*/
enum {
- SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
- SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
+ SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
+ SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
};
static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
new file mode 100644
index 00000000000..6c58e6f73a0
--- /dev/null
+++ b/sound/core/vmaster.c
@@ -0,0 +1,486 @@
+/*
+ * Virtual master and slave controls
+ *
+ * Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+/*
+ * a subset of information returned via ctl info callback
+ */
+struct link_ctl_info {
+ snd_ctl_elem_type_t type; /* value type */
+ int count; /* item count */
+ int min_val, max_val; /* min, max values */
+};
+
+/*
+ * link master - this contains a list of slave controls that are
+ * identical types, i.e. info returns the same value type and value
+ * ranges, but may have different number of counts.
+ *
+ * The master control is so far only mono volume/switch for simplicity.
+ * The same value will be applied to all slaves.
+ */
+struct link_master {
+ struct list_head slaves;
+ struct link_ctl_info info;
+ int val; /* the master value */
+ unsigned int tlv[4];
+ void (*hook)(void *private_data, int);
+ void *hook_private_data;
+};
+
+/*
+ * link slave - this contains a slave control element
+ *
+ * It fakes the control callbacsk with additional attenuation by the
+ * master control. A slave may have either one or two channels.
+ */
+
+struct link_slave {
+ struct list_head list;
+ struct link_master *master;
+ struct link_ctl_info info;
+ int vals[2]; /* current values */
+ unsigned int flags;
+ struct snd_kcontrol *kctl; /* original kcontrol pointer */
+ struct snd_kcontrol slave; /* the copy of original control entry */
+};
+
+static int slave_update(struct link_slave *slave)
+{
+ struct snd_ctl_elem_value *uctl;
+ int err, ch;
+
+ uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
+ if (!uctl)
+ return -ENOMEM;
+ uctl->id = slave->slave.id;
+ err = slave->slave.get(&slave->slave, uctl);
+ for (ch = 0; ch < slave->info.count; ch++)
+ slave->vals[ch] = uctl->value.integer.value[ch];
+ kfree(uctl);
+ return 0;
+}
+
+/* get the slave ctl info and save the initial values */
+static int slave_init(struct link_slave *slave)
+{
+ struct snd_ctl_elem_info *uinfo;
+ int err;
+
+ if (slave->info.count) {
+ /* already initialized */
+ if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
+ return slave_update(slave);
+ return 0;
+ }
+
+ uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+ if (!uinfo)
+ return -ENOMEM;
+ uinfo->id = slave->slave.id;
+ err = slave->slave.info(&slave->slave, uinfo);
+ if (err < 0) {
+ kfree(uinfo);
+ return err;
+ }
+ slave->info.type = uinfo->type;
+ slave->info.count = uinfo->count;
+ if (slave->info.count > 2 ||
+ (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
+ slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
+ pr_err("ALSA: vmaster: invalid slave element\n");
+ kfree(uinfo);
+ return -EINVAL;
+ }
+ slave->info.min_val = uinfo->value.integer.min;
+ slave->info.max_val = uinfo->value.integer.max;
+ kfree(uinfo);
+
+ return slave_update(slave);
+}
+
+/* initialize master volume */
+static int master_init(struct link_master *master)
+{
+ struct link_slave *slave;
+
+ if (master->info.count)
+ return 0; /* already initialized */
+
+ list_for_each_entry(slave, &master->slaves, list) {
+ int err = slave_init(slave);
+ if (err < 0)
+ return err;
+ master->info = slave->info;
+ master->info.count = 1; /* always mono */
+ /* set full volume as default (= no attenuation) */
+ master->val = master->info.max_val;
+ if (master->hook)
+ master->hook(master->hook_private_data, master->val);
+ return 1;
+ }
+ return -ENOENT;
+}
+
+static int slave_get_val(struct link_slave *slave,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int err, ch;
+
+ err = slave_init(slave);
+ if (err < 0)
+ return err;
+ for (ch = 0; ch < slave->info.count; ch++)
+ ucontrol->value.integer.value[ch] = slave->vals[ch];
+ return 0;
+}
+
+static int slave_put_val(struct link_slave *slave,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int err, ch, vol;
+
+ err = master_init(slave->master);
+ if (err < 0)
+ return err;
+
+ switch (slave->info.type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (ch = 0; ch < slave->info.count; ch++)
+ ucontrol->value.integer.value[ch] &=
+ !!slave->master->val;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ for (ch = 0; ch < slave->info.count; ch++) {
+ /* max master volume is supposed to be 0 dB */
+ vol = ucontrol->value.integer.value[ch];
+ vol += slave->master->val - slave->master->info.max_val;
+ if (vol < slave->info.min_val)
+ vol = slave->info.min_val;
+ else if (vol > slave->info.max_val)
+ vol = slave->info.max_val;
+ ucontrol->value.integer.value[ch] = vol;
+ }
+ break;
+ }
+ return slave->slave.put(&slave->slave, ucontrol);
+}
+
+/*
+ * ctl callbacks for slaves
+ */
+static int slave_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+ return slave->slave.info(&slave->slave, uinfo);
+}
+
+static int slave_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+ return slave_get_val(slave, ucontrol);
+}
+
+static int slave_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+ int err, ch, changed = 0;
+
+ err = slave_init(slave);
+ if (err < 0)
+ return err;
+ for (ch = 0; ch < slave->info.count; ch++) {
+ if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
+ changed = 1;
+ slave->vals[ch] = ucontrol->value.integer.value[ch];
+ }
+ }
+ if (!changed)
+ return 0;
+ err = slave_put_val(slave, ucontrol);
+ if (err < 0)
+ return err;
+ return 1;
+}
+
+static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
+ int op_flag, unsigned int size,
+ unsigned int __user *tlv)
+{
+ struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+ /* FIXME: this assumes that the max volume is 0 dB */
+ return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
+}
+
+static void slave_free(struct snd_kcontrol *kcontrol)
+{
+ struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+ if (slave->slave.private_free)
+ slave->slave.private_free(&slave->slave);
+ if (slave->master)
+ list_del(&slave->list);
+ kfree(slave);
+}
+
+/*
+ * Add a slave control to the group with the given master control
+ *
+ * All slaves must be the same type (returning the same information
+ * via info callback). The function doesn't check it, so it's your
+ * responsibility.
+ *
+ * Also, some additional limitations:
+ * - at most two channels
+ * - logarithmic volume control (dB level), no linear volume
+ * - master can only attenuate the volume, no gain
+ */
+int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
+ unsigned int flags)
+{
+ struct link_master *master_link = snd_kcontrol_chip(master);
+ struct link_slave *srec;
+
+ srec = kzalloc(sizeof(*srec) +
+ slave->count * sizeof(*slave->vd), GFP_KERNEL);
+ if (!srec)
+ return -ENOMEM;
+ srec->kctl = slave;
+ srec->slave = *slave;
+ memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
+ srec->master = master_link;
+ srec->flags = flags;
+
+ /* override callbacks */
+ slave->info = slave_info;
+ slave->get = slave_get;
+ slave->put = slave_put;
+ if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
+ slave->tlv.c = slave_tlv_cmd;
+ slave->private_data = srec;
+ slave->private_free = slave_free;
+
+ list_add_tail(&srec->list, &master_link->slaves);
+ return 0;
+}
+EXPORT_SYMBOL(_snd_ctl_add_slave);
+
+/*
+ * ctl callbacks for master controls
+ */
+static int master_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ int ret;
+
+ ret = master_init(master);
+ if (ret < 0)
+ return ret;
+ uinfo->type = master->info.type;
+ uinfo->count = master->info.count;
+ uinfo->value.integer.min = master->info.min_val;
+ uinfo->value.integer.max = master->info.max_val;
+ return 0;
+}
+
+static int master_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ int err = master_init(master);
+ if (err < 0)
+ return err;
+ ucontrol->value.integer.value[0] = master->val;
+ return 0;
+}
+
+static int sync_slaves(struct link_master *master, int old_val, int new_val)
+{
+ struct link_slave *slave;
+ struct snd_ctl_elem_value *uval;
+
+ uval = kmalloc(sizeof(*uval), GFP_KERNEL);
+ if (!uval)
+ return -ENOMEM;
+ list_for_each_entry(slave, &master->slaves, list) {
+ master->val = old_val;
+ uval->id = slave->slave.id;
+ slave_get_val(slave, uval);
+ master->val = new_val;
+ slave_put_val(slave, uval);
+ }
+ kfree(uval);
+ return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ int err, new_val, old_val;
+ bool first_init;
+
+ err = master_init(master);
+ if (err < 0)
+ return err;
+ first_init = err;
+ old_val = master->val;
+ new_val = ucontrol->value.integer.value[0];
+ if (new_val == old_val)
+ return 0;
+
+ err = sync_slaves(master, old_val, new_val);
+ if (err < 0)
+ return err;
+ if (master->hook && !first_init)
+ master->hook(master->hook_private_data, master->val);
+ return 1;
+}
+
+static void master_free(struct snd_kcontrol *kcontrol)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ struct link_slave *slave, *n;
+
+ /* free all slave links and retore the original slave kctls */
+ list_for_each_entry_safe(slave, n, &master->slaves, list) {
+ struct snd_kcontrol *sctl = slave->kctl;
+ struct list_head olist = sctl->list;
+ memcpy(sctl, &slave->slave, sizeof(*sctl));
+ memcpy(sctl->vd, slave->slave.vd,
+ sctl->count * sizeof(*sctl->vd));
+ sctl->list = olist; /* keep the current linked-list */
+ kfree(slave);
+ }
+ kfree(master);
+}
+
+
+/**
+ * snd_ctl_make_virtual_master - Create a virtual master control
+ * @name: name string of the control element to create
+ * @tlv: optional TLV int array for dB information
+ *
+ * Creates a virtual master control with the given name string.
+ *
+ * After creating a vmaster element, you can add the slave controls
+ * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
+ *
+ * The optional argument @tlv can be used to specify the TLV information
+ * for dB scale of the master control. It should be a single element
+ * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
+ * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
+ *
+ * Return: The created control element, or %NULL for errors (ENOMEM).
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+ const unsigned int *tlv)
+{
+ struct link_master *master;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new knew;
+
+ memset(&knew, 0, sizeof(knew));
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.name = name;
+ knew.info = master_info;
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return NULL;
+ INIT_LIST_HEAD(&master->slaves);
+
+ kctl = snd_ctl_new1(&knew, master);
+ if (!kctl) {
+ kfree(master);
+ return NULL;
+ }
+ /* override some callbacks */
+ kctl->info = master_info;
+ kctl->get = master_get;
+ kctl->put = master_put;
+ kctl->private_free = master_free;
+
+ /* additional (constant) TLV read */
+ if (tlv &&
+ (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
+ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
+ tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ memcpy(master->tlv, tlv, sizeof(master->tlv));
+ kctl->tlv.p = master->tlv;
+ }
+
+ return kctl;
+}
+EXPORT_SYMBOL(snd_ctl_make_virtual_master);
+
+/**
+ * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control
+ * @kcontrol: vmaster kctl element
+ * @hook: the hook function
+ * @private_data: the private_data pointer to be saved
+ *
+ * Adds the given hook to the vmaster control element so that it's called
+ * at each time when the value is changed.
+ *
+ * Return: Zero.
+ */
+int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
+ void (*hook)(void *private_data, int),
+ void *private_data)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ master->hook = hook;
+ master->hook_private_data = private_data;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
+
+/**
+ * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
+ * @kcontrol: vmaster kctl element
+ * @hook_only: sync only the hook
+ *
+ * Forcibly call the put callback of each slave and call the hook function
+ * to synchronize with the current value of the given vmaster element.
+ * NOP when NULL is passed to @kcontrol.
+ */
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
+{
+ struct link_master *master;
+ bool first_init = false;
+
+ if (!kcontrol)
+ return;
+ master = snd_kcontrol_chip(kcontrol);
+ if (!hook_only) {
+ int err = master_init(master);
+ if (err < 0)
+ return;
+ first_init = err;
+ err = sync_slaves(master, master->val, master->val);
+ if (err < 0)
+ return;
+ }
+
+ if (master->hook && !first_init)
+ master->hook(master->hook_private_data, master->val);
+}
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
diff --git a/sound/core/wrappers.c b/sound/core/wrappers.c
deleted file mode 100644
index 296b716f137..00000000000
--- a/sound/core/wrappers.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Various wrappers
- * Copyright (c) by Jaroslav Kysela <perex@suse.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/config.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-
-#ifdef CONFIG_SND_DEBUG_MEMORY
-void *snd_wrapper_kmalloc(size_t size, gfp_t flags)
-{
- return kmalloc(size, flags);
-}
-
-void snd_wrapper_kfree(const void *obj)
-{
- kfree(obj);
-}
-
-void *snd_wrapper_vmalloc(unsigned long size)
-{
- return vmalloc(size);
-}
-
-void snd_wrapper_vfree(void *obj)
-{
- vfree(obj);
-}
-#endif
-