diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/sound/core | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/sound/core')
93 files changed, 0 insertions, 43295 deletions
diff --git a/ANDROID_3.4.5/sound/core/Kconfig b/ANDROID_3.4.5/sound/core/Kconfig deleted file mode 100644 index 72261551..00000000 --- a/ANDROID_3.4.5/sound/core/Kconfig +++ /dev/null @@ -1,220 +0,0 @@ -# ALSA soundcard-configuration -config SND_TIMER - tristate - -config SND_PCM - tristate - select SND_TIMER - -config SND_HWDEP - tristate - -config SND_RAWMIDI - tristate - -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" - select SND_TIMER - help - Say Y or M to enable MIDI sequencer and router support. This - feature allows routing and enqueueing of MIDI events. Events - can be processed at a given time. - - Many programs require this feature, so you should enable it - unless you know what you're doing. - -config SND_SEQ_DUMMY - tristate "Sequencer dummy client" - depends on SND_SEQUENCER - help - Say Y here to enable the dummy sequencer client. This client - is a simple MIDI-through client: all normal input events are - redirected to the output port immediately. - - You don't need this unless you want to connect many MIDI - devices or applications together. - - To compile this driver as a module, choose M here: the module - will be called snd-seq-dummy. - -config SND_OSSEMUL - select SOUND_OSS_CORE - bool - -config SND_MIXER_OSS - tristate "OSS Mixer API" - select SND_OSSEMUL - help - To enable OSS mixer API emulation (/dev/mixer*), say Y here - and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. - - Many programs still use the OSS API, so say Y. - - To compile this driver as a module, choose M here: the module - will be called snd-mixer-oss. - -config SND_PCM_OSS - tristate "OSS PCM (digital audio) API" - select SND_OSSEMUL - select SND_PCM - help - To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y - here and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. - - Many programs still use the OSS API, so say Y. - - 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_SEQUENCER - select SND_OSSEMUL - help - Say Y here to enable OSS sequencer emulation (both - /dev/sequencer and /dev/music interfaces). - - 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-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 RTC - select SND_TIMER - help - Say Y here to enable RTC timer support for ALSA. ALSA uses - the RTC timer as a precise timing source and maps the RTC - timer to ALSA's timer interface. 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-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 - timer. This is strongly recommended because it ensures - precise MIDI timing even when the system timer runs at less - than 1000 Hz. - - 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_SUPPORT_OLD_API - bool "Support old ALSA API" - select SND_HWDEP - 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" - help - Say Y here to enable verbose log messages. These messages - will help to identify source file and position containing - printed messages. - - You don't need this unless you're debugging ALSA. - -config SND_DEBUG - bool "Debug" - help - Say Y here to enable ALSA debug code. - -config SND_DEBUG_VERBOSE - bool "More verbose debug" - depends on SND_DEBUG - help - 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 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_VMASTER - bool - -config SND_KCTL_JACK - bool - -config SND_DMA_SGBUF - def_bool y - depends on X86 - -source "sound/core/seq/Kconfig" diff --git a/ANDROID_3.4.5/sound/core/Makefile b/ANDROID_3.4.5/sound/core/Makefile deleted file mode 100644 index 43d41174..00000000 --- a/ANDROID_3.4.5/sound/core/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# Makefile for ALSA -# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@perex.cz> -# - -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-page-alloc-y := memalloc.o -snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.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_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/ANDROID_3.4.5/sound/core/compress_offload.c b/ANDROID_3.4.5/sound/core/compress_offload.c deleted file mode 100644 index a58cf359..00000000 --- a/ANDROID_3.4.5/sound/core/compress_offload.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * 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/mm.h> -#include <linux/mutex.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/sched.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_WRONLY) - dirn = SND_COMPRESS_PLAYBACK; - else if (f->f_flags & O_RDONLY) - dirn = SND_COMPRESS_CAPTURE; - else { - pr_err("invalid direction\n"); - 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 0; -} - -static int snd_compr_free(struct inode *inode, struct file *f) -{ - struct snd_compr_file *data = f->private_data; - data->stream.ops->free(&data->stream); - kfree(data->stream.runtime->buffer); - kfree(data->stream.runtime); - kfree(data); - return 0; -} - -static void snd_compr_update_tstamp(struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp) -{ - if (!stream->ops->pointer) - return; - stream->ops->pointer(stream, tstamp); - pr_debug("dsp consumed till %d total %d bytes\n", - tstamp->byte_offset, tstamp->copied_total); - stream->runtime->hw_pointer = tstamp->byte_offset; - stream->runtime->total_bytes_transferred = tstamp->copied_total; -} - -static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, - struct snd_compr_avail *avail) -{ - long avail_calc; /*this needs to be signed variable */ - - snd_compr_update_tstamp(stream, &avail->tstamp); - - /* FIXME: This needs to be different for capture stream, - available is # of compressed data, for playback it's - remainder of buffer */ - - if (stream->runtime->total_bytes_available == 0 && - stream->runtime->state == SNDRV_PCM_STATE_SETUP) { - 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) { - pr_debug("both pointers are same, returning full avail\n"); - return stream->runtime->buffer_size; - } - - /* FIXME: this routine isn't consistent, in one test we use - * cumulative values and in the other byte offsets. Do we - * really need the byte offsets if the cumulative values have - * been updated? In the PCM interface app_ptr and hw_ptr are - * already cumulative */ - - avail_calc = stream->runtime->buffer_size - - (stream->runtime->app_pointer - stream->runtime->hw_pointer); - pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc, - stream->runtime->app_pointer, - stream->runtime->hw_pointer); - if (avail_calc >= stream->runtime->buffer_size) - avail_calc -= stream->runtime->buffer_size; - pr_debug("ret avail as %ld\n", avail_calc); - avail->avail = avail_calc; - return avail_calc; -} - -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; - - dstn = runtime->buffer + runtime->app_pointer; - pr_debug("copying %ld at %lld\n", - (unsigned long)count, runtime->app_pointer); - if (count < runtime->buffer_size - runtime->app_pointer) { - if (copy_from_user(dstn, buf, count)) - return -EFAULT; - runtime->app_pointer += count; - } else { - copy = runtime->buffer_size - runtime->app_pointer; - if (copy_from_user(dstn, buf, copy)) - return -EFAULT; - if (copy_from_user(runtime->buffer, buf + copy, count - copy)) - return -EFAULT; - runtime->app_pointer = count - copy; - } - /* 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) - retval = stream->ops->copy(stream, buf, 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) -{ - return -ENXIO; -} - -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_PAUSED || - 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; - - 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 = kmalloc(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_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_compr_allocate_buffer(stream, params); - if (retval) { - retval = -ENOMEM; - goto out; - } - retval = stream->ops->set_params(stream, params); - if (retval) - goto out; - stream->runtime->state = SNDRV_PCM_STATE_SETUP; - } 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 = kmalloc(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 inline int -snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) -{ - struct snd_compr_tstamp tstamp; - - snd_compr_update_tstamp(stream, &tstamp); - return copy_to_user((struct snd_compr_tstamp __user *)arg, - &tstamp, sizeof(tstamp)) ? -EFAULT : 0; -} - -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; - wake_up(&stream->runtime->sleep); - } - 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) { - stream->runtime->state = SNDRV_PCM_STATE_SETUP; - wake_up(&stream->runtime->sleep); - } - return retval; -} - -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) { - stream->runtime->state = SNDRV_PCM_STATE_DRAINING; - wake_up(&stream->runtime->sleep); - } - return retval; -} - -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): - 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_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; - } - 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(compr->direction, 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/ANDROID_3.4.5/sound/core/control.c b/ANDROID_3.4.5/sound/core/control.c deleted file mode 100644 index daa4fc88..00000000 --- a/ANDROID_3.4.5/sound/core/control.c +++ /dev/null @@ -1,1726 +0,0 @@ -/* - * Routines for driver control interface - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/threads.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/time.h> -#include <sound/core.h> -#include <sound/minors.h> -#include <sound/info.h> -#include <sound/control.h> - -/* max number of user-defined controls */ -#define MAX_USER_CONTROLS 32 -#define MAX_CONTROL_COUNT 1028 - -struct snd_kctl_ioctl { - struct list_head list; /* list of all ioctls */ - snd_kctl_ioctl_func_t fioctl; -}; - -static DECLARE_RWSEM(snd_ioctl_rwsem); -static LIST_HEAD(snd_control_ioctls); -#ifdef CONFIG_COMPAT -static LIST_HEAD(snd_control_compat_ioctls); -#endif - -static int snd_ctl_open(struct inode *inode, struct file *file) -{ - unsigned long flags; - struct snd_card *card; - struct snd_ctl_file *ctl; - int err; - - 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; - } - err = snd_card_file_add(card, file); - if (err < 0) { - err = -ENODEV; - goto __error1; - } - if (!try_module_get(card->module)) { - err = -EFAULT; - goto __error2; - } - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (ctl == NULL) { - err = -ENOMEM; - goto __error; - } - INIT_LIST_HEAD(&ctl->events); - init_waitqueue_head(&ctl->change_sleep); - spin_lock_init(&ctl->read_lock); - ctl->card = card; - 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: - module_put(card->module); - __error2: - snd_card_file_remove(card, file); - __error1: - if (card) - snd_card_unref(card); - return err; -} - -static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) -{ - unsigned long flags; - struct snd_kctl_event *cread; - - 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_irqrestore(&ctl->read_lock, flags); -} - -static int snd_ctl_release(struct inode *inode, struct file *file) -{ - unsigned long flags; - struct snd_card *card; - struct snd_ctl_file *ctl; - struct snd_kcontrol *control; - unsigned int idx; - - ctl = file->private_data; - 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_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(struct snd_card *card, unsigned int mask, - struct snd_ctl_elem_id *id) -{ - unsigned long flags; - struct snd_ctl_file *ctl; - struct snd_kctl_event *ev; - - 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) - card->mixer_oss_change_count++; -#endif - list_for_each_entry(ctl, &card->ctl_files, list) { - if (!ctl->subscribed) - continue; - spin_lock_irqsave(&ctl->read_lock, flags); - list_for_each_entry(ev, &ctl->events, list) { - if (ev->id.numid == id->numid) { - ev->mask |= mask; - goto _found; - } - } - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (ev) { - ev->id = *id; - ev->mask = mask; - list_add_tail(&ev->list, &ctl->events); - } else { - snd_printk(KERN_ERR "No memory available to allocate event\n"); - } - _found: - wake_up(&ctl->change_sleep); - spin_unlock_irqrestore(&ctl->read_lock, flags); - kill_fasync(&ctl->fasync, SIGIO, POLL_IN); - } - 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 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. - */ -static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, - unsigned int access) -{ - struct snd_kcontrol *kctl; - unsigned int idx; - - 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) { - snd_printk(KERN_ERR "Cannot allocate control instance\n"); - return NULL; - } - *kctl = *control; - for (idx = 0; idx < kctl->count; idx++) - kctl->vd[idx].access = access; - return kctl; -} - -/** - * snd_ctl_new1 - create a control instance from the template - * @ncontrol: the initialization record - * @private_data: the private data to set - * - * 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. - */ -struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, - void *private_data) -{ - struct snd_kcontrol kctl; - unsigned int access; - - 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) { - strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)); - if (strcmp(ncontrol->name, kctl.id.name) != 0) - snd_printk(KERN_WARNING - "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_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 - * - * Releases the control instance created via snd_ctl_new() - * or snd_ctl_new1(). - * Don't call this after the control was added to the card. - */ -void snd_ctl_free_one(struct snd_kcontrol *kcontrol) -{ - if (kcontrol) { - if (kcontrol->private_free) - kcontrol->private_free(kcontrol); - kfree(kcontrol); - } -} - -EXPORT_SYMBOL(snd_ctl_free_one); - -static bool snd_ctl_remove_numid_conflict(struct snd_card *card, - unsigned int count) -{ - struct snd_kcontrol *kctl; - - 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 false; -} - -static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) -{ - unsigned int iter = 100000; - - 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"); - return -ENOMEM; - } - } - return 0; -} - -/** - * snd_ctl_add - add the control instance to the card - * @card: the card instance - * @kcontrol: the control instance to add - * - * Adds the control instance created via snd_ctl_new() or - * 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. - */ -int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) -{ - struct snd_ctl_elem_id id; - unsigned int idx; - int err = -EINVAL; - - if (! kcontrol) - return err; - if (snd_BUG_ON(!card || !kcontrol->info)) - goto error; - id = kcontrol->id; - down_write(&card->controls_rwsem); - if (snd_ctl_find_id(card, &id)) { - up_write(&card->controls_rwsem); - snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n", - id.iface, - id.device, - id.subdevice, - id.name, - id.index); - err = -EBUSY; - goto error; - } - if (snd_ctl_find_hole(card, kcontrol->count) < 0) { - up_write(&card->controls_rwsem); - 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; - up_write(&card->controls_rwsem); - for (idx = 0; idx < kcontrol->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. - * - * Returns zero if successful, or a negative error code on failure. - * - * It frees automatically the control which cannot be added or replaced. - */ -int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, - bool add_on_replace) -{ - struct snd_ctl_elem_id id; - 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; - up_write(&card->controls_rwsem); - for (idx = 0; idx < kcontrol->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 - * @card: the card instance - * @kcontrol: the control instance to remove - * - * 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. - */ -int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) -{ - struct snd_ctl_elem_id id; - unsigned int idx; - - if (snd_BUG_ON(!card || !kcontrol)) - return -EINVAL; - list_del(&kcontrol->list); - card->controls_count -= kcontrol->count; - id = kcontrol->id; - for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id); - snd_ctl_free_one(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 - * @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. - */ -int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) -{ - struct snd_kcontrol *kctl; - int ret; - - down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); - if (kctl == NULL) { - up_write(&card->controls_rwsem); - return -ENOENT; - } - ret = snd_ctl_remove(card, kctl); - up_write(&card->controls_rwsem); - return ret; -} - -EXPORT_SYMBOL(snd_ctl_remove_id); - -/** - * 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. - */ -static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, - struct snd_ctl_elem_id *id) -{ - 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) { - 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) { - 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. - * - * Returns 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 - * @dst_id: the new id - * - * 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. - */ -int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, - struct snd_ctl_elem_id *dst_id) -{ - struct snd_kcontrol *kctl; - - down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, src_id); - if (kctl == NULL) { - up_write(&card->controls_rwsem); - return -ENOENT; - } - kctl->id = *dst_id; - kctl->id.numid = card->last_numid + 1; - card->last_numid += kctl->count; - up_write(&card->controls_rwsem); - 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 - * @numid: the number-id to search - * - * 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). - */ -struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) -{ - struct snd_kcontrol *kctl; - - 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 - * @id: the id to search - * - * 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). - */ -struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, - struct snd_ctl_elem_id *id) -{ - struct snd_kcontrol *kctl; - - if (snd_BUG_ON(!card || !id)) - return NULL; - if (id->numid != 0) - return snd_ctl_find_numid(card, id->numid); - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.iface != id->iface) - continue; - if (kctl->id.device != id->device) - continue; - if (kctl->id.subdevice != id->subdevice) - continue; - if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name))) - continue; - if (kctl->id.index > id->index) - continue; - if (kctl->id.index + kctl->count <= id->index) - continue; - return kctl; - } - return NULL; -} - -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) -{ - struct snd_ctl_card_info *info; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (! info) - return -ENOMEM; - down_read(&snd_ioctl_rwsem); - info->card = card->number; - strlcpy(info->id, card->id, sizeof(info->id)); - strlcpy(info->driver, card->driver, sizeof(info->driver)); - strlcpy(info->name, card->shortname, sizeof(info->name)); - strlcpy(info->longname, card->longname, sizeof(info->longname)); - 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(struct snd_ctl_card_info))) { - kfree(info); - return -EFAULT; - } - kfree(info); - return 0; -} - -static int snd_ctl_elem_list(struct snd_card *card, - struct snd_ctl_elem_list __user *_list) -{ - struct list_head *plist; - 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; - /* try limit maximum space */ - if (space > 16384) - return -ENOMEM; - if (space > 0) { - /* allocate temporary buffer for atomic operation */ - dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); - if (dst == NULL) - return -ENOMEM; - down_read(&card->controls_rwsem); - list.count = card->controls_count; - plist = card->controls.next; - while (plist != &card->controls) { - if (offset == 0) - break; - kctl = snd_kcontrol(plist); - if (offset < kctl->count) - break; - offset -= kctl->count; - plist = plist->next; - } - list.used = 0; - id = dst; - while (space > 0 && plist != &card->controls) { - kctl = snd_kcontrol(plist); - for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) { - snd_ctl_build_ioff(id, kctl, jidx); - id++; - space--; - list.used++; - } - plist = plist->next; - offset = 0; - } - up_read(&card->controls_rwsem); - if (list.used > 0 && - copy_to_user(list.pids, dst, - list.used * sizeof(struct snd_ctl_elem_id))) { - vfree(dst); - return -EFAULT; - } - vfree(dst); - } else { - down_read(&card->controls_rwsem); - list.count = card->controls_count; - up_read(&card->controls_rwsem); - } - if (copy_to_user(_list, &list, sizeof(list))) - return -EFAULT; - return 0; -} - -static int snd_ctl_elem_info(struct snd_ctl_file *ctl, - struct snd_ctl_elem_info *info) -{ - struct snd_card *card = ctl->card; - struct snd_kcontrol *kctl; - struct snd_kcontrol_volatile *vd; - unsigned int index_offset; - int result; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &info->id); - if (kctl == NULL) { - up_read(&card->controls_rwsem); - return -ENOENT; - } -#ifdef CONFIG_SND_DEBUG - info->access = 0; -#endif - result = kctl->info(kctl, info); - if (result >= 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); - info->access = vd->access; - if (vd->owner) { - info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; - if (vd->owner == ctl) - info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = pid_vnr(vd->owner->pid); - } else { - info->owner = -1; - } - } - up_read(&card->controls_rwsem); - return result; -} - -static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, - struct snd_ctl_elem_info __user *_info) -{ - struct snd_ctl_elem_info info; - int result; - - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; - snd_power_lock(ctl->card); - result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (result >= 0) - result = snd_ctl_elem_info(ctl, &info); - snd_power_unlock(ctl->card); - if (result >= 0) - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return result; -} - -static int snd_ctl_elem_read(struct snd_card *card, - struct snd_ctl_elem_value *control) -{ - struct snd_kcontrol *kctl; - struct snd_kcontrol_volatile *vd; - unsigned int index_offset; - int result; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &control->id); - if (kctl == NULL) { - result = -ENOENT; - } else { - index_offset = snd_ctl_get_ioff(kctl, &control->id); - vd = &kctl->vd[index_offset]; - if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && - kctl->get != NULL) { - snd_ctl_build_ioff(&control->id, kctl, index_offset); - result = kctl->get(kctl, control); - } else - result = -EPERM; - } - up_read(&card->controls_rwsem); - return result; -} - -static int snd_ctl_elem_read_user(struct snd_card *card, - struct snd_ctl_elem_value __user *_control) -{ - struct snd_ctl_elem_value *control; - int result; - - 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; - kfree(control); - return result; -} - -static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, - struct snd_ctl_elem_value *control) -{ - struct snd_kcontrol *kctl; - struct snd_kcontrol_volatile *vd; - unsigned int index_offset; - int result; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &control->id); - if (kctl == NULL) { - result = -ENOENT; - } else { - index_offset = snd_ctl_get_ioff(kctl, &control->id); - vd = &kctl->vd[index_offset]; - if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || - kctl->put == NULL || - (file && vd->owner && vd->owner != file)) { - result = -EPERM; - } else { - snd_ctl_build_ioff(&control->id, kctl, index_offset); - result = kctl->put(kctl, control); - } - if (result > 0) { - up_read(&card->controls_rwsem); - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &control->id); - return 0; - } - } - up_read(&card->controls_rwsem); - return result; -} - -static int snd_ctl_elem_write_user(struct snd_ctl_file *file, - struct snd_ctl_elem_value __user *_control) -{ - struct snd_ctl_elem_value *control; - struct snd_card *card; - int result; - - 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; - kfree(control); - return result; -} - -static int snd_ctl_elem_lock(struct snd_ctl_file *file, - struct snd_ctl_elem_id __user *_id) -{ - 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))) - return -EFAULT; - down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &id); - if (kctl == NULL) { - result = -ENOENT; - } else { - vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; - if (vd->owner != NULL) - result = -EBUSY; - else { - vd->owner = file; - result = 0; - } - } - up_write(&card->controls_rwsem); - return result; -} - -static int snd_ctl_elem_unlock(struct snd_ctl_file *file, - struct snd_ctl_elem_id __user *_id) -{ - 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))) - return -EFAULT; - down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, &id); - if (kctl == NULL) { - result = -ENOENT; - } else { - vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; - if (vd->owner == NULL) - result = -EINVAL; - else if (vd->owner != file) - result = -EPERM; - else { - vd->owner = NULL; - result = 0; - } - } - up_write(&card->controls_rwsem); - return result; -} - -struct user_element { - struct snd_ctl_elem_info info; - 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) */ -}; - -static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct user_element *ue = kcontrol->private_data; - - *uinfo = ue->info; - return 0; -} - -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; - - memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); - return 0; -} - -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; - - change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; - if (change) - memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); - return change; -} - -static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, - int op_flag, - unsigned int size, - unsigned int __user *tlv) -{ - 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); - 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; - } else { - if (! ue->tlv_data_size || ! ue->tlv_data) - return -ENXIO; - if (size < ue->tlv_data_size) - return -ENOSPC; - if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) - return -EFAULT; - } - return change; -} - -static int snd_ctl_elem_init_enum_names(struct user_element *ue) -{ - 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 (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) - return -ENOMEM; - 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| - 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; - } - up_write(&card->controls_rwsem); - if (err < 0) - return err; - memcpy(&kctl.id, &info->id, sizeof(info->id)); - kctl.count = info->owner ? info->owner : 1; - access |= SNDRV_CTL_ELEM_ACCESS_USER; - 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: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - private_size = sizeof(long); - if (info->count > 128) - return -EINVAL; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - private_size = sizeof(long long); - 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 snd_aes_iec958); - if (info->count != 1) - return -EINVAL; - break; - default: - return -EINVAL; - } - private_size *= info->count; - ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); - if (ue == NULL) - return -ENOMEM; - 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(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) - return err; - - down_write(&card->controls_rwsem); - card->user_ctl_count++; - up_write(&card->controls_rwsem); - - return 0; -} - -static int snd_ctl_elem_add_user(struct snd_ctl_file *file, - struct snd_ctl_elem_info __user *_info, int replace) -{ - 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(struct snd_ctl_file *file, - struct snd_ctl_elem_id __user *_id) -{ - struct snd_ctl_elem_id id; - - if (copy_from_user(&id, _id, sizeof(id))) - return -EFAULT; - return snd_ctl_remove_user_ctl(file, &id); -} - -static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) -{ - int subscribe; - if (get_user(subscribe, ptr)) - return -EFAULT; - if (subscribe < 0) { - subscribe = file->subscribed; - if (put_user(subscribe, ptr)) - return -EFAULT; - return 0; - } - if (subscribe) { - file->subscribed = 1; - return 0; - } else if (file->subscribed) { - snd_ctl_empty_read_queue(file); - file->subscribed = 0; - } - return 0; -} - -static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, - struct snd_ctl_tlv __user *_tlv, - int op_flag) -{ - 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; - } - err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); - if (err > 0) { - up_read(&card->controls_rwsem); - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); - return 0; - } - } 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; - } - __kctl_end: - up_read(&card->controls_rwsem); - return err; -} - -static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - 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; - 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(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(card, argp); - case SNDRV_CTL_IOCTL_ELEM_WRITE: - return snd_ctl_elem_write_user(ctl, argp); - case SNDRV_CTL_IOCTL_ELEM_LOCK: - return snd_ctl_elem_lock(ctl, argp); - case SNDRV_CTL_IOCTL_ELEM_UNLOCK: - return snd_ctl_elem_unlock(ctl, argp); - case SNDRV_CTL_IOCTL_ELEM_ADD: - return snd_ctl_elem_add_user(ctl, argp, 0); - case SNDRV_CTL_IOCTL_ELEM_REPLACE: - return snd_ctl_elem_add_user(ctl, argp, 1); - case SNDRV_CTL_IOCTL_ELEM_REMOVE: - 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: - return -ENOPROTOOPT; - case SNDRV_CTL_IOCTL_POWER_STATE: -#ifdef CONFIG_PM - return put_user(card->power_state, ip) ? -EFAULT : 0; -#else - return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; -#endif - } - down_read(&snd_ioctl_rwsem); - list_for_each_entry(p, &snd_control_ioctls, list) { - err = p->fioctl(card, ctl, cmd, arg); - if (err != -ENOIOCTLCMD) { - up_read(&snd_ioctl_rwsem); - return err; - } - } - up_read(&snd_ioctl_rwsem); - snd_printdd("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) -{ - struct snd_ctl_file *ctl; - int err = 0; - ssize_t result = 0; - - ctl = file->private_data; - if (snd_BUG_ON(!ctl || !ctl->card)) - return -ENXIO; - if (!ctl->subscribed) - return -EBADFD; - if (count < sizeof(struct snd_ctl_event)) - return -EINVAL; - spin_lock_irq(&ctl->read_lock); - 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) { - err = -EAGAIN; - goto __end_lock; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&ctl->change_sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); - 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 -ERESTARTSYS; - spin_lock_irq(&ctl->read_lock); - } - kev = snd_kctl_event(ctl->events.next); - ev.type = SNDRV_CTL_EVENT_ELEM; - ev.data.elem.mask = kev->mask; - ev.data.elem.id = kev->id; - list_del(&kev->list); - spin_unlock_irq(&ctl->read_lock); - kfree(kev); - if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) { - err = -EFAULT; - goto __end; - } - spin_lock_irq(&ctl->read_lock); - 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); - __end: - return result > 0 ? result : err; -} - -static unsigned int snd_ctl_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - struct snd_ctl_file *ctl; - - ctl = file->private_data; - if (!ctl->subscribed) - return 0; - poll_wait(file, &ctl->change_sleep, wait); - - mask = 0; - if (!list_empty(&ctl->events)) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - -/* - * register the device-specific control-ioctls. - * called from each device manager like pcm.c, hwdep.c, etc. - */ -static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists) -{ - struct snd_kctl_ioctl *pn; - - pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL); - if (pn == NULL) - return -ENOMEM; - pn->fioctl = fcn; - down_write(&snd_ioctl_rwsem); - list_add_tail(&pn->list, lists); - up_write(&snd_ioctl_rwsem); - return 0; -} - -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) -{ - struct snd_kctl_ioctl *p; - - if (snd_BUG_ON(!fcn)) - return -EINVAL; - down_write(&snd_ioctl_rwsem); - list_for_each_entry(p, lists, list) { - if (p->fioctl == fcn) { - list_del(&p->list); - up_write(&snd_ioctl_rwsem); - kfree(p); - return 0; - } - } - up_write(&snd_ioctl_rwsem); - snd_BUG(); - return -EINVAL; -} - -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) -{ - struct snd_ctl_file *ctl; - - ctl = file->private_data; - return fasync_helper(fd, file, on, &ctl->fasync); -} - -/* - * ioctl32 compat - */ -#ifdef CONFIG_COMPAT -#include "control_compat.c" -#else -#define snd_ctl_ioctl_compat NULL -#endif - -/* - * INIT PART - */ - -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, -}; - -/* - * registration of the control device - */ -static int snd_ctl_dev_register(struct snd_device *device) -{ - struct snd_card *card = device->device_data; - int err, cardnum; - char name[16]; - - if (snd_BUG_ON(!card)) - return -ENXIO; - cardnum = card->number; - 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, -1, - &snd_ctl_f_ops, card, name)) < 0) - return err; - return 0; -} - -/* - * disconnection of the control device - */ -static int snd_ctl_dev_disconnect(struct snd_device *device) -{ - struct snd_card *card = device->device_data; - struct snd_ctl_file *ctl; - int err, cardnum; - - 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); - } - 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(struct snd_device *device) -{ - struct snd_card *card = device->device_data; - struct snd_kcontrol *control; - - down_write(&card->controls_rwsem); - while (!list_empty(&card->controls)) { - control = snd_kcontrol(card->controls.next); - snd_ctl_remove(card, control); - } - up_write(&card->controls_rwsem); - return 0; -} - -/* - * create control core: - * called from init.c - */ -int snd_ctl_create(struct snd_card *card) -{ - static struct snd_device_ops ops = { - .dev_free = snd_ctl_dev_free, - .dev_register = snd_ctl_dev_register, - .dev_disconnect = snd_ctl_dev_disconnect, - }; - - 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. - */ -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/ANDROID_3.4.5/sound/core/control_compat.c b/ANDROID_3.4.5/sound/core/control_compat.c deleted file mode 100644 index 2bb95a7a..00000000 --- a/ANDROID_3.4.5/sound/core/control_compat.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * compat ioctls for control API - * - * Copyright (c) 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; 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 - */ - -/* this file included from control.c */ - -#include <linux/compat.h> -#include <linux/slab.h> - -struct snd_ctl_elem_list32 { - u32 offset; - u32 space; - u32 used; - u32 count; - u32 pids; - unsigned char reserved[50]; -} /* don't set packed attribute here */; - -static int snd_ctl_elem_list_compat(struct snd_card *card, - struct snd_ctl_elem_list32 __user *data32) -{ - struct snd_ctl_elem_list __user *data; - compat_caddr_t ptr; - int err; - - data = compat_alloc_user_space(sizeof(*data)); - - /* offset, space, used, count */ - if (copy_in_user(data, data32, 4 * sizeof(u32))) - return -EFAULT; - /* pids */ - if (get_user(ptr, &data32->pids) || - put_user(compat_ptr(ptr), &data->pids)) - return -EFAULT; - err = snd_ctl_elem_list(card, data); - if (err < 0) - return err; - /* copy the result */ - if (copy_in_user(data32, data, 4 * sizeof(u32))) - return -EFAULT; - return 0; -} - -/* - * control element info - * it uses union, so the things are not easy.. - */ - -struct snd_ctl_elem_info32 { - struct snd_ctl_elem_id id; // the size of struct is same - s32 type; - u32 access; - u32 count; - s32 owner; - union { - struct { - s32 min; - s32 max; - s32 step; - } integer; - struct { - u64 min; - u64 max; - u64 step; - } integer64; - struct { - 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(struct snd_ctl_file *ctl, - struct snd_ctl_elem_info32 __user *data32) -{ - struct snd_ctl_elem_info *data; - int err; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (! data) - return -ENOMEM; - - err = -EFAULT; - /* copy id */ - if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) - goto error; - /* we need to copy the item index. - * hope this doesn't break anything.. - */ - if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) - goto error; - - snd_power_lock(ctl->card); - err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (err >= 0) - err = snd_ctl_elem_info(ctl, data); - snd_power_unlock(ctl->card); - - if (err < 0) - goto error; - /* restore info to 32bit */ - err = -EFAULT; - /* id, type, access, count */ - if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || - copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) - goto error; - if (put_user(data->owner, &data32->owner)) - goto error; - switch (data->type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - if (put_user(data->value.integer.min, &data32->value.integer.min) || - put_user(data->value.integer.max, &data32->value.integer.max) || - put_user(data->value.integer.step, &data32->value.integer.step)) - goto error; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - if (copy_to_user(&data32->value.integer64, - &data->value.integer64, - sizeof(data->value.integer64))) - goto error; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - if (copy_to_user(&data32->value.enumerated, - &data->value.enumerated, - sizeof(data->value.enumerated))) - goto error; - break; - default: - break; - } - err = 0; - error: - kfree(data); - return err; -} - -/* read / write */ -struct snd_ctl_elem_value32 { - struct snd_ctl_elem_id id; - unsigned int indirect; /* bit-field causes misalignment */ - union { - s32 integer[128]; - unsigned char data[512]; -#ifndef CONFIG_X86_64 - s64 integer64[64]; -#endif - } value; - unsigned char reserved[128]; -}; - - -/* get the value type and count of the control */ -static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, - int *countp) -{ - struct snd_kcontrol *kctl; - struct snd_ctl_elem_info *info; - int err; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id(card, id); - if (! kctl) { - up_read(&card->controls_rwsem); - return -ENXIO; - } - 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; - } - kfree(info); - return err; -} - -static int get_elem_size(int type, int count) -{ - switch (type) { - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - return sizeof(s64) * count; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - return sizeof(int) * count; - case SNDRV_CTL_ELEM_TYPE_BYTES: - return 512; - case SNDRV_CTL_ELEM_TYPE_IEC958: - return sizeof(struct snd_aes_iec958); - default: - return -1; - } -} - -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, size; - int uninitialized_var(count); - unsigned int indirect; - - if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) - return -EFAULT; - if (get_user(indirect, &data32->indirect)) - return -EFAULT; - if (indirect) - return -EINVAL; - type = get_ctl_type(card, &data->id, &count); - if (type < 0) - return type; - - if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || - type == SNDRV_CTL_ELEM_TYPE_INTEGER) { - for (i = 0; i < count; i++) { - int val; - if (get_user(val, &data32->value.integer[i])) - return -EFAULT; - data->value.integer.value[i] = val; - } - } else { - size = get_elem_size(type, count); - if (size < 0) { - printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); - return -EINVAL; - } - if (copy_from_user(data->value.bytes.data, - data32->value.data, size)) - return -EFAULT; - } - - *typep = type; - *countp = count; - return 0; -} - -/* restore the value to 32bit */ -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; - - if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || - type == SNDRV_CTL_ELEM_TYPE_INTEGER) { - for (i = 0; i < count; i++) { - int val; - val = data->value.integer.value[i]; - if (put_user(val, &data32->value.integer[i])) - return -EFAULT; - } - } else { - size = get_elem_size(type, count); - if (copy_to_user(data32->value.data, - data->value.bytes.data, size)) - return -EFAULT; - } - return 0; -} - -static int snd_ctl_elem_read_user_compat(struct snd_card *card, - struct snd_ctl_elem_value32 __user *data32) -{ - struct snd_ctl_elem_value *data; - int err, type, count; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) - goto error; - - snd_power_lock(card); - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err >= 0) - err = snd_ctl_elem_read(card, data); - snd_power_unlock(card); - if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); - error: - kfree(data); - return err; -} - -static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, - struct snd_ctl_elem_value32 __user *data32) -{ - 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(card, data, data32, &type, &count)) < 0) - goto error; - - snd_power_lock(card); - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err >= 0) - err = snd_ctl_elem_write(card, file, data); - snd_power_unlock(card); - if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); - error: - kfree(data); - return err; -} - -/* add or replace a user control */ -static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, - struct snd_ctl_elem_info32 __user *data32, - int replace) -{ - struct snd_ctl_elem_info *data; - int err; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (! data) - return -ENOMEM; - - err = -EFAULT; - /* id, type, access, count */ \ - if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || - copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) - goto error; - if (get_user(data->owner, &data32->owner) || - get_user(data->type, &data32->type)) - goto error; - switch (data->type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - if (get_user(data->value.integer.min, &data32->value.integer.min) || - get_user(data->value.integer.max, &data32->value.integer.max) || - get_user(data->value.integer.step, &data32->value.integer.step)) - goto error; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - if (copy_from_user(&data->value.integer64, - &data32->value.integer64, - sizeof(data->value.integer64))) - goto error; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - if (copy_from_user(&data->value.enumerated, - &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; - } - err = snd_ctl_elem_add(file, data, replace); - error: - kfree(data); - return err; -} - -enum { - 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) -{ - struct snd_ctl_file *ctl; - struct snd_kctl_ioctl *p; - void __user *argp = compat_ptr(arg); - int err; - - ctl = file->private_data; - if (snd_BUG_ON(!ctl || !ctl->card)) - return -ENXIO; - - switch (cmd) { - case SNDRV_CTL_IOCTL_PVERSION: - case SNDRV_CTL_IOCTL_CARD_INFO: - case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: - case SNDRV_CTL_IOCTL_POWER: - 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); - case SNDRV_CTL_IOCTL_ELEM_INFO32: - return snd_ctl_elem_info_compat(ctl, argp); - case SNDRV_CTL_IOCTL_ELEM_READ32: - return snd_ctl_elem_read_user_compat(ctl->card, argp); - case SNDRV_CTL_IOCTL_ELEM_WRITE32: - return snd_ctl_elem_write_user_compat(ctl, argp); - case SNDRV_CTL_IOCTL_ELEM_ADD32: - return snd_ctl_elem_add_compat(ctl, argp, 0); - case SNDRV_CTL_IOCTL_ELEM_REPLACE32: - return snd_ctl_elem_add_compat(ctl, argp, 1); - } - - down_read(&snd_ioctl_rwsem); - list_for_each_entry(p, &snd_control_compat_ioctls, list) { - if (p->fioctl) { - err = p->fioctl(ctl->card, ctl, cmd, arg); - if (err != -ENOIOCTLCMD) { - up_read(&snd_ioctl_rwsem); - return err; - } - } - } - up_read(&snd_ioctl_rwsem); - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/ctljack.c b/ANDROID_3.4.5/sound/core/ctljack.c deleted file mode 100644 index e4b38fbe..00000000 --- a/ANDROID_3.4.5/sound/core/ctljack.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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/ANDROID_3.4.5/sound/core/device.c b/ANDROID_3.4.5/sound/core/device.c deleted file mode 100644 index f03cb544..00000000 --- a/ANDROID_3.4.5/sound/core/device.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Device management routines - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/export.h> -#include <linux/errno.h> -#include <sound/core.h> - -/** - * snd_device_new - create an ALSA device component - * @card: the card instance - * @type: the device type, SNDRV_DEV_XXX - * @device_data: the data pointer of this device - * @ops: the operator table - * - * Creates a new device component for the given data pointer. - * The device will be assigned to the card and managed together - * by the card. - * - * 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. - */ -int snd_device_new(struct snd_card *card, snd_device_type_t type, - void *device_data, struct snd_device_ops *ops) -{ - struct snd_device *dev; - - if (snd_BUG_ON(!card || !device_data || !ops)) - return -ENXIO; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - snd_printk(KERN_ERR "Cannot allocate device\n"); - return -ENOMEM; - } - 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 */ - return 0; -} - -EXPORT_SYMBOL(snd_device_new); - -/** - * 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 - * 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(struct snd_card *card, void *device_data) -{ - struct snd_device *dev; - - if (snd_BUG_ON(!card || !device_data)) - return -ENXIO; - list_for_each_entry(dev, &card->devices, list) { - if (dev->device_data != device_data) - continue; - /* unlink */ - list_del(&dev->list); - if (dev->state == SNDRV_DEV_REGISTERED && - dev->ops->dev_disconnect) - if (dev->ops->dev_disconnect(dev)) - snd_printk(KERN_ERR - "device disconnect failure\n"); - 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 %pF), not found\n", device_data, - __builtin_return_address(0)); - return -ENXIO; -} - -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(struct snd_card *card, void *device_data) -{ - struct snd_device *dev; - - if (snd_BUG_ON(!card || !device_data)) - return -ENXIO; - list_for_each_entry(dev, &card->devices, 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; - } - return 0; - } - snd_printd("device disconnect %p (from %pF), not found\n", device_data, - __builtin_return_address(0)); - return -ENXIO; -} - -/** - * snd_device_register - register the device - * @card: the card instance - * @device_data: the data pointer to register - * - * Registers the device which was already created via - * snd_device_new(). Usually this is called from snd_card_register(), - * 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 - * device not found. - */ -int snd_device_register(struct snd_card *card, void *device_data) -{ - struct snd_device *dev; - int err; - - if (snd_BUG_ON(!card || !device_data)) - return -ENXIO; - list_for_each_entry(dev, &card->devices, 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; - } - snd_printd("snd_device_register busy\n"); - return -EBUSY; - } - 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(struct snd_card *card) -{ - struct snd_device *dev; - int err; - - if (snd_BUG_ON(!card)) - return -ENXIO; - list_for_each_entry(dev, &card->devices, 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; - } - } - return 0; -} - -/* - * disconnect all the devices on the card. - * called from init.c - */ -int snd_device_disconnect_all(struct snd_card *card) -{ - struct snd_device *dev; - int err = 0; - - if (snd_BUG_ON(!card)) - return -ENXIO; - list_for_each_entry(dev, &card->devices, list) { - if (snd_device_disconnect(card, dev->device_data) < 0) - err = -ENXIO; - } - return err; -} - -/* - * release all the devices on the card. - * called from init.c - */ -int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd) -{ - struct snd_device *dev; - int err; - unsigned int range_low, range_high, type; - - if (snd_BUG_ON(!card)) - return -ENXIO; - range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE; - range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1; - __again: - list_for_each_entry(dev, &card->devices, list) { - type = (__force unsigned int)dev->type; - if (type >= range_low && type <= range_high) { - if ((err = snd_device_free(card, dev->device_data)) < 0) - return err; - goto __again; - } - } - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/hrtimer.c b/ANDROID_3.4.5/sound/core/hrtimer.c deleted file mode 100644 index b8b31c43..00000000 --- a/ANDROID_3.4.5/sound/core/hrtimer.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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) { - snd_printk(KERN_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/ANDROID_3.4.5/sound/core/hwdep.c b/ANDROID_3.4.5/sound/core/hwdep.c deleted file mode 100644 index 3f7f6628..00000000 --- a/ANDROID_3.4.5/sound/core/hwdep.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Hardware dependent layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/major.h> -#include <linux/init.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@perex.cz>"); -MODULE_DESCRIPTION("Hardware dependent layer"); -MODULE_LICENSE("GPL"); - -static LIST_HEAD(snd_hwdep_devices); -static DEFINE_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 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) -{ - 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) -{ - 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) -{ - struct snd_hwdep *hw = file->private_data; - if (hw->ops.write) - return hw->ops.write(hw, buf, count, offset); - return -ENXIO; -} - -static int snd_hwdep_open(struct inode *inode, struct file * file) -{ - int major = imajor(inode); - struct snd_hwdep *hw; - int err; - wait_queue_t wait; - - if (major == snd_major) { - hw = snd_lookup_minor_data(iminor(inode), - SNDRV_DEVICE_TYPE_HWDEP); -#ifdef CONFIG_SND_OSSEMUL - } else if (major == SOUND_MAJOR) { - hw = snd_lookup_oss_minor_data(iminor(inode), - SNDRV_OSS_DEVICE_TYPE_DMFM); -#endif - } else - return -ENXIO; - if (hw == NULL) - return -ENODEV; - - 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); - 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; - if (err == -EAGAIN) { - if (file->f_flags & O_NONBLOCK) { - err = -EBUSY; - break; - } - } else - break; - set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&hw->open_mutex); - schedule(); - mutex_lock(&hw->open_mutex); - if (hw->card->shutdown) { - err = -ENODEV; - break; - } - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - } - remove_wait_queue(&hw->open_wait, &wait); - if (err >= 0) { - err = snd_card_file_add(hw->card, file); - if (err >= 0) { - file->private_data = hw; - hw->used++; - } else { - if (hw->ops.release) - hw->ops.release(hw, file); - } - } - 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 = 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); - if (hw->used > 0) - hw->used--; - mutex_unlock(&hw->open_mutex); - wake_up(&hw->open_wait); - - snd_card_file_remove(hw->card, file); - module_put(mod); - return err; -} - -static unsigned int snd_hwdep_poll(struct file * file, poll_table * wait) -{ - 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(struct snd_hwdep *hw, - struct snd_hwdep_info __user *_info) -{ - struct snd_hwdep_info info; - - memset(&info, 0, sizeof(info)); - info.card = hw->card->number; - strlcpy(info.id, hw->id, sizeof(info.id)); - strlcpy(info.name, hw->name, sizeof(info.name)); - info.iface = hw->iface; - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status __user *_info) -{ - struct snd_hwdep_dsp_status info; - int err; - - if (! hw->ops.dsp_status) - return -ENXIO; - memset(&info, 0, sizeof(info)); - info.dsp_loaded = hw->dsp_loaded; - if ((err = hw->ops.dsp_status(hw, &info)) < 0) - return err; - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image __user *_info) -{ - struct snd_hwdep_dsp_image info; - int err; - - if (! hw->ops.dsp_load) - return -ENXIO; - memset(&info, 0, sizeof(info)); - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; - /* check whether the dsp was already loaded */ - if (hw->dsp_loaded & (1 << info.index)) - return -EBUSY; - if (!access_ok(VERIFY_READ, info.image, info.length)) - return -EFAULT; - err = hw->ops.dsp_load(hw, &info); - if (err < 0) - return err; - hw->dsp_loaded |= (1 << info.index); - return 0; -} - -static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, - unsigned long arg) -{ - struct snd_hwdep *hw = file->private_data; - void __user *argp = (void __user *)arg; - switch (cmd) { - case SNDRV_HWDEP_IOCTL_PVERSION: - return put_user(SNDRV_HWDEP_VERSION, (int __user *)argp); - case SNDRV_HWDEP_IOCTL_INFO: - return snd_hwdep_info(hw, argp); - case SNDRV_HWDEP_IOCTL_DSP_STATUS: - return snd_hwdep_dsp_status(hw, argp); - case SNDRV_HWDEP_IOCTL_DSP_LOAD: - return snd_hwdep_dsp_load(hw, argp); - } - if (hw->ops.ioctl) - return hw->ops.ioctl(hw, file, cmd, arg); - return -ENOTTY; -} - -static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma) -{ - 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(struct snd_card *card, - struct snd_ctl_file * control, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: - { - int device; - - if (get_user(device, (int __user *)arg)) - return -EFAULT; - mutex_lock(®ister_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_search(card, device)) - break; - device++; - } - if (device >= SNDRV_MINOR_HWDEPS) - device = -1; - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)arg)) - return -EFAULT; - return 0; - } - case SNDRV_CTL_IOCTL_HWDEP_INFO: - { - 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; - mutex_lock(®ister_mutex); - hwdep = snd_hwdep_search(card, device); - if (hwdep) - err = snd_hwdep_info(hwdep, info); - else - err = -ENXIO; - mutex_unlock(®ister_mutex); - return err; - } - } - return -ENOIOCTLCMD; -} - -#ifdef CONFIG_COMPAT -#include "hwdep_compat.c" -#else -#define snd_hwdep_ioctl_compat NULL -#endif - -/* - - */ - -static const struct file_operations snd_hwdep_f_ops = -{ - .owner = THIS_MODULE, - .llseek = snd_hwdep_llseek, - .read = snd_hwdep_read, - .write = snd_hwdep_write, - .open = snd_hwdep_open, - .release = snd_hwdep_release, - .poll = snd_hwdep_poll, - .unlocked_ioctl = snd_hwdep_ioctl, - .compat_ioctl = snd_hwdep_ioctl_compat, - .mmap = snd_hwdep_mmap, -}; - -/** - * snd_hwdep_new - create a new hwdep instance - * @card: the card instance - * @id: the id string - * @device: the device index (zero-based) - * @rhwdep: the pointer to store the new hwdep instance - * - * Creates a new hwdep instance with the given index on the card. - * 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. - */ -int snd_hwdep_new(struct snd_card *card, char *id, int device, - struct snd_hwdep **rhwdep) -{ - struct snd_hwdep *hwdep; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_hwdep_dev_free, - .dev_register = snd_hwdep_dev_register, - .dev_disconnect = snd_hwdep_dev_disconnect, - }; - - if (snd_BUG_ON(!card)) - return -ENXIO; - if (rhwdep) - *rhwdep = NULL; - hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); - if (hwdep == NULL) { - snd_printk(KERN_ERR "hwdep: cannot allocate\n"); - return -ENOMEM; - } - hwdep->card = card; - hwdep->device = device; - if (id) - strlcpy(hwdep->id, id, sizeof(hwdep->id)); -#ifdef CONFIG_SND_OSSEMUL - hwdep->oss_type = -1; -#endif - if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) { - snd_hwdep_free(hwdep); - return err; - } - init_waitqueue_head(&hwdep->open_wait); - mutex_init(&hwdep->open_mutex); - if (rhwdep) - *rhwdep = hwdep; - return 0; -} - -static int snd_hwdep_free(struct snd_hwdep *hwdep) -{ - if (!hwdep) - return 0; - if (hwdep->private_free) - hwdep->private_free(hwdep); - kfree(hwdep); - return 0; -} - -static int snd_hwdep_dev_free(struct snd_device *device) -{ - struct snd_hwdep *hwdep = device->device_data; - return snd_hwdep_free(hwdep); -} - -static int snd_hwdep_dev_register(struct snd_device *device) -{ - struct snd_hwdep *hwdep = device->device_data; - int err; - char name[32]; - - mutex_lock(®ister_mutex); - if (snd_hwdep_search(hwdep->card, hwdep->device)) { - mutex_unlock(®ister_mutex); - return -EBUSY; - } - 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_f_ops, hwdep, name)) < 0) { - snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n", - hwdep->card->number, hwdep->device); - list_del(&hwdep->list); - mutex_unlock(®ister_mutex); - return err; - } -#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"); - } else { - if (snd_register_oss_device(hwdep->oss_type, - hwdep->card, hwdep->device, - &snd_hwdep_f_ops, hwdep, - hwdep->oss_dev) < 0) { - snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n", - hwdep->card->number, hwdep->device); - } else - hwdep->ossreg = 1; - } - } -#endif - mutex_unlock(®ister_mutex); - return 0; -} - -static int snd_hwdep_dev_disconnect(struct snd_device *device) -{ - struct snd_hwdep *hwdep = device->device_data; - - if (snd_BUG_ON(!hwdep)) - return -ENXIO; - mutex_lock(®ister_mutex); - if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) { - mutex_unlock(®ister_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); - list_del_init(&hwdep->list); - mutex_unlock(&hwdep->open_mutex); - mutex_unlock(®ister_mutex); - return 0; -} - -#ifdef CONFIG_PROC_FS -/* - * Info interface - */ - -static void snd_hwdep_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_hwdep *hwdep; - - mutex_lock(®ister_mutex); - list_for_each_entry(hwdep, &snd_hwdep_devices, list) - snd_iprintf(buffer, "%02i-%02i: %s\n", - hwdep->card->number, hwdep->device, hwdep->name); - mutex_unlock(®ister_mutex); -} - -static struct snd_info_entry *snd_hwdep_proc_entry; - -static void __init snd_hwdep_proc_init(void) -{ - struct snd_info_entry *entry; - - if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { - entry->c.text.read = snd_hwdep_proc_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - 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; -} - -static void __exit alsa_hwdep_exit(void) -{ - snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl); - snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl); - snd_hwdep_proc_done(); -} - -module_init(alsa_hwdep_init) -module_exit(alsa_hwdep_exit) - -EXPORT_SYMBOL(snd_hwdep_new); diff --git a/ANDROID_3.4.5/sound/core/hwdep_compat.c b/ANDROID_3.4.5/sound/core/hwdep_compat.c deleted file mode 100644 index 3827c0ce..00000000 --- a/ANDROID_3.4.5/sound/core/hwdep_compat.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for hwdep API - * Copyright (c) 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; 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 - * - */ - -/* This file is included from hwdep.c */ - -#include <linux/compat.h> - -struct snd_hwdep_dsp_image32 { - u32 index; - unsigned char name[64]; - u32 image; /* pointer */ - u32 length; - u32 driver_data; -} /* don't set packed attribute here */; - -static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image32 __user *src) -{ - struct snd_hwdep_dsp_image __user *dst; - compat_caddr_t ptr; - u32 val; - - dst = compat_alloc_user_space(sizeof(*dst)); - - /* index and name */ - if (copy_in_user(dst, src, 4 + 64)) - return -EFAULT; - if (get_user(ptr, &src->image) || - put_user(compat_ptr(ptr), &dst->image)) - return -EFAULT; - if (get_user(val, &src->length) || - put_user(val, &dst->length)) - return -EFAULT; - if (get_user(val, &src->driver_data) || - put_user(val, &dst->driver_data)) - return -EFAULT; - - return snd_hwdep_dsp_load(hw, dst); -} - -enum { - 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) -{ - struct snd_hwdep *hw = file->private_data; - void __user *argp = compat_ptr(arg); - switch (cmd) { - case SNDRV_HWDEP_IOCTL_PVERSION: - case SNDRV_HWDEP_IOCTL_INFO: - case SNDRV_HWDEP_IOCTL_DSP_STATUS: - return snd_hwdep_ioctl(file, cmd, (unsigned long)argp); - case SNDRV_HWDEP_IOCTL_DSP_LOAD32: - return snd_hwdep_dsp_load_compat(hw, argp); - } - if (hw->ops.ioctl_compat) - return hw->ops.ioctl_compat(hw, file, cmd, arg); - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/info.c b/ANDROID_3.4.5/sound/core/info.c deleted file mode 100644 index c1e611c6..00000000 --- a/ANDROID_3.4.5/sound/core/info.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Information interface for ALSA driver - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#include <linux/time.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/proc_fs.h> -#include <linux/mutex.h> -#include <stdarg.h> - -/* - * - */ - -#ifdef CONFIG_PROC_FS - -int snd_info_check_reserved_words(const char *str) -{ - static char *reserved[] = - { - "version", - "meminfo", - "memdebug", - "detect", - "devices", - "oss", - "cards", - "timers", - "synth", - "pcm", - "seq", - NULL - }; - char **xstr = reserved; - - while (*xstr) { - if (!strcmp(*xstr, str)) - return 0; - xstr++; - } - if (!strncmp(str, "card", 4)) - return 0; - return 1; -} - -static DEFINE_MUTEX(info_mutex); - -struct snd_info_private_data { - struct snd_info_buffer *rbuffer; - struct snd_info_buffer *wbuffer; - struct snd_info_entry *entry; - void *file_private_data; -}; - -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); - if (! nbuf) - return -ENOMEM; - - buffer->buffer = nbuf; - buffer->len = nsize; - return 0; -} - -/** - * snd_iprintf - printf on the procfs buffer - * @buffer: the procfs buffer - * @fmt: the printf format - * - * Outputs the string on the procfs buffer just like printf(). - * - * Returns the size of output string. - */ -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); - 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; -struct snd_info_entry *snd_seq_root; -EXPORT_SYMBOL(snd_seq_root); - -#ifdef CONFIG_SND_OSSEMUL -struct snd_info_entry *snd_oss_root; -#endif - -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) -{ - struct snd_info_private_data *data; - struct snd_info_entry *entry; - loff_t ret = -EINVAL, size; - - data = file->private_data; - entry = data->entry; - 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 SEEK_CUR: - offset += file->f_pos; - break; - case SEEK_END: - if (!size) - goto out; - offset += size; - break; - default: - goto out; - } - 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) -{ - struct snd_info_private_data *data; - struct snd_info_entry *entry; - struct snd_info_buffer *buf; - size_t size = 0; - loff_t pos; - - data = file->private_data; - if (snd_BUG_ON(!data)) - return -ENXIO; - pos = *offset; - if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) - return -EIO; - if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) - return -EIO; - entry = data->entry; - switch (entry->content) { - case SNDRV_INFO_CONTENT_TEXT: - buf = data->rbuffer; - if (buf == NULL) - return -EIO; - if (pos >= buf->size) - return 0; - size = buf->size - pos; - size = min(count, size); - if (copy_to_user(buffer, buf->buffer + pos, size)) - return -EFAULT; - break; - case SNDRV_INFO_CONTENT_DATA: - 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, size, pos); - } - break; - } - if ((ssize_t) size > 0) - *offset = pos + size; - return size; -} - -static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer, - size_t count, loff_t * offset) -{ - struct snd_info_private_data *data; - struct snd_info_entry *entry; - struct snd_info_buffer *buf; - ssize_t size = 0; - loff_t pos; - - data = file->private_data; - if (snd_BUG_ON(!data)) - return -ENXIO; - entry = data->entry; - pos = *offset; - if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) - return -EIO; - if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) - return -EIO; - switch (entry->content) { - case SNDRV_INFO_CONTENT_TEXT: - buf = data->wbuffer; - if (buf == NULL) - return -EIO; - 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; - } - buf->size = pos + count; - mutex_unlock(&entry->access); - size = count; - break; - case SNDRV_INFO_CONTENT_DATA: - 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) - *offset = pos + size; - return size; -} - -static int snd_info_entry_open(struct inode *inode, struct file *file) -{ - struct snd_info_entry *entry; - struct snd_info_private_data *data; - struct snd_info_buffer *buffer; - struct proc_dir_entry *p; - int mode, err; - - mutex_lock(&info_mutex); - p = PDE(inode); - entry = p == NULL ? NULL : (struct snd_info_entry *)p->data; - if (entry == NULL || ! entry->p) { - mutex_unlock(&info_mutex); - return -ENODEV; - } - if (!try_module_get(entry->module)) { - err = -EFAULT; - goto __error1; - } - mode = file->f_flags & O_ACCMODE; - if (mode == O_RDONLY || mode == O_RDWR) { - 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_DATA && - entry->c.ops->write == NULL)) { - err = -ENODEV; - goto __error; - } - } - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) { - err = -ENOMEM; - goto __error; - } - data->entry = entry; - switch (entry->content) { - case SNDRV_INFO_CONTENT_TEXT: - if (mode == O_RDONLY || mode == O_RDWR) { - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (buffer == NULL) - goto __nomem; - data->rbuffer = buffer; - buffer->len = PAGE_SIZE; - buffer->buffer = kmalloc(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) - 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 */ - if (entry->c.ops->open) { - if ((err = entry->c.ops->open(entry, mode, - &data->file_private_data)) < 0) { - kfree(data); - goto __error; - } - } - break; - } - file->private_data = data; - mutex_unlock(&info_mutex); - if (entry->content == SNDRV_INFO_CONTENT_TEXT && - (mode == O_RDONLY || mode == O_RDWR)) { - if (entry->c.text.read) { - mutex_lock(&entry->access); - entry->c.text.read(entry, data->rbuffer); - 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: - mutex_unlock(&info_mutex); - return err; -} - -static int snd_info_entry_release(struct inode *inode, struct file *file) -{ - struct snd_info_entry *entry; - struct snd_info_private_data *data; - int mode; - - mode = file->f_flags & O_ACCMODE; - data = file->private_data; - entry = data->entry; - switch (entry->content) { - case SNDRV_INFO_CONTENT_TEXT: - if (data->rbuffer) { - kfree(data->rbuffer->buffer); - kfree(data->rbuffer); - } - 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); - } - } - kfree(data->wbuffer->buffer); - kfree(data->wbuffer); - } - break; - case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->release) - entry->c.ops->release(entry, mode, - data->file_private_data); - break; - } - module_put(entry->module); - kfree(data); - return 0; -} - -static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait) -{ - struct snd_info_private_data *data; - struct snd_info_entry *entry; - unsigned int mask; - - data = file->private_data; - if (data == NULL) - return 0; - entry = data->entry; - mask = 0; - switch (entry->content) { - case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->poll) - return entry->c.ops->poll(entry, - data->file_private_data, - file, wait); - if (entry->c.ops->read) - mask |= POLLIN | POLLRDNORM; - if (entry->c.ops->write) - mask |= POLLOUT | POLLWRNORM; - break; - } - return mask; -} - -static long snd_info_entry_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct snd_info_private_data *data; - struct snd_info_entry *entry; - - data = file->private_data; - if (data == NULL) - return 0; - entry = data->entry; - switch (entry->content) { - case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->ioctl) - return entry->c.ops->ioctl(entry, - data->file_private_data, - file, cmd, arg); - break; - } - return -ENOTTY; -} - -static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct inode *inode = file->f_path.dentry->d_inode; - struct snd_info_private_data *data; - struct snd_info_entry *entry; - - data = file->private_data; - if (data == NULL) - return 0; - entry = data->entry; - switch (entry->content) { - case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->mmap) - return entry->c.ops->mmap(entry, - data->file_private_data, - inode, file, vma); - break; - } - return -ENXIO; -} - -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, - .unlocked_ioctl = snd_info_entry_ioctl, - .mmap = snd_info_entry_mmap, - .open = snd_info_entry_open, - .release = snd_info_entry_release, -}; - -int __init snd_info_init(void) -{ - struct proc_dir_entry *p; - - p = proc_mkdir("asound", NULL); - if (p == NULL) - return -ENOMEM; - snd_proc_root = p; -#ifdef CONFIG_SND_OSSEMUL - { - 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; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - snd_oss_root = entry; - } -#endif -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) - { - 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; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - snd_seq_root = entry; - } -#endif - snd_info_version_init(); - snd_minor_info_init(); - snd_minor_info_oss_init(); - snd_card_info_init(); - return 0; -} - -int __exit snd_info_done(void) -{ - snd_card_info_done(); - snd_minor_info_oss_done(); - snd_minor_info_done(); - snd_info_version_done(); - if (snd_proc_root) { -#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) - snd_info_free_entry(snd_seq_root); -#endif -#ifdef CONFIG_SND_OSSEMUL - snd_info_free_entry(snd_oss_root); -#endif - snd_remove_proc_entry(NULL, snd_proc_root); - } - return 0; -} - -/* - - */ - - -/* - * create a card proc file - * called from init.c - */ -int snd_info_card_create(struct snd_card *card) -{ - char str[8]; - struct snd_info_entry *entry; - - 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) - return -ENOMEM; - entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - card->proc_root = entry; - return 0; -} - -/* - * register the card proc file - * called from init.c - */ -int snd_info_card_register(struct snd_card *card) -{ - struct proc_dir_entry *p; - - if (snd_BUG_ON(!card)) - return -ENXIO; - - if (!strcmp(card->id, card->proc_root->name)) - return 0; - - p = proc_symlink(card->id, snd_proc_root, card->proc_root->name); - if (p == NULL) - return -ENOMEM; - card->proc_root_link = p; - return 0; -} - -/* - * called on card->id change - */ -void snd_info_card_id_change(struct snd_card *card) -{ - mutex_lock(&info_mutex); - if (card->proc_root_link) { - snd_remove_proc_entry(snd_proc_root, card->proc_root_link); - card->proc_root_link = 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); - if (card->proc_root_link) { - snd_remove_proc_entry(snd_proc_root, 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; -} - - -/** - * snd_info_get_line - read one line from the procfs buffer - * @buffer: the procfs buffer - * @line: the buffer to store - * @len: the max. buffer size - 1 - * - * Reads one line from the buffer and stores the string. - * - * Returns zero if successful, or 1 if error or EOF. - */ -int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) -{ - int c = -1; - - if (len <= 0 || buffer->stop || buffer->error) - return 1; - while (--len > 0) { - c = buffer->buffer[buffer->curr++]; - if (c == '\n') { - if (buffer->curr >= buffer->size) - buffer->stop = 1; - break; - } - *line++ = c; - if (buffer->curr >= buffer->size) { - buffer->stop = 1; - break; - } - } - while (c != '\n' && !buffer->stop) { - c = buffer->buffer[buffer->curr++]; - if (buffer->curr >= buffer->size) - buffer->stop = 1; - } - *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 - * @src: the original string - * @len: the max. length of token - 1 - * - * Parses the original string and copy a token to the given - * string buffer. - * - * Returns the updated pointer of the original string so that - * it can be used for the next call. - */ -const char *snd_info_get_str(char *dest, const char *src, int len) -{ - int c; - - while (*src == ' ' || *src == '\t') - src++; - if (*src == '"' || *src == '\'') { - c = *src++; - while (--len > 0 && *src && *src != c) { - *dest++ = *src++; - } - if (*src == c) - src++; - } else { - while (--len > 0 && *src && *src != ' ' && *src != '\t') { - *dest++ = *src++; - } - } - *dest = 0; - while (*src == ' ' || *src == '\t') - src++; - return src; -} - -EXPORT_SYMBOL(snd_info_get_str); - -/** - * snd_info_create_entry - create an info entry - * @name: the proc file name - * - * Creates an info entry with the given file name and initializes as - * the default state. - * - * Usually called from other functions such as - * snd_info_create_card_entry(). - * - * Returns the pointer of the new instance, or NULL on failure. - */ -static struct snd_info_entry *snd_info_create_entry(const char *name) -{ - struct snd_info_entry *entry; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) - return NULL; - entry->name = kstrdup(name, GFP_KERNEL); - if (entry->name == NULL) { - kfree(entry); - return NULL; - } - entry->mode = S_IFREG | S_IRUGO; - entry->content = SNDRV_INFO_CONTENT_TEXT; - mutex_init(&entry->access); - INIT_LIST_HEAD(&entry->children); - INIT_LIST_HEAD(&entry->list); - return entry; -} - -/** - * snd_info_create_module_entry - create an info entry for the given module - * @module: the module pointer - * @name: the file name - * @parent: the parent directory - * - * Creates a new info entry and assigns it to the given module. - * - * Returns the pointer of the new instance, or NULL on failure. - */ -struct snd_info_entry *snd_info_create_module_entry(struct module * module, - const char *name, - struct snd_info_entry *parent) -{ - struct snd_info_entry *entry = snd_info_create_entry(name); - if (entry) { - entry->module = module; - entry->parent = parent; - } - 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 - * @name: the file name - * @parent: the parent directory - * - * Creates a new info entry and assigns it to the given card. - * - * Returns the pointer of the new instance, or NULL on failure. - */ -struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, - const char *name, - struct snd_info_entry * parent) -{ - struct snd_info_entry *entry = snd_info_create_entry(name); - if (entry) { - entry->module = card->module; - entry->card = card; - entry->parent = parent; - } - return entry; -} - -EXPORT_SYMBOL(snd_info_create_card_entry); - -static void snd_info_disconnect(struct snd_info_entry *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); - snd_remove_proc_entry(root, entry->p); - entry->p = NULL; -} - -static int snd_info_dev_free_entry(struct snd_device *device) -{ - struct snd_info_entry *entry = device->device_data; - snd_info_free_entry(entry); - return 0; -} - -static int snd_info_dev_register_entry(struct snd_device *device) -{ - struct snd_info_entry *entry = device->device_data; - return snd_info_register(entry); -} - -/** - * snd_card_proc_new - create an info entry for the given card - * @card: the card instance - * @name: the file name - * @entryp: the pointer to store the new info entry - * - * Creates a new info entry and assigns it to the given card. - * Unlike snd_info_create_card_entry(), this function registers the - * info entry as an ALSA device component, so that it can be - * unregistered/released without explicit call. - * Also, you don't have to register this entry via snd_info_register(), - * since this will be registered by snd_card_register() automatically. - * - * The parent is assumed as card->proc_root. - * - * 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. - */ -int snd_card_proc_new(struct snd_card *card, const char *name, - struct snd_info_entry **entryp) -{ - static struct snd_device_ops ops = { - .dev_free = snd_info_dev_free_entry, - .dev_register = snd_info_dev_register_entry, - /* disconnect is done via snd_info_card_disconnect() */ - }; - struct snd_info_entry *entry; - int err; - - entry = snd_info_create_card_entry(card, name, card->proc_root); - if (! entry) - return -ENOMEM; - if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) { - snd_info_free_entry(entry); - return err; - } - if (entryp) - *entryp = entry; - 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(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. - */ -int snd_info_register(struct snd_info_entry * entry) -{ - struct proc_dir_entry *root, *p = NULL; - - if (snd_BUG_ON(!entry)) - return -ENXIO; - root = entry->parent == NULL ? snd_proc_root : entry->parent->p; - mutex_lock(&info_mutex); - p = create_proc_entry(entry->name, entry->mode, root); - if (!p) { - mutex_unlock(&info_mutex); - return -ENOMEM; - } - if (!S_ISDIR(entry->mode)) - p->proc_fops = &snd_info_entry_operations; - p->size = entry->size; - p->data = entry; - entry->p = p; - if (entry->parent) - list_add_tail(&entry->list, &entry->parent->children); - mutex_unlock(&info_mutex); - return 0; -} - -EXPORT_SYMBOL(snd_info_register); - -/* - - */ - -static struct snd_info_entry *snd_info_version_entry; - -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" - ); -} - -static int __init snd_info_version_init(void) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); - if (entry == NULL) - return -ENOMEM; - entry->c.text.read = snd_info_version_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - snd_info_version_entry = entry; - return 0; -} - -static int __exit snd_info_version_done(void) -{ - snd_info_free_entry(snd_info_version_entry); - return 0; -} - -#endif /* CONFIG_PROC_FS */ diff --git a/ANDROID_3.4.5/sound/core/info_oss.c b/ANDROID_3.4.5/sound/core/info_oss.c deleted file mode 100644 index cf42ab50..00000000 --- a/ANDROID_3.4.5/sound/core/info_oss.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Information interface for ALSA driver - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/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) - -/* - * OSS compatible part - */ - -static DEFINE_MUTEX(strings); -static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT]; -static struct snd_info_entry *snd_sndstat_proc_entry; - -int snd_oss_info_register(int dev, int num, char *string) -{ - char *x; - - 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); - x = NULL; - } - } else { - x = kstrdup(string, GFP_KERNEL); - if (x == NULL) { - mutex_unlock(&strings); - return -ENOMEM; - } - } - snd_sndstat_strings[num][dev] = x; - mutex_unlock(&strings); - return 0; -} - -EXPORT_SYMBOL(snd_oss_info_register); - -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); - mutex_lock(&strings); - for (idx = 0; idx < SNDRV_CARDS; idx++) { - str = snd_sndstat_strings[idx][dev]; - if (str) { - if (ok < 0) { - snd_iprintf(buf, "\n"); - ok++; - } - snd_iprintf(buf, "%i: %s\n", idx, str); - } - } - mutex_unlock(&strings); - if (ok < 0) - snd_iprintf(buf, " NOT ENABLED IN CONFIG\n"); - return ok; -} - -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, "Kernel: %s %s %s %s %s\n", - 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"); - snd_iprintf(buffer, "\nCard config: \n"); - snd_card_info_read_oss(buffer); - snd_sndstat_show_strings(buffer, "Audio devices", SNDRV_OSS_INFO_DEV_AUDIO); - snd_sndstat_show_strings(buffer, "Synth devices", SNDRV_OSS_INFO_DEV_SYNTH); - snd_sndstat_show_strings(buffer, "Midi devices", SNDRV_OSS_INFO_DEV_MIDI); - snd_sndstat_show_strings(buffer, "Timers", SNDRV_OSS_INFO_DEV_TIMERS); - snd_sndstat_show_strings(buffer, "Mixers", SNDRV_OSS_INFO_DEV_MIXERS); -} - -int snd_info_minor_register(void) -{ - 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 = snd_sndstat_proc_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - snd_sndstat_proc_entry = entry; - return 0; -} - -int snd_info_minor_unregister(void) -{ - snd_info_free_entry(snd_sndstat_proc_entry); - snd_sndstat_proc_entry = NULL; - return 0; -} - -#endif /* CONFIG_SND_OSSEMUL */ diff --git a/ANDROID_3.4.5/sound/core/init.c b/ANDROID_3.4.5/sound/core/init.c deleted file mode 100644 index 7b012d15..00000000 --- a/ANDROID_3.4.5/sound/core/init.c +++ /dev/null @@ -1,991 +0,0 @@ -/* - * Initialization routines - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#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/pm.h> - -#include <sound/core.h> -#include <sound/control.h> -#include <sound/info.h> - -/* 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 */ -}; - -static DEFINE_SPINLOCK(shutdown_lock); -static LIST_HEAD(shutdown_files); - -static const struct file_operations snd_shutdown_f_ops; - -static unsigned int snd_cards_lock; /* locked for registering/using */ -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; - - 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 defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) -int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); -EXPORT_SYMBOL(snd_mixer_oss_notify_callback); -#endif - -#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 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) { - snd_printd("unable to create card info\n"); - return err; - } - if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) { - snd_printd("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 - -/** - * snd_card_create - create and initialize a soundcard structure - * @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. - * - * 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. - * - * Returns zero if successful or a negative error code. - */ -int snd_card_create(int idx, const char *xid, - struct module *module, int extra_size, - struct snd_card **card_ret) -{ - struct snd_card *card; - int err, idx2; - - 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) - return -ENOMEM; - if (xid) - strlcpy(card->id, xid, sizeof(card->id)); - err = 0; - mutex_lock(&snd_card_mutex); - if (idx < 0) { - for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) - /* idx == -1 == 0xffff means: take any free slot */ - if (~snd_cards_lock & idx & 1<<idx2) { - if (module_slot_match(module, idx2)) { - idx = idx2; - break; - } - } - } - if (idx < 0) { - for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) - /* idx == -1 == 0xffff means: take any free slot */ - if (~snd_cards_lock & idx & 1<<idx2) { - if (!slots[idx2] || !*slots[idx2]) { - idx = idx2; - break; - } - } - } - if (idx < 0) - err = -ENODEV; - else if (idx < snd_ecards_limit) { - if (snd_cards_lock & (1 << idx)) - err = -EBUSY; /* invalid */ - } else if (idx >= SNDRV_CARDS) - err = -ENODEV; - if (err < 0) { - mutex_unlock(&snd_card_mutex); - snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", - idx, snd_ecards_limit - 1, err); - goto __error; - } - snd_cards_lock |= 1 << idx; /* lock it */ - if (idx >= snd_ecards_limit) - snd_ecards_limit = idx + 1; /* increase the limit */ - mutex_unlock(&snd_card_mutex); - card->number = idx; - card->module = module; - INIT_LIST_HEAD(&card->devices); - init_rwsem(&card->controls_rwsem); - rwlock_init(&card->ctl_files_rwlock); - INIT_LIST_HEAD(&card->controls); - INIT_LIST_HEAD(&card->ctl_files); - spin_lock_init(&card->files_lock); - INIT_LIST_HEAD(&card->files_list); - init_waitqueue_head(&card->shutdown_sleep); - atomic_set(&card->refcount, 0); -#ifdef CONFIG_PM - mutex_init(&card->power_lock); - init_waitqueue_head(&card->power_sleep); -#endif - /* the control interface cannot be accessed from the user space until */ - /* snd_cards_bitmask and snd_cards are set with snd_card_register */ - err = snd_ctl_create(card); - if (err < 0) { - snd_printk(KERN_ERR "unable to register control minors\n"); - goto __error; - } - err = snd_info_card_create(card); - if (err < 0) { - snd_printk(KERN_ERR "unable to create card info\n"); - goto __error_ctl; - } - if (extra_size > 0) - card->private_data = (char *)card + sizeof(struct snd_card); - *card_ret = card; - return 0; - - __error_ctl: - snd_device_free_all(card, SNDRV_DEV_CMD_PRE); - __error: - kfree(card); - return err; -} -EXPORT_SYMBOL(snd_card_create); - -/* return non-zero if a card is already locked */ -int snd_card_locked(int card) -{ - int locked; - - mutex_lock(&snd_card_mutex); - locked = snd_cards_lock & (1 << card); - 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) -{ - 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. - * - * Note: The current implementation replaces all active file->f_op with special - * dummy file operations (they do nothing except release). - */ -int snd_card_disconnect(struct snd_card *card) -{ - struct snd_monitor_file *mfile; - int err; - - if (!card) - return -EINVAL; - - spin_lock(&card->files_lock); - if (card->shutdown) { - spin_unlock(&card->files_lock); - return 0; - } - card->shutdown = 1; - spin_unlock(&card->files_lock); - - /* phase 1: disable fops (user space) operations for ALSA API */ - mutex_lock(&snd_card_mutex); - snd_cards[card->number] = NULL; - snd_cards_lock &= ~(1 << card->number); - mutex_unlock(&snd_card_mutex); - - /* phase 2: replace file->f_op with special dummy operations */ - - spin_lock(&card->files_lock); - list_for_each_entry(mfile, &card->files_list, list) { - /* it's critical part, use endless loop */ - /* we have no room to fail */ - mfile->disconnected_f_op = mfile->file->f_op; - - spin_lock(&shutdown_lock); - list_add(&mfile->shutdown_list, &shutdown_files); - spin_unlock(&shutdown_lock); - - 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 (snd_mixer_oss_notify_callback) - snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT); -#endif - - /* 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); - - snd_info_card_disconnect(card); - if (card->card_dev) { - device_unregister(card->card_dev); - card->card_dev = NULL; - } -#ifdef CONFIG_PM - wake_up(&card->power_sleep); -#endif - return 0; -} - -EXPORT_SYMBOL(snd_card_disconnect); - -/** - * snd_card_free - frees given soundcard structure - * @card: soundcard structure - * - * This function releases the soundcard structure and the all assigned - * devices automatically. That is, you don't have to release the devices - * by yourself. - * - * Returns zero. Frees all associated devices and frees the control - * interface associated to given soundcard. - */ -static int snd_card_do_free(struct snd_card *card) -{ -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) - 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 */ - } - if (card->private_free) - card->private_free(card); - snd_info_free_entry(card->proc_id); - if (snd_info_card_free(card) < 0) { - snd_printk(KERN_WARNING "unable to free card info\n"); - /* Not fatal error */ - } - kfree(card); - return 0; -} - -/** - * snd_card_unref - release the reference counter - * @card: the card instance - * - * Decrements the reference counter. When it reaches to zero, wake up - * the sleeper and call the destructor if needed. - */ -void snd_card_unref(struct snd_card *card) -{ - if (atomic_dec_and_test(&card->refcount)) { - wake_up(&card->shutdown_sleep); - if (card->free_on_last_close) - snd_card_do_free(card); - } -} -EXPORT_SYMBOL(snd_card_unref); - -int snd_card_free_when_closed(struct snd_card *card) -{ - int ret; - - atomic_inc(&card->refcount); - ret = snd_card_disconnect(card); - if (ret) { - atomic_dec(&card->refcount); - return ret; - } - - card->free_on_last_close = 1; - if (atomic_dec_and_test(&card->refcount)) - snd_card_do_free(card); - return 0; -} - -EXPORT_SYMBOL(snd_card_free_when_closed); - -int snd_card_free(struct snd_card *card) -{ - int ret = snd_card_disconnect(card); - if (ret) - return ret; - - /* wait, until all devices are ready for the free operation */ - wait_event(card->shutdown_sleep, !atomic_read(&card->refcount)); - snd_card_do_free(card); - 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; -} - -/* 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; -} - -/* 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 with_suffix; - 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; - } - - with_suffix = false; - for (loops = 0; loops < SNDRV_CARDS; loops++) { - if (card_id_ok(card, id)) - return; /* OK */ - - len = strlen(id); - if (!with_suffix) { - /* add the "_X" suffix */ - char *spos = id + len; - if (len > sizeof(card->id) - 3) - spos = id + sizeof(card->id) - 3; - strcpy(spos, "_1"); - with_suffix = true; - } else { - /* modify the existing suffix */ - if (id[len - 1] != '9') - id[len - 1]++; - else - id[len - 1] = 'A'; - } - } - /* fallback to the default id */ - if (!is_default) { - *id = 0; - goto again; - } - /* last resort... */ - snd_printk(KERN_ERR "unable to set card id (%s)\n", id); - if (card->proc_root->name) - strcpy(card->id, card->proc_root->name); -} - -/** - * snd_card_set_id - set card identification name - * @card: soundcard structure - * @nid: new identification string - * - * This function sets the card identification and checks for name - * collisions. - */ -void snd_card_set_id(struct snd_card *card, const char *nid) -{ - /* 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); - -static ssize_t -card_id_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_card *card = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)"); -} - -static ssize_t -card_id_store_attr(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_card *card = dev_get_drvdata(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; -} - -static struct device_attribute card_id_attrs = - __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr); - -static ssize_t -card_number_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_card *card = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1); -} - -static struct device_attribute card_number_attrs = - __ATTR(number, S_IRUGO, card_number_show_attr, NULL); - -/** - * snd_card_register - register the soundcard - * @card: soundcard structure - * - * This function registers all the devices assigned to the soundcard. - * Until calling this, the ALSA control interface is blocked from the - * 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 registration failed. - */ -int snd_card_register(struct snd_card *card) -{ - int err; - - if (snd_BUG_ON(!card)) - return -EINVAL; - - if (!card->card_dev) { - card->card_dev = device_create(sound_class, card->dev, - MKDEV(0, 0), card, - "card%i", card->number); - if (IS_ERR(card->card_dev)) - card->card_dev = NULL; - } - - if ((err = snd_device_register_all(card)) < 0) - return err; - mutex_lock(&snd_card_mutex); - if (snd_cards[card->number]) { - /* already registered */ - mutex_unlock(&snd_card_mutex); - return 0; - } - 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)); - } - snd_cards[card->number] = card; - mutex_unlock(&snd_card_mutex); - init_info_for_card(card); -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) - if (snd_mixer_oss_notify_callback) - snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); -#endif - if (card->card_dev) { - err = device_create_file(card->card_dev, &card_id_attrs); - if (err < 0) - return err; - err = device_create_file(card->card_dev, &card_number_attrs); - if (err < 0) - return err; - } - - return 0; -} - -EXPORT_SYMBOL(snd_card_register); - -#ifdef CONFIG_PROC_FS -static struct snd_info_entry *snd_card_info_entry; - -static void snd_card_info_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - int idx, count; - struct snd_card *card; - - for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { - count++; - snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", - idx, - card->id, - card->driver, - card->shortname); - snd_iprintf(buffer, " %s\n", - card->longname); - } - mutex_unlock(&snd_card_mutex); - } - if (!count) - snd_iprintf(buffer, "--- no soundcards ---\n"); -} - -#ifdef CONFIG_SND_OSSEMUL - -void snd_card_info_read_oss(struct snd_info_buffer *buffer) -{ - int idx, count; - struct snd_card *card; - - for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { - count++; - snd_iprintf(buffer, "%s\n", card->longname); - } - mutex_unlock(&snd_card_mutex); - } - if (!count) { - snd_iprintf(buffer, "--- no soundcards ---\n"); - } -} - -#endif - -#ifdef MODULE -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; - struct snd_card *card; - - for (idx = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) - snd_iprintf(buffer, "%2i %s\n", - idx, card->module->name); - mutex_unlock(&snd_card_mutex); - } -} -#endif - -int __init snd_card_info_init(void) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); - if (! entry) - return -ENOMEM; - entry->c.text.read = snd_card_info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - snd_card_info_entry = entry; - -#ifdef MODULE - entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); - if (entry) { - entry->c.text.read = snd_card_module_info_read; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - else - snd_card_module_info_entry = entry; - } -#endif - - return 0; -} - -int __exit snd_card_info_done(void) -{ - snd_info_free_entry(snd_card_info_entry); -#ifdef MODULE - 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 - * @component: the component id string - * - * 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. - */ - -int snd_component_add(struct snd_card *card, const char *component) -{ - char *ptr; - int len = strlen(component); - - ptr = strstr(card->components, component); - if (ptr != NULL) { - if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */ - return 1; - } - if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) { - snd_BUG(); - return -ENOMEM; - } - if (card->components[0] != '\0') - strcat(card->components, " "); - strcat(card->components, 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 - * @file: file pointer - * - * This function adds the file to the file linked-list of the card. - * 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. - */ -int snd_card_file_add(struct snd_card *card, struct file *file) -{ - struct snd_monitor_file *mfile; - - mfile = kmalloc(sizeof(*mfile), GFP_KERNEL); - if (mfile == NULL) - return -ENOMEM; - mfile->file = file; - 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; - } - list_add(&mfile->list, &card->files_list); - atomic_inc(&card->refcount); - 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 - * @file: file pointer - * - * This function removes the file formerly added to the card via - * snd_card_file_add() 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. - */ -int snd_card_file_remove(struct snd_card *card, struct file *file) -{ - struct snd_monitor_file *mfile, *found = NULL; - - spin_lock(&card->files_lock); - list_for_each_entry(mfile, &card->files_list, list) { - if (mfile->file == file) { - 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; - } - } - spin_unlock(&card->files_lock); - if (!found) { - snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); - return -ENOENT; - } - kfree(found); - snd_card_unref(card); - return 0; -} - -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 - * - * Waits until the power-state is changed. - * - * Note: the power lock must be active before call. - */ -int snd_power_wait(struct snd_card *card, unsigned int power_state) -{ - wait_queue_t wait; - int result = 0; - - /* fastpath */ - if (snd_power_get_state(card) == power_state) - return 0; - init_waitqueue_entry(&wait, current); - add_wait_queue(&card->power_sleep, &wait); - while (1) { - if (card->shutdown) { - result = -ENODEV; - break; - } - if (snd_power_get_state(card) == power_state) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - snd_power_unlock(card); - schedule_timeout(30 * HZ); - snd_power_lock(card); - } - remove_wait_queue(&card->power_sleep, &wait); - return result; -} - -EXPORT_SYMBOL(snd_power_wait); -#endif /* CONFIG_PM */ diff --git a/ANDROID_3.4.5/sound/core/isadma.c b/ANDROID_3.4.5/sound/core/isadma.c deleted file mode 100644 index c0f1208b..00000000 --- a/ANDROID_3.4.5/sound/core/isadma.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ISA DMA support functions - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Defining following add some delay. Maybe this helps for some broken - * ISA DMA controllers. - */ - -#undef HAVE_REALLY_SLOW_DMA_CONTROLLER - -#include <linux/export.h> -#include <sound/core.h> -#include <asm/dma.h> - -/** - * snd_dma_program - program an ISA DMA transfer - * @dma: the dma number - * @addr: the physical address of the buffer - * @size: the DMA transfer size - * @mode: the DMA transfer mode, DMA_MODE_XXX - * - * Programs an ISA DMA transfer for the given buffer. - */ -void snd_dma_program(unsigned long dma, - unsigned long addr, unsigned int size, - unsigned short mode) -{ - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, mode); - set_dma_addr(dma, addr); - set_dma_count(dma, size); - if (!(mode & DMA_MODE_NO_ENABLE)) - enable_dma(dma); - release_dma_lock(flags); -} - -EXPORT_SYMBOL(snd_dma_program); - -/** - * snd_dma_disable - stop the ISA DMA transfer - * @dma: the dma number - * - * Stops the ISA DMA transfer. - */ -void snd_dma_disable(unsigned long dma) -{ - unsigned long flags; - - flags = claim_dma_lock(); - clear_dma_ff(dma); - disable_dma(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 - */ -unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) -{ - unsigned long flags; - 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); -#endif - if (result >= size || result == 0) - return 0; - else - return size - result; -} - -EXPORT_SYMBOL(snd_dma_pointer); diff --git a/ANDROID_3.4.5/sound/core/jack.c b/ANDROID_3.4.5/sound/core/jack.c deleted file mode 100644 index 471e1e3b..00000000 --- a/ANDROID_3.4.5/sound/core/jack.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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_free(struct snd_device *device) -{ - struct snd_jack *jack = device->device_data; - - if (jack->private_free) - jack->private_free(jack); - - /* 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); - - 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. - * - * Returns 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, - }; - - 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 input device 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. - * - * 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. - */ -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/ANDROID_3.4.5/sound/core/memalloc.c b/ANDROID_3.4.5/sound/core/memalloc.c deleted file mode 100644 index 69156923..00000000 --- a/ANDROID_3.4.5/sound/core/memalloc.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Takashi Iwai <tiwai@suse.de> - * - * Generic memory allocators - * - * - * 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/module.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/seq_file.h> -#include <asm/uaccess.h> -#include <linux/dma-mapping.h> -#include <linux/moduleparam.h> -#include <linux/mutex.h> -#include <sound/memalloc.h> - - -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>"); -MODULE_DESCRIPTION("Memory allocator for ALSA system."); -MODULE_LICENSE("GPL"); - - -/* - */ - -static DEFINE_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 - -/* - * - * Generic memory allocators - * - */ - -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; -} - -/** - * snd_malloc_pages - allocate pages with the given size - * @size: the size to allocate in bytes - * @gfp_flags: the allocation conditions, GFP_XXX - * - * Allocates the physically contiguous pages with the given size. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pages(size_t size, gfp_t gfp_flags) -{ - int pg; - void *res; - - 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) - inc_snd_pages(pg); - return res; -} - -/** - * snd_free_pages - release the pages - * @ptr: the buffer pointer to release - * @size: the allocated buffer size - * - * Releases the buffer allocated via snd_malloc_pages(). - */ -void snd_free_pages(void *ptr, size_t size) -{ - int pg; - - if (ptr == NULL) - return; - pg = get_order(size); - dec_snd_pages(pg); - free_pages((unsigned long) ptr, pg); -} - -/* - * - * Bus-specific memory allocators - * - */ - -#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; - - 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) - inc_snd_pages(pg); - - return res; -} - -/* free the coherent DMA pages */ -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, - dma_addr_t dma) -{ - int pg; - - if (ptr == NULL) - return; - pg = get_order(size); - dec_snd_pages(pg); - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); -} -#endif /* CONFIG_HAS_DMA */ - -/* - * - * ALSA generic memory management - * - */ - - -/** - * snd_dma_alloc_pages - allocate the buffer area according to the given type - * @type: the DMA buffer type - * @device: the device pointer - * @size: the buffer size to allocate - * @dmab: buffer allocation record to store the allocated data - * - * Calls the memory-allocator function for the corresponding - * buffer type. - * - * Returns zero if the buffer with the given size is allocated successfully, - * other a negative value at error. - */ -int snd_dma_alloc_pages(int type, struct device *device, size_t size, - struct snd_dma_buffer *dmab) -{ - 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, - (__force gfp_t)(unsigned long)device); - dmab->addr = 0; - break; -#ifdef CONFIG_HAS_DMA - 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); - dmab->area = NULL; - dmab->addr = 0; - return -ENXIO; - } - if (! dmab->area) - return -ENOMEM; - dmab->bytes = size; - return 0; -} - -/** - * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback - * @type: the DMA buffer type - * @device: the device pointer - * @size: the buffer size to allocate - * @dmab: buffer allocation record to store the allocated data - * - * Calls the memory-allocator function for the corresponding - * 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 successfully, - * other a negative value at error. - */ -int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, - struct snd_dma_buffer *dmab) -{ - int err; - - while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { - size_t aligned_size; - if (err != -ENOMEM) - return err; - 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; - return 0; -} - - -/** - * snd_dma_free_pages - release the allocated buffer - * @dmab: the buffer allocation record to release - * - * Releases the allocated buffer via snd_dma_alloc_pages(). - */ -void snd_dma_free_pages(struct snd_dma_buffer *dmab) -{ - switch (dmab->dev.type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - snd_free_pages(dmab->area, dmab->bytes); - break; -#ifdef CONFIG_HAS_DMA - 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; -#endif - 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 snd_mem_list *mem; - - if (WARN_ON(!dmab)) - return 0; - - mutex_lock(&list_mutex); - list_for_each_entry(mem, &mem_list_head, 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(&mem->list); - *dmab = mem->buffer; - if (dmab->dev.dev == NULL) - dmab->dev.dev = dev; - kfree(mem); - mutex_unlock(&list_mutex); - return dmab->bytes; - } - } - mutex_unlock(&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; - - if (WARN_ON(!dmab)) - return -EINVAL; - mem = kmalloc(sizeof(*mem), GFP_KERNEL); - if (! mem) - return -ENOMEM; - mutex_lock(&list_mutex); - mem->buffer = *dmab; - mem->id = id; - list_add_tail(&mem->list, &mem_list_head); - mutex_unlock(&list_mutex); - return 0; -} - -/* - * purge all reserved buffers - */ -static void free_all_reserved_pages(void) -{ - struct list_head *p; - struct snd_mem_list *mem; - - mutex_lock(&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); - } - mutex_unlock(&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(struct seq_file *seq, void *offset) -{ - long pages = snd_allocated_pages >> (PAGE_SHIFT-12); - struct snd_mem_list *mem; - int devno; - static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" }; - - mutex_lock(&list_mutex); - seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n", - pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); - devno = 0; - list_for_each_entry(mem, &mem_list_head, list) { - devno++; - seq_printf(seq, "buffer %d : ID %08x : type %s\n", - devno, mem->id, types[mem->buffer.dev.type]); - seq_printf(seq, " addr = 0x%lx, size = %d bytes\n", - (unsigned long)mem->buffer.addr, - (int)mem->buffer.bytes); - } - mutex_unlock(&list_mutex); - return 0; -} - -static int snd_mem_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, snd_mem_proc_read, NULL); -} - -/* FIXME: for pci only - other bus? */ -#ifdef CONFIG_PCI -#define gettoken(bufp) strsep(bufp, " \t\n") - -static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer, - size_t count, loff_t * ppos) -{ - char buf[128]; - char *token, *p; - - if (count > sizeof(buf) - 1) - return -EINVAL; - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - buf[count] = '\0'; - - p = buf; - token = gettoken(&p); - if (! token || *token == '#') - return 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 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); - pci_dev_put(pci); - return 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 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 count; -} -#endif /* CONFIG_PCI */ - -static const struct file_operations snd_mem_proc_fops = { - .owner = THIS_MODULE, - .open = snd_mem_proc_open, - .read = seq_read, -#ifdef CONFIG_PCI - .write = snd_mem_proc_write, -#endif - .llseek = seq_lseek, - .release = single_release, -}; - -#endif /* CONFIG_PROC_FS */ - -/* - * module entry - */ - -static int __init snd_mem_init(void) -{ -#ifdef CONFIG_PROC_FS - snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL, - &snd_mem_proc_fops); -#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 - */ -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/ANDROID_3.4.5/sound/core/memory.c b/ANDROID_3.4.5/sound/core/memory.c deleted file mode 100644 index 66a278d0..00000000 --- a/ANDROID_3.4.5/sound/core/memory.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * Misc memory accessors - * - * - * 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/export.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <sound/core.h> - -/** - * copy_to_user_fromio - copy data from mmio-space to user-space - * @dst: the destination pointer on user-space - * @src: the source pointer on mmio - * @count: the data size to copy in bytes - * - * Copies the data from mmio-space to user-space. - * - * Returns zero if successful, or non-zero on failure. - */ -int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count) -{ -#if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_to_user(dst, (const void __force*)src, count) ? -EFAULT : 0; -#else - char buf[256]; - while (count) { - size_t c = count; - if (c > sizeof(buf)) - c = sizeof(buf); - memcpy_fromio(buf, (void __iomem *)src, c); - if (copy_to_user(dst, buf, c)) - return -EFAULT; - count -= c; - dst += c; - src += c; - } - return 0; -#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 - * @src: the source pointer on user-space - * @count: the data size to copy in bytes - * - * Copies the data from user-space to mmio-space. - * - * Returns zero if successful, or non-zero on failure. - */ -int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count) -{ -#if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_from_user((void __force *)dst, src, count) ? -EFAULT : 0; -#else - char buf[256]; - while (count) { - size_t c = count; - if (c > sizeof(buf)) - c = sizeof(buf); - if (copy_from_user(buf, src, c)) - return -EFAULT; - memcpy_toio(dst, buf, c); - count -= c; - dst += c; - src += c; - } - return 0; -#endif -} - -EXPORT_SYMBOL(copy_from_user_toio); diff --git a/ANDROID_3.4.5/sound/core/misc.c b/ANDROID_3.4.5/sound/core/misc.c deleted file mode 100644 index 76816792..00000000 --- a/ANDROID_3.4.5/sound/core/misc.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Misc and compatibility things - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#include <linux/export.h> -#include <linux/moduleparam.h> -#include <linux/time.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <sound/core.h> - -#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 */ - -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 -/* 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; -#ifdef CONFIG_SND_VERBOSE_PRINTK - 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; - if (format[0] == '<' && format[2] == '>') { - memcpy(verbose_fmt, format, 3); - vaf.fmt = format + 3; - } else if (level) - memcpy(verbose_fmt, KERN_DEBUG, 3); - printk(verbose_fmt, sanity_file_name(path), line, &vaf); -#else - vprintk(format, args); -#endif - va_end(args); -} -EXPORT_SYMBOL_GPL(__snd_printk); -#endif - -#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) -{ - 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; - } - 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/ANDROID_3.4.5/sound/core/oss/Makefile b/ANDROID_3.4.5/sound/core/oss/Makefile deleted file mode 100644 index 10a79453..00000000 --- a/ANDROID_3.4.5/sound/core/oss/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> -# - -snd-mixer-oss-objs := mixer_oss.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/ANDROID_3.4.5/sound/core/oss/copy.c b/ANDROID_3.4.5/sound/core/oss/copy.c deleted file mode 100644 index 05b58d4f..00000000 --- a/ANDROID_3.4.5/sound/core/oss/copy.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Linear conversion Plug-In - * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> - * - * - * 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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include "pcm_plugin.h" - -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; - - 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++) { - 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); - dst_channels->enabled = 0; - continue; - } - dst_channels->enabled = 1; - snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format); - src_channels++; - dst_channels++; - } - return frames; -} - -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; - struct snd_pcm_plugin *plugin; - int width; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - - 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); - if (snd_BUG_ON(width <= 0)) - return -ENXIO; - - err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format, - 0, &plugin); - if (err < 0) - return err; - plugin->transfer = copy_transfer; - *r_plugin = plugin; - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/oss/io.c b/ANDROID_3.4.5/sound/core/oss/io.c deleted file mode 100644 index 6faa1d71..00000000 --- a/ANDROID_3.4.5/sound/core/oss/io.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * PCM I/O Plug-In Interface - * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include "pcm_plugin.h" - -#define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) -#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1) -#define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) -#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1) - -/* - * Basic io plugin - */ - -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) -{ - 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; - 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; - else - bufs[channel] = NULL; - } - return pcm_writev(plugin->plug, bufs, frames); - } -} - -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) -{ - 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; - 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; - else - bufs[channel] = NULL; - } - return pcm_readv(plugin->plug, bufs, frames); - } - return 0; -} - -static snd_pcm_sframes_t io_src_channels(struct snd_pcm_plugin *plugin, - snd_pcm_uframes_t frames, - struct snd_pcm_plugin_channel **channels) -{ - int err; - unsigned int channel; - struct snd_pcm_plugin_channel *v; - err = snd_pcm_plugin_client_channels(plugin, frames, &v); - if (err < 0) - return err; - *channels = v; - if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { - for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v) - v->wanted = 1; - } - return frames; -} - -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; - struct snd_pcm_plugin_format format; - struct snd_pcm_plugin *plugin; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - if (snd_BUG_ON(!plug || !params)) - return -ENXIO; - format.format = params_format(params); - format.rate = params_rate(params); - format.channels = params_channels(params); - err = snd_pcm_plugin_build(plug, "I/O io", - &format, &format, - sizeof(void *) * format.channels, - &plugin); - if (err < 0) - return err; - plugin->access = params_access(params); - if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { - plugin->transfer = io_playback_transfer; - if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) - plugin->client_channels = io_src_channels; - } else { - plugin->transfer = io_capture_transfer; - } - - *r_plugin = plugin; - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/oss/linear.c b/ANDROID_3.4.5/sound/core/oss/linear.c deleted file mode 100644 index 2045697f..00000000 --- a/ANDROID_3.4.5/sound/core/oss/linear.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Linear conversion Plug-In - * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>, - * Abramo Bagnara <abramo@alsa-project.org> - * - * - * 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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include "pcm_plugin.h" - -/* - * Basic linear conversion plugin - */ - -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 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) -{ - struct linear_priv *data = (struct linear_priv *)plugin->extra_data; - int channel; - int nchannels = plugin->src_format.channels; - for (channel = 0; channel < nchannels; ++channel) { - char *src; - char *dst; - int src_step, dst_step; - snd_pcm_uframes_t frames1; - if (!src_channels[channel].enabled) { - if (dst_channels[channel].wanted) - snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); - dst_channels[channel].enabled = 0; - continue; - } - dst_channels[channel].enabled = 1; - src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; - dst = 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; - frames1 = frames; - while (frames1-- > 0) { - do_convert(data, dst, src); - src += src_step; - dst += dst_step; - } - } -} - -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) -{ - 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++) { - 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 - convert(plugin, src_channels, dst_channels, frames); - return frames; -} - -static void init_data(struct linear_priv *data, - snd_pcm_format_t src_format, snd_pcm_format_t dst_format) -{ - int src_le, dst_le, src_bytes, dst_bytes; - - 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; - - 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(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_priv *data; - struct snd_pcm_plugin *plugin; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - - 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(struct linear_priv), &plugin); - if (err < 0) - return err; - 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/ANDROID_3.4.5/sound/core/oss/mixer_oss.c b/ANDROID_3.4.5/sound/core/oss/mixer_oss.c deleted file mode 100644 index c3537688..00000000 --- a/ANDROID_3.4.5/sound/core/oss/mixer_oss.c +++ /dev/null @@ -1,1422 +0,0 @@ -/* - * OSS emulation layer for the mixer interface - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#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> -#include <sound/info.h> -#include <sound/mixer_oss.h> -#include <linux/soundcard.h> - -#define OSS_ALSAEMULVER _SIOR ('M', 249, int) - -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) -{ - struct snd_card *card; - struct snd_mixer_oss_file *fmixer; - int err; - - 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) { - snd_card_unref(card); - return -ENODEV; - } - err = snd_card_file_add(card, file); - 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; - fmixer->mixer = card->mixer_oss; - file->private_data = fmixer; - 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) -{ - struct snd_mixer_oss_file *fmixer; - - if (file->private_data) { - fmixer = file->private_data; - module_put(fmixer->card->module); - snd_card_file_remove(fmixer->card, file); - kfree(fmixer); - } - return 0; -} - -static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer, - mixer_info __user *_info) -{ - struct snd_card *card = fmixer->card; - struct snd_mixer_oss *mixer = fmixer->mixer; - struct mixer_info info; - - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); - strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); - info.modify_counter = card->mixer_oss_change_count; - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer, - _old_mixer_info __user *_info) -{ - struct snd_card *card = fmixer->card; - struct snd_mixer_oss *mixer = fmixer->mixer; - _old_mixer_info info; - - memset(&info, 0, sizeof(info)); - strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); - strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer) -{ - struct snd_mixer_oss *mixer = fmixer->mixer; - int result = 0; - - if (mixer == NULL) - return -EIO; - if (mixer->get_recsrc && mixer->put_recsrc) - result |= SOUND_CAP_EXCL_INPUT; - return result; -} - -static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer) -{ - struct snd_mixer_oss *mixer = fmixer->mixer; - struct snd_mixer_oss_slot *pslot; - int result = 0, chn; - - if (mixer == NULL) - return -EIO; - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->put_volume || pslot->put_recsrc) - result |= 1 << chn; - } - return result; -} - -static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer) -{ - struct snd_mixer_oss *mixer = fmixer->mixer; - struct snd_mixer_oss_slot *pslot; - int result = 0, chn; - - if (mixer == NULL) - return -EIO; - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->put_volume && pslot->stereo) - result |= 1 << chn; - } - return result; -} - -static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer) -{ - struct snd_mixer_oss *mixer = fmixer->mixer; - int result = 0; - - if (mixer == NULL) - return -EIO; - if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ - result = mixer->mask_recsrc; - } else { - struct snd_mixer_oss_slot *pslot; - int chn; - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->put_recsrc) - result |= 1 << chn; - } - } - return result; -} - -static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) -{ - 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; - unsigned int index; - if ((err = mixer->get_recsrc(fmixer, &index)) < 0) - return err; - result = 1 << index; - } else { - struct snd_mixer_oss_slot *pslot; - int chn; - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->get_recsrc) { - int active = 0; - pslot->get_recsrc(fmixer, pslot, &active); - if (active) - result |= 1 << chn; - } - } - } - return mixer->oss_recsrc = result; -} - -static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc) -{ - 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) - return -EIO; - if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */ - if (recsrc & ~mixer->oss_recsrc) - recsrc &= ~mixer->oss_recsrc; - mixer->put_recsrc(fmixer, ffz(~recsrc)); - mixer->get_recsrc(fmixer, &index); - result = 1 << index; - } - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->put_recsrc) { - active = (recsrc & (1 << chn)) ? 1 : 0; - pslot->put_recsrc(fmixer, pslot, active); - } - } - if (! result) { - for (chn = 0; chn < 31; chn++) { - pslot = &mixer->slots[chn]; - if (pslot->get_recsrc) { - active = 0; - pslot->get_recsrc(fmixer, pslot, &active); - if (active) - result |= 1 << chn; - } - } - } - return result; -} - -static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot) -{ - struct snd_mixer_oss *mixer = fmixer->mixer; - struct snd_mixer_oss_slot *pslot; - int result = 0, left, right; - - if (mixer == NULL || slot > 30) - return -EIO; - pslot = &mixer->slots[slot]; - left = pslot->volume[0]; - right = pslot->volume[1]; - if (pslot->get_volume) - result = pslot->get_volume(fmixer, pslot, &left, &right); - if (!pslot->stereo) - right = left; - 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; - result = (left & 0xff) | ((right & 0xff) << 8); - } - return result; -} - -static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer, - int slot, int volume) -{ - 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) - return -EIO; - pslot = &mixer->slots[slot]; - if (left > 100) - left = 100; - if (right > 100) - right = 100; - if (!pslot->stereo) - right = left; - if (pslot->put_volume) - result = pslot->put_volume(fmixer, pslot, left, right); - if (result < 0) - return result; - pslot->volume[0] = left; - pslot->volume[1] = right; - return (left & 0xff) | ((right & 0xff) << 8); -} - -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; - - if (snd_BUG_ON(!fmixer)) - return -ENXIO; - if (((cmd >> 8) & 0xff) == 'M') { - switch (cmd) { - case SOUND_MIXER_INFO: - return snd_mixer_oss_info(fmixer, argp); - case SOUND_OLD_MIXER_INFO: - return snd_mixer_oss_info_obsolete(fmixer, argp); - case SOUND_MIXER_WRITE_RECSRC: - if (get_user(tmp, p)) - return -EFAULT; - tmp = snd_mixer_oss_set_recsrc(fmixer, tmp); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - case OSS_GETVERSION: - return put_user(SNDRV_OSS_VERSION, p); - case OSS_ALSAEMULVER: - return put_user(1, p); - case SOUND_MIXER_READ_DEVMASK: - tmp = snd_mixer_oss_devmask(fmixer); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - case SOUND_MIXER_READ_STEREODEVS: - tmp = snd_mixer_oss_stereodevs(fmixer); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - case SOUND_MIXER_READ_RECMASK: - tmp = snd_mixer_oss_recmask(fmixer); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - case SOUND_MIXER_READ_CAPS: - tmp = snd_mixer_oss_caps(fmixer); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - case SOUND_MIXER_READ_RECSRC: - tmp = snd_mixer_oss_get_recsrc(fmixer); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - } - } - if (cmd & SIOC_IN) { - if (get_user(tmp, p)) - return -EFAULT; - tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - } else if (cmd & SIOC_OUT) { - tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff); - if (tmp < 0) - return tmp; - return put_user(tmp, p); - } - return -ENXIO; -} - -static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); -} - -int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) -{ - struct snd_mixer_oss_file fmixer; - - if (snd_BUG_ON(!card)) - return -ENXIO; - if (card->mixer_oss == NULL) - return -ENXIO; - memset(&fmixer, 0, sizeof(fmixer)); - fmixer.card = card; - fmixer.mixer = card->mixer_oss; - return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); -} - -#ifdef CONFIG_COMPAT -/* all compatible */ -#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl -#else -#define snd_mixer_oss_ioctl_compat NULL -#endif - -/* - * REGISTRATION PART - */ - -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, -}; - -/* - * utilities - */ - -static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax) -{ - long orange = omax - omin, nrange = nmax - nmin; - - if (orange == 0) - return 0; - return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin; -} - -/* convert from alsa native to oss values (0-100) */ -static long snd_mixer_oss_conv1(long val, long min, long max, int *old) -{ - if (val == snd_mixer_oss_conv(*old, 0, 100, min, max)) - return *old; - return snd_mixer_oss_conv(val, min, max, 0, 100); -} - -/* convert from oss to alsa native values */ -static long snd_mixer_oss_conv2(long val, long min, long max) -{ - return snd_mixer_oss_conv(val, 0, 100, min, max); -} - -#if 0 -static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot) -{ - struct snd_mixer_oss *mixer = card->mixer_oss; - if (mixer) - mixer->mask_recsrc |= 1 << slot; -} - -static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot) -{ - struct snd_mixer_oss *mixer = card->mixer_oss; - if (mixer && (mixer->mask_recsrc & (1 << slot))) - return 1; - return 0; -} -#endif - -#define SNDRV_MIXER_OSS_SIGNATURE 0x65999250 - -#define SNDRV_MIXER_OSS_ITEM_GLOBAL 0 -#define SNDRV_MIXER_OSS_ITEM_GSWITCH 1 -#define SNDRV_MIXER_OSS_ITEM_GROUTE 2 -#define SNDRV_MIXER_OSS_ITEM_GVOLUME 3 -#define SNDRV_MIXER_OSS_ITEM_PSWITCH 4 -#define SNDRV_MIXER_OSS_ITEM_PROUTE 5 -#define SNDRV_MIXER_OSS_ITEM_PVOLUME 6 -#define SNDRV_MIXER_OSS_ITEM_CSWITCH 7 -#define SNDRV_MIXER_OSS_ITEM_CROUTE 8 -#define SNDRV_MIXER_OSS_ITEM_CVOLUME 9 -#define SNDRV_MIXER_OSS_ITEM_CAPTURE 10 - -#define SNDRV_MIXER_OSS_ITEM_COUNT 11 - -#define SNDRV_MIXER_OSS_PRESENT_GLOBAL (1<<0) -#define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1) -#define SNDRV_MIXER_OSS_PRESENT_GROUTE (1<<2) -#define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3) -#define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4) -#define SNDRV_MIXER_OSS_PRESENT_PROUTE (1<<5) -#define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6) -#define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7) -#define SNDRV_MIXER_OSS_PRESENT_CROUTE (1<<8) -#define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9) -#define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10) - -struct slot { - unsigned int signature; - unsigned int present; - unsigned int channels; - unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; - unsigned int capture_item; - struct snd_mixer_oss_assign_table *assigned; - unsigned int allocated: 1; -}; - -#define ID_UNKNOWN ((unsigned int)-1) - -static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index) -{ - struct snd_card *card = mixer->card; - struct snd_ctl_elem_id id; - - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - 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(struct snd_mixer_oss_file *fmixer, - struct snd_mixer_oss_slot *pslot, - unsigned int numid, - int *left, int *right) -{ - 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; - down_read(&card->controls_rwsem); - 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; - 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]); - __unalloc: - up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); -} - -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) -{ - 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; - down_read(&card->controls_rwsem); - 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; - 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) - *right = 0; - } - if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) - *right = 0; - __unalloc: - up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); -} - -static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, - struct snd_mixer_oss_slot *pslot, - int *left, int *right) -{ - struct slot *slot = pslot->private_data; - - *left = *right = 100; - if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); - } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); - } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); - } - if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); - } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { - snd_mixer_oss_get_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_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); - } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); - } - return 0; -} - -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) -{ - 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(&card->controls_rwsem); - return; - } - uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (uinfo == NULL || uctl == NULL) - 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); - if ((res = kctl->put(kctl, uctl)) < 0) - goto __unalloc; - if (res > 0) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - __unalloc: - up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); -} - -static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, - struct snd_mixer_oss_slot *pslot, - unsigned int numid, - int left, int right, - int route) -{ - 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(&card->controls_rwsem); - return; - } - uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (uinfo == NULL || uctl == NULL) - 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; - if (route) { - uctl->value.integer.value[1] = - uctl->value.integer.value[2] = 0; - } - } else { - uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; - } - if ((res = kctl->put(kctl, uctl)) < 0) - goto __unalloc; - if (res > 0) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - __unalloc: - up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); -} - -static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, - struct snd_mixer_oss_slot *pslot, - int left, int right) -{ - 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) { - snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); - } - 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); - } - } - return 0; -} - -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 = pslot->private_data; - int left, right; - - left = right = 1; - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); - *active = (left || right) ? 1 : 0; - return 0; -} - -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 = pslot->private_data; - int left, right; - - left = right = 1; - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); - *active = (left || right) ? 1 : 0; - return 0; -} - -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 = 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(struct snd_mixer_oss_file *fmixer, - struct snd_mixer_oss_slot *pslot, - int active) -{ - 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(struct snd_mixer_oss_file *fmixer, unsigned int *active_index) -{ - 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; - 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 __free_only; - } - down_read(&card->controls_rwsem); - kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - if (! kctl) { - err = -ENOENT; - goto __unlock; - } - if ((err = kctl->info(kctl, uinfo)) < 0) - goto __unlock; - if ((err = kctl->get(kctl, uctl)) < 0) - goto __unlock; - for (idx = 0; idx < 32; idx++) { - if (!(mixer->mask_recsrc & (1 << idx))) - continue; - pslot = &mixer->slots[idx]; - slot = pslot->private_data; - if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) - continue; - if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) - continue; - if (slot->capture_item == uctl->value.enumerated.item[0]) { - *active_index = idx; - break; - } - } - err = 0; - __unlock: - up_read(&card->controls_rwsem); - __free_only: - kfree(uctl); - kfree(uinfo); - return err; -} - -static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index) -{ - 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; - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; - int err; - unsigned int idx; - - uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (uinfo == NULL || uctl == NULL) { - err = -ENOMEM; - goto __free_only; - } - down_read(&card->controls_rwsem); - kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - if (! kctl) { - err = -ENOENT; - goto __unlock; - } - if ((err = kctl->info(kctl, uinfo)) < 0) - goto __unlock; - for (idx = 0; idx < 32; idx++) { - if (!(mixer->mask_recsrc & (1 << idx))) - continue; - pslot = &mixer->slots[idx]; - slot = pslot->private_data; - if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) - continue; - if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) - continue; - if (idx == active_index) - break; - slot = NULL; - } - if (! slot) - goto __unlock; - for (idx = 0; idx < uinfo->count; idx++) - uctl->value.enumerated.item[idx] = slot->capture_item; - err = kctl->put(kctl, uctl); - if (err > 0) - snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - err = 0; - __unlock: - up_read(&card->controls_rwsem); - __free_only: - kfree(uctl); - kfree(uinfo); - return err; -} - -struct snd_mixer_oss_assign_table { - int oss_id; - const char *name; - int index; -}; - -static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item) -{ - struct snd_ctl_elem_info *info; - struct snd_kcontrol *kcontrol; - struct snd_card *card = mixer->card; - int err; - - down_read(&card->controls_rwsem); - kcontrol = snd_mixer_oss_test_id(mixer, name, index); - if (kcontrol == NULL) { - up_read(&card->controls_rwsem); - return 0; - } - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) { - up_read(&card->controls_rwsem); - return -ENOMEM; - } - if ((err = kcontrol->info(kcontrol, info)) < 0) { - up_read(&card->controls_rwsem); - kfree(info); - return err; - } - slot->numid[item] = kcontrol->id.numid; - up_read(&card->controls_rwsem); - if (info->count > slot->channels) - slot->channels = info->count; - slot->present |= 1 << item; - kfree(info); - return 0; -} - -static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) -{ - struct slot *p = chn->private_data; - if (p) { - if (p->allocated && p->assigned) { - kfree(p->assigned->name); - kfree(p->assigned); - } - kfree(p); - } -} - -static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot) -{ - int idx = rslot->number; /* remember this */ - if (rslot->private_free) - rslot->private_free(rslot); - memset(rslot, 0, sizeof(*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(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) -{ - struct slot slot; - struct slot *pslot; - struct snd_kcontrol *kctl; - struct snd_mixer_oss_slot *rslot; - char str[64]; - - /* check if already assigned */ - if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) - return 0; - - memset(&slot, 0, sizeof(slot)); - memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ - if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) - return 0; - down_read(&mixer->card->controls_rwsem); - if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { - struct snd_ctl_elem_info *uinfo; - - uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); - if (! uinfo) { - up_read(&mixer->card->controls_rwsem); - return -ENOMEM; - } - - if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); - return 0; - } - strcpy(str, ptr->name); - if (!strcmp(str, "Master")) - strcpy(str, "Mix"); - if (!strcmp(str, "Master Mono")) - strcpy(str, "Mix Mono"); - slot.capture_item = 0; - if (!strcmp(uinfo->value.enumerated.name, str)) { - slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; - } else { - for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { - uinfo->value.enumerated.item = slot.capture_item; - if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); - return 0; - } - if (!strcmp(uinfo->value.enumerated.name, str)) { - slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; - break; - } - } - } - kfree(uinfo); - } - up_read(&mixer->card->controls_rwsem); - if (slot.present != 0) { - pslot = kmalloc(sizeof(slot), GFP_KERNEL); - if (! pslot) - return -ENOMEM; - *pslot = slot; - pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; - pslot->assigned = ptr; - pslot->allocated = ptr_allocated; - rslot = &mixer->slots[ptr->oss_id]; - mixer_slot_clear(rslot); - rslot->stereo = slot.channels > 1 ? 1 : 0; - rslot->get_volume = snd_mixer_oss_get_volume1; - rslot->put_volume = snd_mixer_oss_put_volume1; - /* note: ES18xx have both Capture Source and XX Capture Volume !!! */ - if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { - rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; - rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; - } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { - rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; - rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; - } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { - mixer->mask_recsrc |= 1 << ptr->oss_id; - } - rslot->private_data = pslot; - rslot->private_free = snd_mixer_oss_slot_free; - return 1; - } - return 0; -} - -#ifdef CONFIG_PROC_FS -/* - */ -#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name -static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { - MIXER_VOL(VOLUME), - MIXER_VOL(BASS), - MIXER_VOL(TREBLE), - MIXER_VOL(SYNTH), - MIXER_VOL(PCM), - MIXER_VOL(SPEAKER), - MIXER_VOL(LINE), - MIXER_VOL(MIC), - MIXER_VOL(CD), - MIXER_VOL(IMIX), - MIXER_VOL(ALTPCM), - MIXER_VOL(RECLEV), - MIXER_VOL(IGAIN), - MIXER_VOL(OGAIN), - MIXER_VOL(LINE1), - MIXER_VOL(LINE2), - MIXER_VOL(LINE3), - MIXER_VOL(DIGITAL1), - MIXER_VOL(DIGITAL2), - MIXER_VOL(DIGITAL3), - MIXER_VOL(PHONEIN), - MIXER_VOL(PHONEOUT), - MIXER_VOL(VIDEO), - MIXER_VOL(RADIO), - MIXER_VOL(MONITOR), -}; - -/* - * /proc interface - */ - -static void snd_mixer_oss_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_mixer_oss *mixer = entry->private_data; - int i; - - mutex_lock(&mixer->reg_mutex); - for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { - struct slot *p; - - if (! oss_mixer_names[i]) - continue; - p = (struct slot *)mixer->slots[i].private_data; - snd_iprintf(buffer, "%s ", oss_mixer_names[i]); - if (p && p->assigned) - snd_iprintf(buffer, "\"%s\" %d\n", - p->assigned->name, - p->assigned->index); - else - snd_iprintf(buffer, "\"\" 0\n"); - } - mutex_unlock(&mixer->reg_mutex); -} - -static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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; - - while (!snd_info_get_line(buffer, line, sizeof(line))) { - cptr = snd_info_get_str(str, line, sizeof(str)); - for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) - 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); - continue; - } - cptr = snd_info_get_str(str, cptr, sizeof(str)); - if (! *str) { - /* remove the entry */ - mutex_lock(&mixer->reg_mutex); - mixer_slot_clear(&mixer->slots[ch]); - mutex_unlock(&mixer->reg_mutex); - 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); - continue; - } - mutex_lock(&mixer->reg_mutex); - slot = (struct slot *)mixer->slots[ch].private_data; - if (slot && slot->assigned && - slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) - /* not changed */ - goto __unlock; - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); - if (! tbl) { - snd_printk(KERN_ERR "mixer_oss: no memory\n"); - goto __unlock; - } - tbl->oss_id = ch; - tbl->name = kstrdup(str, GFP_KERNEL); - if (! tbl->name) { - kfree(tbl); - goto __unlock; - } - tbl->index = idx; - if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { - kfree(tbl->name); - kfree(tbl); - } - __unlock: - mutex_unlock(&mixer->reg_mutex); - } -} - -static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_card_entry(mixer->card, "oss_mixer", - mixer->card->proc_root); - if (! entry) - return; - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read = snd_mixer_oss_proc_read; - entry->c.text.write = snd_mixer_oss_proc_write; - entry->private_data = mixer; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - mixer->proc_entry = entry; -} - -static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) -{ - snd_info_free_entry(mixer->proc_entry); - mixer->proc_entry = NULL; -} -#else /* !CONFIG_PROC_FS */ -#define snd_mixer_oss_proc_init(mix) -#define snd_mixer_oss_proc_done(mix) -#endif /* CONFIG_PROC_FS */ - -static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) -{ - static struct snd_mixer_oss_assign_table table[] = { - { SOUND_MIXER_VOLUME, "Master", 0 }, - { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ - { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, - { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, - { SOUND_MIXER_SYNTH, "Synth", 0 }, - { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ - { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ - { SOUND_MIXER_PCM, "PCM", 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 }, - { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, - { SOUND_MIXER_ALTPCM, "PCM", 1 }, - { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */ - { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ - { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, - { SOUND_MIXER_IGAIN, "Capture", 0 }, - { SOUND_MIXER_OGAIN, "Playback", 0 }, - { SOUND_MIXER_LINE1, "Aux", 0 }, - { SOUND_MIXER_LINE2, "Aux", 1 }, - { SOUND_MIXER_LINE3, "Aux", 2 }, - { SOUND_MIXER_DIGITAL1, "Digital", 0 }, - { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */ - { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */ - { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */ - { SOUND_MIXER_DIGITAL2, "Digital", 1 }, - { 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 }, - { SOUND_MIXER_MONITOR, "Monitor", 0 } - }; - unsigned int idx; - - for (idx = 0; idx < ARRAY_SIZE(table); idx++) - snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); - if (mixer->mask_recsrc) { - mixer->get_recsrc = snd_mixer_oss_get_recsrc2; - mixer->put_recsrc = snd_mixer_oss_put_recsrc2; - } -} - -/* - * - */ - -static int snd_mixer_oss_free1(void *private) -{ - struct snd_mixer_oss *mixer = private; - struct snd_card *card; - int idx; - - if (!mixer) - return 0; - card = mixer->card; - if (snd_BUG_ON(mixer != card->mixer_oss)) - return -ENXIO; - card->mixer_oss = NULL; - for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { - struct snd_mixer_oss_slot *chn = &mixer->slots[idx]; - if (chn->private_free) - chn->private_free(chn); - } - kfree(mixer); - return 0; -} - -static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) -{ - struct snd_mixer_oss *mixer; - - if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { - char name[128]; - int idx, err; - - mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); - if (mixer == NULL) - return -ENOMEM; - mutex_init(&mixer->reg_mutex); - sprintf(name, "mixer%i%i", card->number, 0); - if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, - card, 0, - &snd_mixer_oss_f_ops, card, - name)) < 0) { - snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n", - card->number, 0); - kfree(mixer); - return err; - } - mixer->oss_dev_alloc = 1; - mixer->card = card; - if (*card->mixername) - strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); - else - strlcpy(mixer->name, name, sizeof(mixer->name)); -#ifdef SNDRV_OSS_INFO_DEV_MIXERS - snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, - card->number, - mixer->name); -#endif - for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) - mixer->slots[idx].number = idx; - card->mixer_oss = mixer; - snd_mixer_oss_build(mixer); - snd_mixer_oss_proc_init(mixer); - } 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); -#endif - 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); - } - return 0; -} - -static int __init alsa_mixer_oss_init(void) -{ - int idx; - - snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; - for (idx = 0; idx < SNDRV_CARDS; idx++) { - if (snd_cards[idx]) - snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); - } - return 0; -} - -static void __exit alsa_mixer_oss_exit(void) -{ - int idx; - - snd_mixer_oss_notify_callback = NULL; - for (idx = 0; idx < SNDRV_CARDS; idx++) { - if (snd_cards[idx]) - snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); - } -} - -module_init(alsa_mixer_oss_init) -module_exit(alsa_mixer_oss_exit) - -EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); diff --git a/ANDROID_3.4.5/sound/core/oss/mulaw.c b/ANDROID_3.4.5/sound/core/oss/mulaw.c deleted file mode 100644 index 7915564b..00000000 --- a/ANDROID_3.4.5/sound/core/oss/mulaw.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Mu-Law conversion Plug-In Interface - * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> - * Uros Bizjak <uros@kss-loka.si> - * - * Based on reference implementation by Sun Microsystems, Inc. - * - * 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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include "pcm_plugin.h" - -#define SIGN_BIT (0x80) /* Sign bit for a u-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of u-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ - -static inline int val_seg(int val) -{ - int r = 0; - val >>= 7; - if (val & 0xf0) { - val >>= 4; - r += 4; - } - if (val & 0x0c) { - val >>= 2; - r += 2; - } - if (val & 0x02) - r += 1; - return r; -} - -#define BIAS (0x84) /* Bias for linear code. */ - -/* - * linear2ulaw() - Convert a linear PCM value to u-law - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -static unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ -{ - int mask; - int seg; - unsigned char uval; - - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = BIAS - pcm_val; - mask = 0x7F; - } else { - pcm_val += BIAS; - mask = 0xFF; - } - if (pcm_val > 0x7FFF) - pcm_val = 0x7FFF; - - /* Convert the scaled magnitude to segment number. */ - seg = val_seg(pcm_val); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); - return uval ^ mask; -} - -/* - * ulaw2linear() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -static int ulaw2linear(unsigned char u_val) -{ - int t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); -} - -/* - * Basic Mu-Law plugin - */ - -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); - -struct mulaw_priv { - mulaw_f func; - 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 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) -{ - struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - int channel; - int nchannels = plugin->src_format.channels; - for (channel = 0; channel < nchannels; ++channel) { - char *src; - char *dst; - int src_step, dst_step; - snd_pcm_uframes_t frames1; - if (!src_channels[channel].enabled) { - if (dst_channels[channel].wanted) - snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); - dst_channels[channel].enabled = 0; - continue; - } - dst_channels[channel].enabled = 1; - src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; - dst = 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; - frames1 = frames; - while (frames1-- > 0) { - signed short sample = ulaw2linear(*src); - cvt_s16_to_native(data, dst, sample); - src += src_step; - dst += dst_step; - } - } -} - -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) -{ - struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - int channel; - int nchannels = plugin->src_format.channels; - for (channel = 0; channel < nchannels; ++channel) { - char *src; - char *dst; - int src_step, dst_step; - snd_pcm_uframes_t frames1; - if (!src_channels[channel].enabled) { - if (dst_channels[channel].wanted) - snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format); - dst_channels[channel].enabled = 0; - continue; - } - dst_channels[channel].enabled = 1; - src = src_channels[channel].area.addr + src_channels[channel].area.first / 8; - dst = 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; - frames1 = frames; - while (frames1-- > 0) { - signed short sample = cvt_native_to_s16(data, src); - *dst = linear2ulaw(sample); - src += src_step; - dst += dst_step; - } - } -} - -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) -{ - struct mulaw_priv *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++) { - 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 = (struct mulaw_priv *)plugin->extra_data; - data->func(plugin, src_channels, dst_channels, frames); - return frames; -} - -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; - struct mulaw_priv *data; - struct snd_pcm_plugin *plugin; - struct snd_pcm_plugin_format *format; - mulaw_f func; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - - 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; - func = mulaw_encode; - } - else if (src_format->format == SNDRV_PCM_FORMAT_MU_LAW) { - format = dst_format; - func = mulaw_decode; - } - else { - snd_BUG(); - return -EINVAL; - } - 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(struct mulaw_priv), &plugin); - if (err < 0) - return err; - data = (struct mulaw_priv *)plugin->extra_data; - data->func = func; - init_data(data, format->format); - plugin->transfer = mulaw_transfer; - *r_plugin = plugin; - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/oss/pcm_oss.c b/ANDROID_3.4.5/sound/core/oss/pcm_oss.c deleted file mode 100644 index 4c1cc517..00000000 --- a/ANDROID_3.4.5/sound/core/oss/pcm_oss.c +++ /dev/null @@ -1,3117 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer / OSS compatible - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#if 0 -#define PLUGIN_DEBUG -#endif -#if 0 -#define OSS_DEBUG -#endif - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/vmalloc.h> -#include <linux/module.h> -#include <linux/math64.h> -#include <linux/string.h> -#include <sound/core.h> -#include <sound/minors.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include "pcm_plugin.h" -#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]; -static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; -static bool nonblock_open = 1; - -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); -MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device."); -module_param_array(adsp_map, int, NULL, 0444); -MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device."); -module_param(nonblock_open, bool, 0644); -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); - -static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file); -static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file); -static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); - -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - -/* - * helper functions to process hw_params - */ -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) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_plugin *plugin, *next; - - plugin = runtime->oss.plugin_first; - while (plugin) { - next = plugin->next; - snd_pcm_plugin_free(plugin); - plugin = next; - } - runtime->oss.plugin_first = runtime->oss.plugin_last = NULL; - return 0; -} - -static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin) -{ - struct snd_pcm_runtime *runtime = plugin->plug->runtime; - plugin->next = runtime->oss.plugin_first; - plugin->prev = NULL; - if (runtime->oss.plugin_first) { - runtime->oss.plugin_first->prev = plugin; - runtime->oss.plugin_first = plugin; - } else { - runtime->oss.plugin_last = - runtime->oss.plugin_first = plugin; - } - return 0; -} - -int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin) -{ - struct snd_pcm_runtime *runtime = plugin->plug->runtime; - plugin->next = NULL; - plugin->prev = runtime->oss.plugin_last; - if (runtime->oss.plugin_last) { - runtime->oss.plugin_last->next = plugin; - runtime->oss.plugin_last = plugin; - } else { - runtime->oss.plugin_last = - runtime->oss.plugin_first = plugin; - } - return 0; -} -#endif /* CONFIG_SND_PCM_OSS_PLUGINS */ - -static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames) -{ - 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) - return bytes; -#if BITS_PER_LONG >= 64 - return runtime->oss.buffer_bytes * bytes / buffer_size; -#else - { - u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; - return div_u64(bsize, buffer_size); - } -#endif -} - -static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) -{ - 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 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; - case AFMT_A_LAW: return SNDRV_PCM_FORMAT_A_LAW; - case AFMT_IMA_ADPCM: return SNDRV_PCM_FORMAT_IMA_ADPCM; - case AFMT_U8: return SNDRV_PCM_FORMAT_U8; - case AFMT_S16_LE: return SNDRV_PCM_FORMAT_S16_LE; - case AFMT_S16_BE: return SNDRV_PCM_FORMAT_S16_BE; - case AFMT_S8: return SNDRV_PCM_FORMAT_S8; - 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(snd_pcm_format_t format) -{ - switch (format) { - case SNDRV_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW; - case SNDRV_PCM_FORMAT_A_LAW: return AFMT_A_LAW; - case SNDRV_PCM_FORMAT_IMA_ADPCM: return AFMT_IMA_ADPCM; - case SNDRV_PCM_FORMAT_U8: return AFMT_U8; - case SNDRV_PCM_FORMAT_S16_LE: return AFMT_S16_LE; - case SNDRV_PCM_FORMAT_S16_BE: return AFMT_S16_BE; - case SNDRV_PCM_FORMAT_S8: return AFMT_S8; - 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(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; - struct snd_pcm_runtime *runtime = substream->runtime; - size_t oss_frame_size; - - oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) * - params_channels(oss_params) / 8; - - oss_buffer_size = snd_pcm_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(&substream->mmap_count)) { - if (oss_buffer_size > runtime->oss.mmap_bytes) - oss_buffer_size = runtime->oss.mmap_bytes; - } - - 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) - oss_period_size = oss_buffer_size / 2; - } else { - int sd; - size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8; - - oss_period_size = oss_buffer_size; - do { - oss_period_size /= 2; - } while (oss_period_size > bytes_per_sec); - if (runtime->oss.subdivision == 0) { - sd = 4; - if (oss_period_size / sd > 4096) - sd *= 2; - if (oss_period_size / sd < 4096) - sd = 1; - } else - sd = runtime->oss.subdivision; - oss_period_size /= sd; - if (oss_period_size < 16) - oss_period_size = 16; - } - - min_period_size = snd_pcm_plug_client_size(substream, - snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); - min_period_size *= oss_frame_size; - min_period_size = 1 << (ld2(min_period_size - 1) + 1); - if (oss_period_size < min_period_size) - oss_period_size = min_period_size; - - max_period_size = snd_pcm_plug_client_size(substream, - snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL)); - max_period_size *= oss_frame_size; - max_period_size = 1 << ld2(max_period_size); - if (oss_period_size > max_period_size) - oss_period_size = max_period_size; - - oss_periods = oss_buffer_size / oss_period_size; - - 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) - s = runtime->oss.maxfrags; - if (oss_periods > s) - oss_periods = s; - - s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL); - if (s < 2) - s = 2; - if (oss_periods < s) - oss_periods = s; - - while (oss_period_size * oss_periods > oss_buffer_size) - oss_period_size /= 2; - - 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(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, unsigned int best_rate) -{ - struct snd_interval *it; - struct snd_pcm_hw_params *save; - unsigned int rate, prev; - - save = kmalloc(sizeof(*save), GFP_KERNEL); - if (save == NULL) - return -ENOMEM; - *save = *params; - it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE); - - /* try multiples of the best rate */ - rate = best_rate; - for (;;) { - if (it->max < rate || (it->max == rate && it->openmax)) - break; - if (it->min < rate || (it->min == rate && !it->openmin)) { - int ret; - ret = snd_pcm_hw_param_set(substream, params, - SNDRV_PCM_HW_PARAM_RATE, - rate, 0); - if (ret == (int)rate) { - kfree(save); - return rate; - } - *params = *save; - } - prev = rate; - rate += best_rate; - if (rate <= prev) - break; - } - - /* not found, use the nearest rate */ - kfree(save); - return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); -} - -static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) -{ - 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; - 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"); - err = -ENOMEM; - goto failure; - } - - if (atomic_read(&substream->mmap_count)) - direct = 1; - 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(&substream->mmap_count)) - snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); - else { - snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED); - if (!direct) - 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"); - err = -EINVAL; - goto failure; - } - choose_rate(substream, sparams, runtime->oss.rate); - snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL); - - format = snd_pcm_oss_format_from(runtime->oss.format); - - sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT); - if (direct) - sformat = format; - else - sformat = snd_pcm_plug_slave_format(format, &sformat_mask); - - if ((__force int)sformat < 0 || - !snd_mask_test(&sformat_mask, (__force int)sformat)) { - for (sformat = (__force snd_pcm_format_t)0; - (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; - sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { - if (snd_mask_test(&sformat_mask, (__force int)sformat) && - snd_pcm_oss_format_to(sformat) >= 0) - break; - } - if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) { - snd_printd("Cannot find a format!!!\n"); - err = -EINVAL; - goto failure; - } - } - 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, - (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0); - _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, - (__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, - runtime->oss.rate, 0); - pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n", - params_access(params), params_format(params), - params_channels(params), params_rate(params)); - } - pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n", - params_access(sparams), params_format(sparams), - params_channels(sparams), params_rate(sparams)); - - 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 */ - snd_pcm_oss_plugin_clear(substream); - if ((err = snd_pcm_plug_format_plugins(substream, - params, - sparams)) < 0) { - snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err); - snd_pcm_oss_plugin_clear(substream); - goto failure; - } - if (runtime->oss.plugin_first) { - struct snd_pcm_plugin *plugin; - if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) { - snd_printd("snd_pcm_plugin_build_io failed: %i\n", err); - snd_pcm_oss_plugin_clear(substream); - goto failure; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - err = snd_pcm_plugin_append(plugin); - } else { - err = snd_pcm_plugin_insert(plugin); - } - if (err < 0) { - snd_pcm_oss_plugin_clear(substream); - goto failure; - } - } - } -#endif - - err = snd_pcm_oss_period_size(substream, params, sparams); - if (err < 0) - goto failure; - - n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size); - err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL); - if (err < 0) - goto failure; - - err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS, - runtime->oss.periods, NULL); - if (err < 0) - goto failure; - - snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - - if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) { - snd_printd("HW_PARAMS failed: %i\n", err); - goto failure; - } - - memset(sw_params, 0, sizeof(*sw_params)); - if (runtime->oss.trigger) { - sw_params->start_threshold = 1; - } else { - sw_params->start_threshold = runtime->boundary; - } - 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->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - 1 : runtime->period_size; - if (atomic_read(&substream->mmap_count) || - substream->oss.setup.nosilence) { - sw_params->silence_threshold = 0; - sw_params->silence_size = 0; - } else { - snd_pcm_uframes_t frames; - frames = runtime->period_size + 16; - if (frames > runtime->buffer_size) - frames = runtime->buffer_size; - sw_params->silence_threshold = frames; - sw_params->silence_size = frames; - } - - if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { - snd_printd("SW_PARAMS failed: %i\n", err); - goto failure; - } - - runtime->oss.periods = params_periods(sparams); - oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams)); - 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; - if (oss_buffer_size < 0) { - err = -EINVAL; - goto failure; - } - - runtime->oss.period_bytes = oss_period_size; - runtime->oss.buffer_bytes = oss_buffer_size; - - pdprintf("oss: period bytes = %i, buffer bytes = %i\n", - runtime->oss.period_bytes, - runtime->oss.buffer_bytes); - pdprintf("slave: period_size = %i, buffer_size = %i\n", - params_period_size(sparams), - params_buffer_size(sparams)); - - runtime->oss.format = snd_pcm_oss_format_to(params_format(params)); - runtime->oss.channels = params_channels(params); - runtime->oss.rate = params_rate(params); - - 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)); - - runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); - - err = 0; -failure: - kfree(sw_params); - kfree(params); - kfree(sparams); - mutex_unlock(&runtime->oss.params_lock); - return err; -} - -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; - struct snd_pcm_substream *asubstream = NULL, *substream; - - for (idx = 0; idx < 2; idx++) { - substream = pcm_oss_file->streams[idx]; - if (substream == NULL) - continue; - if (asubstream == NULL) - asubstream = substream; - if (substream->runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); - if (err < 0) - return err; - } - } - if (!asubstream) - return -EIO; - if (r_substream) - *r_substream = asubstream; - return 0; -} - -static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) -{ - int err; - 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"); - return err; - } - runtime->oss.prepare = 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(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - int err; - - if (substream == NULL) - return 0; - runtime = substream->runtime; - if (runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); - if (err < 0) - return err; - } - if (runtime->oss.prepare) { - err = snd_pcm_oss_prepare(substream); - if (err < 0) - return err; - } - return 0; -} - -static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay) -{ - struct snd_pcm_runtime *runtime; - snd_pcm_uframes_t frames; - int err = 0; - - while (1) { - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay); - if (err < 0) - break; - runtime = substream->runtime; - if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size) - break; - /* in case of overrun, skip whole periods like OSS/Linux driver does */ - /* until avail(delay) <= buffer_size */ - frames = (*delay - runtime->buffer_size) + runtime->period_size - 1; - frames /= runtime->period_size; - frames *= runtime->period_size; - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames); - if (err < 0) - break; - } - return err; -} - -snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel) -{ - 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(KERN_DEBUG "pcm_oss: write: " - "recovering from XRUN\n"); - else - printk(KERN_DEBUG "pcm_oss: write: " - "recovering from SUSPEND\n"); -#endif - ret = snd_pcm_oss_prepare(substream); - if (ret < 0) - break; - } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); - } - if (ret != -EPIPE && ret != -ESTRPIPE) - break; - /* test, if we can't store new data, because the stream */ - /* has not been started */ - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) - return -EAGAIN; - } - return ret; -} - -snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel) -{ - 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(KERN_DEBUG "pcm_oss: read: " - "recovering from XRUN\n"); - else - printk(KERN_DEBUG "pcm_oss: read: " - "recovering from SUSPEND\n"); -#endif - ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); - if (ret < 0) - break; - } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { - ret = snd_pcm_oss_prepare(substream); - if (ret < 0) - break; - } - ret = snd_pcm_oss_capture_position_fixup(substream, &delay); - if (ret < 0) - break; - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); - } - if (ret == -EPIPE) { - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { - ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - if (ret < 0) - break; - } - continue; - } - if (ret != -ESTRPIPE) - break; - } - return ret; -} - -snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) -{ - 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(KERN_DEBUG "pcm_oss: writev: " - "recovering from XRUN\n"); - else - printk(KERN_DEBUG "pcm_oss: writev: " - "recovering from SUSPEND\n"); -#endif - ret = snd_pcm_oss_prepare(substream); - if (ret < 0) - break; - } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); - } - if (ret != -EPIPE && ret != -ESTRPIPE) - break; - - /* test, if we can't store new data, because the stream */ - /* has not been started */ - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) - return -EAGAIN; - } - return ret; -} - -snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) -{ - 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(KERN_DEBUG "pcm_oss: readv: " - "recovering from XRUN\n"); - else - printk(KERN_DEBUG "pcm_oss: readv: " - "recovering from SUSPEND\n"); -#endif - ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); - if (ret < 0) - break; - } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { - ret = snd_pcm_oss_prepare(substream); - if (ret < 0) - break; - } - if (in_kernel) { - mm_segment_t fs; - fs = snd_enter_user(); - ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); - snd_leave_user(fs); - } else { - ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); - } - if (ret != -EPIPE && ret != -ESTRPIPE) - break; - } - return ret; -} - -static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t frames, frames1; -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - if (runtime->oss.plugin_first) { - 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 __force __user *)buf, bytes)) - return -EFAULT; - buf = runtime->oss.buffer; - } - frames = bytes / oss_frame_bytes; - frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels); - if (frames1 < 0) - return frames1; - frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1); - if (frames1 <= 0) - return frames1; - bytes = frames1 * oss_frame_bytes; - } else -#endif - { - frames = bytes_to_frames(runtime, bytes); - frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel); - if (frames1 <= 0) - return frames1; - bytes = frames_to_bytes(runtime, frames1); - } - return 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; - struct snd_pcm_runtime *runtime = substream->runtime; - - if (atomic_read(&substream->mmap_count)) - return -ENXIO; - - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; - mutex_lock(&runtime->oss.params_lock); - 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)) { - tmp = -EFAULT; - goto err; - } - } - runtime->oss.buffer_used += tmp; - buf += tmp; - bytes -= tmp; - xfer += tmp; - 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) - 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->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) - goto err; - runtime->oss.bytes += tmp; - buf += tmp; - bytes -= tmp; - xfer += tmp; - 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(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t frames, frames1; -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - char __user *final_dst = (char __force __user *)buf; - if (runtime->oss.plugin_first) { - 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; - frames = bytes / oss_frame_bytes; - frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels); - if (frames1 < 0) - return frames1; - frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1); - if (frames1 <= 0) - return frames1; - bytes = frames1 * oss_frame_bytes; - if (!in_kernel && copy_to_user(final_dst, buf, bytes)) - return -EFAULT; - } else -#endif - { - frames = bytes_to_frames(runtime, bytes); - frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel); - if (frames1 <= 0) - return frames1; - bytes = frames_to_bytes(runtime, frames1); - } - return 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; - struct snd_pcm_runtime *runtime = substream->runtime; - - if (atomic_read(&substream->mmap_count)) - return -ENXIO; - - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; - mutex_lock(&runtime->oss.params_lock); - 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) - goto err; - runtime->oss.bytes += tmp; - runtime->oss.period_ptr = tmp; - runtime->oss.buffer_used = tmp; - } - 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)) { - tmp = -EFAULT; - goto err; - } - buf += tmp; - bytes -= tmp; - xfer += tmp; - runtime->oss.buffer_used -= tmp; - } else { - tmp = snd_pcm_oss_read2(substream, (char __force *)buf, - runtime->oss.period_bytes, 0); - if (tmp <= 0) - 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(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - int i; - - 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(struct snd_pcm_oss_file *pcm_oss_file) -{ - 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_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(struct snd_pcm_substream *substream, size_t size) -{ - struct snd_pcm_runtime *runtime; - ssize_t result = 0; - snd_pcm_state_t state; - long res; - wait_queue_t wait; - - runtime = substream->runtime; - init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->sleep, &wait); -#ifdef OSS_DEBUG - printk(KERN_DEBUG "sync1: size = %li\n", size); -#endif - while (1) { - result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); - if (result > 0) { - runtime->oss.buffer_used = 0; - result = 0; - break; - } - if (result != 0 && result != -EAGAIN) - break; - result = 0; - set_current_state(TASK_INTERRUPTIBLE); - snd_pcm_stream_lock_irq(substream); - state = runtime->status->state; - snd_pcm_stream_unlock_irq(substream); - if (state != SNDRV_PCM_STATE_RUNNING) { - set_current_state(TASK_RUNNING); - break; - } - res = schedule_timeout(10 * HZ); - if (signal_pending(current)) { - result = -ERESTARTSYS; - break; - } - if (res == 0) { - snd_printk(KERN_ERR "OSS sync error - DMA timeout\n"); - result = -EIO; - break; - } - } - remove_wait_queue(&runtime->sleep, &wait); - return result; -} - -static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) -{ - int err = 0; - unsigned int saved_f_flags; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - snd_pcm_format_t format; - unsigned long width; - size_t size; - - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - if (substream != NULL) { - runtime = substream->runtime; - 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(KERN_DEBUG "sync: buffer_used\n"); -#endif - size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width; - snd_pcm_format_set_silence(format, - runtime->oss.buffer + runtime->oss.buffer_used, - size); - err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } - } else if (runtime->oss.period_ptr > 0) { -#ifdef OSS_DEBUG - printk(KERN_DEBUG "sync: period_ptr\n"); -#endif - size = runtime->oss.period_bytes - runtime->oss.period_ptr; - snd_pcm_format_set_silence(format, - runtime->oss.buffer, - size * 8 / width); - err = snd_pcm_oss_sync1(substream, size); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } - } - /* - * The ALSA's period might be a bit large than OSS one. - * Fill the remain portion of ALSA period with zeros. - */ - size = runtime->control->appl_ptr % runtime->period_size; - if (size > 0) { - size = runtime->period_size - size; - if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { - size = (runtime->frame_bits * size) / 8; - while (size > 0) { - mm_segment_t fs; - size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; - size -= size1; - size1 *= 8; - size1 /= runtime->sample_bits; - snd_pcm_format_set_silence(runtime->format, - runtime->oss.buffer, - size1); - size1 /= runtime->channels; /* frames */ - fs = snd_enter_user(); - snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); - snd_leave_user(fs); - } - } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { - void __user *buffers[runtime->channels]; - memset(buffers, 0, runtime->channels * sizeof(void *)); - snd_pcm_lib_writev(substream, buffers, size); - } - } - mutex_unlock(&runtime->oss.params_lock); - /* - * finish sync: drain the buffer - */ - __direct: - 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; - } - - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - if (substream != NULL) { - if ((err = snd_pcm_oss_make_ready(substream)) < 0) - return err; - runtime = substream->runtime; - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - if (err < 0) - return err; - runtime->oss.buffer_used = 0; - runtime->oss.prepare = 1; - } - return 0; -} - -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) { - struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; - struct snd_pcm_runtime *runtime; - if (substream == NULL) - continue; - runtime = substream->runtime; - if (rate < 1000) - rate = 1000; - else if (rate > 192000) - rate = 192000; - if (runtime->oss.rate != rate) { - runtime->oss.params = 1; - runtime->oss.rate = rate; - } - } - return snd_pcm_oss_get_rate(pcm_oss_file); -} - -static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - int err; - - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) - return err; - return substream->runtime->oss.rate; -} - -static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels) -{ - int idx; - if (channels < 1) - channels = 1; - if (channels > 128) - return -EINVAL; - for (idx = 1; idx >= 0; --idx) { - struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; - struct snd_pcm_runtime *runtime; - if (substream == NULL) - continue; - runtime = substream->runtime; - if (runtime->oss.channels != channels) { - runtime->oss.params = 1; - runtime->oss.channels = channels; - } - } - return snd_pcm_oss_get_channels(pcm_oss_file); -} - -static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - int err; - - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) - return err; - return substream->runtime->oss.channels; -} - -static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - int err; - - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) - return err; - return substream->runtime->oss.period_bytes; -} - -static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - int err; - int direct; - struct snd_pcm_hw_params *params; - unsigned int formats = 0; - 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->mmap_count)) - direct = 1; - 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_S32_LE | AFMT_S32_BE | - AFMT_S24_LE | AFMT_S24_BE | - AFMT_S24_PACKED; - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - _snd_pcm_hw_params_any(params); - err = snd_pcm_hw_refine(substream, params); - format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - kfree(params); - if (err < 0) - return err; - for (fmt = 0; fmt < 32; ++fmt) { - if (snd_mask_test(&format_mask, fmt)) { - int f = snd_pcm_oss_format_to(fmt); - if (f >= 0) - formats |= f; - } - } - return formats; -} - -static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) -{ - int formats, idx; - - 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) { - struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; - struct snd_pcm_runtime *runtime; - if (substream == NULL) - continue; - runtime = substream->runtime; - if (runtime->oss.format != format) { - runtime->oss.params = 1; - runtime->oss.format = format; - } - } - } - return snd_pcm_oss_get_format(pcm_oss_file); -} - -static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - int err; - - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) - return err; - return substream->runtime->oss.format; -} - -static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide) -{ - struct snd_pcm_runtime *runtime; - - if (substream == NULL) - return 0; - runtime = substream->runtime; - if (subdivide == 0) { - subdivide = runtime->oss.subdivision; - if (subdivide == 0) - subdivide = 1; - return subdivide; - } - if (runtime->oss.subdivision || runtime->oss.fragshift) - return -EINVAL; - if (subdivide != 1 && subdivide != 2 && subdivide != 4 && - subdivide != 8 && subdivide != 16) - return -EINVAL; - runtime->oss.subdivision = subdivide; - runtime->oss.params = 1; - return 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) { - struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; - if (substream == NULL) - continue; - if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0) - return err; - } - return err; -} - -static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val) -{ - struct snd_pcm_runtime *runtime; - - if (substream == NULL) - return 0; - runtime = substream->runtime; - if (runtime->oss.subdivision || runtime->oss.fragshift) - return -EINVAL; - runtime->oss.fragshift = val & 0xffff; - runtime->oss.maxfrags = (val >> 16) & 0xffff; - if (runtime->oss.fragshift < 4) /* < 16 */ - runtime->oss.fragshift = 4; - if (runtime->oss.maxfrags < 2) - runtime->oss.maxfrags = 2; - runtime->oss.params = 1; - return 0; -} - -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) { - struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; - if (substream == NULL) - continue; - if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0) - return err; - } - return err; -} - -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(struct snd_pcm_substream *substream, int res) -{ - - if (substream == NULL) { - res &= ~DSP_CAP_DUPLEX; - return res; - } -#ifdef DSP_CAP_MULTI - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - if (substream->pstr->substream_count > 1) - res |= DSP_CAP_MULTI; -#endif - /* DSP_CAP_REALTIME is set all times: */ - /* all ALSA drivers can return actual pointer in ring buffer */ -#if defined(DSP_CAP_REALTIME) && 0 - { - struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH)) - res &= ~DSP_CAP_REALTIME; - } -#endif - return res; -} - -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++) { - 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(struct snd_pcm_substream *substream, - snd_pcm_uframes_t hw_ptr) -{ - 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(struct snd_pcm_oss_file *pcm_oss_file, int trigger) -{ - struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL; - int err, cmd; - -#ifdef OSS_DEBUG - printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger); -#endif - - psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - - if (psubstream) { - if ((err = snd_pcm_oss_make_ready(psubstream)) < 0) - return err; - } - if (csubstream) { - if ((err = snd_pcm_oss_make_ready(csubstream)) < 0) - return err; - } - if (psubstream) { - runtime = psubstream->runtime; - if (trigger & PCM_ENABLE_OUTPUT) { - if (runtime->oss.trigger) - goto _skip1; - 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; - } else { - if (!runtime->oss.trigger) - goto _skip1; - runtime->oss.trigger = 0; - runtime->start_threshold = runtime->boundary; - cmd = SNDRV_PCM_IOCTL_DROP; - runtime->oss.prepare = 1; - } - err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); - if (err < 0) - return err; - } - _skip1: - if (csubstream) { - runtime = csubstream->runtime; - if (trigger & PCM_ENABLE_INPUT) { - if (runtime->oss.trigger) - goto _skip2; - runtime->oss.trigger = 1; - runtime->start_threshold = 1; - cmd = SNDRV_PCM_IOCTL_START; - } else { - if (!runtime->oss.trigger) - goto _skip2; - runtime->oss.trigger = 0; - runtime->start_threshold = runtime->boundary; - cmd = SNDRV_PCM_IOCTL_DROP; - runtime->oss.prepare = 1; - } - err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); - if (err < 0) - return err; - } - _skip2: - return 0; -} - -static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL; - int result = 0; - - psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger) - result |= PCM_ENABLE_OUTPUT; - if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger) - result |= PCM_ENABLE_INPUT; - return result; -} - -static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - snd_pcm_sframes_t delay; - int err; - - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - if (substream == NULL) - return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) - return err; - runtime = substream->runtime; - if (runtime->oss.params || runtime->oss.prepare) - return 0; - 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) - return err; - return snd_pcm_oss_bytes(substream, delay); -} - -static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct count_info __user * _info) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - snd_pcm_sframes_t delay; - int fixup; - struct count_info info; - int err; - - if (_info == NULL) - return -EFAULT; - substream = pcm_oss_file->streams[stream]; - if (substream == NULL) - return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) - return err; - runtime = substream->runtime; - if (runtime->oss.params || runtime->oss.prepare) { - memset(&info, 0, sizeof(info)); - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay); - if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) { - err = 0; - delay = 0; - fixup = 0; - } else { - fixup = runtime->oss.buffer_used; - } - } else { - err = snd_pcm_oss_capture_position_fixup(substream, &delay); - fixup = -runtime->oss.buffer_used; - } - if (err < 0) - return err; - info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); - if (atomic_read(&substream->mmap_count)) { - snd_pcm_sframes_t n; - 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_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) { - 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; - info.bytes = (runtime->oss.bytes - delay) & INT_MAX; - } else { - delay += fixup; - info.blocks = delay / runtime->oss.period_bytes; - info.bytes = (runtime->oss.bytes + delay) & INT_MAX; - } - } - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct audio_buf_info __user *_info) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - snd_pcm_sframes_t avail; - int fixup; - struct audio_buf_info info; - int err; - - if (_info == NULL) - return -EFAULT; - substream = pcm_oss_file->streams[stream]; - if (substream == NULL) - return -EINVAL; - runtime = substream->runtime; - - if (runtime->oss.params && - (err = snd_pcm_oss_change_params(substream)) < 0) - return err; - - info.fragsize = runtime->oss.period_bytes; - info.fragstotal = runtime->periods; - if (runtime->oss.prepare) { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.bytes = runtime->oss.period_bytes * runtime->oss.periods; - info.fragments = runtime->oss.periods; - } else { - info.bytes = 0; - info.fragments = 0; - } - } else { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail); - if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) { - avail = runtime->buffer_size; - err = 0; - fixup = 0; - } else { - avail = runtime->buffer_size - avail; - fixup = -runtime->oss.buffer_used; - } - } else { - err = snd_pcm_oss_capture_position_fixup(substream, &avail); - fixup = runtime->oss.buffer_used; - } - if (err < 0) - return err; - info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup; - info.fragments = info.bytes / runtime->oss.period_bytes; - } - -#ifdef OSS_DEBUG - printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, " - "fragstotal = %i, fragsize = %i\n", - info.bytes, info.fragments, info.fragstotal, info.fragsize); -#endif - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -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"); - return -EINVAL; -} - -static const char *strip_task_path(const char *path) -{ - const char *ptr, *ptrl = NULL; - for (ptr = path; *ptr; ptr++) { - if (*ptr == '/') - ptrl = ptr + 1; - } - 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; - } - } 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(struct snd_pcm_substream *substream, - struct snd_pcm_oss_setup *setup, - int minor) -{ - struct snd_pcm_runtime *runtime; - - substream->oss.oss = 1; - 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; - break; - case SNDRV_MINOR_OSS_PCM_16: - runtime->oss.format = AFMT_S16_LE; - break; - default: - runtime->oss.format = AFMT_MU_LAW; - } - runtime->oss.channels = 1; - runtime->oss.fragshift = 0; - runtime->oss.maxfrags = 0; - runtime->oss.subdivision = 0; - substream->pcm_release = snd_pcm_oss_release_substream; -} - -static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file) -{ - int cidx; - if (!pcm_oss_file) - return 0; - for (cidx = 0; cidx < 2; ++cidx) { - 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, - struct snd_pcm *pcm, - struct snd_pcm_oss_file **rpcm_oss_file, - int minor, - struct snd_pcm_oss_setup *setup) -{ - int idx, err; - struct snd_pcm_oss_file *pcm_oss_file; - struct snd_pcm_substream *substream; - fmode_t f_mode = file->f_mode; - - if (rpcm_oss_file) - *rpcm_oss_file = NULL; - - pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL); - if (pcm_oss_file == NULL) - return -ENOMEM; - - if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) && - (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) - f_mode = FMODE_WRITE; - - 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[idx] = substream; - substream->file = pcm_oss_file; - snd_pcm_oss_init_substream(substream, &setup[idx], minor); - } - - if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) { - snd_pcm_oss_release_file(pcm_oss_file); - return -EINVAL; - } - - file->private_data = 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 err; - char task_name[32]; - 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; - - err = nonseekable_open(inode, file); - if (err < 0) - return err; - - pcm = snd_lookup_oss_minor_data(iminor(inode), - SNDRV_OSS_DEVICE_TYPE_PCM); - if (pcm == NULL) { - err = -ENODEV; - goto __error1; - } - err = snd_card_file_add(pcm->card, file); - if (err < 0) - goto __error1; - if (!try_module_get(pcm->card->module)) { - err = -EFAULT; - goto __error2; - } - if (snd_task_name(current, task_name, sizeof(task_name)) < 0) { - err = -EFAULT; - goto __error; - } - memset(setup, 0, sizeof(setup)); - if (file->f_mode & FMODE_WRITE) - snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, - task_name, &setup[0]); - if (file->f_mode & FMODE_READ) - snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, - task_name, &setup[1]); - - nonblock = !!(file->f_flags & O_NONBLOCK); - if (!nonblock) - nonblock = nonblock_open; - - init_waitqueue_entry(&wait, current); - add_wait_queue(&pcm->open_wait, &wait); - mutex_lock(&pcm->open_mutex); - while (1) { - err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file, - iminor(inode), setup); - if (err >= 0) - break; - if (err == -EAGAIN) { - if (nonblock) { - err = -EBUSY; - break; - } - } else - break; - set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&pcm->open_mutex); - schedule(); - 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); - mutex_unlock(&pcm->open_mutex); - if (err < 0) - goto __error; - snd_card_unref(pcm->card); - return err; - - __error: - module_put(pcm->card->module); - __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) -{ - 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]; - if (snd_BUG_ON(!substream)) - return -ENXIO; - pcm = substream->pcm; - if (!pcm->card->shutdown) - snd_pcm_oss_sync(pcm_oss_file); - mutex_lock(&pcm->open_mutex); - snd_pcm_oss_release_file(pcm_oss_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 long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct snd_pcm_oss_file *pcm_oss_file; - int __user *p = (int __user *)arg; - int res; - - pcm_oss_file = file->private_data; - if (cmd == OSS_GETVERSION) - return put_user(SNDRV_OSS_VERSION, p); - if (cmd == OSS_ALSAEMULVER) - return put_user(1, p); -#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE)) - if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ - struct snd_pcm_substream *substream; - int idx; - for (idx = 0; idx < 2; ++idx) { - substream = pcm_oss_file->streams[idx]; - if (substream != NULL) - break; - } - 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(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd); -#endif - switch (cmd) { - case SNDCTL_DSP_RESET: - return snd_pcm_oss_reset(pcm_oss_file); - case SNDCTL_DSP_SYNC: - return snd_pcm_oss_sync(pcm_oss_file); - case SNDCTL_DSP_SPEED: - if (get_user(res, p)) - return -EFAULT; - if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) - return res; - return put_user(res, p); - case SOUND_PCM_READ_RATE: - res = snd_pcm_oss_get_rate(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_STEREO: - if (get_user(res, p)) - return -EFAULT; - res = res > 0 ? 2 : 1; - if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) - return res; - return put_user(--res, p); - case SNDCTL_DSP_GETBLKSIZE: - res = snd_pcm_oss_get_block_size(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_SETFMT: - if (get_user(res, p)) - return -EFAULT; - res = snd_pcm_oss_set_format(pcm_oss_file, res); - if (res < 0) - return res; - return put_user(res, p); - case SOUND_PCM_READ_BITS: - res = snd_pcm_oss_get_format(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_CHANNELS: - if (get_user(res, p)) - return -EFAULT; - res = snd_pcm_oss_set_channels(pcm_oss_file, res); - if (res < 0) - return res; - return put_user(res, p); - case SOUND_PCM_READ_CHANNELS: - res = snd_pcm_oss_get_channels(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EIO; - case SNDCTL_DSP_POST: - return snd_pcm_oss_post(pcm_oss_file); - case SNDCTL_DSP_SUBDIVIDE: - if (get_user(res, p)) - return -EFAULT; - res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(res, p)) - return -EFAULT; - return snd_pcm_oss_set_fragment(pcm_oss_file, res); - case SNDCTL_DSP_GETFMTS: - res = snd_pcm_oss_get_formats(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_GETOSPACE: - case SNDCTL_DSP_GETISPACE: - return snd_pcm_oss_get_space(pcm_oss_file, - cmd == SNDCTL_DSP_GETISPACE ? - SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct audio_buf_info __user *) arg); - case SNDCTL_DSP_NONBLOCK: - return snd_pcm_oss_nonblock(file); - case SNDCTL_DSP_GETCAPS: - res = snd_pcm_oss_get_caps(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_GETTRIGGER: - res = snd_pcm_oss_get_trigger(pcm_oss_file); - if (res < 0) - return res; - return put_user(res, p); - case SNDCTL_DSP_SETTRIGGER: - if (get_user(res, p)) - return -EFAULT; - return snd_pcm_oss_set_trigger(pcm_oss_file, res); - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - return snd_pcm_oss_get_ptr(pcm_oss_file, - cmd == SNDCTL_DSP_GETIPTR ? - SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct count_info __user *) arg); - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - return snd_pcm_oss_get_mapbuf(pcm_oss_file, - cmd == SNDCTL_DSP_MAPINBUF ? - SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, - (struct buffmem_desc __user *) arg); - case SNDCTL_DSP_SETSYNCRO: - /* stop DMA now.. */ - return 0; - case SNDCTL_DSP_SETDUPLEX: - if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX) - return 0; - return -EIO; - case SNDCTL_DSP_GETODELAY: - res = snd_pcm_oss_get_odelay(pcm_oss_file); - if (res < 0) { - /* it's for sure, some broken apps don't check for error codes */ - put_user(0, p); - return res; - } - return put_user(res, p); - case SNDCTL_DSP_PROFILE: - return 0; /* silently ignore */ - default: - snd_printd("pcm_oss: unknown command = 0x%x\n", cmd); - } - return -EINVAL; -} - -#ifdef CONFIG_COMPAT -/* all compatible */ -#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl -#else -#define snd_pcm_oss_ioctl_compat NULL -#endif - -static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -{ - 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(KERN_DEBUG "pcm_oss: read %li bytes " - "(returned %li bytes)\n", (long)count, (long)res); - return res; - } -#endif -} - -static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) -{ - 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; - substream->f_flags = file->f_flags & O_NONBLOCK; - result = snd_pcm_oss_write1(substream, buf, count); -#ifdef OSS_DEBUG - printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n", - (long)count, (long)result); -#endif - return result; -} - -static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) -{ - 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; -} - -static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) -{ - 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; -} - -static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) -{ - struct snd_pcm_oss_file *pcm_oss_file; - unsigned int mask; - struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL; - - pcm_oss_file = file->private_data; - - psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - - mask = 0; - if (psubstream != NULL) { - struct snd_pcm_runtime *runtime = psubstream->runtime; - poll_wait(file, &runtime->sleep, wait); - snd_pcm_stream_lock_irq(psubstream); - if (runtime->status->state != SNDRV_PCM_STATE_DRAINING && - (runtime->status->state != SNDRV_PCM_STATE_RUNNING || - snd_pcm_oss_playback_ready(psubstream))) - mask |= POLLOUT | POLLWRNORM; - snd_pcm_stream_unlock_irq(psubstream); - } - if (csubstream != NULL) { - struct snd_pcm_runtime *runtime = csubstream->runtime; - snd_pcm_state_t ostate; - poll_wait(file, &runtime->sleep, wait); - snd_pcm_stream_lock_irq(csubstream); - if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING || - snd_pcm_oss_capture_ready(csubstream)) - mask |= POLLIN | POLLRDNORM; - snd_pcm_stream_unlock_irq(csubstream); - if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { - 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; - snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT); - } - } - - return mask; -} - -static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) -{ - 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(KERN_DEBUG "pcm_oss: mmap begin\n"); -#endif - pcm_oss_file = file->private_data; - switch ((area->vm_flags & (VM_READ | VM_WRITE))) { - case VM_READ | VM_WRITE: - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - if (substream) - break; - /* Fall through */ - case VM_READ: - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - break; - case VM_WRITE: - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - break; - default: - return -EINVAL; - } - /* set VM_READ access as well to fix memset() routines that do - reads before writes (to improve performance) */ - area->vm_flags |= VM_READ; - if (substream == NULL) - return -ENXIO; - runtime = substream->runtime; - if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID)) - return -EIO; - if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED) - runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; - else - return -EIO; - - if (runtime->oss.params) { - 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; - - err = snd_pcm_mmap_data(substream, file, area); - if (err < 0) - return err; - runtime->oss.mmap_bytes = area->vm_end - area->vm_start; - runtime->silence_threshold = 0; - runtime->silence_size = 0; -#ifdef OSS_DEBUG - printk(KERN_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; - - return 0; -} - -#ifdef CONFIG_SND_VERBOSE_PROCFS -/* - * /proc interface - */ - -static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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, - setup->periods, - setup->period_size, - setup->disable ? " disable" : "", - setup->direct ? " direct" : "", - setup->block ? " block" : "", - setup->nonblock ? " non-block" : "", - setup->partialfrag ? " partial-frag" : "", - setup->nosilence ? " no-silence" : ""); - setup = setup->next; - } - mutex_unlock(&pstr->oss.setup_mutex); -} - -static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr) -{ - struct snd_pcm_oss_setup *setup, *setupn; - - for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL; - setup; setup = setupn) { - setupn = setup->next; - kfree(setup->task_name); - kfree(setup); - } - pstr->oss.setup_list = NULL; -} - -static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_pcm_str *pstr = entry->private_data; - char line[128], str[32], task_name[32]; - const char *ptr; - int idx1; - struct snd_pcm_oss_setup *setup, *setup1, template; - - while (!snd_info_get_line(buffer, line, sizeof(line))) { - 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); - mutex_unlock(&pstr->oss.setup_mutex); - continue; - } - for (setup = pstr->oss.setup_list; setup; setup = setup->next) { - if (!strcmp(setup->task_name, task_name)) { - template = *setup; - break; - } - } - ptr = snd_info_get_str(str, ptr, sizeof(str)); - template.periods = simple_strtoul(str, NULL, 10); - ptr = snd_info_get_str(str, ptr, sizeof(str)); - template.period_size = simple_strtoul(str, NULL, 10); - for (idx1 = 31; idx1 >= 0; idx1--) - if (template.period_size & (1 << idx1)) - break; - for (idx1--; idx1 >= 0; idx1--) - template.period_size &= ~(1 << idx1); - do { - ptr = snd_info_get_str(str, ptr, sizeof(str)); - if (!strcmp(str, "disable")) { - template.disable = 1; - } else if (!strcmp(str, "direct")) { - template.direct = 1; - } else if (!strcmp(str, "block")) { - template.block = 1; - } else if (!strcmp(str, "non-block")) { - template.nonblock = 1; - } else if (!strcmp(str, "partial-frag")) { - template.partialfrag = 1; - } else if (!strcmp(str, "no-silence")) { - template.nosilence = 1; - } else if (!strcmp(str, "buggy-ptr")) { - template.buggyptr = 1; - } - } while (*str); - if (setup == NULL) { - 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; - } - } - *setup = template; - mutex_unlock(&pstr->oss.setup_mutex); - } -} - -static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) -{ - int stream; - for (stream = 0; stream < 2; ++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 = snd_pcm_oss_proc_read; - entry->c.text.write = snd_pcm_oss_proc_write; - entry->private_data = pstr; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - pstr->oss.proc_entry = entry; - } -} - -static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) -{ - int stream; - for (stream = 0; stream < 2; ++stream) { - 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 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 void register_oss_dsp(struct snd_pcm *pcm, int index) -{ - char name[128]; - sprintf(name, "dsp%i%i", pcm->card->number, pcm->device); - if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, - pcm->card, index, &snd_pcm_oss_f_reg, - pcm, name) < 0) { - snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n", - pcm->card->number, pcm->device); - } -} - -static int snd_pcm_oss_register_minor(struct snd_pcm *pcm) -{ - pcm->oss.reg = 0; - if (dsp_map[pcm->card->number] == (int)pcm->device) { - char name[128]; - int duplex; - register_oss_dsp(pcm, 0); - duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 && - pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && - !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)); - sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : ""); -#ifdef SNDRV_OSS_INFO_DEV_AUDIO - snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO, - pcm->card->number, - name); -#endif - pcm->oss.reg++; - pcm->oss.reg_mask |= 1; - } - if (adsp_map[pcm->card->number] == (int)pcm->device) { - register_oss_dsp(pcm, 1); - pcm->oss.reg++; - pcm->oss.reg_mask |= 2; - } - - if (pcm->oss.reg) - snd_pcm_oss_proc_init(pcm); - - return 0; -} - -static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) -{ - if (pcm->oss.reg) { - if (pcm->oss.reg_mask & 1) { - pcm->oss.reg_mask &= ~1; - snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, - pcm->card, 0); - } - if (pcm->oss.reg_mask & 2) { - pcm->oss.reg_mask &= ~2; - snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, - pcm->card, 1); - } - 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; - } - return 0; -} - -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, - .n_unregister = snd_pcm_oss_unregister_minor, -}; - -static int __init alsa_pcm_oss_init(void) -{ - int i; - int err; - - /* check device map table */ - for (i = 0; i < SNDRV_CARDS; i++) { - if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) { - snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n", - i, dsp_map[i]); - dsp_map[i] = 0; - } - if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) { - snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n", - i, adsp_map[i]); - adsp_map[i] = 1; - } - } - if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0) - return err; - return 0; -} - -static void __exit alsa_pcm_oss_exit(void) -{ - snd_pcm_notify(&snd_pcm_oss_notify, 1); -} - -module_init(alsa_pcm_oss_init) -module_exit(alsa_pcm_oss_exit) diff --git a/ANDROID_3.4.5/sound/core/oss/pcm_plugin.c b/ANDROID_3.4.5/sound/core/oss/pcm_plugin.c deleted file mode 100644 index 71cc3ddf..00000000 --- a/ANDROID_3.4.5/sound/core/oss/pcm_plugin.c +++ /dev/null @@ -1,756 +0,0 @@ -/* - * PCM Plug-In shared (kernel/library) code - * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> - * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> - * - * - * 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 - * - */ - -#if 0 -#define PLUGIN_DEBUG -#endif - -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/vmalloc.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include "pcm_plugin.h" - -#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) -#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) - -/* - * because some cards might have rates "very close", we ignore - * all "resampling" requests within +-5% - */ -static int rate_match(unsigned int src_rate, unsigned int dst_rate) -{ - unsigned int low = (src_rate * 95) / 100; - unsigned int high = (src_rate * 105) / 100; - return dst_rate >= low && dst_rate <= high; -} - -static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) -{ - struct snd_pcm_plugin_format *format; - ssize_t width; - size_t size; - unsigned int channel; - struct snd_pcm_plugin_channel *c; - - if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) { - format = &plugin->src_format; - } else { - format = &plugin->dst_format; - } - if ((width = snd_pcm_format_physical_width(format->format)) < 0) - return width; - size = frames * format->channels * width; - if (snd_BUG_ON(size % 8)) - return -ENXIO; - size /= 8; - if (plugin->buf_frames < frames) { - vfree(plugin->buf); - plugin->buf = vmalloc(size); - plugin->buf_frames = frames; - } - if (!plugin->buf) { - plugin->buf_frames = 0; - return -ENOMEM; - } - c = plugin->buf_channels; - if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { - for (channel = 0; channel < format->channels; channel++, c++) { - c->frames = frames; - c->enabled = 1; - c->wanted = 0; - c->area.addr = plugin->buf; - c->area.first = channel * width; - c->area.step = format->channels * width; - } - } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { - if (snd_BUG_ON(size % format->channels)) - return -EINVAL; - size /= format->channels; - for (channel = 0; channel < format->channels; channel++, c++) { - c->frames = frames; - c->enabled = 1; - c->wanted = 0; - c->area.addr = plugin->buf + (channel * size); - c->area.first = 0; - c->area.step = width; - } - } else - return -EINVAL; - return 0; -} - -int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) -{ - int err; - if (snd_BUG_ON(!snd_pcm_plug_first(plug))) - return -ENXIO; - if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { - struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug); - while (plugin->next) { - if (plugin->dst_frames) - frames = plugin->dst_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) - return -ENXIO; - plugin = plugin->next; - err = snd_pcm_plugin_alloc(plugin, frames); - if (err < 0) - return err; - } - } else { - struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug); - while (plugin->prev) { - if (plugin->src_frames) - frames = plugin->src_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) - return -ENXIO; - plugin = plugin->prev; - err = snd_pcm_plugin_alloc(plugin, frames); - if (err < 0) - return err; - } - } - return 0; -} - - -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) -{ - *channels = plugin->buf_channels; - return frames; -} - -int snd_pcm_plugin_build(struct snd_pcm_substream *plug, - const char *name, - struct snd_pcm_plugin_format *src_format, - struct snd_pcm_plugin_format *dst_format, - size_t extra, - struct snd_pcm_plugin **ret) -{ - struct snd_pcm_plugin *plugin; - unsigned int channels; - - 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; - plugin->name = name; - plugin->plug = plug; - plugin->stream = snd_pcm_plug_stream(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_BUG_ON(plugin->src_width <= 0); - plugin->dst_format = *dst_format; - plugin->dst_width = snd_pcm_format_physical_width(dst_format->format); - snd_BUG_ON(plugin->dst_width <= 0); - if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) - channels = src_format->channels; - else - channels = dst_format->channels; - plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL); - if (plugin->buf_channels == NULL) { - snd_pcm_plugin_free(plugin); - return -ENOMEM; - } - plugin->client_channels = snd_pcm_plugin_client_channels; - *ret = plugin; - return 0; -} - -int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) -{ - if (! plugin) - return 0; - if (plugin->private_free) - plugin->private_free(plugin); - kfree(plugin->buf_channels); - vfree(plugin->buf); - kfree(plugin); - return 0; -} - -snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) -{ - struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; - int stream = snd_pcm_plug_stream(plug); - - if (snd_BUG_ON(!plug)) - return -ENXIO; - if (drv_frames == 0) - return 0; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - plugin = snd_pcm_plug_last(plug); - while (plugin && drv_frames > 0) { - plugin_prev = plugin->prev; - if (plugin->src_frames) - drv_frames = plugin->src_frames(plugin, drv_frames); - plugin = plugin_prev; - } - } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { - plugin = snd_pcm_plug_first(plug); - while (plugin && drv_frames > 0) { - plugin_next = plugin->next; - if (plugin->dst_frames) - drv_frames = plugin->dst_frames(plugin, drv_frames); - plugin = plugin_next; - } - } else - snd_BUG(); - return drv_frames; -} - -snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames) -{ - struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next; - snd_pcm_sframes_t frames; - int stream = snd_pcm_plug_stream(plug); - - if (snd_BUG_ON(!plug)) - return -ENXIO; - if (clt_frames == 0) - return 0; - frames = clt_frames; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - plugin = snd_pcm_plug_first(plug); - while (plugin && frames > 0) { - plugin_next = plugin->next; - if (plugin->dst_frames) { - frames = plugin->dst_frames(plugin, frames); - if (frames < 0) - return frames; - } - plugin = plugin_next; - } - } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { - plugin = snd_pcm_plug_last(plug); - while (plugin) { - plugin_prev = plugin->prev; - if (plugin->src_frames) { - frames = plugin->src_frames(plugin, frames); - if (frames < 0) - return frames; - } - plugin = plugin_prev; - } - } else - snd_BUG(); - return frames; -} - -static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format) -{ - 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, (__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, (__force int)format); -} - -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, - 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, - SNDRV_PCM_FORMAT_S8, - SNDRV_PCM_FORMAT_U8 -}; - -snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - struct snd_mask *format_mask) -{ - int i; - - if (snd_mask_test(format_mask, (__force int)format)) - return format; - if (!snd_pcm_plug_formats(format_mask, format)) - return (__force snd_pcm_format_t)-EINVAL; - if (snd_pcm_format_linear(format)) { - 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; - } - } - if ((__force int)best_format >= 0) - return best_format; - else - return (__force snd_pcm_format_t)-EINVAL; - } else { - switch (format) { - case SNDRV_PCM_FORMAT_MU_LAW: - for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { - snd_pcm_format_t format1 = preferred_formats[i]; - if (snd_mask_test(format_mask, (__force int)format1)) - return format1; - } - default: - return (__force snd_pcm_format_t)-EINVAL; - } - } -} - -int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug, - struct snd_pcm_hw_params *params, - struct snd_pcm_hw_params *slave_params) -{ - 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 || - params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED); - - switch (stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - dstformat.format = params_format(slave_params); - dstformat.rate = params_rate(slave_params); - dstformat.channels = params_channels(slave_params); - srcformat.format = params_format(params); - srcformat.rate = params_rate(params); - srcformat.channels = params_channels(params); - src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; - dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : - SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); - break; - case SNDRV_PCM_STREAM_CAPTURE: - dstformat.format = params_format(params); - dstformat.rate = params_rate(params); - dstformat.channels = params_channels(params); - srcformat.format = params_format(slave_params); - srcformat.rate = params_rate(slave_params); - srcformat.channels = params_channels(slave_params); - src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : - SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); - dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; - break; - default: - snd_BUG(); - return -EINVAL; - } - tmpformat = srcformat; - - pdprintf("srcformat: format=%i, rate=%i, channels=%i\n", - srcformat.format, - srcformat.rate, - srcformat.channels); - pdprintf("dstformat: format=%i, rate=%i, channels=%i\n", - dstformat.format, - dstformat.rate, - dstformat.channels); - - /* Format change (linearization) */ - if (! rate_match(srcformat.rate, dstformat.rate) && - ! snd_pcm_format_linear(srcformat.format)) { - if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW) - return -EINVAL; - 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); - if (err < 0) { - snd_pcm_plugin_free(plugin); - return err; - } - srcformat = tmpformat; - src_access = dst_access; - } - - /* channels reduction */ - if (srcformat.channels > dstformat.channels) { - tmpformat.channels = dstformat.channels; - 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) - return err; - err = snd_pcm_plugin_append(plugin); - if (err < 0) { - snd_pcm_plugin_free(plugin); - return err; - } - srcformat = tmpformat; - src_access = dst_access; - } - - /* 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; - 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) - 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 (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW || - tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { - err = snd_pcm_plugin_build_mulaw(plug, - &srcformat, &tmpformat, - &plugin); - } - else if (snd_pcm_format_linear(srcformat.format) && - snd_pcm_format_linear(tmpformat.format)) { - err = snd_pcm_plugin_build_linear(plug, - &srcformat, &tmpformat, - &plugin); - } - else - return -EINVAL; - pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, 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; - } - - /* 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, - &srcformat, - &tmpformat, - &plugin); - pdprintf("interleave change (copy: returns %i)\n", err); - if (err < 0) - return err; - err = snd_pcm_plugin_append(plugin); - if (err < 0) { - snd_pcm_plugin_free(plugin); - return err; - } - } - - return 0; -} - -snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug, - char *buf, - snd_pcm_uframes_t count, - struct snd_pcm_plugin_channel **channels) -{ - 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); - - if (snd_BUG_ON(!buf)) - return -ENXIO; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - plugin = snd_pcm_plug_first(plug); - format = &plugin->src_format; - } else { - plugin = snd_pcm_plug_last(plug); - format = &plugin->dst_format; - } - v = plugin->buf_channels; - *channels = v; - if ((width = snd_pcm_format_physical_width(format->format)) < 0) - return width; - nchannels = format->channels; - 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; - v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE); - v->area.addr = buf; - v->area.first = channel * width; - v->area.step = nchannels * width; - } - return count; -} - -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) -{ - struct snd_pcm_plugin *plugin, *next; - struct snd_pcm_plugin_channel *dst_channels; - int err; - snd_pcm_sframes_t frames = size; - - plugin = snd_pcm_plug_first(plug); - while (plugin && frames > 0) { - if ((next = plugin->next) != NULL) { - snd_pcm_sframes_t frames1 = frames; - if (plugin->dst_frames) - frames1 = plugin->dst_frames(plugin, frames); - if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { - return err; - } - if (err != frames1) { - frames = err; - if (plugin->src_frames) - frames = plugin->src_frames(plugin, frames1); - } - } else - dst_channels = NULL; - pdprintf("write plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) - return frames; - src_channels = dst_channels; - plugin = next; - } - return snd_pcm_plug_client_size(plug, frames); -} - -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) -{ - struct snd_pcm_plugin *plugin, *next; - struct snd_pcm_plugin_channel *src_channels, *dst_channels; - snd_pcm_sframes_t frames = size; - int err; - - frames = snd_pcm_plug_slave_size(plug, frames); - if (frames < 0) - return frames; - - src_channels = NULL; - plugin = snd_pcm_plug_first(plug); - while (plugin && frames > 0) { - if ((next = plugin->next) != NULL) { - if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { - return err; - } - frames = err; - } else { - dst_channels = dst_channels_final; - } - pdprintf("read plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) - return frames; - plugin = next; - src_channels = dst_channels; - } - return frames; -} - -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; - unsigned int dst_step; - int width; - const unsigned char *silence; - if (!dst_area->addr) - return 0; - dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; - width = snd_pcm_format_physical_width(format); - if (width <= 0) - return -EINVAL; - if (dst_area->step == (unsigned int) width && width >= 8) - return snd_pcm_format_set_silence(format, dst, samples); - silence = snd_pcm_format_silence_64(format); - if (! silence) - return -EINVAL; - dst_step = dst_area->step / 8; - if (width == 4) { - /* Ima ADPCM */ - int dstbit = dst_area->first % 8; - int dstbit_step = dst_area->step % 8; - while (samples-- > 0) { - if (dstbit) - *dst &= 0xf0; - else - *dst &= 0x0f; - dst += dst_step; - dstbit += dstbit_step; - if (dstbit == 8) { - dst++; - dstbit = 0; - } - } - } else { - width /= 8; - while (samples-- > 0) { - memcpy(dst, silence, width); - dst += dst_step; - } - } - return 0; -} - -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; - int width; - int src_step, dst_step; - src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; - if (!src_area->addr) - return snd_pcm_area_silence(dst_area, dst_offset, samples, format); - dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; - if (!dst_area->addr) - return 0; - width = snd_pcm_format_physical_width(format); - if (width <= 0) - return -EINVAL; - if (src_area->step == (unsigned int) width && - dst_area->step == (unsigned int) width && width >= 8) { - size_t bytes = samples * width / 8; - memcpy(dst, src, bytes); - return 0; - } - src_step = src_area->step / 8; - dst_step = dst_area->step / 8; - if (width == 4) { - /* Ima ADPCM */ - int srcbit = src_area->first % 8; - int srcbit_step = src_area->step % 8; - int dstbit = dst_area->first % 8; - int dstbit_step = dst_area->step % 8; - while (samples-- > 0) { - unsigned char srcval; - if (srcbit) - srcval = *src & 0x0f; - else - srcval = (*src & 0xf0) >> 4; - if (dstbit) - *dst = (*dst & 0xf0) | srcval; - else - *dst = (*dst & 0x0f) | (srcval << 4); - src += src_step; - srcbit += srcbit_step; - if (srcbit == 8) { - src++; - srcbit = 0; - } - dst += dst_step; - dstbit += dstbit_step; - if (dstbit == 8) { - dst++; - dstbit = 0; - } - } - } else { - width /= 8; - while (samples-- > 0) { - memcpy(dst, src, width); - src += src_step; - dst += dst_step; - } - } - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/oss/pcm_plugin.h b/ANDROID_3.4.5/sound/core/oss/pcm_plugin.h deleted file mode 100644 index a5035c23..00000000 --- a/ANDROID_3.4.5/sound/core/oss/pcm_plugin.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef __PCM_PLUGIN_H -#define __PCM_PLUGIN_H - -/* - * Digital Audio (Plugin interface) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - -#define snd_pcm_plug_stream(plug) ((plug)->stream) - -enum snd_pcm_plugin_action { - INIT = 0, - PREPARE = 1, -}; - -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 */ -}; - -struct snd_pcm_plugin_channel { - void *aptr; /* pointer to the allocated 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 */ -}; - -struct snd_pcm_plugin_format { - snd_pcm_format_t format; - unsigned int rate; - unsigned int channels; -}; - -struct snd_pcm_plugin { - const char *name; /* plug-in name */ - int stream; - 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 */ - 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); - struct snd_pcm_plugin *prev; - struct snd_pcm_plugin *next; - struct snd_pcm_substream *plug; - void *private_data; - void (*private_free)(struct snd_pcm_plugin *plugin); - char *buf; - snd_pcm_uframes_t buf_frames; - struct snd_pcm_plugin_channel *buf_channels; - char extra_data[0]; -}; - -int snd_pcm_plugin_build(struct snd_pcm_substream *handle, - const char *name, - struct snd_pcm_plugin_format *src_format, - struct snd_pcm_plugin_format *dst_format, - size_t extra, - struct snd_pcm_plugin **ret); -int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin); -int snd_pcm_plugin_clear(struct snd_pcm_plugin **first); -int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size); -snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size); - -#define FULL ROUTE_PLUGIN_RESOLUTION -#define HALF ROUTE_PLUGIN_RESOLUTION / 2 - -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(KERN_DEBUG "plugin: " fmt, ##args) -#else -#define pdprintf(fmt, args...) -#endif - -#endif /* __PCM_PLUGIN_H */ diff --git a/ANDROID_3.4.5/sound/core/oss/rate.c b/ANDROID_3.4.5/sound/core/oss/rate.c deleted file mode 100644 index 2fa9299a..00000000 --- a/ANDROID_3.4.5/sound/core/oss/rate.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Rate conversion Plug-In - * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include "pcm_plugin.h" - -#define SHIFT 11 -#define BITS (1<<SHIFT) -#define R_MASK (BITS-1) - -/* - * Basic rate conversion plugin - */ - -struct rate_channel { - signed short last_S1; - signed short last_S2; -}; - -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); - -struct rate_priv { - unsigned int pitch; - unsigned int pos; - rate_f func; - snd_pcm_sframes_t old_src_frames, old_dst_frames; - struct rate_channel channels[0]; -}; - -static void rate_init(struct snd_pcm_plugin *plugin) -{ - unsigned int channel; - 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; - data->channels[channel].last_S2 = 0; - } -} - -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; - signed short *src, *dst; - unsigned int channel; - int src_step, dst_step; - int src_frames1, dst_frames1; - 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; - S1 = rchannels->last_S1; - S2 = rchannels->last_S2; - if (!src_channels[channel].enabled) { - if (dst_channels[channel].wanted) - snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format); - dst_channels[channel].enabled = 0; - continue; - } - dst_channels[channel].enabled = 1; - 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) { - if (pos & ~R_MASK) { - pos &= R_MASK; - S1 = S2; - if (src_frames1-- > 0) { - S2 = *src; - src += src_step; - } - } - val = S1 + ((S2 - S1) * (signed int)pos) / BITS; - if (val < -32768) - val = -32768; - else if (val > 32767) - val = 32767; - *dst = val; - dst += dst_step; - pos += data->pitch; - } - rchannels->last_S1 = S1; - rchannels->last_S2 = S2; - rchannels++; - } - data->pos = pos; -} - -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; - signed short *src, *dst; - unsigned int channel; - int src_step, dst_step; - int src_frames1, dst_frames1; - 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; - S1 = rchannels->last_S1; - S2 = rchannels->last_S2; - if (!src_channels[channel].enabled) { - if (dst_channels[channel].wanted) - snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format); - dst_channels[channel].enabled = 0; - continue; - } - dst_channels[channel].enabled = 1; - 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) { - S2 = *src; - src += src_step; - } - if (pos & ~R_MASK) { - pos &= R_MASK; - val = S1 + ((S2 - S1) * (signed int)pos) / BITS; - if (val < -32768) - val = -32768; - else if (val > 32767) - val = 32767; - *dst = val; - dst += dst_step; - dst_frames1--; - } - pos += data->pitch; - } - rchannels->last_S1 = S1; - rchannels->last_S2 = S2; - rchannels++; - } - data->pos = pos; -} - -static snd_pcm_sframes_t rate_src_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) -{ - struct rate_priv *data; - snd_pcm_sframes_t res; - - if (snd_BUG_ON(!plugin)) - return -ENXIO; - if (frames == 0) - return 0; - data = (struct rate_priv *)plugin->extra_data; - if (plugin->src_format.rate < plugin->dst_format.rate) { - res = (((frames * data->pitch) + (BITS/2)) >> SHIFT); - } else { - res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch); - } - if (data->old_src_frames > 0) { - snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames; - while (data->old_src_frames < frames1) { - frames1 >>= 1; - res1 <<= 1; - } - while (data->old_src_frames > frames1) { - frames1 <<= 1; - res1 >>= 1; - } - if (data->old_src_frames == frames1) - return res1; - } - data->old_src_frames = frames; - data->old_dst_frames = res; - return res; -} - -static snd_pcm_sframes_t rate_dst_frames(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) -{ - struct rate_priv *data; - snd_pcm_sframes_t res; - - if (snd_BUG_ON(!plugin)) - return -ENXIO; - if (frames == 0) - return 0; - data = (struct rate_priv *)plugin->extra_data; - if (plugin->src_format.rate < plugin->dst_format.rate) { - res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch); - } else { - res = (((frames * data->pitch) + (BITS/2)) >> SHIFT); - } - if (data->old_dst_frames > 0) { - snd_pcm_sframes_t frames1 = frames, res1 = data->old_src_frames; - while (data->old_dst_frames < frames1) { - frames1 >>= 1; - res1 <<= 1; - } - while (data->old_dst_frames > frames1) { - frames1 <<= 1; - res1 >>= 1; - } - if (data->old_dst_frames == frames1) - return res1; - } - data->old_dst_frames = frames; - data->old_src_frames = res; - return res; -} - -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; - struct rate_priv *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++) { - 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 - - dst_frames = rate_dst_frames(plugin, frames); - if (dst_frames > dst_channels[0].frames) - dst_frames = dst_channels[0].frames; - data = (struct rate_priv *)plugin->extra_data; - data->func(plugin, src_channels, dst_channels, frames, dst_frames); - return dst_frames; -} - -static int rate_action(struct snd_pcm_plugin *plugin, - enum snd_pcm_plugin_action action, - unsigned long udata) -{ - if (snd_BUG_ON(!plugin)) - return -ENXIO; - switch (action) { - case INIT: - case PREPARE: - rate_init(plugin); - break; - default: - break; - } - return 0; /* silenty ignore other actions */ -} - -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; - struct rate_priv *data; - struct snd_pcm_plugin *plugin; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - - 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(struct rate_priv) + - src_format->channels * sizeof(struct rate_channel), - &plugin); - if (err < 0) - return err; - 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; - } else { - data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate; - data->func = resample_shrink; - } - data->pos = 0; - rate_init(plugin); - data->old_src_frames = data->old_dst_frames = 0; - plugin->transfer = rate_transfer; - plugin->src_frames = rate_src_frames; - plugin->dst_frames = rate_dst_frames; - plugin->action = rate_action; - *r_plugin = plugin; - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/oss/route.c b/ANDROID_3.4.5/sound/core/oss/route.c deleted file mode 100644 index c8171f57..00000000 --- a/ANDROID_3.4.5/sound/core/oss/route.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Route Plug-In - * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> - * - * - * 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 - * - */ - -#include <linux/time.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include "pcm_plugin.h" - -static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts, - snd_pcm_uframes_t frames, snd_pcm_format_t format) -{ - int dst = 0; - for (; dst < ndsts; ++dst) { - if (dvp->wanted) - snd_pcm_area_silence(&dvp->area, 0, frames, format); - dvp->enabled = 0; - dvp++; - } -} - -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) -{ - dst_channel->enabled = 1; - snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format); -} - -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) -{ - int nsrcs, ndsts, dst; - struct snd_pcm_plugin_channel *dvp; - snd_pcm_format_t format; - - if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) - return -ENXIO; - if (frames == 0) - return 0; - - nsrcs = plugin->src_format.channels; - ndsts = plugin->dst_format.channels; - - 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; - } - - for (dst = 0; dst < ndsts && dst < nsrcs; ++dst) { - copy_area(src_channels, dvp, frames, format); - dvp++; - src_channels++; - } - if (dst < ndsts) - zero_areas(dvp, ndsts - dst, frames, format); - return frames; -} - -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) -{ - struct snd_pcm_plugin *plugin; - int err; - - if (snd_BUG_ON(!r_plugin)) - return -ENXIO; - *r_plugin = NULL; - 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, "route conversion", - src_format, dst_format, 0, &plugin); - if (err < 0) - return err; - - plugin->transfer = route_transfer; - *r_plugin = plugin; - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/pcm.c b/ANDROID_3.4.5/sound/core/pcm.c deleted file mode 100644 index e30e1be3..00000000 --- a/ANDROID_3.4.5/sound/core/pcm.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#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@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); -MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); -MODULE_LICENSE("GPL"); - -static LIST_HEAD(snd_pcm_devices); -static LIST_HEAD(snd_pcm_notify_list); -static DEFINE_MUTEX(register_mutex); - -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 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->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->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) -{ - 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; -} - -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: - { - int device; - - if (get_user(device, (int __user *)arg)) - return -EFAULT; - mutex_lock(®ister_mutex); - device = snd_pcm_next(card, device); - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)arg)) - return -EFAULT; - return 0; - } - case SNDRV_CTL_IOCTL_PCM_INFO: - { - struct snd_pcm_info __user *info; - unsigned int device, subdevice; - 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 (get_user(stream, &info->stream)) - return -EFAULT; - if (stream < 0 || stream > 1) - return -EINVAL; - if (get_user(subdevice, &info->subdevice)) - return -EFAULT; - mutex_lock(®ister_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) { - err = -ENXIO; - goto _error; - } - err = snd_pcm_info_user(substream, info); - _error: - mutex_unlock(®ister_mutex); - return err; - } - case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE: - { - int val; - - if (get_user(val, (int __user *)arg)) - return -EFAULT; - control->prefer_pcm_subdevice = val; - return 0; - } - } - return -ENOIOCTLCMD; -} - -#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v - -static char *snd_pcm_format_names[] = { - FORMAT(S8), - FORMAT(U8), - FORMAT(S16_LE), - FORMAT(S16_BE), - FORMAT(U16_LE), - FORMAT(U16_BE), - FORMAT(S24_LE), - FORMAT(S24_BE), - FORMAT(U24_LE), - FORMAT(U24_BE), - FORMAT(S32_LE), - FORMAT(S32_BE), - FORMAT(U32_LE), - FORMAT(U32_BE), - FORMAT(FLOAT_LE), - FORMAT(FLOAT_BE), - FORMAT(FLOAT64_LE), - FORMAT(FLOAT64_BE), - FORMAT(IEC958_SUBFRAME_LE), - FORMAT(IEC958_SUBFRAME_BE), - FORMAT(MU_LAW), - FORMAT(A_LAW), - FORMAT(IMA_ADPCM), - FORMAT(MPEG), - FORMAT(GSM), - FORMAT(SPECIAL), - FORMAT(S24_3LE), - FORMAT(S24_3BE), - FORMAT(U24_3LE), - FORMAT(U24_3BE), - FORMAT(S20_3LE), - FORMAT(S20_3BE), - FORMAT(U20_3LE), - FORMAT(U20_3BE), - FORMAT(S18_3LE), - FORMAT(S18_3BE), - FORMAT(U18_3LE), - FORMAT(U18_3BE), - FORMAT(G723_24), - FORMAT(G723_24_1B), - FORMAT(G723_40), - FORMAT(G723_40_1B), -}; - -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[] = { - SUBFORMAT(STD), -}; - -static char *snd_pcm_tstamp_mode_names[] = { - TSTAMP(NONE), - TSTAMP(ENABLE), -}; - -static const char *snd_pcm_stream_name(int stream) -{ - return snd_pcm_stream_names[stream]; -} - -static const char *snd_pcm_access_name(snd_pcm_access_t access) -{ - return snd_pcm_access_names[(__force int)access]; -} - -static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat) -{ - return snd_pcm_subformat_names[(__force int)subformat]; -} - -static const char *snd_pcm_tstamp_mode_name(int mode) -{ - return snd_pcm_tstamp_mode_names[mode]; -} - -static const char *snd_pcm_state_name(snd_pcm_state_t state) -{ - return snd_pcm_state_names[(__force int)state]; -} - -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -#include <linux/soundcard.h> - -static const char *snd_pcm_oss_format_name(int format) -{ - switch (format) { - case AFMT_MU_LAW: - return "MU_LAW"; - case AFMT_A_LAW: - return "A_LAW"; - case AFMT_IMA_ADPCM: - return "IMA_ADPCM"; - case AFMT_U8: - return "U8"; - case AFMT_S16_LE: - return "S16_LE"; - case AFMT_S16_BE: - return "S16_BE"; - case AFMT_S8: - return "S8"; - case AFMT_U16_LE: - return "U16_LE"; - case AFMT_U16_BE: - return "U16_BE"; - case AFMT_MPEG: - return "MPEG"; - default: - return "unknown"; - } -} -#endif - -static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, - struct snd_info_buffer *buffer) -{ - struct snd_pcm_info *info; - int err; - - if (! substream) - return; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) { - printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n"); - return; - } - - err = snd_pcm_info(substream, info); - if (err < 0) { - snd_iprintf(buffer, "error %d\n", err); - kfree(info); - return; - } - snd_iprintf(buffer, "card: %d\n", info->card); - snd_iprintf(buffer, "device: %d\n", info->device); - snd_iprintf(buffer, "subdevice: %d\n", info->subdevice); - snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info->stream)); - snd_iprintf(buffer, "id: %s\n", info->id); - snd_iprintf(buffer, "name: %s\n", info->name); - snd_iprintf(buffer, "subname: %s\n", info->subname); - snd_iprintf(buffer, "class: %d\n", info->dev_class); - snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass); - snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count); - snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail); - kfree(info); -} - -static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - snd_pcm_proc_info_read(((struct snd_pcm_str *)entry->private_data)->substream, - buffer); -} - -static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - snd_pcm_proc_info_read(entry->private_data, buffer); -} - -static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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"); - goto unlock; - } - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - snd_iprintf(buffer, "no setup\n"); - 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)); - snd_iprintf(buffer, "subformat: %s\n", snd_pcm_subformat_name(runtime->subformat)); - snd_iprintf(buffer, "channels: %u\n", runtime->channels); - 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); -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) - 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); - snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate); - snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes); - snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods); - snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); - } -#endif - unlock: - mutex_unlock(&substream->pcm->open_mutex); -} - -static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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"); - goto unlock; - } - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - snd_iprintf(buffer, "no setup\n"); - 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, "avail_min: %lu\n", runtime->control->avail_min); - 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); - unlock: - mutex_unlock(&substream->pcm->open_mutex); -} - -static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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"); - goto unlock; - } - memset(&status, 0, sizeof(status)); - err = snd_pcm_status(substream, &status); - if (err < 0) { - snd_iprintf(buffer, "error %d\n", err); - 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", - status.tstamp.tv_sec, status.tstamp.tv_nsec); - snd_iprintf(buffer, "delay : %ld\n", status.delay); - snd_iprintf(buffer, "avail : %ld\n", status.avail); - snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max); - 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); -} - -#ifdef CONFIG_SND_PCM_XRUN_DEBUG -static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_pcm_str *pstr = entry->private_data; - snd_iprintf(buffer, "%d\n", pstr->xrun_debug); -} - -static void snd_pcm_xrun_debug_write(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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(struct snd_pcm_str *pstr) -{ - struct snd_pcm *pcm = pstr->pcm; - struct snd_info_entry *entry; - char name[16]; - - sprintf(name, "pcm%i%c", pcm->device, - pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); - if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL) - return -ENOMEM; - entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - 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, snd_pcm_stream_proc_info_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - pstr->proc_info_entry = entry; - -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", - pstr->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_xrun_debug_read; - entry->c.text.write = snd_pcm_xrun_debug_write; - entry->mode |= S_IWUSR; - entry->private_data = pstr; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - pstr->proc_xrun_debug_entry = entry; -#endif - return 0; -} - -static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) -{ -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - snd_info_free_entry(pstr->proc_xrun_debug_entry); - pstr->proc_xrun_debug_entry = NULL; -#endif - 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(struct snd_pcm_substream *substream) -{ - struct snd_info_entry *entry; - struct snd_card *card; - char name[16]; - - card = substream->pcm->card; - - sprintf(name, "sub%i", substream->number); - if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL) - return -ENOMEM; - entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - substream->proc_root = entry; - - if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { - 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; - } - } - 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, - snd_pcm_substream_proc_hw_params_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - 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, - snd_pcm_substream_proc_sw_params_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - 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, - snd_pcm_substream_proc_status_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - substream->proc_status_entry = entry; - - return 0; -} - -static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) -{ - 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 - * @pcm: the pcm instance - * @stream: the stream direction, SNDRV_PCM_STREAM_XXX - * @substream_count: the number of substreams - * - * Creates a new stream for the pcm. - * The corresponding stream on the pcm must have been empty before - * 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. - */ -int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) -{ - int idx, err; - 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) - mutex_init(&pstr->oss.setup_mutex); -#endif - pstr->stream = stream; - pstr->pcm = pcm; - pstr->substream_count = substream_count; - if (substream_count > 0 && !pcm->internal) { - err = snd_pcm_stream_proc_init(pstr); - if (err < 0) { - snd_printk(KERN_ERR "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) { - snd_printk(KERN_ERR "Cannot allocate PCM substream\n"); - return -ENOMEM; - } - substream->pcm = pcm; - substream->pstr = pstr; - substream->number = idx; - substream->stream = stream; - sprintf(substream->name, "subdevice #%i", idx); - substream->buffer_bytes_max = UINT_MAX; - if (prev == NULL) - pstr->substream = substream; - else - prev->next = substream; - - if (!pcm->internal) { - err = snd_pcm_substream_proc_init(substream); - if (err < 0) { - snd_printk(KERN_ERR "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); - atomic_set(&substream->mmap_count, 0); - prev = substream; - } - return 0; -} - -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) -{ - struct snd_pcm *pcm; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_pcm_dev_free, - .dev_register = snd_pcm_dev_register, - .dev_disconnect = snd_pcm_dev_disconnect, - }; - - if (snd_BUG_ON(!card)) - return -ENXIO; - if (rpcm) - *rpcm = NULL; - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); - if (pcm == NULL) { - snd_printk(KERN_ERR "Cannot allocate PCM\n"); - return -ENOMEM; - } - pcm->card = card; - pcm->device = device; - 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; - } - if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) { - snd_pcm_free(pcm); - return err; - } - 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; - } - if (rpcm) - *rpcm = pcm; - 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(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, - 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(). - * - * Returns 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 defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) - 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) - for (setup = pstr->oss.setup_list; setup; setup = setupn) { - setupn = setup->next; - kfree(setup->task_name); - kfree(setup); - } -#endif -} - -static int snd_pcm_free(struct snd_pcm *pcm) -{ - 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); - snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]); - snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]); - kfree(pcm); - return 0; -} - -static int snd_pcm_dev_free(struct snd_device *device) -{ - struct snd_pcm *pcm = device->device_data; - return snd_pcm_free(pcm); -} - -int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, - struct file *file, - struct snd_pcm_substream **rsubstream) -{ - 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; - - if (snd_BUG_ON(!pcm || !rsubstream)) - return -ENXIO; - *rsubstream = NULL; - pstr = &pcm->streams[stream]; - if (pstr->substream == NULL || pstr->substream_count == 0) - return -ENODEV; - - card = pcm->card; - 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; - if (prefer_subdevice != -1) - break; - } - } - read_unlock(&card->ctl_files_rwlock); - - switch (stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { - for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { - if (SUBSTREAM_BUSY(substream)) - return -EAGAIN; - } - } - break; - case SNDRV_PCM_STREAM_CAPTURE: - if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { - for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { - if (SUBSTREAM_BUSY(substream)) - return -EAGAIN; - } - } - break; - default: - 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) - goto __ok; - } - for (substream = pstr->substream; substream; substream = substream->next) - if (!SUBSTREAM_BUSY(substream)) - break; - __ok: - if (substream == NULL) - return -EAGAIN; - - runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); - if (runtime == NULL) - return -ENOMEM; - - size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)); - runtime->status = snd_malloc_pages(size, GFP_KERNEL); - if (runtime->status == NULL) { - kfree(runtime); - return -ENOMEM; - } - memset((void*)runtime->status, 0, size); - - 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(struct snd_pcm_mmap_status))); - kfree(runtime); - return -ENOMEM; - } - memset((void*)runtime->control, 0, size); - - init_waitqueue_head(&runtime->sleep); - 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_detach_substream(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - - if (PCM_RUNTIME_CHECK(substream)) - return; - runtime = substream->runtime; - if (runtime->private_free != NULL) - runtime->private_free(runtime); - 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 - if (runtime->hwptr_log) - kfree(runtime->hwptr_log); -#endif - kfree(runtime); - substream->runtime = NULL; - put_pid(substream->pid); - substream->pid = NULL; - substream->pstr->substream_opened--; -} - -static ssize_t show_pcm_class(struct device *dev, - struct device_attribute *attr, char *buf) -{ - 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 struct device_attribute pcm_attrs = - __ATTR(pcm_class, S_IRUGO, show_pcm_class, 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]; - struct snd_pcm *pcm; - struct device *dev; - - if (snd_BUG_ON(!device || !device->device_data)) - return -ENXIO; - pcm = device->device_data; - mutex_lock(®ister_mutex); - err = snd_pcm_add(pcm); - if (err) { - mutex_unlock(®ister_mutex); - return err; - } - for (cidx = 0; cidx < 2; cidx++) { - int devtype = -1; - 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); - devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; - break; - case SNDRV_PCM_STREAM_CAPTURE: - sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device); - devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; - break; - } - /* 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(®ister_mutex); - return err; - } - snd_add_device_sysfs_file(devtype, pcm->card, pcm->device, - &pcm_attrs); - for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) - snd_pcm_timer_init(substream); - } - - list_for_each_entry(notify, &snd_pcm_notify_list, list) - notify->n_register(pcm); - - mutex_unlock(®ister_mutex); - return 0; -} - -static int snd_pcm_dev_disconnect(struct snd_device *device) -{ - struct snd_pcm *pcm = device->device_data; - struct snd_pcm_notify *notify; - struct snd_pcm_substream *substream; - int cidx, devtype; - - mutex_lock(®ister_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) { - snd_pcm_stream_lock_irq(substream); - if (substream->runtime) { - substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; - 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); - } - for (cidx = 0; cidx < 2; cidx++) { - devtype = -1; - switch (cidx) { - case SNDRV_PCM_STREAM_PLAYBACK: - devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; - break; - case SNDRV_PCM_STREAM_CAPTURE: - devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; - break; - } - snd_unregister_device(devtype, pcm->card, pcm->device); - } - mutex_unlock(&pcm->open_mutex); - unlock: - mutex_unlock(®ister_mutex); - return 0; -} - -int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) -{ - struct snd_pcm *pcm; - - if (snd_BUG_ON(!notify || - !notify->n_register || - !notify->n_unregister || - !notify->n_disconnect)) - return -EINVAL; - mutex_lock(®ister_mutex); - if (nfree) { - list_del(¬ify->list); - list_for_each_entry(pcm, &snd_pcm_devices, list) - notify->n_unregister(pcm); - } else { - list_add_tail(¬ify->list, &snd_pcm_notify_list); - list_for_each_entry(pcm, &snd_pcm_devices, list) - notify->n_register(pcm); - } - mutex_unlock(®ister_mutex); - return 0; -} - -EXPORT_SYMBOL(snd_pcm_notify); - -#ifdef CONFIG_PROC_FS -/* - * Info interface - */ - -static void snd_pcm_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_pcm *pcm; - - mutex_lock(®ister_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); - if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) - snd_iprintf(buffer, " : capture %i", - pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count); - snd_iprintf(buffer, "\n"); - } - mutex_unlock(®ister_mutex); -} - -static struct snd_info_entry *snd_pcm_proc_entry; - -static void snd_pcm_proc_init(void) -{ - struct snd_info_entry *entry; - - if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { - 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; -} - -static void __exit alsa_pcm_exit(void) -{ - snd_ctl_unregister_ioctl(snd_pcm_control_ioctl); - snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl); - snd_pcm_proc_done(); -} - -module_init(alsa_pcm_init) -module_exit(alsa_pcm_exit) diff --git a/ANDROID_3.4.5/sound/core/pcm_compat.c b/ANDROID_3.4.5/sound/core/pcm_compat.c deleted file mode 100644 index 91cdf943..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_compat.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for PCM API - * Copyright (c) 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; 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 - * - */ - -/* This file included from pcm_native.c */ - -#include <linux/compat.h> -#include <linux/slab.h> - -static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, - s32 __user *src) -{ - snd_pcm_sframes_t delay; - mm_segment_t fs; - int err; - - fs = snd_enter_user(); - err = snd_pcm_delay(substream, &delay); - snd_leave_user(fs); - if (err < 0) - return err; - if (put_user(delay, src)) - return -EFAULT; - return err; -} - -static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, - u32 __user *src) -{ - snd_pcm_uframes_t frames; - int err; - - if (get_user(frames, src)) - return -EFAULT; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_pcm_playback_rewind(substream, frames); - else - err = snd_pcm_capture_rewind(substream, frames); - if (put_user(err, src)) - return -EFAULT; - return err < 0 ? err : 0; -} - -static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream, - u32 __user *src) -{ - snd_pcm_uframes_t frames; - int err; - - if (get_user(frames, src)) - return -EFAULT; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_pcm_playback_forward(substream, frames); - else - err = snd_pcm_capture_forward(substream, frames); - if (put_user(err, src)) - return -EFAULT; - return err < 0 ? err : 0; -} - -struct snd_pcm_hw_params32 { - u32 flags; - 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; - u32 msbits; - u32 rate_num; - u32 rate_den; - u32 fifo_size; - unsigned char reserved[64]; -}; - -struct snd_pcm_sw_params32 { - s32 tstamp_mode; - u32 period_step; - u32 sleep_min; - u32 avail_min; - u32 xfer_align; - u32 start_threshold; - u32 stop_threshold; - u32 silence_threshold; - u32 silence_size; - u32 boundary; - unsigned char reserved[64]; -}; - -/* recalcuate the boundary within 32bit */ -static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime) -{ - snd_pcm_uframes_t boundary; - - if (! runtime->buffer_size) - return 0; - boundary = runtime->buffer_size; - while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) - boundary *= 2; - return boundary; -} - -static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, - struct snd_pcm_sw_params32 __user *src) -{ - struct snd_pcm_sw_params params; - snd_pcm_uframes_t boundary; - int err; - - memset(¶ms, 0, sizeof(params)); - if (get_user(params.tstamp_mode, &src->tstamp_mode) || - get_user(params.period_step, &src->period_step) || - get_user(params.sleep_min, &src->sleep_min) || - get_user(params.avail_min, &src->avail_min) || - get_user(params.xfer_align, &src->xfer_align) || - get_user(params.start_threshold, &src->start_threshold) || - get_user(params.stop_threshold, &src->stop_threshold) || - get_user(params.silence_threshold, &src->silence_threshold) || - get_user(params.silence_size, &src->silence_size)) - return -EFAULT; - /* - * Check silent_size parameter. Since we have 64bit boundary, - * silence_size must be compared with the 32bit boundary. - */ - boundary = recalculate_boundary(substream->runtime); - if (boundary && params.silence_size >= boundary) - params.silence_size = substream->runtime->boundary; - err = snd_pcm_sw_params(substream, ¶ms); - if (err < 0) - return err; - if (boundary && put_user(boundary, &src->boundary)) - return -EFAULT; - return err; -} - -struct snd_pcm_channel_info32 { - u32 channel; - u32 offset; - u32 first; - u32 step; -}; - -static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream, - struct snd_pcm_channel_info32 __user *src) -{ - struct snd_pcm_channel_info info; - int err; - - if (get_user(info.channel, &src->channel) || - get_user(info.offset, &src->offset) || - get_user(info.first, &src->first) || - get_user(info.step, &src->step)) - return -EFAULT; - err = snd_pcm_channel_info(substream, &info); - if (err < 0) - return err; - if (put_user(info.channel, &src->channel) || - put_user(info.offset, &src->offset) || - put_user(info.first, &src->first) || - put_user(info.step, &src->step)) - return -EFAULT; - return err; -} - -struct snd_pcm_status32 { - s32 state; - struct compat_timespec trigger_tstamp; - struct compat_timespec tstamp; - u32 appl_ptr; - u32 hw_ptr; - s32 delay; - u32 avail; - u32 avail_max; - u32 overrange; - s32 suspended_state; - unsigned char reserved[60]; -} __attribute__((packed)); - - -static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, - struct snd_pcm_status32 __user *src) -{ - struct snd_pcm_status status; - int err; - - err = snd_pcm_status(substream, &status); - if (err < 0) - 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) || - 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)) - return -EFAULT; - - return err; -} - -/* both for HW_PARAMS and HW_REFINE */ -static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, - int refine, - struct snd_pcm_hw_params32 __user *data32) -{ - struct snd_pcm_hw_params *data; - struct snd_pcm_runtime *runtime; - int err; - - if (! (runtime = substream->runtime)) - return -ENOTTY; - - /* only fifo_size is different, so just copy all */ - data = memdup_user(data32, sizeof(*data32)); - if (IS_ERR(data)) - return PTR_ERR(data); - - if (refine) - err = snd_pcm_hw_refine(substream, data); - else - err = snd_pcm_hw_params(substream, data); - if (err < 0) - goto error; - if (copy_to_user(data32, data, sizeof(*data32)) || - put_user(data->fifo_size, &data32->fifo_size)) { - err = -EFAULT; - goto error; - } - - if (! refine) { - unsigned int new_boundary = recalculate_boundary(runtime); - if (new_boundary) - runtime->boundary = new_boundary; - } - error: - kfree(data); - return err; -} - - -/* - */ -struct snd_xferi32 { - s32 result; - u32 buf; - u32 frames; -}; - -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; - int err; - - if (! substream->runtime) - return -ENOTTY; - if (substream->stream != dir) - return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - - if (get_user(buf, &data32->buf) || - get_user(frames, &data32->frames)) - return -EFAULT; - - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_pcm_lib_write(substream, compat_ptr(buf), frames); - else - err = snd_pcm_lib_read(substream, compat_ptr(buf), frames); - if (err < 0) - return err; - /* copy the result */ - if (put_user(err, &data32->result)) - return -EFAULT; - return 0; -} - - -/* snd_xfern needs remapping of bufs */ -struct snd_xfern32 { - s32 result; - u32 bufs; /* this is void **; */ - u32 frames; -}; - -/* - * xfern ioctl nees to copy (up to) 128 pointers on stack. - * although we may pass the copied pointers through f_op->ioctl, but the ioctl - * 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(struct snd_pcm_substream *substream, - int dir, struct snd_xfern32 __user *data32) -{ - compat_caddr_t buf; - compat_caddr_t __user *bufptr; - u32 frames; - void __user **bufs; - int err, ch, i; - - if (! substream->runtime) - return -ENOTTY; - if (substream->stream != dir) - return -EINVAL; - - if ((ch = substream->runtime->channels) > 128) - return -EINVAL; - if (get_user(buf, &data32->bufs) || - get_user(frames, &data32->frames)) - return -EFAULT; - bufptr = compat_ptr(buf); - bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL); - if (bufs == NULL) - return -ENOMEM; - for (i = 0; i < ch; i++) { - u32 ptr; - if (get_user(ptr, bufptr)) { - kfree(bufs); - return -EFAULT; - } - bufs[i] = compat_ptr(ptr); - bufptr++; - } - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_pcm_lib_writev(substream, bufs, frames); - else - err = snd_pcm_lib_readv(substream, bufs, frames); - if (err >= 0) { - if (put_user(err, &data32->result)) - err = -EFAULT; - } - kfree(bufs); - return err; -} - - -struct snd_pcm_mmap_status32 { - s32 state; - s32 pad1; - u32 hw_ptr; - struct compat_timespec tstamp; - s32 suspended_state; -} __attribute__((packed)); - -struct snd_pcm_mmap_control32 { - u32 appl_ptr; - u32 avail_min; -}; - -struct snd_pcm_sync_ptr32 { - u32 flags; - union { - struct snd_pcm_mmap_status32 status; - unsigned char reserved[64]; - } s; - union { - struct snd_pcm_mmap_control32 control; - unsigned char reserved[64]; - } c; -} __attribute__((packed)); - -static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, - struct snd_pcm_sync_ptr32 __user *src) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - volatile struct snd_pcm_mmap_status *status; - volatile struct snd_pcm_mmap_control *control; - u32 sflags; - struct snd_pcm_mmap_control scontrol; - struct snd_pcm_mmap_status sstatus; - snd_pcm_uframes_t boundary; - int err; - - if (snd_BUG_ON(!runtime)) - return -EINVAL; - - if (get_user(sflags, &src->flags) || - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - get_user(scontrol.avail_min, &src->c.control.avail_min)) - return -EFAULT; - if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { - err = snd_pcm_hwsync(substream); - if (err < 0) - return err; - } - status = runtime->status; - control = runtime->control; - boundary = recalculate_boundary(runtime); - if (! boundary) - boundary = 0x7fffffff; - snd_pcm_stream_lock_irq(substream); - /* FIXME: we should consider the boundary for the sync from app */ - if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = scontrol.appl_ptr; - else - scontrol.appl_ptr = control->appl_ptr % boundary; - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = scontrol.avail_min; - else - scontrol.avail_min = control->avail_min; - sstatus.state = status->state; - sstatus.hw_ptr = status->hw_ptr % boundary; - sstatus.tstamp = status->tstamp; - sstatus.suspended_state = status->suspended_state; - 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) || - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - put_user(scontrol.avail_min, &src->c.control.avail_min)) - return -EFAULT; - - return 0; -} - - -/* - */ -enum { - 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 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 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) -{ - struct snd_pcm_file *pcm_file; - struct snd_pcm_substream *substream; - void __user *argp = compat_ptr(arg); - - pcm_file = file->private_data; - if (! pcm_file) - return -ENOTTY; - substream = pcm_file->substream; - if (! substream) - return -ENOTTY; - - /* - * When PCM is used on 32bit mode, we need to disable - * mmap of PCM status/control records because of the size - * incompatibility. - */ - 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: - case SNDRV_PCM_IOCTL_START: - case SNDRV_PCM_IOCTL_DROP: - case SNDRV_PCM_IOCTL_DRAIN: - case SNDRV_PCM_IOCTL_PAUSE: - case SNDRV_PCM_IOCTL_HW_FREE: - case SNDRV_PCM_IOCTL_RESUME: - case SNDRV_PCM_IOCTL_XRUN: - case SNDRV_PCM_IOCTL_LINK: - case SNDRV_PCM_IOCTL_UNLINK: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return snd_pcm_playback_ioctl1(file, substream, cmd, argp); - else - return snd_pcm_capture_ioctl1(file, substream, cmd, argp); - case SNDRV_PCM_IOCTL_HW_REFINE32: - return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); - case SNDRV_PCM_IOCTL_HW_PARAMS32: - return snd_pcm_ioctl_hw_params_compat(substream, 0, argp); - case SNDRV_PCM_IOCTL_SW_PARAMS32: - return snd_pcm_ioctl_sw_params_compat(substream, argp); - case SNDRV_PCM_IOCTL_STATUS32: - return snd_pcm_status_user_compat(substream, argp); - case SNDRV_PCM_IOCTL_SYNC_PTR32: - return snd_pcm_ioctl_sync_ptr_compat(substream, argp); - case SNDRV_PCM_IOCTL_CHANNEL_INFO32: - return snd_pcm_ioctl_channel_info_compat(substream, argp); - case SNDRV_PCM_IOCTL_WRITEI_FRAMES32: - return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp); - case SNDRV_PCM_IOCTL_READI_FRAMES32: - return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp); - case SNDRV_PCM_IOCTL_WRITEN_FRAMES32: - return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp); - case SNDRV_PCM_IOCTL_READN_FRAMES32: - return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp); - case SNDRV_PCM_IOCTL_DELAY32: - return snd_pcm_ioctl_delay_compat(substream, argp); - case SNDRV_PCM_IOCTL_REWIND32: - return snd_pcm_ioctl_rewind_compat(substream, argp); - case SNDRV_PCM_IOCTL_FORWARD32: - return snd_pcm_ioctl_forward_compat(substream, argp); - } - - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/pcm_lib.c b/ANDROID_3.4.5/sound/core/pcm_lib.c deleted file mode 100644 index 4d189411..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_lib.c +++ /dev/null @@ -1,2289 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Abramo Bagnara <abramo@alsa-project.org> - * - * - * 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/slab.h> -#include <linux/time.h> -#include <linux/math64.h> -#include <linux/export.h> -#include <sound/core.h> -#include <sound/control.h> -#include <sound/info.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/timer.h> - -/* - * fill ring buffer with silence - * runtime->silence_start: starting pointer to silence area - * runtime->silence_filled: size filled with silence - * runtime->silence_threshold: threshold from application - * runtime->silence_size: maximal size from application - * - * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately - */ -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t frames, ofs, transfer; - - if (runtime->silence_size < runtime->boundary) { - snd_pcm_sframes_t noise_dist, n; - if (runtime->silence_start != runtime->control->appl_ptr) { - n = runtime->control->appl_ptr - runtime->silence_start; - if (n < 0) - n += runtime->boundary; - if ((snd_pcm_uframes_t)n < runtime->silence_filled) - runtime->silence_filled -= n; - else - runtime->silence_filled = 0; - runtime->silence_start = runtime->control->appl_ptr; - } - if (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; - frames = runtime->silence_threshold - noise_dist; - if (frames > runtime->silence_size) - frames = runtime->silence_size; - } 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) % - runtime->boundary; - } else { - ofs = runtime->status->hw_ptr; - frames = new_hw_ptr - ofs; - if ((snd_pcm_sframes_t)frames < 0) - frames += runtime->boundary; - runtime->silence_filled -= frames; - if ((snd_pcm_sframes_t)runtime->silence_filled < 0) { - runtime->silence_filled = 0; - runtime->silence_start = new_hw_ptr; - } else { - runtime->silence_start = ofs; - } - } - frames = runtime->buffer_size - runtime->silence_filled; - } - if (snd_BUG_ON(frames > runtime->buffer_size)) - return; - if (frames == 0) - return; - 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 || - runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - if (substream->ops->silence) { - int err; - err = substream->ops->silence(substream, -1, ofs, transfer); - 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); - } - } else { - unsigned int c; - unsigned int channels = runtime->channels; - if (substream->ops->silence) { - for (c = 0; c < channels; ++c) { - int err; - err = substream->ops->silence(substream, c, ofs, transfer); - snd_BUG_ON(err < 0); - } - } else { - size_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c) { - char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); - snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); - } - } - } - runtime->silence_filled += transfer; - frames -= transfer; - ofs = 0; - } -} - -#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); - if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printd(KERN_DEBUG "XRUN: %s\n", name); - dump_stack_on_xrun(substream); - } -} - -#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); \ - if (printk_ratelimit()) { \ - snd_printd("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; -} - -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; - snd_printd("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; -} - -#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; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail > runtime->avail_max) - runtime->avail_max = avail; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { - if (avail >= runtime->buffer_size) { - snd_pcm_drain_done(substream); - return -EPIPE; - } - } else { - if (avail >= runtime->stop_threshold) { - xrun(substream); - return -EPIPE; - } - } - 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 int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, - unsigned int in_interrupt) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; - snd_pcm_sframes_t hdelta, delta; - unsigned long jdelta; - - old_hw_ptr = runtime->status->hw_ptr; - pos = substream->ops->pointer(substream); - if (pos == SNDRV_PCM_POS_XRUN) { - xrun(substream); - return -EPIPE; - } - if (pos >= runtime->buffer_size) { - if (printk_ratelimit()) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); - xrun_log_show(substream); - snd_printd(KERN_ERR "BUG: %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 = 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; - new_hw_ptr = hw_base + pos; - goto __delta; - } - } - } - /* 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; - 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)); - snd_printd("%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 = 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; - 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 = 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; - 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_jiffies = jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - - return snd_pcm_update_state(substream, runtime); -} - -/* CAUTION: call it with irq disabled */ -int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) -{ - return snd_pcm_update_hw_ptr0(substream, 0); -} - -/** - * snd_pcm_set_ops - set the PCM operators - * @pcm: the pcm instance - * @direction: stream direction, SNDRV_PCM_STREAM_XXX - * @ops: the operator table - * - * Sets the given PCM operators to the pcm instance. - */ -void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops) -{ - 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 - * @substream: the pcm substream - * - * Sets the PCM sync identifier for the card. - */ -void snd_pcm_set_sync(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = -1; - runtime->sync.id32[2] = -1; - runtime->sync.id32[3] = -1; -} - -EXPORT_SYMBOL(snd_pcm_set_sync); - -/* - * Standard ioctl routine - */ - -static inline unsigned int div32(unsigned int a, unsigned int b, - unsigned int *r) -{ - if (b == 0) { - *r = 0; - return UINT_MAX; - } - *r = a % b; - return a / b; -} - -static inline unsigned int div_down(unsigned int a, unsigned int b) -{ - if (b == 0) - return UINT_MAX; - return a / b; -} - -static inline unsigned int div_up(unsigned int a, unsigned int b) -{ - unsigned int r; - unsigned int q; - if (b == 0) - return UINT_MAX; - q = div32(a, b, &r); - if (r) - ++q; - return q; -} - -static inline unsigned int mul(unsigned int a, unsigned int b) -{ - if (a == 0) - return 0; - if (div_down(UINT_MAX, a) < b) - return UINT_MAX; - return a * b; -} - -static inline unsigned int muldiv32(unsigned int a, unsigned int b, - unsigned int c, unsigned int *r) -{ - u_int64_t n = (u_int64_t) a * b; - if (c == 0) { - snd_BUG_ON(!n); - *r = 0; - return UINT_MAX; - } - n = div_u64_rem(n, c, r); - if (n >= UINT_MAX) { - *r = 0; - return UINT_MAX; - } - return n; -} - -/** - * snd_interval_refine - refine the interval value of configurator - * @i: the interval value to refine - * @v: the interval value to refer to - * - * Refines the interval value with the reference value. - * 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. - */ -int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) -{ - int changed = 0; - if (snd_BUG_ON(snd_interval_empty(i))) - return -EINVAL; - if (i->min < v->min) { - i->min = v->min; - i->openmin = v->openmin; - changed = 1; - } else if (i->min == v->min && !i->openmin && v->openmin) { - i->openmin = 1; - changed = 1; - } - if (i->max > v->max) { - i->max = v->max; - i->openmax = v->openmax; - changed = 1; - } else if (i->max == v->max && !i->openmax && v->openmax) { - i->openmax = 1; - changed = 1; - } - if (!i->integer && v->integer) { - i->integer = 1; - changed = 1; - } - if (i->integer) { - if (i->openmin) { - i->min++; - i->openmin = 0; - } - if (i->openmax) { - i->max--; - i->openmax = 0; - } - } else if (!i->openmin && !i->openmax && i->min == i->max) - i->integer = 1; - if (snd_interval_checkempty(i)) { - snd_interval_none(i); - return -EINVAL; - } - return changed; -} - -EXPORT_SYMBOL(snd_interval_refine); - -static int snd_interval_refine_first(struct snd_interval *i) -{ - if (snd_BUG_ON(snd_interval_empty(i))) - return -EINVAL; - if (snd_interval_single(i)) - return 0; - i->max = i->min; - i->openmax = i->openmin; - if (i->openmax) - i->max++; - return 1; -} - -static int snd_interval_refine_last(struct snd_interval *i) -{ - if (snd_BUG_ON(snd_interval_empty(i))) - return -EINVAL; - if (snd_interval_single(i)) - return 0; - i->min = i->max; - i->openmin = i->openmax; - if (i->openmin) - i->min--; - return 1; -} - -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); - return; - } - c->empty = 0; - c->min = mul(a->min, b->min); - c->openmin = (a->openmin || b->openmin); - c->max = mul(a->max, b->max); - c->openmax = (a->openmax || b->openmax); - c->integer = (a->integer && b->integer); -} - -/** - * snd_interval_div - refine the interval value with division - * @a: dividend - * @b: divisor - * @c: quotient - * - * c = a / b - * - * Returns non-zero if the value is changed, zero if not changed. - */ -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) { - snd_interval_none(c); - return; - } - c->empty = 0; - c->min = div32(a->min, b->max, &r); - c->openmin = (r || a->openmin || b->openmax); - if (b->min > 0) { - c->max = div32(a->max, b->min, &r); - if (r) { - c->max++; - c->openmax = 1; - } else - c->openmax = (a->openmax || b->openmin); - } else { - c->max = UINT_MAX; - c->openmax = 0; - } - c->integer = 0; -} - -/** - * snd_interval_muldivk - refine the interval value - * @a: dividend 1 - * @b: dividend 2 - * @k: divisor (as integer) - * @c: result - * - * c = a * b / k - * - * Returns non-zero if the value is changed, zero if not changed. - */ -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) { - snd_interval_none(c); - return; - } - c->empty = 0; - c->min = muldiv32(a->min, b->min, k, &r); - c->openmin = (r || a->openmin || b->openmin); - c->max = muldiv32(a->max, b->max, k, &r); - if (r) { - c->max++; - c->openmax = 1; - } else - c->openmax = (a->openmax || b->openmax); - c->integer = 0; -} - -/** - * snd_interval_mulkdiv - refine the interval value - * @a: dividend 1 - * @k: dividend 2 (as integer) - * @b: divisor - * @c: result - * - * c = a * k / b - * - * Returns non-zero if the value is changed, zero if not changed. - */ -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) { - snd_interval_none(c); - return; - } - c->empty = 0; - c->min = muldiv32(a->min, k, b->max, &r); - c->openmin = (r || a->openmin || b->openmax); - if (b->min > 0) { - c->max = muldiv32(a->max, k, b->min, &r); - if (r) { - c->max++; - c->openmax = 1; - } else - c->openmax = (a->openmax || b->openmin); - } else { - c->max = UINT_MAX; - c->openmax = 0; - } - c->integer = 0; -} - -/* ---- */ - - -/** - * snd_interval_ratnum - refine the interval value - * @i: interval to refine - * @rats_count: number of ratnum_t - * @rats: ratnum_t 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. - */ -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_den; - int best_diff; - unsigned int k; - 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) { - unsigned int num = rats[k].num; - unsigned int den; - unsigned int q = i->min; - int diff; - if (q == 0) - q = 1; - den = div_up(num, q); - if (den < rats[k].den_min) - continue; - if (den > rats[k].den_max) - den = rats[k].den_max; - else { - unsigned int r; - r = (den - rats[k].den_min) % rats[k].den_step; - if (r != 0) - den -= r; - } - diff = num - q * den; - if (diff < 0) - diff = -diff; - if (best_num == 0 || - diff * best_den < best_diff * den) { - best_diff = diff; - best_den = den; - best_num = num; - } - } - if (best_den == 0) { - i->empty = 1; - return -EINVAL; - } - 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; - unsigned int den; - unsigned int q = i->max; - int diff; - if (q == 0) { - i->empty = 1; - return -EINVAL; - } - den = div_down(num, q); - if (den > rats[k].den_max) - continue; - if (den < rats[k].den_min) - den = rats[k].den_min; - else { - unsigned int r; - r = (den - rats[k].den_min) % rats[k].den_step; - if (r != 0) - 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; - best_den = den; - best_num = num; - } - } - if (best_den == 0) { - i->empty = 1; - return -EINVAL; - } - t.max = div_up(best_num, best_den); - t.openmax = !!(best_num % best_den); - t.integer = 0; - err = snd_interval_refine(i, &t); - if (err < 0) - 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 = result_num; - if (denp) - *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 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. - */ -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; - struct snd_interval t; - int err; - - best_num = best_den = best_diff = 0; - for (k = 0; k < rats_count; ++k) { - unsigned int num; - unsigned int den = rats[k].den; - unsigned int q = i->min; - int diff; - num = mul(q, den); - if (num > rats[k].num_max) - continue; - if (num < rats[k].num_min) - num = rats[k].num_max; - else { - unsigned int r; - r = (num - rats[k].num_min) % rats[k].num_step; - if (r != 0) - num += rats[k].num_step - r; - } - diff = num - q * den; - if (best_num == 0 || - diff * best_den < best_diff * den) { - best_diff = diff; - best_den = den; - best_num = num; - } - } - if (best_den == 0) { - i->empty = 1; - return -EINVAL; - } - t.min = div_down(best_num, best_den); - t.openmin = !!(best_num % best_den); - - best_num = best_den = best_diff = 0; - for (k = 0; k < rats_count; ++k) { - unsigned int num; - unsigned int den = rats[k].den; - unsigned int q = i->max; - int diff; - num = mul(q, den); - if (num < rats[k].num_min) - continue; - if (num > rats[k].num_max) - num = rats[k].num_max; - else { - unsigned int r; - r = (num - rats[k].num_min) % rats[k].num_step; - if (r != 0) - num -= r; - } - diff = q * den - num; - if (best_num == 0 || - diff * best_den < best_diff * den) { - best_diff = diff; - best_den = den; - best_num = num; - } - } - if (best_den == 0) { - i->empty = 1; - return -EINVAL; - } - t.max = div_up(best_num, best_den); - t.openmax = !!(best_num % best_den); - t.integer = 0; - err = snd_interval_refine(i, &t); - if (err < 0) - return err; - - if (snd_interval_single(i)) { - if (nump) - *nump = best_num; - if (denp) - *denp = best_den; - } - return err; -} - -/** - * snd_interval_list - refine the interval value from the list - * @i: the interval value to refine - * @count: the number of elements in the list - * @list: the value list - * @mask: the bit-mask to evaluate - * - * Refines the interval value from the list. - * 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. - */ -int snd_interval_list(struct snd_interval *i, unsigned int count, - const unsigned int *list, unsigned int mask) -{ - unsigned int k; - 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 (!snd_interval_test(i, list[k])) - continue; - list_range.min = min(list_range.min, list[k]); - list_range.max = max(list_range.max, list[k]); - } - return snd_interval_refine(i, &list_range); -} - -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; - n = (i->min - min) % step; - if (n != 0 || i->openmin) { - i->min += step - n; - changed = 1; - } - n = (i->max - min) % step; - if (n != 0 || i->openmax) { - i->max -= n; - changed = 1; - } - if (snd_interval_checkempty(i)) { - i->empty = 1; - return -EINVAL; - } - return changed; -} - -/* Info constraints helpers */ - -/** - * snd_pcm_hw_rule_add - add the hw-constraint rule - * @runtime: the pcm runtime instance - * @cond: condition bits - * @var: the variable to evaluate - * @func: the evaluation function - * @private: the private data pointer passed to function - * @dep: the dependent variables - * - * Returns zero if successful, or a negative error code on failure. - */ -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, ...) -{ - 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) { - struct snd_pcm_hw_rule *new; - unsigned int new_rules = constrs->rules_all + 16; - new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL); - if (!new) { - va_end(args); - return -ENOMEM; - } - if (constrs->rules) { - memcpy(new, constrs->rules, - constrs->rules_num * sizeof(*c)); - kfree(constrs->rules); - } - constrs->rules = new; - constrs->rules_all = new_rules; - } - c = &constrs->rules[constrs->rules_num]; - c->cond = cond; - c->func = func; - c->var = var; - c->private = private; - k = 0; - while (1) { - if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) { - va_end(args); - return -EINVAL; - } - c->deps[k++] = dep; - if (dep < 0) - break; - dep = va_arg(args, int); - } - constrs->rules_num++; - va_end(args); - return 0; -} - -EXPORT_SYMBOL(snd_pcm_hw_rule_add); - -/** - * 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 32-bit mask parameter. - */ -int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, - u_int32_t mask) -{ - 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) - return -EINVAL; - return 0; -} - -/** - * 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 64-bit mask parameter. - */ -int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, - u_int64_t mask) -{ - 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 */ - if (! maskp->bits[0] && ! maskp->bits[1]) - return -EINVAL; - return 0; -} - -/** - * 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. - */ -int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var) -{ - 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 - 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. - */ -int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, - unsigned int min, unsigned int max) -{ - struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; - struct snd_interval t; - t.min = min; - t.max = max; - t.openmin = t.openmax = 0; - t.integer = 0; - return snd_interval_refine(constrs_interval(constrs, var), &t); -} - -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) -{ - 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 - 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. - */ -int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, - unsigned int cond, - snd_pcm_hw_param_t var, - struct snd_pcm_hw_constraint_list *l) -{ - return snd_pcm_hw_rule_add(runtime, cond, var, - snd_pcm_hw_rule_list, l, - var, -1); -} - -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) -{ - 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), - r->nrats, r->rats, &num, &den); - if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { - params->rate_num = num; - params->rate_den = den; - } - return err; -} - -/** - * 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: struct snd_ratnums constriants - */ -int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, - unsigned int cond, - snd_pcm_hw_param_t var, - struct snd_pcm_hw_constraint_ratnums *r) -{ - return snd_pcm_hw_rule_add(runtime, cond, var, - snd_pcm_hw_rule_ratnums, r, - var, -1); -} - -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) -{ - 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); - if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { - params->rate_num = num; - params->rate_den = den; - } - return err; -} - -/** - * 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: struct snd_ratdens constriants - */ -int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, - unsigned int cond, - snd_pcm_hw_param_t var, - struct snd_pcm_hw_constraint_ratdens *r) -{ - return snd_pcm_hw_rule_add(runtime, cond, var, - snd_pcm_hw_rule_ratdens, r, - var, -1); -} - -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; - 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 - add a hw constraint msbits rule - * @runtime: PCM runtime instance - * @cond: condition bits - * @width: sample bits width - * @msbits: msbits width - */ -int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, - unsigned int cond, - unsigned int width, - unsigned int msbits) -{ - unsigned long l = (msbits << 16) | width; - return snd_pcm_hw_rule_add(runtime, cond, -1, - snd_pcm_hw_rule_msbits, - (void*) l, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -} - -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 - 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 - */ -int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, - unsigned int cond, - snd_pcm_hw_param_t var, - unsigned long step) -{ - return snd_pcm_hw_rule_add(runtime, cond, var, - snd_pcm_hw_rule_step, (void *) step, - var, -1); -} - -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 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, - 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30 - }; - return snd_interval_list(hw_param_interval(params, rule->var), - ARRAY_SIZE(pow2_sizes), pow2_sizes, 0); -} - -/** - * 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 - */ -int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, - unsigned int cond, - snd_pcm_hw_param_t var) -{ - return snd_pcm_hw_rule_add(runtime, cond, var, - snd_pcm_hw_rule_pow2, NULL, - var, -1); -} - -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 - */ -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(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - if (hw_is_mask(var)) { - snd_mask_any(hw_param_mask(params, var)); - params->cmask |= 1 << var; - params->rmask |= 1 << var; - return; - } - if (hw_is_interval(var)) { - snd_interval_any(hw_param_interval(params, var)); - params->cmask |= 1 << var; - params->rmask |= 1 << var; - return; - } - snd_BUG(); -} - -void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) -{ - unsigned int k; - memset(params, 0, sizeof(*params)); - for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) - _snd_pcm_hw_param_any(params, k); - for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) - _snd_pcm_hw_param_any(params, k); - params->info = ~0U; -} - -EXPORT_SYMBOL(_snd_pcm_hw_params_any); - -/** - * 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 - * - * Return the value for field @var if it's fixed in configuration space - * defined by @params. Return -%EINVAL otherwise. - */ -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 struct snd_mask *mask = hw_param_mask_c(params, var); - if (!snd_mask_single(mask)) - return -EINVAL; - if (dir) - *dir = 0; - return snd_mask_value(mask); - } - if (hw_is_interval(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); - } - return -EINVAL; -} - -EXPORT_SYMBOL(snd_pcm_hw_param_value); - -void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - if (hw_is_mask(var)) { - snd_mask_none(hw_param_mask(params, var)); - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } else if (hw_is_interval(var)) { - snd_interval_none(hw_param_interval(params, var)); - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } else { - snd_BUG(); - } -} - -EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); - -static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - int changed; - if (hw_is_mask(var)) - 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 - return -EINVAL; - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - - -/** - * 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 - * - * Inside configuration space defined by @params remove from @var all - * values > minimum. Reduce configuration space accordingly. - * Return the minimum. - */ -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); - if (snd_BUG_ON(err < 0)) - return err; - } - return snd_pcm_hw_param_value(params, var, dir); -} - -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; - if (hw_is_mask(var)) - 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 - return -EINVAL; - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - - -/** - * 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 - * - * Inside configuration space defined by @params remove from @var all - * values < maximum. Reduce configuration space accordingly. - * Return the maximum. - */ -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_last(params, var); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (snd_BUG_ON(err < 0)) - return err; - } - return snd_pcm_hw_param_value(params, var, dir); -} - -EXPORT_SYMBOL(snd_pcm_hw_param_last); - -/** - * 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. - * 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 - */ -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; -} - -static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, - void *arg) -{ - 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 - runtime->status->hw_ptr = 0; - snd_pcm_stream_unlock_irqrestore(substream, flags); - return 0; -} - -static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream, - void *arg) -{ - 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; - return 0; - } - width = snd_pcm_format_physical_width(runtime->format); - if (width < 0) - return width; - info->offset = 0; - switch (runtime->access) { - case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED: - case SNDRV_PCM_ACCESS_RW_INTERLEAVED: - info->first = info->channel * width; - info->step = runtime->channels * width; - break; - case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED: - case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED: - { - size_t size = runtime->dma_bytes / runtime->channels; - info->first = info->channel * size * 8; - info->step = width; - break; - } - default: - snd_BUG(); - break; - } - 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 - * @cmd: ioctl command - * @arg: ioctl argument - * - * 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. - */ -int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case SNDRV_PCM_IOCTL1_INFO: - return 0; - case SNDRV_PCM_IOCTL1_RESET: - 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; -} - -EXPORT_SYMBOL(snd_pcm_lib_ioctl); - -/** - * snd_pcm_period_elapsed - update the pcm status for the next period - * @substream: the pcm substream instance - * - * This function is called from the interrupt handler when the - * PCM has processed the period size. It will update the current - * 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(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - unsigned long flags; - - if (PCM_RUNTIME_CHECK(substream)) - return; - runtime = substream->runtime; - - 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_ptr0(substream, 1) < 0) - goto _end; - - if (substream->timer_running) - snd_timer_interrupt(substream->timer, 1); - _end: - snd_pcm_stream_unlock_irqrestore(substream, flags); - if (runtime->transfer_ack_end) - runtime->transfer_ack_end(substream); - kill_fasync(&runtime->fasync, SIGIO, POLL_IN); -} - -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; - } - if (!tout) { - snd_printd("%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) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy) { - if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) - return err; - } else { - char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); - if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) - return -EFAULT; - } - return 0; -} - -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(struct snd_pcm_substream *substream, - unsigned long data, - snd_pcm_uframes_t size, - int nonblock, - transfer_f transfer) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t xfer = 0; - snd_pcm_uframes_t offset = 0; - int err = 0; - - if (size == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - err = -EBADFD; - goto _end_unlock; - } - - runtime->twake = runtime->control->avail_min ? : 1; - while (size > 0) { - snd_pcm_uframes_t frames, appl_ptr, appl_ofs; - snd_pcm_uframes_t avail; - snd_pcm_uframes_t cont; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_playback_avail(runtime); - if (!avail) { - if (nonblock) { - err = -EAGAIN; - goto _end_unlock; - } - 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; - } - frames = size > avail ? avail : size; - cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; - if (frames > cont) - frames = cont; - 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); - 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; - goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - break; - } - appl_ptr += frames; - if (appl_ptr >= runtime->boundary) - appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) - substream->ops->ack(substream); - - offset += frames; - size -= frames; - xfer += 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; - } - } - _end_unlock: - runtime->twake = 0; - if (xfer > 0 && err >= 0) - snd_pcm_update_state(substream, runtime); - snd_pcm_stream_unlock_irq(substream); - return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; -} - -/* sanity-check for read/write methods */ -static int pcm_sanity_check(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - 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_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) - return -EINVAL; - return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, - snd_pcm_lib_write_transfer); -} - -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) -{ - 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) { - 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) - return err; - } else { - char __user *buf = *bufs + samples_to_bytes(runtime, off); - if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) - return err; - } - } - } else { - /* default transfer behaviour */ - size_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - if (*bufs == NULL) { - snd_pcm_format_set_silence(runtime->format, hwbuf, frames); - } else { - char __user *buf = *bufs + samples_to_bytes(runtime, off); - if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } - } - return 0; -} - -snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, - void __user **bufs, - snd_pcm_uframes_t frames) -{ - 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_NONINTERLEAVED) - return -EINVAL; - return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, - nonblock, snd_pcm_lib_writev_transfer); -} - -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) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); - if (substream->ops->copy) { - if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) - return err; - } else { - char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); - if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) - return -EFAULT; - } - return 0; -} - -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) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t xfer = 0; - snd_pcm_uframes_t offset = 0; - int err = 0; - - if (size == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - if (size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) - goto _end_unlock; - } - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - err = -EBADFD; - goto _end_unlock; - } - - runtime->twake = runtime->control->avail_min ? : 1; - while (size > 0) { - snd_pcm_uframes_t frames, appl_ptr, appl_ofs; - snd_pcm_uframes_t avail; - snd_pcm_uframes_t cont; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_capture_avail(runtime); - if (!avail) { - if (runtime->status->state == - SNDRV_PCM_STATE_DRAINING) { - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - goto _end_unlock; - } - if (nonblock) { - err = -EAGAIN; - goto _end_unlock; - } - 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; - if (!avail) - continue; /* draining */ - } - frames = size > avail ? avail : size; - cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; - if (frames > cont) - frames = cont; - 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); - 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; - goto _end_unlock; - case SNDRV_PCM_STATE_SUSPENDED: - err = -ESTRPIPE; - goto _end_unlock; - default: - break; - } - appl_ptr += frames; - if (appl_ptr >= runtime->boundary) - appl_ptr -= runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) - substream->ops->ack(substream); - - offset += frames; - size -= frames; - xfer += frames; - } - _end_unlock: - runtime->twake = 0; - if (xfer > 0 && err >= 0) - snd_pcm_update_state(substream, runtime); - snd_pcm_stream_unlock_irq(substream); - return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; -} - -snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, 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) - return -EINVAL; - return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); -} - -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) -{ - 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) { - for (c = 0; c < channels; ++c, ++bufs) { - char __user *buf; - if (*bufs == NULL) - continue; - buf = *bufs + samples_to_bytes(runtime, off); - if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) - return err; - } - } else { - snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; - for (c = 0; c < channels; ++c, ++bufs) { - char *hwbuf; - char __user *buf; - if (*bufs == NULL) - continue; - - hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); - buf = *bufs + samples_to_bytes(runtime, off); - if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) - return -EFAULT; - } - } - return 0; -} - -snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, - void __user **bufs, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime; - int nonblock; - int err; - - err = pcm_sanity_check(substream); - if (err < 0) - return err; - runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - - 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); diff --git a/ANDROID_3.4.5/sound/core/pcm_memory.c b/ANDROID_3.4.5/sound/core/pcm_memory.c deleted file mode 100644 index 95713136..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_memory.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#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> -#include <sound/initval.h> - -static int preallocate_dma = 1; -module_param(preallocate_dma, int, 0444); -MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized."); - -static int maximum_substreams = 4; -module_param(maximum_substreams, int, 0444); -MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory."); - -static const size_t snd_minimum_buffer = 16384; - - -/* - * try to allocate as the large pages as possible. - * stores the resultant memory size in *res_size. - * - * the minimum size is snd_minimum_buffer. it should be power of 2. - */ -static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size) -{ - struct snd_dma_buffer *dmab = &substream->dma_buffer; - int err; - - /* 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) { - if (err != -ENOMEM) - return err; /* fatal error */ - } else - return 0; - size >>= 1; - } while (size >= snd_minimum_buffer); - dmab->bytes = 0; /* tell error */ - return 0; -} - -/* - * release the preallocated buffer if not yet done. - */ -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); - substream->dma_buffer.area = NULL; -} - -/** - * snd_pcm_lib_preallocate_free - release the preallocated buffer of the specified substream. - * @substream: the pcm substream instance - * - * Releases the pre-allocated buffer of the given substream. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) -{ - snd_pcm_lib_preallocate_dma_free(substream); -#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; -} - -/** - * snd_pcm_lib_preallocate_free_for_all - release all pre-allocated buffers on the pcm - * @pcm: the pcm instance - * - * Releases all the pre-allocated buffers on the given pcm. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - int stream; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_free(substream); - 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(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_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(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_pcm_substream *substream = entry->private_data; - char line[64], str[64]; - size_t size; - struct snd_dma_buffer new_dmab; - - if (substream->runtime) { - buffer->error = -EBUSY; - return; - } - if (!snd_info_get_line(buffer, line, sizeof(line))) { - snd_info_get_str(str, line, sizeof(str)); - size = simple_strtoul(str, NULL, 10) * 1024; - if ((size != 0 && size < 8192) || size > substream->dma_max) { - buffer->error = -EINVAL; - return; - } - if (substream->dma_buffer.bytes == size) - return; - memset(&new_dmab, 0, sizeof(new_dmab)); - new_dmab.dev = substream->dma_buffer.dev; - if (size > 0) { - if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, - substream->dma_buffer.dev.dev, - size, &new_dmab) < 0) { - buffer->error = -ENOMEM; - return; - } - substream->buffer_bytes_max = size; - } else { - substream->buffer_bytes_max = UINT_MAX; - } - if (substream->dma_buffer.area) - snd_dma_free_pages(&substream->dma_buffer); - substream->dma_buffer = new_dmab; - } else { - buffer->error = -EINVAL; - } -} - -static inline void preallocate_info_init(struct snd_pcm_substream *substream) -{ - struct snd_info_entry *entry; - - if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_lib_preallocate_proc_read; - entry->c.text.write = snd_pcm_lib_preallocate_proc_write; - entry->mode |= S_IWUSR; - entry->private_data = substream; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - 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; -} - - -/** - * 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 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. - */ -int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, - int type, struct device *data, - size_t size, size_t max) -{ - substream->dma_buffer.dev.type = type; - substream->dma_buffer.dev.dev = data; - 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 continuous memory type (all substreams) - * @pcm: the pcm instance - * @type: DMA type (SNDRV_DMA_TYPE_*) - * @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. - */ -int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, - int type, void *data, - size_t size, size_t max) -{ - struct snd_pcm_substream *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0) - return err; - 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. - */ -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); - - unsigned int idx = offset >> PAGE_SHIFT; - if (idx >= (unsigned int)sgbuf->pages) - return NULL; - return sgbuf->page_table[idx]; -} - -EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); - -/* - * compute the max chunk size with continuous pages on sg-buffer - */ -unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, - unsigned int ofs, unsigned int size) -{ - struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream); - 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_pcm_sgbuf_get_chunk_size); -#endif /* CONFIG_SND_DMA_SGBUF */ - -/** - * snd_pcm_lib_malloc_pages - allocate the DMA buffer - * @substream: the substream to allocate the DMA buffer to - * @size: the requested buffer size in bytes - * - * 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 - * code on failure. - */ -int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) -{ - struct snd_pcm_runtime *runtime; - struct snd_dma_buffer *dmab = NULL; - - 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; - - if (runtime->dma_buffer_p) { - /* perphaps, we might free the large DMA memory region - to save some space here, but the actual solution - costs us less time */ - if (runtime->dma_buffer_p->bytes >= size) { - runtime->dma_bytes = size; - return 0; /* ok, do not change */ - } - snd_pcm_lib_free_pages(substream); - } - 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); - if (! dmab) - return -ENOMEM; - dmab->dev = substream->dma_buffer.dev; - if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, - substream->dma_buffer.dev.dev, - size, dmab) < 0) { - kfree(dmab); - return -ENOMEM; - } - } - snd_pcm_set_runtime_buffer(substream, dmab); - runtime->dma_bytes = 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. - */ -int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - - if (PCM_RUNTIME_CHECK(substream)) - return -EINVAL; - runtime = substream->runtime; - if (runtime->dma_area == NULL) - return 0; - if (runtime->dma_buffer_p != &substream->dma_buffer) { - /* it's a newly allocated buffer. release it now. */ - snd_dma_free_pages(runtime->dma_buffer_p); - kfree(runtime->dma_buffer_p); - } - 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() - */ -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. - */ -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/ANDROID_3.4.5/sound/core/pcm_misc.c b/ANDROID_3.4.5/sound/core/pcm_misc.c deleted file mode 100644 index 9c9eff9a..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_misc.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * PCM Interface - misc routines - * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.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 - * - */ - -#include <linux/time.h> -#include <linux/export.h> -#include <sound/core.h> -#include <sound/pcm.h> -#define SND_PCM_FORMAT_UNKNOWN (-1) - -/* NOTE: "signed" prefix must be given below since the default char is - * unsigned on some architectures! - */ -struct pcm_format_data { - unsigned char width; /* bit width */ - unsigned char phys; /* physical bit width */ - signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */ - signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */ - unsigned char silence[8]; /* silence data to fill */ -}; - -/* 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 = {}, - }, - [SNDRV_PCM_FORMAT_U8] = { - .width = 8, .phys = 8, .le = -1, .signd = 0, - .silence = { 0x80 }, - }, - [SNDRV_PCM_FORMAT_S16_LE] = { - .width = 16, .phys = 16, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S16_BE] = { - .width = 16, .phys = 16, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U16_LE] = { - .width = 16, .phys = 16, .le = 1, .signd = 0, - .silence = { 0x00, 0x80 }, - }, - [SNDRV_PCM_FORMAT_U16_BE] = { - .width = 16, .phys = 16, .le = 0, .signd = 0, - .silence = { 0x80, 0x00 }, - }, - [SNDRV_PCM_FORMAT_S24_LE] = { - .width = 24, .phys = 32, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S24_BE] = { - .width = 24, .phys = 32, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U24_LE] = { - .width = 24, .phys = 32, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x80 }, - }, - [SNDRV_PCM_FORMAT_U24_BE] = { - .width = 24, .phys = 32, .le = 0, .signd = 0, - .silence = { 0x00, 0x80, 0x00, 0x00 }, - }, - [SNDRV_PCM_FORMAT_S32_LE] = { - .width = 32, .phys = 32, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S32_BE] = { - .width = 32, .phys = 32, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U32_LE] = { - .width = 32, .phys = 32, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x00, 0x80 }, - }, - [SNDRV_PCM_FORMAT_U32_BE] = { - .width = 32, .phys = 32, .le = 0, .signd = 0, - .silence = { 0x80, 0x00, 0x00, 0x00 }, - }, - [SNDRV_PCM_FORMAT_FLOAT_LE] = { - .width = 32, .phys = 32, .le = 1, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_FLOAT_BE] = { - .width = 32, .phys = 32, .le = 0, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_FLOAT64_LE] = { - .width = 64, .phys = 64, .le = 1, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_FLOAT64_BE] = { - .width = 64, .phys = 64, .le = 0, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = { - .width = 32, .phys = 32, .le = 1, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = { - .width = 32, .phys = 32, .le = 0, .signd = -1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_MU_LAW] = { - .width = 8, .phys = 8, .le = -1, .signd = -1, - .silence = { 0x7f }, - }, - [SNDRV_PCM_FORMAT_A_LAW] = { - .width = 8, .phys = 8, .le = -1, .signd = -1, - .silence = { 0x55 }, - }, - [SNDRV_PCM_FORMAT_IMA_ADPCM] = { - .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 = {}, - }, - /* FIXME: the following three formats are not defined properly yet */ - [SNDRV_PCM_FORMAT_MPEG] = { - .le = -1, .signd = -1, - }, - [SNDRV_PCM_FORMAT_GSM] = { - .le = -1, .signd = -1, - }, - [SNDRV_PCM_FORMAT_SPECIAL] = { - .le = -1, .signd = -1, - }, - [SNDRV_PCM_FORMAT_S24_3LE] = { - .width = 24, .phys = 24, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S24_3BE] = { - .width = 24, .phys = 24, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U24_3LE] = { - .width = 24, .phys = 24, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x80 }, - }, - [SNDRV_PCM_FORMAT_U24_3BE] = { - .width = 24, .phys = 24, .le = 0, .signd = 0, - .silence = { 0x80, 0x00, 0x00 }, - }, - [SNDRV_PCM_FORMAT_S20_3LE] = { - .width = 20, .phys = 24, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S20_3BE] = { - .width = 20, .phys = 24, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U20_3LE] = { - .width = 20, .phys = 24, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x08 }, - }, - [SNDRV_PCM_FORMAT_U20_3BE] = { - .width = 20, .phys = 24, .le = 0, .signd = 0, - .silence = { 0x08, 0x00, 0x00 }, - }, - [SNDRV_PCM_FORMAT_S18_3LE] = { - .width = 18, .phys = 24, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S18_3BE] = { - .width = 18, .phys = 24, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U18_3LE] = { - .width = 18, .phys = 24, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x02 }, - }, - [SNDRV_PCM_FORMAT_U18_3BE] = { - .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 = {}, - }, -}; - - -/** - * 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 - * linear, and a negative error code for non-linear formats. - */ -int snd_pcm_format_signed(snd_pcm_format_t format) -{ - int val; - if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return -EINVAL; - 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 - * linear, and a negative error code for non-linear formats. - */ -int snd_pcm_format_unsigned(snd_pcm_format_t format) -{ - int val; - - val = snd_pcm_format_signed(format); - if (val < 0) - return val; - 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. - */ -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 - * 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 ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return -EINVAL; - 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 - * little-endian, or a negative error code if endian not specified. - */ -int snd_pcm_format_big_endian(snd_pcm_format_t format) -{ - int val; - - val = snd_pcm_format_little_endian(format); - if (val < 0) - return val; - 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 - * if unknown format. - */ -int snd_pcm_format_width(snd_pcm_format_t format) -{ - int val; - if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return -EINVAL; - 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 - * if unknown format. - */ -int snd_pcm_format_physical_width(snd_pcm_format_t format) -{ - int val; - if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return -EINVAL; - 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 - * negative error code if unknown format. - */ -ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) -{ - int phys_width = snd_pcm_format_physical_width(format); - if (phys_width < 0) - return -EINVAL; - 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. - */ -const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) -{ - if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return NULL; - if (! pcm_formats[(INT)format].phys) - return NULL; - 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 - * @data: the buffer pointer - * @samples: the number of samples to set silence - * - * Sets the silence data on the buffer for the given samples. - * - * Returns 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 ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) - return -EINVAL; - if (samples == 0) - return 0; - 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[(INT)format].signd == 1 || width <= 8) { - unsigned int bytes = samples * width / 8; - memset(data, *pat, bytes); - return 0; - } - /* non-zero samples, fill using a loop */ - width /= 8; - dst = data; -#if 0 - while (samples--) { - memcpy(dst, pat, width); - dst += width; - } -#else - /* a bit optimization for constant width */ - switch (width) { - case 2: - while (samples--) { - memcpy(dst, pat, 2); - dst += 2; - } - break; - case 3: - while (samples--) { - memcpy(dst, pat, 3); - dst += 3; - } - break; - case 4: - while (samples--) { - memcpy(dst, pat, 4); - dst += 4; - } - break; - case 8: - while (samples--) { - memcpy(dst, pat, 8); - dst += 8; - } - break; - } -#endif - return 0; -} - -EXPORT_SYMBOL(snd_pcm_format_set_silence); - -/** - * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields - * @runtime: the runtime instance - * - * Determines the rate_min and rate_max fields from the rates bits of - * the given runtime->hw. - * - * Returns zero if successful. - */ -int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) -{ - int i; - for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { - if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = snd_pcm_known_rates.list[i]; - break; - } - } - for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) { - if (runtime->hw.rates & (1 << 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 - * - * Returns 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); diff --git a/ANDROID_3.4.5/sound/core/pcm_native.c b/ANDROID_3.4.5/sound/core/pcm_native.c deleted file mode 100644 index d535b341..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_native.c +++ /dev/null @@ -1,3492 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/file.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/pm_qos.h> -#include <linux/uio.h> -#include <linux/dma-mapping.h> -#include <sound/core.h> -#include <sound/control.h> -#include <sound/info.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#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 snd_pcm_hw_params_old { - unsigned int flags; - unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - - SNDRV_PCM_HW_PARAM_ACCESS + 1]; - struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - - SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; - unsigned int rmask; - unsigned int cmask; - unsigned int info; - unsigned int msbits; - unsigned int rate_num; - unsigned int rate_den; - snd_pcm_uframes_t fifo_size; - unsigned char reserved[64]; -}; - -#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(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); -EXPORT_SYMBOL(snd_pcm_link_rwlock); - -static DECLARE_RWSEM(snd_pcm_link_rwsem); - -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - - - -int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) -{ - struct snd_pcm_runtime *runtime; - struct snd_pcm *pcm = substream->pcm; - struct snd_pcm_str *pstr = substream->pstr; - - memset(info, 0, sizeof(*info)); - info->card = pcm->card->number; - info->device = pcm->device; - info->stream = substream->stream; - info->subdevice = substream->number; - strlcpy(info->id, pcm->id, sizeof(info->id)); - strlcpy(info->name, pcm->name, sizeof(info->name)); - info->dev_class = pcm->dev_class; - info->dev_subclass = pcm->dev_subclass; - info->subdevices_count = pstr->substream_count; - info->subdevices_avail = pstr->substream_count - pstr->substream_opened; - strlcpy(info->subname, substream->name, sizeof(info->subname)); - runtime = substream->runtime; - /* AB: FIXME!!! This is definitely nonsense */ - if (runtime) { - info->sync = runtime->sync; - substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); - } - return 0; -} - -int snd_pcm_info_user(struct snd_pcm_substream *substream, - struct snd_pcm_info __user * _info) -{ - struct snd_pcm_info *info; - int err; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) - return -ENOMEM; - err = snd_pcm_info(substream, info); - if (err >= 0) { - if (copy_to_user(_info, info, sizeof(*info))) - err = -EFAULT; - } - kfree(info); - return err; -} - -#undef RULES_DEBUG - -#ifdef RULES_DEBUG -#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -static const char * const snd_pcm_hw_param_names[] = { - HW_PARAM(ACCESS), - HW_PARAM(FORMAT), - HW_PARAM(SUBFORMAT), - HW_PARAM(SAMPLE_BITS), - HW_PARAM(FRAME_BITS), - HW_PARAM(CHANNELS), - HW_PARAM(RATE), - HW_PARAM(PERIOD_TIME), - HW_PARAM(PERIOD_SIZE), - HW_PARAM(PERIOD_BYTES), - HW_PARAM(PERIODS), - HW_PARAM(BUFFER_TIME), - HW_PARAM(BUFFER_SIZE), - HW_PARAM(BUFFER_BYTES), - HW_PARAM(TICK_TIME), -}; -#endif - -int snd_pcm_hw_refine(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - unsigned int k; - 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; - int changed, again; - - params->info = 0; - params->fifo_size = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) - params->msbits = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { - params->rate_num = 0; - params->rate_den = 0; - } - - for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { - m = hw_param_mask(params, k); - if (snd_mask_empty(m)) - return -EINVAL; - if (!(params->rmask & (1 << k))) - continue; -#ifdef RULES_DEBUG - printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]); - printk("%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]); -#endif - if (changed) - params->cmask |= 1 << k; - if (changed < 0) - return changed; - } - - for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { - i = hw_param_interval(params, k); - if (snd_interval_empty(i)) - return -EINVAL; - if (!(params->rmask & (1 << k))) - continue; -#ifdef RULES_DEBUG - printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]); - if (i->empty) - printk("empty"); - else - printk("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - printk(" -> "); -#endif - changed = snd_interval_refine(i, constrs_interval(constrs, k)); -#ifdef RULES_DEBUG - if (i->empty) - printk("empty\n"); - else - printk("%c%u %u%c\n", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); -#endif - if (changed) - params->cmask |= 1 << k; - if (changed < 0) - return changed; - } - - for (k = 0; k < constrs->rules_num; k++) - rstamps[k] = 0; - for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) - vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; - do { - again = 0; - for (k = 0; k < constrs->rules_num; k++) { - struct snd_pcm_hw_rule *r = &constrs->rules[k]; - unsigned int d; - int doit = 0; - if (r->cond && !(r->cond & params->flags)) - continue; - for (d = 0; r->deps[d] >= 0; d++) { - if (vstamps[r->deps[d]] > rstamps[k]) { - doit = 1; - break; - } - } - if (!doit) - continue; -#ifdef RULES_DEBUG - printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func); - if (r->var >= 0) { - printk("%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); - } else { - i = hw_param_interval(params, r->var); - if (i->empty) - printk("empty"); - else - printk("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - } - } -#endif - changed = r->func(params, r); -#ifdef RULES_DEBUG - if (r->var >= 0) { - printk(" -> "); - if (hw_is_mask(r->var)) - printk("%x", *m->bits); - else { - if (i->empty) - printk("empty"); - else - printk("%c%u %u%c", - i->openmin ? '(' : '[', i->min, - i->max, i->openmax ? ')' : ']'); - } - } - printk("\n"); -#endif - rstamps[k] = stamp; - if (changed && r->var >= 0) { - params->cmask |= (1 << r->var); - vstamps[r->var] = stamp; - again = 1; - } - if (changed < 0) - return changed; - stamp++; - } - } while (again); - if (!params->msbits) { - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - if (snd_interval_single(i)) - params->msbits = snd_interval_value(i); - } - - if (!params->rate_den) { - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - if (snd_interval_single(i)) { - params->rate_num = snd_interval_value(i); - params->rate_den = 1; - } - } - - hw = &substream->runtime->hw; - if (!params->info) - 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; -} - -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) -{ - struct snd_pcm_hw_params *params; - int err; - - 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; - } - - kfree(params); - return err; -} - -static int period_to_usecs(struct snd_pcm_runtime *runtime) -{ - 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; - - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_OPEN: - case SNDRV_PCM_STATE_SETUP: - case SNDRV_PCM_STATE_PREPARED: - break; - default: - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; - } - snd_pcm_stream_unlock_irq(substream); -#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) - if (!substream->oss.oss) -#endif - if (atomic_read(&substream->mmap_count)) - return -EBADFD; - - params->rmask = ~0U; - err = snd_pcm_hw_refine(substream, params); - if (err < 0) - goto _error; - - err = snd_pcm_hw_params_choose(substream, params); - if (err < 0) - goto _error; - - if (substream->ops->hw_params != NULL) { - err = substream->ops->hw_params(substream, params); - if (err < 0) - goto _error; - } - - runtime->access = params_access(params); - runtime->format = params_format(params); - runtime->subformat = params_subformat(params); - runtime->channels = params_channels(params); - runtime->rate = params_rate(params); - runtime->period_size = params_period_size(params); - runtime->periods = params_periods(params); - runtime->buffer_size = params_buffer_size(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; - bits *= runtime->channels; - runtime->frame_bits = bits; - frames = 1; - while (bits % 8 != 0) { - bits *= 2; - frames *= 2; - } - runtime->byte_align = bits / 8; - runtime->min_align = frames; - - /* Default sw params */ - runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; - runtime->period_step = 1; - runtime->control->avail_min = runtime->period_size; - runtime->start_threshold = 1; - runtime->stop_threshold = runtime->buffer_size; - runtime->silence_threshold = 0; - runtime->silence_size = 0; - runtime->boundary = runtime->buffer_size; - while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) - runtime->boundary *= 2; - - snd_pcm_timer_resolution_change(substream); - 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 unusable from this time, - so we force application to retry to set - the correct hardware parameter settings */ - 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(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params __user * _params) -{ - struct snd_pcm_hw_params *params; - int err; - - 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; - } - - kfree(params); - return err; -} - -static int snd_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - int result = 0; - - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_SETUP: - case SNDRV_PCM_STATE_PREPARED: - break; - default: - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; - } - snd_pcm_stream_unlock_irq(substream); - if (atomic_read(&substream->mmap_count)) - return -EBADFD; - if (substream->ops->hw_free) - result = substream->ops->hw_free(substream); - 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(struct snd_pcm_substream *substream, - struct snd_pcm_sw_params *params) -{ - struct snd_pcm_runtime *runtime; - int err; - - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; - } - snd_pcm_stream_unlock_irq(substream); - - if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) - return -EINVAL; - if (params->avail_min == 0) - return -EINVAL; - if (params->silence_size >= runtime->boundary) { - if (params->silence_threshold != 0) - return -EINVAL; - } else { - if (params->silence_size > params->silence_threshold) - return -EINVAL; - if (params->silence_threshold > runtime->buffer_size) - return -EINVAL; - } - err = 0; - snd_pcm_stream_lock_irq(substream); - runtime->tstamp_mode = params->tstamp_mode; - 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; - params->boundary = runtime->boundary; - if (snd_pcm_running(substream)) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - runtime->silence_size > 0) - snd_pcm_playback_silence(substream, ULONG_MAX); - err = snd_pcm_update_state(substream, runtime); - } - snd_pcm_stream_unlock_irq(substream); - return err; -} - -static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, - struct snd_pcm_sw_params __user * _params) -{ - struct snd_pcm_sw_params params; - int err; - if (copy_from_user(¶ms, _params, sizeof(params))) - return -EFAULT; - err = snd_pcm_sw_params(substream, ¶ms); - if (copy_to_user(_params, ¶ms, sizeof(params))) - return -EFAULT; - return err; -} - -int snd_pcm_status(struct snd_pcm_substream *substream, - struct snd_pcm_status *status) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - snd_pcm_stream_lock_irq(substream); - status->state = runtime->status->state; - status->suspended_state = runtime->status->suspended_state; - if (status->state == SNDRV_PCM_STATE_OPEN) - goto _end; - status->trigger_tstamp = runtime->trigger_tstamp; - if (snd_pcm_running(substream)) { - snd_pcm_update_hw_ptr(substream); - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { - status->tstamp = runtime->status->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) { - status->delay = runtime->buffer_size - status->avail; - 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 + runtime->delay; - else - status->delay = 0; - } - status->avail_max = runtime->avail_max; - status->overrange = runtime->overrange; - runtime->avail_max = 0; - runtime->overrange = 0; - _end: - snd_pcm_stream_unlock_irq(substream); - return 0; -} - -static int snd_pcm_status_user(struct snd_pcm_substream *substream, - struct snd_pcm_status __user * _status) -{ - struct snd_pcm_status status; - int res; - - memset(&status, 0, sizeof(status)); - res = snd_pcm_status(substream, &status); - if (res < 0) - return res; - if (copy_to_user(_status, &status, sizeof(status))) - return -EFAULT; - return 0; -} - -static int snd_pcm_channel_info(struct snd_pcm_substream *substream, - struct snd_pcm_channel_info * info) -{ - struct snd_pcm_runtime *runtime; - unsigned int channel; - - channel = info->channel; - runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; - } - snd_pcm_stream_unlock_irq(substream); - if (channel >= runtime->channels) - return -EINVAL; - memset(info, 0, sizeof(*info)); - info->channel = channel; - return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); -} - -static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, - struct snd_pcm_channel_info __user * _info) -{ - struct snd_pcm_channel_info info; - int res; - - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; - res = snd_pcm_channel_info(substream, &info); - if (res < 0) - return res; - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->trigger_master == NULL) - return; - if (runtime->trigger_master == substream) { - snd_pcm_gettime(runtime, &runtime->trigger_tstamp); - } else { - snd_pcm_trigger_tstamp(runtime->trigger_master); - runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; - } - runtime->trigger_master = NULL; -} - -struct action_ops { - 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); -}; - -/* - * this functions is core for handling of linked stream - * Note: the stream state might be changed also on failure - * Note2: call with calling stream lock + link lock - */ -static int snd_pcm_action_group(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state, int do_lock) -{ - struct snd_pcm_substream *s = NULL; - struct snd_pcm_substream *s1; - int res = 0; - - snd_pcm_group_for_each_entry(s, substream) { - if (do_lock && s != substream) - 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_entry(s, substream) { - res = ops->do_action(s, state); - if (res < 0) { - if (ops->undo_action) { - snd_pcm_group_for_each_entry(s1, substream) { - if (s1 == s) /* failed stream */ - break; - ops->undo_action(s1, state); - } - } - s = NULL; /* unlock all */ - goto _unlock; - } - } - snd_pcm_group_for_each_entry(s, substream) { - ops->post_action(s, state); - } - _unlock: - if (do_lock) { - /* unlock streams */ - snd_pcm_group_for_each_entry(s1, substream) { - if (s1 != substream) - spin_unlock(&s1->self_group.lock); - if (s1 == s) /* end */ - break; - } - } - return res; -} - -/* - * Note: call with stream lock - */ -static int snd_pcm_action_single(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - res = ops->pre_action(substream, state); - if (res < 0) - return res; - res = ops->do_action(substream, state); - if (res == 0) - ops->post_action(substream, state); - else if (ops->undo_action) - ops->undo_action(substream, state); - return res; -} - -/* - * Note: call with stream lock - */ -static int snd_pcm_action(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - if (snd_pcm_stream_linked(substream)) { - if (!spin_trylock(&substream->group->lock)) { - spin_unlock(&substream->self_group.lock); - spin_lock(&substream->group->lock); - spin_lock(&substream->self_group.lock); - } - res = snd_pcm_action_group(ops, substream, state, 1); - spin_unlock(&substream->group->lock); - } else { - res = snd_pcm_action_single(ops, substream, state); - } - return res; -} - -/* - * Note: don't use any locks before - */ -static int snd_pcm_action_lock_irq(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - read_lock_irq(&snd_pcm_link_rwlock); - if (snd_pcm_stream_linked(substream)) { - spin_lock(&substream->group->lock); - spin_lock(&substream->self_group.lock); - res = snd_pcm_action_group(ops, substream, state, 1); - spin_unlock(&substream->self_group.lock); - spin_unlock(&substream->group->lock); - } else { - spin_lock(&substream->self_group.lock); - res = snd_pcm_action_single(ops, substream, state); - spin_unlock(&substream->self_group.lock); - } - read_unlock_irq(&snd_pcm_link_rwlock); - return res; -} - -/* - */ -static int snd_pcm_action_nonatomic(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - down_read(&snd_pcm_link_rwsem); - if (snd_pcm_stream_linked(substream)) - res = snd_pcm_action_group(ops, substream, state, 0); - else - res = snd_pcm_action_single(ops, substream, state); - up_read(&snd_pcm_link_rwsem); - return res; -} - -/* - * start callbacks - */ -static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) - return -EBADFD; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - !snd_pcm_playback_data(substream)) - return -EPIPE; - runtime->trigger_master = substream; - return 0; -} - -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(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(struct snd_pcm_substream *substream, int state) -{ - 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 (substream->timer) - snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, - &runtime->trigger_tstamp); -} - -static struct action_ops snd_pcm_action_start = { - .pre_action = snd_pcm_pre_start, - .do_action = snd_pcm_do_start, - .undo_action = snd_pcm_undo_start, - .post_action = snd_pcm_post_start -}; - -/** - * snd_pcm_start - start all linked streams - * @substream: the PCM substream instance - */ -int snd_pcm_start(struct snd_pcm_substream *substream) -{ - return snd_pcm_action(&snd_pcm_action_start, substream, - SNDRV_PCM_STATE_RUNNING); -} - -/* - * stop callbacks - */ -static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state) -{ - 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(struct snd_pcm_substream *substream, int state) -{ - if (substream->runtime->trigger_master == substream && - snd_pcm_running(substream)) - substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); - return 0; /* unconditonally stop all substreams */ -} - -static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) -{ - 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); - runtime->status->state = state; - } - wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); -} - -static struct action_ops snd_pcm_action_stop = { - .pre_action = snd_pcm_pre_stop, - .do_action = snd_pcm_do_stop, - .post_action = snd_pcm_post_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 - * - * The state of each stream is then changed to the given state unconditionally. - */ -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 - stop the DMA only when the given stream is playback - * @substream: the PCM substream - * - * After stopping, the state is changed to SETUP. - * Unlike snd_pcm_stop(), this affects only the given stream. - */ -int snd_pcm_drain_done(struct snd_pcm_substream *substream) -{ - return snd_pcm_action_single(&snd_pcm_action_stop, substream, - SNDRV_PCM_STATE_SETUP); -} - -/* - * pause callbacks - */ -static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) - return -ENOSYS; - if (push) { - if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) - return -EBADFD; - } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) - return -EBADFD; - runtime->trigger_master = substream; - return 0; -} - -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(struct snd_pcm_substream *substream, int push) -{ - if (substream->runtime->trigger_master == substream) - substream->ops->trigger(substream, - push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE : - SNDRV_PCM_TRIGGER_PAUSE_PUSH); -} - -static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) -{ - 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); - wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); - } else { - runtime->status->state = SNDRV_PCM_STATE_RUNNING; - if (substream->timer) - snd_timer_notify(substream->timer, - SNDRV_TIMER_EVENT_MCONTINUE, - &runtime->trigger_tstamp); - } -} - -static struct action_ops snd_pcm_action_pause = { - .pre_action = snd_pcm_pre_pause, - .do_action = snd_pcm_do_pause, - .undo_action = snd_pcm_undo_pause, - .post_action = snd_pcm_post_pause -}; - -/* - * Push/release the pause for all linked streams. - */ -static int snd_pcm_pause(struct snd_pcm_substream *substream, int push) -{ - return snd_pcm_action(&snd_pcm_action_pause, substream, push); -} - -#ifdef CONFIG_PM -/* suspend */ - -static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state) -{ - 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(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->trigger_master != substream) - return 0; - if (! snd_pcm_running(substream)) - return 0; - substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); - return 0; /* suspend unconditionally */ -} - -static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) -{ - 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); - runtime->status->suspended_state = runtime->status->state; - runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; - wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); -} - -static struct action_ops snd_pcm_action_suspend = { - .pre_action = snd_pcm_pre_suspend, - .do_action = snd_pcm_do_suspend, - .post_action = snd_pcm_post_suspend -}; - -/** - * snd_pcm_suspend - trigger SUSPEND to all linked streams - * @substream: the PCM substream - * - * After this call, all streams are changed to SUSPENDED state. - */ -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 - trigger SUSPEND to all substreams in the given pcm - * @pcm: the PCM instance - * - * After this call, all streams are changed to SUSPENDED state. - */ -int snd_pcm_suspend_all(struct snd_pcm *pcm) -{ - 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) { - /* FIXME: the open/close code should lock this as well */ - if (substream->runtime == NULL) - continue; - err = snd_pcm_suspend(substream); - if (err < 0 && err != -EBUSY) - return err; - } - } - return 0; -} - -EXPORT_SYMBOL(snd_pcm_suspend_all); - -/* resume */ - -static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) -{ - 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(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->trigger_master != substream) - return 0; - /* DMA not running previously? */ - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && - (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING || - substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) - return 0; - return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); -} - -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(struct snd_pcm_substream *substream, int state) -{ - 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); - runtime->status->state = runtime->status->suspended_state; -} - -static struct action_ops snd_pcm_action_resume = { - .pre_action = snd_pcm_pre_resume, - .do_action = snd_pcm_do_resume, - .undo_action = snd_pcm_undo_resume, - .post_action = snd_pcm_post_resume -}; - -static int snd_pcm_resume(struct snd_pcm_substream *substream) -{ - struct snd_card *card = substream->pcm->card; - int res; - - snd_power_lock(card); - 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; -} - -#else - -static int snd_pcm_resume(struct snd_pcm_substream *substream) -{ - return -ENOSYS; -} - -#endif /* CONFIG_PM */ - -/* - * xrun ioctl - * - * Change the RUNNING stream(s) to XRUN state. - */ -static int snd_pcm_xrun(struct snd_pcm_substream *substream) -{ - 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); - if (result < 0) - goto _unlock; - } - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_XRUN: - result = 0; /* already there */ - break; - case SNDRV_PCM_STATE_RUNNING: - result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - break; - default: - result = -EBADFD; - } - snd_pcm_stream_unlock_irq(substream); - _unlock: - snd_power_unlock(card); - return result; -} - -/* - * reset ioctl - */ -static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - switch (runtime->status->state) { - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_PAUSED: - case SNDRV_PCM_STATE_SUSPENDED: - return 0; - default: - return -EBADFD; - } -} - -static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); - if (err < 0) - return err; - runtime->hw_ptr_base = 0; - 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(struct snd_pcm_substream *substream, int state) -{ - 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) - snd_pcm_playback_silence(substream, ULONG_MAX); -} - -static struct action_ops snd_pcm_action_reset = { - .pre_action = snd_pcm_pre_reset, - .do_action = snd_pcm_do_reset, - .post_action = snd_pcm_post_reset -}; - -static int snd_pcm_reset(struct snd_pcm_substream *substream) -{ - return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0); -} - -/* - * prepare ioctl - */ -/* we use the second argument for updating f_flags */ -static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, - int f_flags) -{ - 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(struct snd_pcm_substream *substream, int state) -{ - int err; - err = substream->ops->prepare(substream); - if (err < 0) - return err; - return snd_pcm_do_reset(substream, 0); -} - -static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - runtime->control->appl_ptr = runtime->status->hw_ptr; - snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); -} - -static struct action_ops snd_pcm_action_prepare = { - .pre_action = snd_pcm_pre_prepare, - .do_action = snd_pcm_do_prepare, - .post_action = snd_pcm_post_prepare -}; - -/** - * snd_pcm_prepare - prepare the PCM substream to be triggerable - * @substream: the PCM substream instance - * @file: file to refer f_flags - */ -static int snd_pcm_prepare(struct snd_pcm_substream *substream, - struct file *file) -{ - int res; - 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)) >= 0) - res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, - substream, f_flags); - snd_power_unlock(card); - return res; -} - -/* - * drain ioctl - */ - -static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) -{ - substream->runtime->trigger_master = substream; - return 0; -} - -static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - /* start playback stream if possible */ - if (! snd_pcm_playback_empty(substream)) { - snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); - snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); - } - break; - case SNDRV_PCM_STATE_RUNNING: - runtime->status->state = SNDRV_PCM_STATE_DRAINING; - break; - default: - break; - } - } else { - /* stop running stream */ - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { - int new_state = snd_pcm_capture_avail(runtime) > 0 ? - SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; - snd_pcm_do_stop(substream, new_state); - snd_pcm_post_stop(substream, new_state); - } - } - return 0; -} - -static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state) -{ -} - -static struct action_ops snd_pcm_action_drain_init = { - .pre_action = snd_pcm_pre_drain_init, - .do_action = snd_pcm_do_drain_init, - .post_action = snd_pcm_post_drain_init -}; - -static int snd_pcm_drop(struct snd_pcm_substream *substream); - -/* - * Drain the stream(s). - * When the substream is linked, sync until the draining of all playback streams - * is finished. - * After this call, all streams are supposed to be either SETUP or DRAINING - * (capture only) state. - */ -static int snd_pcm_drain(struct snd_pcm_substream *substream, - struct file *file) -{ - struct snd_card *card; - struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *s; - wait_queue_t wait; - int result = 0; - int nonblock = 0; - - card = substream->pcm->card; - runtime = substream->runtime; - - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - - snd_power_lock(card); - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) { - snd_power_unlock(card); - return result; - } - } - - 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) - snd_pcm_pause(substream, 0); - - /* 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) - 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; - } - /* 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 (!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); - 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"); - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - result = -EIO; - } - break; - } - } - - unlock: - snd_pcm_stream_unlock_irq(substream); - up_read(&snd_pcm_link_rwsem); - snd_power_unlock(card); - - return result; -} - -/* - * drop ioctl - * - * Immediately put all linked substreams into SETUP state. - */ -static int snd_pcm_drop(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime; - int result = 0; - - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - - 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_pcm_stream_lock_irq(substream); - /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) - snd_pcm_pause(substream, 0); - - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ - snd_pcm_stream_unlock_irq(substream); - - return result; -} - - -/* WARNING: Don't forget to fput back the file */ -static struct file *snd_pcm_file_fd(int fd) -{ - struct file *file; - struct inode *inode; - unsigned int minor; - - file = fget(fd); - if (!file) - return NULL; - inode = file->f_path.dentry->d_inode; - if (!S_ISCHR(inode->i_mode) || - imajor(inode) != snd_major) { - fput(file); - return NULL; - } - minor = iminor(inode); - if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) && - !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) { - fput(file); - return NULL; - } - return file; -} - -/* - * PCM link handling - */ -static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) -{ - int res = 0; - struct file *file; - struct snd_pcm_file *pcm_file; - struct snd_pcm_substream *substream1; - struct snd_pcm_group *group; - - file = snd_pcm_file_fd(fd); - if (!file) - return -EBADFD; - pcm_file = 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 || - substream->runtime->status->state != substream1->runtime->status->state) { - res = -EBADFD; - goto _end; - } - if (snd_pcm_stream_linked(substream1)) { - res = -EALREADY; - goto _end; - } - if (!snd_pcm_stream_linked(substream)) { - substream->group = group; - spin_lock_init(&substream->group->lock); - INIT_LIST_HEAD(&substream->group->substreams); - list_add_tail(&substream->link_list, &substream->group->substreams); - substream->group->count = 1; - } - list_add_tail(&substream1->link_list, &substream->group->substreams); - substream->group->count++; - substream1->group = substream->group; - _end: - write_unlock_irq(&snd_pcm_link_rwlock); - up_write(&snd_pcm_link_rwsem); - _nolock: - snd_card_unref(substream1->pcm->card); - fput(file); - if (res < 0) - kfree(group); - return res; -} - -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(struct snd_pcm_substream *substream) -{ - struct snd_pcm_substream *s; - int res = 0; - - down_write(&snd_pcm_link_rwsem); - write_lock_irq(&snd_pcm_link_rwlock); - if (!snd_pcm_stream_linked(substream)) { - res = -EALREADY; - goto _end; - } - list_del(&substream->link_list); - substream->group->count--; - if (substream->group->count == 1) { /* detach the last stream, too */ - snd_pcm_group_for_each_entry(s, substream) { - relink_to_local(s); - break; - } - kfree(substream->group); - } - relink_to_local(substream); - _end: - write_unlock_irq(&snd_pcm_link_rwlock); - up_write(&snd_pcm_link_rwsem); - return res; -} - -/* - * hw configurator - */ -static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - 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(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - 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(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - 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(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - 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(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - unsigned int k; - 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; - if (! snd_mask_test(mask, k)) - continue; - bits = snd_pcm_format_physical_width(k); - if (bits <= 0) - continue; /* ignore invalid formats */ - if ((unsigned)bits < i->min || (unsigned)bits > i->max) - snd_mask_reset(&m, k); - } - return snd_mask_refine(mask, &m); -} - -static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval t; - unsigned int k; - t.min = UINT_MAX; - t.max = 0; - t.openmin = 0; - t.openmax = 0; - for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { - int bits; - if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) - continue; - bits = snd_pcm_format_physical_width(k); - if (bits <= 0) - continue; /* ignore invalid formats */ - if (t.min > (unsigned)bits) - t.min = bits; - if (t.max < (unsigned)bits) - t.max = bits; - } - t.integer = 1; - return snd_interval_refine(hw_param_interval(params, rule->var), &t); -} - -#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 -#error "Change this table" -#endif - -static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 }; - -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) -{ - struct snd_pcm_hardware *hw = rule->private; - return snd_interval_list(hw_param_interval(params, rule->var), - snd_pcm_known_rates.count, - snd_pcm_known_rates.list, hw->rates); -} - -static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval t; - struct snd_pcm_substream *substream = rule->private; - t.min = 0; - t.max = substream->buffer_bytes_max; - t.openmin = 0; - t.openmax = 0; - t.integer = 1; - return snd_interval_refine(hw_param_interval(params, rule->var), &t); -} - -int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) -{ - 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++) { - snd_mask_any(constrs_mask(constrs, k)); - } - - for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { - snd_interval_any(constrs_interval(constrs, k)); - } - - snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS)); - snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE)); - snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)); - snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)); - snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS)); - - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, - snd_pcm_hw_rule_format, NULL, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - snd_pcm_hw_rule_sample_bits, NULL, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - snd_pcm_hw_rule_div, NULL, - SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, - snd_pcm_hw_rule_mul, NULL, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, - snd_pcm_hw_rule_mulkdiv, (void*) 8, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, - snd_pcm_hw_rule_mulkdiv, (void*) 8, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_pcm_hw_rule_div, NULL, - SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_pcm_hw_rule_mulkdiv, (void*) 1000000, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_pcm_hw_rule_mulkdiv, (void*) 1000000, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, - snd_pcm_hw_rule_div, NULL, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - snd_pcm_hw_rule_div, NULL, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - snd_pcm_hw_rule_mulkdiv, (void*) 8, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - snd_pcm_hw_rule_muldivk, (void*) 1000000, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - snd_pcm_hw_rule_mul, NULL, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - snd_pcm_hw_rule_mulkdiv, (void*) 8, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - snd_pcm_hw_rule_muldivk, (void*) 1000000, - SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - snd_pcm_hw_rule_muldivk, (void*) 8, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - snd_pcm_hw_rule_muldivk, (void*) 8, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - snd_pcm_hw_rule_mulkdiv, (void*) 1000000, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, - snd_pcm_hw_rule_mulkdiv, (void*) 1000000, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - return 0; -} - -int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_hardware *hw = &runtime->hw; - int err; - unsigned int mask = 0; - - if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) - mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; - if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) - mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; - if (hw->info & SNDRV_PCM_INFO_MMAP) { - if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; - if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; - if (hw->info & SNDRV_PCM_INFO_COMPLEX) - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; - } - err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, - hw->channels_min, hw->channels_max); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, - hw->rate_min, hw->rate_max); - 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); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, - hw->periods_min, hw->periods_max); - 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); - 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, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); - if (err < 0) - return err; - - /* FIXME: remove */ - if (runtime->dma_bytes) { - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); - if (err < 0) - return -EINVAL; - } - - if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_pcm_hw_rule_rate, hw, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - } - - /* FIXME: this belong to lowlevel */ - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - - return 0; -} - -static void pcm_release_private(struct snd_pcm_substream *substream) -{ - snd_pcm_unlink(substream); -} - -void snd_pcm_release_substream(struct snd_pcm_substream *substream) -{ - substream->ref_count--; - if (substream->ref_count > 0) - return; - - snd_pcm_drop(substream); - if (substream->hw_opened) { - if (substream->ops->hw_free != NULL) - substream->ops->hw_free(substream); - substream->ops->close(substream); - substream->hw_opened = 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); -} - -EXPORT_SYMBOL(snd_pcm_release_substream); - -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; - - err = snd_pcm_attach_substream(pcm, stream, file, &substream); - if (err < 0) - return err; - if (substream->ref_count > 1) { - *rsubstream = substream; - return 0; - } - - err = snd_pcm_hw_constraints_init(substream); - if (err < 0) { - snd_printd("snd_pcm_hw_constraints_init failed\n"); - goto error; - } - - 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"); - 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; - - return 0; -} - -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 err; - wait_queue_t wait; - - if (pcm == NULL) { - err = -ENODEV; - goto __error1; - } - err = snd_card_file_add(pcm->card, file); - if (err < 0) - goto __error1; - if (!try_module_get(pcm->card->module)) { - err = -EFAULT; - goto __error2; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&pcm->open_wait, &wait); - mutex_lock(&pcm->open_mutex); - while (1) { - err = snd_pcm_open_file(file, pcm, stream); - if (err >= 0) - break; - if (err == -EAGAIN) { - if (file->f_flags & O_NONBLOCK) { - err = -EBUSY; - break; - } - } else - break; - set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&pcm->open_mutex); - schedule(); - 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); - mutex_unlock(&pcm->open_mutex); - if (err < 0) - goto __error; - return err; - - __error: - module_put(pcm->card->module); - __error2: - snd_card_file_remove(pcm->card, file); - __error1: - return err; -} - -static int snd_pcm_release(struct inode *inode, struct file *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; - if (snd_BUG_ON(!substream)) - return -ENXIO; - pcm = substream->pcm; - 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(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; - snd_pcm_sframes_t ret; - snd_pcm_sframes_t hw_avail; - - if (frames == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; - goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - - hw_avail = snd_pcm_playback_hw_avail(runtime); - if (hw_avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)hw_avail) - frames = hw_avail; - appl_ptr = runtime->control->appl_ptr - frames; - if (appl_ptr < 0) - appl_ptr += runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: - snd_pcm_stream_unlock_irq(substream); - return ret; -} - -static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; - snd_pcm_sframes_t ret; - snd_pcm_sframes_t hw_avail; - - if (frames == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_DRAINING: - break; - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; - goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - - hw_avail = snd_pcm_capture_hw_avail(runtime); - if (hw_avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)hw_avail) - frames = hw_avail; - appl_ptr = runtime->control->appl_ptr - frames; - if (appl_ptr < 0) - appl_ptr += runtime->boundary; - runtime->control->appl_ptr = appl_ptr; - ret = frames; - __end: - snd_pcm_stream_unlock_irq(substream); - return ret; -} - -static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; - snd_pcm_sframes_t ret; - snd_pcm_sframes_t avail; - - if (frames == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; - goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - - avail = snd_pcm_playback_avail(runtime); - if (avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)avail) - frames = avail; - 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; - ret = frames; - __end: - snd_pcm_stream_unlock_irq(substream); - return ret; -} - -static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t appl_ptr; - snd_pcm_sframes_t ret; - snd_pcm_sframes_t avail; - - if (frames == 0) - return 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_PAUSED: - break; - case SNDRV_PCM_STATE_RUNNING: - if (snd_pcm_update_hw_ptr(substream) >= 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_XRUN: - ret = -EPIPE; - goto __end; - case SNDRV_PCM_STATE_SUSPENDED: - ret = -ESTRPIPE; - goto __end; - default: - ret = -EBADFD; - goto __end; - } - - avail = snd_pcm_capture_avail(runtime); - if (avail <= 0) { - ret = 0; - goto __end; - } - if (frames > (snd_pcm_uframes_t)avail) - frames = avail; - 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; - ret = frames; - __end: - snd_pcm_stream_unlock_irq(substream); - return ret; -} - -static int snd_pcm_hwsync(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_DRAINING: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - goto __badfd; - case SNDRV_PCM_STATE_RUNNING: - if ((err = snd_pcm_update_hw_ptr(substream)) < 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_SUSPENDED: - err = 0; - break; - case SNDRV_PCM_STATE_XRUN: - err = -EPIPE; - break; - default: - __badfd: - err = -EBADFD; - break; - } - snd_pcm_stream_unlock_irq(substream); - return err; -} - -static int snd_pcm_delay(struct snd_pcm_substream *substream, - snd_pcm_sframes_t __user *res) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - snd_pcm_sframes_t n = 0; - - snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_DRAINING: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - goto __badfd; - case SNDRV_PCM_STATE_RUNNING: - if ((err = snd_pcm_update_hw_ptr(substream)) < 0) - break; - /* Fall through */ - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_SUSPENDED: - err = 0; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - 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; - break; - default: - __badfd: - err = -EBADFD; - break; - } - snd_pcm_stream_unlock_irq(substream); - if (!err) - if (put_user(n, res)) - err = -EFAULT; - return err; -} - -static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, - struct snd_pcm_sync_ptr __user *_sync_ptr) -{ - 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 snd_pcm_mmap_control))) - return -EFAULT; - status = runtime->status; - control = runtime->control; - if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { - err = snd_pcm_hwsync(substream); - if (err < 0) - return err; - } - snd_pcm_stream_lock_irq(substream); - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = sync_ptr.c.control.appl_ptr; - else - sync_ptr.c.control.appl_ptr = control->appl_ptr; - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = sync_ptr.c.control.avail_min; - else - sync_ptr.c.control.avail_min = control->avail_min; - sync_ptr.s.status.state = status->state; - sync_ptr.s.status.hw_ptr = status->hw_ptr; - sync_ptr.s.status.tstamp = status->tstamp; - sync_ptr.s.status.suspended_state = status->suspended_state; - snd_pcm_stream_unlock_irq(substream); - if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) - return -EFAULT; - return 0; -} - -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) -{ - 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: /* 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: - return snd_pcm_hw_params_user(substream, arg); - case SNDRV_PCM_IOCTL_HW_FREE: - return snd_pcm_hw_free(substream); - case SNDRV_PCM_IOCTL_SW_PARAMS: - return snd_pcm_sw_params_user(substream, arg); - case SNDRV_PCM_IOCTL_STATUS: - return snd_pcm_status_user(substream, arg); - case SNDRV_PCM_IOCTL_CHANNEL_INFO: - return snd_pcm_channel_info_user(substream, arg); - case SNDRV_PCM_IOCTL_PREPARE: - return snd_pcm_prepare(substream, file); - case SNDRV_PCM_IOCTL_RESET: - return snd_pcm_reset(substream); - case SNDRV_PCM_IOCTL_START: - return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); - case SNDRV_PCM_IOCTL_LINK: - return snd_pcm_link(substream, (int)(unsigned long) arg); - case SNDRV_PCM_IOCTL_UNLINK: - return snd_pcm_unlink(substream); - case SNDRV_PCM_IOCTL_RESUME: - return snd_pcm_resume(substream); - case SNDRV_PCM_IOCTL_XRUN: - return snd_pcm_xrun(substream); - case SNDRV_PCM_IOCTL_HWSYNC: - return snd_pcm_hwsync(substream); - case SNDRV_PCM_IOCTL_DELAY: - 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, 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); - return -ENOTTY; -} - -static int snd_pcm_playback_ioctl1(struct file *file, - struct snd_pcm_substream *substream, - unsigned int cmd, void __user *arg) -{ - 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: - { - struct snd_xferi xferi; - struct snd_xferi __user *_xferi = arg; - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (put_user(0, &_xferi->result)) - return -EFAULT; - if (copy_from_user(&xferi, _xferi, sizeof(xferi))) - return -EFAULT; - result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); - __put_user(result, &_xferi->result); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_WRITEN_FRAMES: - { - struct snd_xfern xfern; - struct snd_xfern __user *_xfern = arg; - struct snd_pcm_runtime *runtime = substream->runtime; - void __user **bufs; - snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (runtime->channels > 128) - return -EINVAL; - if (put_user(0, &_xfern->result)) - return -EFAULT; - if (copy_from_user(&xfern, _xfern, sizeof(xfern))) - return -EFAULT; - - bufs = memdup_user(xfern.bufs, - sizeof(void *) * runtime->channels); - if (IS_ERR(bufs)) - return PTR_ERR(bufs); - result = snd_pcm_lib_writev(substream, bufs, xfern.frames); - kfree(bufs); - __put_user(result, &_xfern->result); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_REWIND: - { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; - snd_pcm_sframes_t result; - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_playback_rewind(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_FORWARD: - { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; - snd_pcm_sframes_t result; - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_playback_forward(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; - } - } - return snd_pcm_common_ioctl1(file, substream, cmd, arg); -} - -static int snd_pcm_capture_ioctl1(struct file *file, - struct snd_pcm_substream *substream, - unsigned int cmd, void __user *arg) -{ - if (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: - { - struct snd_xferi xferi; - struct snd_xferi __user *_xferi = arg; - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (put_user(0, &_xferi->result)) - return -EFAULT; - if (copy_from_user(&xferi, _xferi, sizeof(xferi))) - return -EFAULT; - result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); - __put_user(result, &_xferi->result); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_READN_FRAMES: - { - struct snd_xfern xfern; - struct snd_xfern __user *_xfern = arg; - struct snd_pcm_runtime *runtime = substream->runtime; - void *bufs; - snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (runtime->channels > 128) - return -EINVAL; - if (put_user(0, &_xfern->result)) - return -EFAULT; - if (copy_from_user(&xfern, _xfern, sizeof(xfern))) - return -EFAULT; - - bufs = memdup_user(xfern.bufs, - sizeof(void *) * runtime->channels); - if (IS_ERR(bufs)) - return PTR_ERR(bufs); - result = snd_pcm_lib_readv(substream, bufs, xfern.frames); - kfree(bufs); - __put_user(result, &_xfern->result); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_REWIND: - { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; - snd_pcm_sframes_t result; - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_capture_rewind(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_FORWARD: - { - snd_pcm_uframes_t frames; - snd_pcm_uframes_t __user *_frames = arg; - snd_pcm_sframes_t result; - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_capture_forward(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; - } - } - return snd_pcm_common_ioctl1(file, substream, cmd, arg); -} - -static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct snd_pcm_file *pcm_file; - - pcm_file = file->private_data; - - if (((cmd >> 8) & 0xff) != 'A') - return -ENOTTY; - - return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, - (void __user *)arg); -} - -static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct snd_pcm_file *pcm_file; - - pcm_file = file->private_data; - - if (((cmd >> 8) & 0xff) != 'A') - return -ENOTTY; - - return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, - (void __user *)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(); - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - result = snd_pcm_playback_ioctl1(NULL, substream, cmd, - (void __user *)arg); - break; - case SNDRV_PCM_STREAM_CAPTURE: - result = snd_pcm_capture_ioctl1(NULL, substream, cmd, - (void __user *)arg); - break; - default: - result = -EINVAL; - break; - } - snd_leave_user(fs); - return result; -} - -EXPORT_SYMBOL(snd_pcm_kernel_ioctl); - -static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, - loff_t * offset) -{ - 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; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - 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_read(substream, buf, count); - if (result > 0) - result = frames_to_bytes(runtime, result); - return result; -} - -static ssize_t snd_pcm_write(struct file *file, const char __user *buf, - size_t count, loff_t * offset) -{ - 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; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - 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); - return result; -} - -static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) - -{ - 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 = iocb->ki_filp->private_data; - substream = pcm_file->substream; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (nr_segs > 1024 || nr_segs != runtime->channels) - return -EINVAL; - if (!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 < 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); - kfree(bufs); - return result; -} - -static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - 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 = iocb->ki_filp->private_data; - substream = pcm_file->substream; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - 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 < 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); - return result; -} - -static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) -{ - 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; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - - poll_wait(file, &runtime->sleep, wait); - - snd_pcm_stream_lock_irq(substream); - avail = snd_pcm_playback_avail(runtime); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_PAUSED: - if (avail >= runtime->control->avail_min) { - mask = POLLOUT | POLLWRNORM; - break; - } - /* Fall through */ - case SNDRV_PCM_STATE_DRAINING: - mask = 0; - break; - default: - mask = POLLOUT | POLLWRNORM | POLLERR; - break; - } - snd_pcm_stream_unlock_irq(substream); - return mask; -} - -static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) -{ - 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; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - - poll_wait(file, &runtime->sleep, wait); - - snd_pcm_stream_lock_irq(substream); - avail = snd_pcm_capture_avail(runtime); - switch (runtime->status->state) { - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_PAUSED: - if (avail >= runtime->control->avail_min) { - mask = POLLIN | POLLRDNORM; - break; - } - mask = 0; - break; - case SNDRV_PCM_STATE_DRAINING: - if (avail > 0) { - mask = POLLIN | POLLRDNORM; - break; - } - /* Fall through */ - default: - mask = POLLIN | POLLRDNORM | POLLERR; - break; - } - snd_pcm_stream_unlock_irq(substream); - return mask; -} - -/* - * mmap support - */ - -/* - * Only on coherent architectures, we can mmap the status and the control records - * for effcient data transfer. On others, we have to use HWSYNC ioctl... - */ -#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) -/* - * mmap status record - */ -static int snd_pcm_mmap_status_fault(struct vm_area_struct *area, - struct vm_fault *vmf) -{ - struct snd_pcm_substream *substream = area->vm_private_data; - struct snd_pcm_runtime *runtime; - - if (substream == NULL) - return VM_FAULT_SIGBUS; - runtime = substream->runtime; - vmf->page = virt_to_page(runtime->status); - get_page(vmf->page); - return 0; -} - -static const struct vm_operations_struct snd_pcm_vm_ops_status = -{ - .fault = snd_pcm_mmap_status_fault, -}; - -static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, - struct vm_area_struct *area) -{ - long size; - if (!(area->vm_flags & VM_READ)) - return -EINVAL; - size = area->vm_end - area->vm_start; - 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; - return 0; -} - -/* - * mmap control record - */ -static int snd_pcm_mmap_control_fault(struct vm_area_struct *area, - struct vm_fault *vmf) -{ - struct snd_pcm_substream *substream = area->vm_private_data; - struct snd_pcm_runtime *runtime; - - if (substream == NULL) - return VM_FAULT_SIGBUS; - runtime = substream->runtime; - vmf->page = virt_to_page(runtime->control); - get_page(vmf->page); - return 0; -} - -static const struct vm_operations_struct snd_pcm_vm_ops_control = -{ - .fault = snd_pcm_mmap_control_fault, -}; - -static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, - struct vm_area_struct *area) -{ - long size; - if (!(area->vm_flags & VM_READ)) - return -EINVAL; - size = area->vm_end - area->vm_start; - 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; - return 0; -} -#else /* ! coherent mmap */ -/* - * don't support mmap for status and control records. - */ -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(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); -} - -/* - * fault callback for mmapping a RAM page - */ -static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, - struct vm_fault *vmf) -{ - struct snd_pcm_substream *substream = area->vm_private_data; - struct snd_pcm_runtime *runtime; - unsigned long offset; - struct page * page; - size_t dma_bytes; - - if (substream == NULL) - return VM_FAULT_SIGBUS; - runtime = substream->runtime; - offset = vmf->pgoff << PAGE_SHIFT; - dma_bytes = PAGE_ALIGN(runtime->dma_bytes); - if (offset > dma_bytes - PAGE_SIZE) - return VM_FAULT_SIGBUS; - if (substream->ops->page) - page = substream->ops->page(substream, offset); - else - page = snd_pcm_default_page_ops(substream, offset); - if (!page) - return VM_FAULT_SIGBUS; - get_page(page); - vmf->page = page; - return 0; -} - -static const struct vm_operations_struct snd_pcm_vm_ops_data = { - .open = snd_pcm_mmap_data_open, - .close = snd_pcm_mmap_data_close, -}; - -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 - */ -int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area) -{ - area->vm_flags |= VM_RESERVED; -#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 -int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, - struct vm_area_struct *area) -{ - long size; - unsigned long offset; - - area->vm_page_prot = pgprot_noncached(area->vm_page_prot); - 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; - return 0; -} - -EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); -#endif /* SNDRV_PCM_INFO_MMAP */ - -/* - * mmap DMA buffer - */ -int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, - struct vm_area_struct *area) -{ - 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))) - return -EINVAL; - } else { - if (!(area->vm_flags & VM_READ)) - return -EINVAL; - } - runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) - return -ENXIO; - if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || - runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; - size = area->vm_end - area->vm_start; - offset = area->vm_pgoff << PAGE_SHIFT; - dma_bytes = PAGE_ALIGN(runtime->dma_bytes); - if ((size_t)size > dma_bytes) - return -EINVAL; - if (offset > dma_bytes - size) - return -EINVAL; - - area->vm_ops = &snd_pcm_vm_ops_data; - area->vm_private_data = substream; - if (substream->ops->mmap) - err = substream->ops->mmap(substream, area); - else - 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) -{ - struct snd_pcm_file * pcm_file; - struct snd_pcm_substream *substream; - unsigned long offset; - - pcm_file = file->private_data; - substream = pcm_file->substream; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - - offset = area->vm_pgoff << PAGE_SHIFT; - switch (offset) { - case SNDRV_PCM_MMAP_OFFSET_STATUS: - if (pcm_file->no_compat_mmap) - return -ENXIO; - return snd_pcm_mmap_status(substream, file, area); - case SNDRV_PCM_MMAP_OFFSET_CONTROL: - if (pcm_file->no_compat_mmap) - return -ENXIO; - return snd_pcm_mmap_control(substream, file, area); - default: - return snd_pcm_mmap_data(substream, file, area); - } - return 0; -} - -static int snd_pcm_fasync(int fd, struct file * file, int on) -{ - 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; - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - runtime = substream->runtime; - return fasync_helper(fd, file, on, &runtime->fasync); -} - -/* - * ioctl32 compat - */ -#ifdef CONFIG_COMPAT -#include "pcm_compat.c" -#else -#define snd_pcm_ioctl_compat NULL -#endif - -/* - * 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(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_params_old *oparams) -{ - unsigned int i; - - memset(params, 0, sizeof(*params)); - params->flags = oparams->flags; - for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) - params->masks[i].bits[0] = oparams->masks[i]; - memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); - params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); - params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); - params->info = oparams->info; - params->msbits = oparams->msbits; - params->rate_num = oparams->rate_num; - params->rate_den = oparams->rate_den; - params->fifo_size = oparams->fifo_size; -} - -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; - - memset(oparams, 0, sizeof(*oparams)); - oparams->flags = params->flags; - for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) - oparams->masks[i] = params->masks[i].bits[0]; - memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); - oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); - oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); - oparams->info = params->info; - oparams->msbits = params->msbits; - oparams->rate_num = params->rate_num; - oparams->rate_den = params->rate_den; - oparams->fifo_size = params->fifo_size; -} - -static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params_old __user * _oparams) -{ - struct snd_pcm_hw_params *params; - struct snd_pcm_hw_params_old *oparams = NULL; - int err; - - params = kmalloc(sizeof(*params), GFP_KERNEL); - 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); - err = snd_pcm_hw_refine(substream, params); - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { - if (!err) - err = -EFAULT; - } - - kfree(oparams); -out: - kfree(params); - return err; -} - -static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params_old __user * _oparams) -{ - struct snd_pcm_hw_params *params; - struct snd_pcm_hw_params_old *oparams = NULL; - int err; - - params = kmalloc(sizeof(*params), GFP_KERNEL); - 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); - err = snd_pcm_hw_params(substream, params); - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { - if (!err) - err = -EFAULT; - } - - kfree(oparams); -out: - kfree(params); - 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 - */ - -const struct file_operations snd_pcm_f_ops[2] = { - { - .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, - }, - { - .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/ANDROID_3.4.5/sound/core/pcm_timer.c b/ANDROID_3.4.5/sound/core/pcm_timer.c deleted file mode 100644 index b01d9481..00000000 --- a/ANDROID_3.4.5/sound/core/pcm_timer.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/time.h> -#include <linux/gcd.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/timer.h> - -/* - * Timer functions - */ - -void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) -{ - unsigned long rate, mult, fsize, l, post; - struct snd_pcm_runtime *runtime = substream->runtime; - - mult = 1000000000; - rate = runtime->rate; - if (snd_BUG_ON(!rate)) - return; - l = gcd(mult, rate); - mult /= l; - rate /= l; - fsize = runtime->period_size; - if (snd_BUG_ON(!fsize)) - return; - l = gcd(rate, fsize); - rate /= l; - fsize /= l; - post = 1; - while ((mult * fsize) / fsize != mult) { - mult /= 2; - 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); - runtime->timer_resolution = -1; - return; - } - runtime->timer_resolution = (mult * fsize / rate) * post; -} - -static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) -{ - struct snd_pcm_substream *substream; - - substream = timer->private_data; - return substream->runtime ? substream->runtime->timer_resolution : 0; -} - -static int snd_pcm_timer_start(struct snd_timer * timer) -{ - struct snd_pcm_substream *substream; - - substream = snd_timer_chip(timer); - substream->timer_running = 1; - return 0; -} - -static int snd_pcm_timer_stop(struct snd_timer * timer) -{ - struct snd_pcm_substream *substream; - - substream = snd_timer_chip(timer); - substream->timer_running = 0; - return 0; -} - -static struct snd_timer_hardware snd_pcm_timer = -{ - .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE, - .resolution = 0, - .ticks = 1, - .c_resolution = snd_pcm_timer_resolution, - .start = snd_pcm_timer_start, - .stop = snd_pcm_timer_stop, -}; - -/* - * Init functions - */ - -static void snd_pcm_timer_free(struct snd_timer *timer) -{ - struct snd_pcm_substream *substream = timer->private_data; - substream->timer = NULL; -} - -void snd_pcm_timer_init(struct snd_pcm_substream *substream) -{ - struct snd_timer_id tid; - struct snd_timer *timer; - - tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; - tid.dev_class = SNDRV_TIMER_CLASS_PCM; - tid.card = substream->pcm->card->number; - tid.device = substream->pcm->device; - tid.subdevice = (substream->number << 1) | (substream->stream & 1); - if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0) - return; - sprintf(timer->name, "PCM %s %i-%i-%i", - substream->stream == SNDRV_PCM_STREAM_CAPTURE ? - "capture" : "playback", - tid.card, tid.device, tid.subdevice); - timer->hw = snd_pcm_timer; - if (snd_device_register(timer->card, timer) < 0) { - snd_device_free(timer->card, timer); - return; - } - timer->private_data = substream; - timer->private_free = snd_pcm_timer_free; - substream->timer = timer; -} - -void snd_pcm_timer_done(struct snd_pcm_substream *substream) -{ - if (substream->timer) { - snd_device_free(substream->pcm->card, substream->timer); - substream->timer = NULL; - } -} diff --git a/ANDROID_3.4.5/sound/core/rawmidi.c b/ANDROID_3.4.5/sound/core/rawmidi.c deleted file mode 100644 index 1bb95aee..00000000 --- a/ANDROID_3.4.5/sound/core/rawmidi.c +++ /dev/null @@ -1,1726 +0,0 @@ -/* - * Abstract layer for MIDI v1.0 stream - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <sound/core.h> -#include <linux/major.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/mutex.h> -#include <linux/module.h> -#include <linux/delay.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@perex.cz>"); -MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA."); -MODULE_LICENSE("GPL"); - -#ifdef CONFIG_SND_OSSEMUL -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."); -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(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 struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) -{ - struct snd_rawmidi *rawmidi; - - 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) -{ - switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { - case FMODE_WRITE: - return SNDRV_RAWMIDI_LFLG_OUTPUT; - case FMODE_READ: - return SNDRV_RAWMIDI_LFLG_INPUT; - default: - return SNDRV_RAWMIDI_LFLG_OPEN; - } -} - -static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - return runtime->avail >= runtime->avail_min; -} - -static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream, - size_t count) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - return runtime->avail >= runtime->avail_min && - (!substream->append || runtime->avail >= count); -} - -static void snd_rawmidi_input_event_work(struct work_struct *work) -{ - 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(struct snd_rawmidi_substream *substream) -{ - 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); - INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); - runtime->event = NULL; - runtime->buffer_size = PAGE_SIZE; - runtime->avail_min = 1; - if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) - runtime->avail = 0; - else - runtime->avail = runtime->buffer_size; - if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) { - kfree(runtime); - return -ENOMEM; - } - runtime->appl_ptr = runtime->hw_ptr = 0; - substream->runtime = runtime; - return 0; -} - -static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - - kfree(runtime->buffer); - kfree(runtime); - substream->runtime = NULL; - return 0; -} - -static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up) -{ - if (!substream->opened) - return; - substream->ops->trigger(substream, 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) - cancel_work_sync(&substream->runtime->event_work); -} - -int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) -{ - unsigned long flags; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - snd_rawmidi_output_trigger(substream, 0); - runtime->drain = 0; - spin_lock_irqsave(&runtime->lock, flags); - runtime->appl_ptr = runtime->hw_ptr = 0; - runtime->avail = runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); - return 0; -} - -int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) -{ - int err; - long timeout; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - err = 0; - runtime->drain = 1; - timeout = wait_event_interruptible_timeout(runtime->sleep, - (runtime->avail >= runtime->buffer_size), - 10*HZ); - 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); - err = -EIO; - } - runtime->drain = 0; - if (err != -ERESTARTSYS) { - /* we need wait a while to make sure that Tx FIFOs are empty */ - if (substream->ops->drain) - substream->ops->drain(substream); - else - msleep(50); - snd_rawmidi_drop_output(substream); - } - return err; -} - -int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) -{ - unsigned long flags; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - snd_rawmidi_input_trigger(substream, 0); - runtime->drain = 0; - spin_lock_irqsave(&runtime->lock, flags); - runtime->appl_ptr = runtime->hw_ptr = 0; - runtime->avail = 0; - spin_unlock_irqrestore(&runtime->lock, flags); - return 0; -} - -/* 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) -{ - 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 (!(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 (subdevice < 0 || subdevice == substream->number) { - *sub_ret = substream; - return 0; - } - } - 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; - } - 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) { - err = assign_substream(rmidi, subdevice, - SNDRV_RAWMIDI_STREAM_INPUT, - mode, &sinput); - if (err < 0) - return err; - } - if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { - err = assign_substream(rmidi, subdevice, - SNDRV_RAWMIDI_STREAM_OUTPUT, - mode, &soutput); - if (err < 0) - return err; - } - - 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; -} - -/* 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(®ister_mutex); - rmidi = snd_rawmidi_search(card, device); - if (rmidi == NULL) { - mutex_unlock(®ister_mutex); - return -ENODEV; - } - if (!try_module_get(rmidi->card->module)) { - mutex_unlock(®ister_mutex); - return -ENXIO; - } - mutex_unlock(®ister_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; -} - -static int snd_rawmidi_open(struct inode *inode, struct file *file) -{ - int maj = imajor(inode); - struct snd_card *card; - int subdevice; - unsigned short fflags; - int err; - struct snd_rawmidi *rmidi; - struct snd_rawmidi_file *rawmidi_file = NULL; - wait_queue_t wait; - 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 - } else if (maj == SOUND_MAJOR) { - rmidi = snd_lookup_oss_minor_data(iminor(inode), - SNDRV_OSS_DEVICE_TYPE_MIDI); -#endif - } else - return -ENXIO; - - if (rmidi == NULL) - return -ENODEV; - - if (!try_module_get(rmidi->card->module)) { - snd_card_unref(rmidi->card); - return -ENXIO; - } - - mutex_lock(&rmidi->open_mutex); - card = rmidi->card; - err = snd_card_file_add(card, file); - if (err < 0) - goto __error_card; - fflags = snd_rawmidi_file_flags(file); - if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ - fflags |= SNDRV_RAWMIDI_LFLG_APPEND; - rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); - if (rawmidi_file == NULL) { - err = -ENOMEM; - goto __error; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&rmidi->open_wait, &wait); - while (1) { - subdevice = -1; - 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; - if (subdevice != -1) - break; - } - } - read_unlock(&card->ctl_files_rwlock); - err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); - if (err >= 0) - break; - if (err == -EAGAIN) { - if (file->f_flags & O_NONBLOCK) { - err = -EBUSY; - break; - } - } else - break; - set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&rmidi->open_mutex); - schedule(); - 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 - 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; -} - -static void close_substream(struct snd_rawmidi *rmidi, - struct snd_rawmidi_substream *substream, - int cleanup) -{ - if (--substream->use_count) - return; - - 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 - */ - 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 (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; -} - -static int snd_rawmidi_release(struct inode *inode, struct file *file) -{ - struct snd_rawmidi_file *rfile; - struct snd_rawmidi *rmidi; - struct module *module; - - rfile = file->private_data; - rmidi = rfile->rmidi; - rawmidi_release_priv(rfile); - kfree(rfile); - module = rmidi->card->module; - snd_card_file_remove(rmidi->card, file); - module_put(module); - return 0; -} - -static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_info *info) -{ - struct snd_rawmidi *rmidi; - - if (substream == NULL) - return -ENODEV; - rmidi = substream->rmidi; - memset(info, 0, sizeof(*info)); - info->card = rmidi->card->number; - info->device = rmidi->device; - info->subdevice = substream->number; - info->stream = substream->stream; - info->flags = rmidi->info_flags; - strcpy(info->id, rmidi->id); - strcpy(info->name, rmidi->name); - strcpy(info->subname, substream->name); - info->subdevices_count = substream->pstr->substream_count; - info->subdevices_avail = (substream->pstr->substream_count - - substream->pstr->substream_opened); - return 0; -} - -static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_info __user * _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(struct snd_rawmidi_info))) - return -EFAULT; - return 0; -} - -int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) -{ - struct snd_rawmidi *rmidi; - struct snd_rawmidi_str *pstr; - struct snd_rawmidi_substream *substream; - - mutex_lock(®ister_mutex); - rmidi = snd_rawmidi_search(card, info->device); - mutex_unlock(®ister_mutex); - if (!rmidi) - return -ENXIO; - if (info->stream < 0 || info->stream > 1) - return -EINVAL; - pstr = &rmidi->streams[info->stream]; - if (pstr->substream_count == 0) - return -ENOENT; - if (info->subdevice >= pstr->substream_count) - return -ENXIO; - list_for_each_entry(substream, &pstr->substreams, list) { - if ((unsigned int)substream->number == info->subdevice) - return snd_rawmidi_info(substream, info); - } - return -ENXIO; -} - -static int snd_rawmidi_info_select_user(struct snd_card *card, - struct snd_rawmidi_info __user *_info) -{ - int err; - struct snd_rawmidi_info info; - if (get_user(info.device, &_info->device)) - return -EFAULT; - if (get_user(info.stream, &_info->stream)) - return -EFAULT; - if (get_user(info.subdevice, &_info->subdevice)) - return -EFAULT; - if ((err = snd_rawmidi_info_select(card, &info)) < 0) - return err; - if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info))) - return -EFAULT; - return 0; -} - -int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params * params) -{ - char *newbuf; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - if (substream->append && substream->use_count > 1) - return -EBUSY; - snd_rawmidi_drain_output(substream); - if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { - return -EINVAL; - } - if (params->avail_min < 1 || params->avail_min > params->buffer_size) { - return -EINVAL; - } - if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); - if (!newbuf) - return -ENOMEM; - 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; -} - -int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params * params) -{ - char *newbuf; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - snd_rawmidi_drain_input(substream); - if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { - return -EINVAL; - } - if (params->avail_min < 1 || params->avail_min > params->buffer_size) { - return -EINVAL; - } - if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); - if (!newbuf) - return -ENOMEM; - runtime->buffer = newbuf; - runtime->buffer_size = params->buffer_size; - } - runtime->avail_min = params->avail_min; - return 0; -} - -static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_status * status) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - - memset(status, 0, sizeof(*status)); - status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - spin_lock_irq(&runtime->lock); - status->avail = runtime->avail; - spin_unlock_irq(&runtime->lock); - return 0; -} - -static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_status * status) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - - memset(status, 0, sizeof(*status)); - status->stream = SNDRV_RAWMIDI_STREAM_INPUT; - spin_lock_irq(&runtime->lock); - status->avail = runtime->avail; - status->xruns = runtime->xruns; - runtime->xruns = 0; - spin_unlock_irq(&runtime->lock); - return 0; -} - -static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct snd_rawmidi_file *rfile; - void __user *argp = (void __user *)arg; - - rfile = file->private_data; - if (((cmd >> 8) & 0xff) != 'W') - return -ENOTTY; - switch (cmd) { - case SNDRV_RAWMIDI_IOCTL_PVERSION: - return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0; - case SNDRV_RAWMIDI_IOCTL_INFO: - { - int stream; - struct snd_rawmidi_info __user *info = argp; - if (get_user(stream, &info->stream)) - return -EFAULT; - switch (stream) { - case SNDRV_RAWMIDI_STREAM_INPUT: - return snd_rawmidi_info_user(rfile->input, info); - case SNDRV_RAWMIDI_STREAM_OUTPUT: - return snd_rawmidi_info_user(rfile->output, info); - default: - return -EINVAL; - } - } - case SNDRV_RAWMIDI_IOCTL_PARAMS: - { - struct snd_rawmidi_params params; - if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) - return -EFAULT; - switch (params.stream) { - case SNDRV_RAWMIDI_STREAM_OUTPUT: - if (rfile->output == NULL) - return -EINVAL; - return snd_rawmidi_output_params(rfile->output, ¶ms); - case SNDRV_RAWMIDI_STREAM_INPUT: - if (rfile->input == NULL) - return -EINVAL; - return snd_rawmidi_input_params(rfile->input, ¶ms); - default: - return -EINVAL; - } - } - case SNDRV_RAWMIDI_IOCTL_STATUS: - { - int err = 0; - 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: - if (rfile->output == NULL) - return -EINVAL; - err = snd_rawmidi_output_status(rfile->output, &status); - break; - case SNDRV_RAWMIDI_STREAM_INPUT: - if (rfile->input == NULL) - return -EINVAL; - err = snd_rawmidi_input_status(rfile->input, &status); - break; - default: - return -EINVAL; - } - if (err < 0) - return err; - if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status))) - return -EFAULT; - return 0; - } - case SNDRV_RAWMIDI_IOCTL_DROP: - { - int val; - if (get_user(val, (int __user *) argp)) - return -EFAULT; - switch (val) { - case SNDRV_RAWMIDI_STREAM_OUTPUT: - if (rfile->output == NULL) - return -EINVAL; - return snd_rawmidi_drop_output(rfile->output); - default: - return -EINVAL; - } - } - case SNDRV_RAWMIDI_IOCTL_DRAIN: - { - int val; - if (get_user(val, (int __user *) argp)) - return -EFAULT; - switch (val) { - case SNDRV_RAWMIDI_STREAM_OUTPUT: - if (rfile->output == NULL) - return -EINVAL; - return snd_rawmidi_drain_output(rfile->output); - case SNDRV_RAWMIDI_STREAM_INPUT: - if (rfile->input == NULL) - return -EINVAL; - return snd_rawmidi_drain_input(rfile->input); - default: - return -EINVAL; - } - } -#ifdef CONFIG_SND_DEBUG - default: - snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd); -#endif - } - return -ENOTTY; -} - -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; - - switch (cmd) { - case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: - { - int device; - - 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(®ister_mutex); - device = device < 0 ? 0 : device + 1; - while (device < SNDRV_RAWMIDI_DEVICES) { - if (snd_rawmidi_search(card, device)) - break; - device++; - } - if (device == SNDRV_RAWMIDI_DEVICES) - device = -1; - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)argp)) - return -EFAULT; - return 0; - } - case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: - { - int val; - - if (get_user(val, (int __user *)argp)) - return -EFAULT; - control->prefer_rawmidi_subdevice = val; - return 0; - } - case SNDRV_CTL_IOCTL_RAWMIDI_INFO: - return snd_rawmidi_info_select_user(card, argp); - } - return -ENOIOCTLCMD; -} - -/** - * snd_rawmidi_receive - receive the input data from the device - * @substream: the rawmidi substream - * @buffer: the buffer pointer - * @count: the data size to read - * - * Reads the data from the internal buffer. - * - * Returns the size of read data, or a negative error code on failure. - */ -int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, - const unsigned char *buffer, int count) -{ - unsigned long flags; - int result = 0, count1; - 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"); - return -EINVAL; - } - spin_lock_irqsave(&runtime->lock, flags); - if (count == 1) { /* special case, faster code */ - substream->bytes++; - if (runtime->avail < runtime->buffer_size) { - runtime->buffer[runtime->hw_ptr++] = buffer[0]; - runtime->hw_ptr %= runtime->buffer_size; - runtime->avail++; - result++; - } else { - runtime->xruns++; - } - } else { - substream->bytes += count; - count1 = runtime->buffer_size - runtime->hw_ptr; - if (count1 > count) - count1 = count; - if (count1 > (int)(runtime->buffer_size - runtime->avail)) - count1 = runtime->buffer_size - runtime->avail; - memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); - runtime->hw_ptr += count1; - runtime->hw_ptr %= runtime->buffer_size; - runtime->avail += count1; - count -= count1; - result += count1; - if (count > 0) { - buffer += count1; - count1 = count; - if (count1 > (int)(runtime->buffer_size - runtime->avail)) { - count1 = runtime->buffer_size - runtime->avail; - runtime->xruns += count - count1; - } - if (count1 > 0) { - memcpy(runtime->buffer, buffer, count1); - runtime->hw_ptr = count1; - runtime->avail += count1; - result += count1; - } - } - } - if (result > 0) { - if (runtime->event) - schedule_work(&runtime->event_work); - else if (snd_rawmidi_ready(substream)) - wake_up(&runtime->sleep); - } - spin_unlock_irqrestore(&runtime->lock, flags); - return result; -} - -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; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - while (count > 0 && runtime->avail) { - count1 = runtime->buffer_size - runtime->appl_ptr; - if (count1 > count) - count1 = count; - spin_lock_irqsave(&runtime->lock, flags); - if (count1 > (int)runtime->avail) - count1 = runtime->avail; - if (kernelbuf) - memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); - if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); - if (copy_to_user(userbuf + result, - runtime->buffer + runtime->appl_ptr, count1)) { - return result > 0 ? result : -EFAULT; - } - spin_lock_irqsave(&runtime->lock, flags); - } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - spin_unlock_irqrestore(&runtime->lock, flags); - result += count1; - count -= count1; - } - return result; -} - -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, NULL/*userbuf*/, buf, count); -} - -static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, - loff_t *offset) -{ - long result; - int count1; - struct snd_rawmidi_file *rfile; - struct snd_rawmidi_substream *substream; - struct snd_rawmidi_runtime *runtime; - - rfile = file->private_data; - substream = rfile->input; - if (substream == NULL) - return -EIO; - runtime = substream->runtime; - snd_rawmidi_input_trigger(substream, 1); - result = 0; - while (count > 0) { - spin_lock_irq(&runtime->lock); - while (!snd_rawmidi_ready(substream)) { - wait_queue_t wait; - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - spin_unlock_irq(&runtime->lock); - return result > 0 ? result : -EAGAIN; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); - 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) - return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); - } - spin_unlock_irq(&runtime->lock); - count1 = snd_rawmidi_kernel_read1(substream, - (unsigned char __user *)buf, - NULL/*kernelbuf*/, - count); - if (count1 < 0) - return result > 0 ? result : count1; - result += count1; - buf += count1; - count -= count1; - } - return result; -} - -/** - * 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. - */ -int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) -{ - 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"); - return 1; - } - spin_lock_irqsave(&runtime->lock, flags); - result = runtime->avail >= runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); - return result; -} - -/** - * snd_rawmidi_transmit_peek - copy data from the internal buffer - * @substream: the rawmidi substream - * @buffer: the buffer pointer - * @count: data size to transfer - * - * Copies data from the internal output buffer to the given buffer. - * - * Call this in the interrupt handler when the midi output is ready, - * and call snd_rawmidi_transmit_ack() after the transmission is - * finished. - * - * Returns the size of copied data, or a negative error code on failure. - */ -int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, - unsigned char *buffer, int count) -{ - unsigned long flags; - int result, count1; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n"); - return -EINVAL; - } - result = 0; - spin_lock_irqsave(&runtime->lock, flags); - if (runtime->avail >= runtime->buffer_size) { - /* warning: lowlevel layer MUST trigger down the hardware */ - goto __skip; - } - if (count == 1) { /* special case, faster code */ - *buffer = runtime->buffer[runtime->hw_ptr]; - result++; - } else { - count1 = runtime->buffer_size - runtime->hw_ptr; - if (count1 > count) - count1 = count; - if (count1 > (int)(runtime->buffer_size - runtime->avail)) - count1 = runtime->buffer_size - runtime->avail; - memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1); - count -= count1; - result += count1; - if (count > 0) { - if (count > (int)(runtime->buffer_size - runtime->avail - count1)) - count = runtime->buffer_size - runtime->avail - count1; - memcpy(buffer + count1, runtime->buffer, count); - result += count; - } - } - __skip: - spin_unlock_irqrestore(&runtime->lock, flags); - return result; -} - -/** - * snd_rawmidi_transmit_ack - acknowledge the transmission - * @substream: the rawmidi substream - * @count: the tranferred 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. - */ -int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) -{ - unsigned long flags; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n"); - return -EINVAL; - } - spin_lock_irqsave(&runtime->lock, flags); - snd_BUG_ON(runtime->avail + count > runtime->buffer_size); - runtime->hw_ptr += count; - runtime->hw_ptr %= runtime->buffer_size; - runtime->avail += count; - substream->bytes += count; - if (count > 0) { - if (runtime->drain || snd_rawmidi_ready(substream)) - wake_up(&runtime->sleep); - } - spin_unlock_irqrestore(&runtime->lock, flags); - return count; -} - -/** - * snd_rawmidi_transmit - copy from the buffer to the device - * @substream: the rawmidi substream - * @buffer: the buffer pointer - * @count: the data size to transfer - * - * 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. - */ -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); -} - -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; - struct snd_rawmidi_runtime *runtime = substream->runtime; - - if (snd_BUG_ON(!kernelbuf && !userbuf)) - return -EINVAL; - if (snd_BUG_ON(!runtime->buffer)) - return -EINVAL; - - result = 0; - spin_lock_irqsave(&runtime->lock, flags); - if (substream->append) { - if ((long)runtime->avail < count) { - spin_unlock_irqrestore(&runtime->lock, flags); - return -EAGAIN; - } - } - while (count > 0 && runtime->avail > 0) { - count1 = runtime->buffer_size - runtime->appl_ptr; - if (count1 > count) - count1 = count; - if (count1 > (long)runtime->avail) - count1 = runtime->avail; - 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, - userbuf + result, count1)) { - spin_lock_irqsave(&runtime->lock, flags); - result = result > 0 ? result : -EFAULT; - goto __end; - } - spin_lock_irqsave(&runtime->lock, flags); - } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - result += count1; - count -= count1; - } - __end: - count1 = runtime->avail < runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); - if (count1) - snd_rawmidi_output_trigger(substream, 1); - return result; -} - -long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, - const unsigned char *buf, long count) -{ - return snd_rawmidi_kernel_write1(substream, NULL, buf, count); -} - -static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - long result, timeout; - int count1; - struct snd_rawmidi_file *rfile; - struct snd_rawmidi_runtime *runtime; - struct snd_rawmidi_substream *substream; - - rfile = file->private_data; - substream = rfile->output; - runtime = substream->runtime; - /* we cannot put an atomic message to our buffer */ - if (substream->append && count > runtime->buffer_size) - return -EIO; - result = 0; - while (count > 0) { - spin_lock_irq(&runtime->lock); - while (!snd_rawmidi_ready_append(substream, count)) { - wait_queue_t wait; - if (file->f_flags & O_NONBLOCK) { - spin_unlock_irq(&runtime->lock); - return result > 0 ? result : -EAGAIN; - } - init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); - 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) - return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); - } - spin_unlock_irq(&runtime->lock); - count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); - if (count1 < 0) - return result > 0 ? result : count1; - result += count1; - buf += count1; - if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK)) - break; - count -= count1; - } - if (file->f_flags & O_DSYNC) { - spin_lock_irq(&runtime->lock); - while (runtime->avail != runtime->buffer_size) { - wait_queue_t wait; - unsigned int last_avail = runtime->avail; - init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); - timeout = schedule_timeout(30 * HZ); - remove_wait_queue(&runtime->sleep, &wait); - if (signal_pending(current)) - return result > 0 ? result : -ERESTARTSYS; - if (runtime->avail == last_avail && !timeout) - return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); - } - spin_unlock_irq(&runtime->lock); - } - return result; -} - -static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) -{ - struct snd_rawmidi_file *rfile; - struct snd_rawmidi_runtime *runtime; - unsigned int mask; - - rfile = file->private_data; - if (rfile->input != NULL) { - runtime = rfile->input->runtime; - snd_rawmidi_input_trigger(rfile->input, 1); - poll_wait(file, &runtime->sleep, wait); - } - if (rfile->output != NULL) { - runtime = rfile->output->runtime; - poll_wait(file, &runtime->sleep, wait); - } - mask = 0; - if (rfile->input != NULL) { - if (snd_rawmidi_ready(rfile->input)) - mask |= POLLIN | POLLRDNORM; - } - if (rfile->output != NULL) { - if (snd_rawmidi_ready(rfile->output)) - mask |= POLLOUT | POLLWRNORM; - } - return mask; -} - -/* - */ -#ifdef CONFIG_COMPAT -#include "rawmidi_compat.c" -#else -#define snd_rawmidi_ioctl_compat NULL -#endif - -/* - - */ - -static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - 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); - mutex_lock(&rmidi->open_mutex); - if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { - 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" - " Buffer size : %lu\n" - " Avail : %lu\n", - runtime->oss ? "OSS compatible" : "native", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail); - } - } - } - if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { - 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" - " Avail : %lu\n" - " Overruns : %lu\n", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail, - (unsigned long) runtime->xruns); - } - } - } - mutex_unlock(&rmidi->open_mutex); -} - -/* - * Register functions - */ - -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 int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, - struct snd_rawmidi_str *stream, - int direction, - int count) -{ - struct snd_rawmidi_substream *substream; - int idx; - - for (idx = 0; idx < count; idx++) { - substream = kzalloc(sizeof(*substream), GFP_KERNEL); - if (substream == NULL) { - snd_printk(KERN_ERR "rawmidi: cannot allocate substream\n"); - return -ENOMEM; - } - substream->stream = direction; - substream->number = idx; - substream->rmidi = rmidi; - substream->pstr = stream; - list_add_tail(&substream->list, &stream->substreams); - stream->substream_count++; - } - return 0; -} - -/** - * snd_rawmidi_new - create a rawmidi instance - * @card: the card instance - * @id: the id string - * @device: the device index - * @output_count: the number of output streams - * @input_count: the number of input streams - * @rrawmidi: the pointer to store the new rawmidi instance - * - * 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. - */ -int snd_rawmidi_new(struct snd_card *card, char *id, int device, - int output_count, int input_count, - struct snd_rawmidi ** rrawmidi) -{ - struct snd_rawmidi *rmidi; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_rawmidi_dev_free, - .dev_register = snd_rawmidi_dev_register, - .dev_disconnect = snd_rawmidi_dev_disconnect, - }; - - if (snd_BUG_ON(!card)) - return -ENXIO; - if (rrawmidi) - *rrawmidi = NULL; - rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); - if (rmidi == NULL) { - snd_printk(KERN_ERR "rawmidi: cannot allocate\n"); - return -ENOMEM; - } - rmidi->card = card; - rmidi->device = device; - 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) { - 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) { - snd_rawmidi_free(rmidi); - return err; - } - if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) { - snd_rawmidi_free(rmidi); - return err; - } - if (rrawmidi) - *rrawmidi = rmidi; - return 0; -} - -static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) -{ - struct snd_rawmidi_substream *substream; - - while (!list_empty(&stream->substreams)) { - substream = list_entry(stream->substreams.next, struct snd_rawmidi_substream, list); - list_del(&substream->list); - kfree(substream); - } -} - -static int snd_rawmidi_free(struct snd_rawmidi *rmidi) -{ - if (!rmidi) - return 0; - - snd_info_free_entry(rmidi->proc_entry); - rmidi->proc_entry = NULL; - mutex_lock(®ister_mutex); - if (rmidi->ops && rmidi->ops->dev_unregister) - rmidi->ops->dev_unregister(rmidi); - mutex_unlock(®ister_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) - rmidi->private_free(rmidi); - kfree(rmidi); - return 0; -} - -static int snd_rawmidi_dev_free(struct snd_device *device) -{ - 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(struct snd_seq_device *device) -{ - struct snd_rawmidi *rmidi = device->private_data; - rmidi->seq_dev = NULL; -} -#endif - -static int snd_rawmidi_dev_register(struct snd_device *device) -{ - int err; - struct snd_info_entry *entry; - char name[16]; - struct snd_rawmidi *rmidi = device->device_data; - - if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) - return -ENOMEM; - mutex_lock(®ister_mutex); - if (snd_rawmidi_search(rmidi->card, rmidi->device)) { - mutex_unlock(®ister_mutex); - return -EBUSY; - } - 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_f_ops, rmidi, name)) < 0) { - snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device); - list_del(&rmidi->list); - mutex_unlock(®ister_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); - list_del(&rmidi->list); - mutex_unlock(®ister_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_f_ops, - rmidi, name) < 0) { - snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0); - } else { - rmidi->ossreg++; -#ifdef SNDRV_OSS_INFO_DEV_MIDI - snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name); -#endif - } - } - if ((int)rmidi->device == amidi_map[rmidi->card->number]) { - if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, - rmidi->card, 1, &snd_rawmidi_f_ops, - rmidi, name) < 0) { - snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); - } else { - rmidi->ossreg++; - } - } -#endif /* CONFIG_SND_OSSEMUL */ - mutex_unlock(®ister_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 = snd_rawmidi_proc_info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - rmidi->proc_entry = entry; -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) - if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ - if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { - rmidi->seq_dev->private_data = rmidi; - rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free; - sprintf(rmidi->seq_dev->name, "MIDI %d-%d", rmidi->card->number, rmidi->device); - snd_device_register(rmidi->card, rmidi->seq_dev); - } - } -#endif - return 0; -} - -static int snd_rawmidi_dev_disconnect(struct snd_device *device) -{ - struct snd_rawmidi *rmidi = device->device_data; - int dir; - - mutex_lock(®ister_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]) { - snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0); -#ifdef SNDRV_OSS_INFO_DEV_MIDI - snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number); -#endif - } - if ((int)rmidi->device == amidi_map[rmidi->card->number]) - snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1); - rmidi->ossreg = 0; - } -#endif /* CONFIG_SND_OSSEMUL */ - snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); - mutex_unlock(&rmidi->open_mutex); - mutex_unlock(®ister_mutex); - return 0; -} - -/** - * snd_rawmidi_set_ops - set the rawmidi operators - * @rmidi: the rawmidi instance - * @stream: the stream direction, SNDRV_RAWMIDI_STREAM_XXX - * @ops: the operator table - * - * Sets the rawmidi operators for the given stream direction. - */ -void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, - struct snd_rawmidi_ops *ops) -{ - struct snd_rawmidi_substream *substream; - - list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) - substream->ops = ops; -} - -/* - * ENTRY functions - */ - -static int __init alsa_rawmidi_init(void) -{ - - snd_ctl_register_ioctl(snd_rawmidi_control_ioctl); - snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl); -#ifdef CONFIG_SND_OSSEMUL - { int i; - /* 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]); - 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]); - amidi_map[i] = 1; - } - } - } -#endif /* CONFIG_SND_OSSEMUL */ - return 0; -} - -static void __exit alsa_rawmidi_exit(void) -{ - snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl); - snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl); -} - -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_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/ANDROID_3.4.5/sound/core/rawmidi_compat.c b/ANDROID_3.4.5/sound/core/rawmidi_compat.c deleted file mode 100644 index 5268c1f5..00000000 --- a/ANDROID_3.4.5/sound/core/rawmidi_compat.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for raw MIDI API - * Copyright (c) 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; 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 - * - */ - -/* This file included from rawmidi.c */ - -#include <linux/compat.h> - -struct snd_rawmidi_params32 { - s32 stream; - u32 buffer_size; - u32 avail_min; - unsigned int no_active_sensing; /* avoid bit-field */ - unsigned char reserved[16]; -} __attribute__((packed)); - -static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, - struct snd_rawmidi_params32 __user *src) -{ - struct snd_rawmidi_params params; - unsigned int val; - - if (rfile->output == NULL) - return -EINVAL; - if (get_user(params.stream, &src->stream) || - get_user(params.buffer_size, &src->buffer_size) || - get_user(params.avail_min, &src->avail_min) || - get_user(val, &src->no_active_sensing)) - return -EFAULT; - params.no_active_sensing = val; - switch (params.stream) { - case SNDRV_RAWMIDI_STREAM_OUTPUT: - return snd_rawmidi_output_params(rfile->output, ¶ms); - case SNDRV_RAWMIDI_STREAM_INPUT: - return snd_rawmidi_input_params(rfile->input, ¶ms); - } - return -EINVAL; -} - -struct snd_rawmidi_status32 { - s32 stream; - struct compat_timespec tstamp; - u32 avail; - u32 xruns; - unsigned char reserved[16]; -} __attribute__((packed)); - -static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, - struct snd_rawmidi_status32 __user *src) -{ - int err; - struct snd_rawmidi_status status; - - if (rfile->output == NULL) - return -EINVAL; - if (get_user(status.stream, &src->stream)) - return -EFAULT; - - switch (status.stream) { - case SNDRV_RAWMIDI_STREAM_OUTPUT: - err = snd_rawmidi_output_status(rfile->output, &status); - break; - case SNDRV_RAWMIDI_STREAM_INPUT: - err = snd_rawmidi_input_status(rfile->input, &status); - break; - default: - return -EINVAL; - } - if (err < 0) - return err; - - if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || - put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) || - put_user(status.avail, &src->avail) || - put_user(status.xruns, &src->xruns)) - return -EFAULT; - - return 0; -} - -enum { - 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) -{ - struct snd_rawmidi_file *rfile; - void __user *argp = compat_ptr(arg); - - rfile = file->private_data; - switch (cmd) { - case SNDRV_RAWMIDI_IOCTL_PVERSION: - case SNDRV_RAWMIDI_IOCTL_INFO: - case SNDRV_RAWMIDI_IOCTL_DROP: - case SNDRV_RAWMIDI_IOCTL_DRAIN: - return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); - case SNDRV_RAWMIDI_IOCTL_PARAMS32: - return snd_rawmidi_ioctl_params_compat(rfile, argp); - case SNDRV_RAWMIDI_IOCTL_STATUS32: - return snd_rawmidi_ioctl_status_compat(rfile, argp); - } - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/rtctimer.c b/ANDROID_3.4.5/sound/core/rtctimer.c deleted file mode 100644 index e85e72ba..00000000 --- a/ANDROID_3.4.5/sound/core/rtctimer.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * RTC based high-frequency timer - * - * Copyright (C) 2000 Takashi Iwai - * based on rtctimer.c by Steve Ratcliffe - * - * 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/interrupt.h> -#include <linux/module.h> -#include <linux/log2.h> -#include <sound/core.h> -#include <sound/timer.h> - -#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE) - -#include <linux/mc146818rtc.h> - -#define RTC_FREQ 1024 /* default frequency */ -#define NANO_SEC 1000000000L /* 10^9 in sec */ - -/* - * prototypes - */ -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_AUTO | - SNDRV_TIMER_HW_FIRST | - SNDRV_TIMER_HW_TASKLET, - .ticks = 100000000L, /* FIXME: XXX */ - .open = rtctimer_open, - .close = rtctimer_close, - .start = rtctimer_start, - .stop = rtctimer_stop, -}; - -static int rtctimer_freq = RTC_FREQ; /* frequency */ -static struct snd_timer *rtctimer; -static struct tasklet_struct rtc_tasklet; -static rtc_task_t rtc_task; - - -static int -rtctimer_open(struct snd_timer *t) -{ - int err; - - err = rtc_register(&rtc_task); - if (err < 0) - return err; - t->private_data = &rtc_task; - return 0; -} - -static int -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(struct snd_timer *timer) -{ - rtc_task_t *rtc = timer->private_data; - if (snd_BUG_ON(!rtc)) - return -EINVAL; - rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq); - rtc_control(rtc, RTC_PIE_ON, 0); - return 0; -} - -static int -rtctimer_stop(struct snd_timer *timer) -{ - rtc_task_t *rtc = timer->private_data; - 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) -{ - tasklet_schedule(private_data); -} - - -/* - * ENTRY functions - */ -static int __init rtctimer_init(void) -{ - int err; - struct snd_timer *timer; - - if (rtctimer_freq < 2 || rtctimer_freq > 8192 || - !is_power_of_2(rtctimer_freq)) { - snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", - rtctimer_freq); - return -EINVAL; - } - - /* Create a new timer and set up the fields */ - err = snd_timer_global_new("rtc", SNDRV_TIMER_GLOBAL_RTC, &timer); - 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 = &rtc_tasklet; - - err = snd_timer_global_register(timer); - if (err < 0) { - snd_timer_global_free(timer); - return err; - } - rtctimer = timer; /* remember this */ - - return 0; -} - -static void __exit rtctimer_exit(void) -{ - if (rtctimer) { - snd_timer_global_free(rtctimer); - rtctimer = NULL; - } -} - - -/* - * exported stuff - */ -module_init(rtctimer_init) -module_exit(rtctimer_exit) - -module_param(rtctimer_freq, int, 0444); -MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz"); - -MODULE_LICENSE("GPL"); - -MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC)); - -#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */ diff --git a/ANDROID_3.4.5/sound/core/seq/Kconfig b/ANDROID_3.4.5/sound/core/seq/Kconfig deleted file mode 100644 index b851fd89..00000000 --- a/ANDROID_3.4.5/sound/core/seq/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# 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/ANDROID_3.4.5/sound/core/seq/Makefile b/ANDROID_3.4.5/sound/core/seq/Makefile deleted file mode 100644 index 941f64a8..00000000 --- a/ANDROID_3.4.5/sound/core/seq/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> -# - -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 \ - seq_system.o seq_ports.o seq_info.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-dummy-objs := seq_dummy.o -snd-seq-virmidi-objs := seq_virmidi.o - -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) += 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-$(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/ANDROID_3.4.5/sound/core/seq/oss/Makefile b/ANDROID_3.4.5/sound/core/seq/oss/Makefile deleted file mode 100644 index b38406b8..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for ALSA -# 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 \ - seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \ - seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o - -obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss.c deleted file mode 100644 index 8d4d5e85..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * registration of device and proc - * - * Copyright (C) 1998,99 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. - * - * 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/module.h> -#include <linux/mutex.h> -#include <sound/core.h> -#include <sound/minors.h> -#include <sound/initval.h> -#include "seq_oss_device.h" -#include "seq_oss_synth.h" - -/* - * module option - */ -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); -MODULE_DESCRIPTION("OSS-compatible sequencer module"); -MODULE_LICENSE("GPL"); -/* Takashi says this is really only for sound-service-0-, but this is OK. */ -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); -static ssize_t 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); -static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static unsigned int odev_poll(struct file *file, poll_table * wait); - - -/* - * module interface - */ - -static int __init alsa_seq_oss_init(void) -{ - int rc; - static struct snd_seq_dev_ops ops = { - snd_seq_oss_synth_register, - snd_seq_oss_synth_unregister, - }; - - snd_seq_autoload_lock(); - if ((rc = register_device()) < 0) - goto error; - if ((rc = register_proc()) < 0) { - unregister_device(); - goto error; - } - if ((rc = snd_seq_oss_create_client()) < 0) { - unregister_proc(); - unregister_device(); - goto error; - } - - if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops, - sizeof(struct snd_seq_oss_reg))) < 0) { - snd_seq_oss_delete_client(); - unregister_proc(); - unregister_device(); - goto error; - } - - /* success */ - snd_seq_oss_synth_init(); - - error: - snd_seq_autoload_unlock(); - return rc; -} - -static void __exit alsa_seq_oss_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS); - snd_seq_oss_delete_client(); - unregister_proc(); - unregister_device(); -} - -module_init(alsa_seq_oss_init) -module_exit(alsa_seq_oss_exit) - -/* - * ALSA minor device interface - */ - -static DEFINE_MUTEX(register_mutex); - -static int -odev_open(struct inode *inode, struct file *file) -{ - int level, rc; - - if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC) - level = SNDRV_SEQ_OSS_MODE_MUSIC; - else - level = SNDRV_SEQ_OSS_MODE_SYNTH; - - mutex_lock(®ister_mutex); - rc = snd_seq_oss_open(file, level); - mutex_unlock(®ister_mutex); - - return rc; -} - -static int -odev_release(struct inode *inode, struct file *file) -{ - struct seq_oss_devinfo *dp; - - if ((dp = file->private_data) == NULL) - return 0; - - snd_seq_oss_drain_write(dp); - - mutex_lock(®ister_mutex); - snd_seq_oss_release(dp); - mutex_unlock(®ister_mutex); - - return 0; -} - -static ssize_t -odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) -{ - struct seq_oss_devinfo *dp; - dp = file->private_data; - if (snd_BUG_ON(!dp)) - return -ENXIO; - return snd_seq_oss_read(dp, buf, count); -} - - -static ssize_t -odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) -{ - struct seq_oss_devinfo *dp; - dp = file->private_data; - 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) -{ - struct seq_oss_devinfo *dp; - dp = file->private_data; - if (snd_BUG_ON(!dp)) - return -ENXIO; - return snd_seq_oss_ioctl(dp, cmd, arg); -} - -#ifdef CONFIG_COMPAT -#define odev_ioctl_compat odev_ioctl -#else -#define odev_ioctl_compat NULL -#endif - -static unsigned int -odev_poll(struct file *file, poll_table * wait) -{ - struct seq_oss_devinfo *dp; - dp = file->private_data; - if (snd_BUG_ON(!dp)) - return -ENXIO; - return snd_seq_oss_poll(dp, file, wait); -} - -/* - * registration of sequencer minor device - */ - -static const struct file_operations seq_oss_f_ops = -{ - .owner = THIS_MODULE, - .read = odev_read, - .write = odev_write, - .open = odev_open, - .release = odev_release, - .poll = odev_poll, - .unlocked_ioctl = odev_ioctl, - .compat_ioctl = odev_ioctl_compat, - .llseek = noop_llseek, -}; - -static int __init -register_device(void) -{ - int rc; - - mutex_lock(®ister_mutex); - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, - NULL, 0, - &seq_oss_f_ops, NULL, - SNDRV_SEQ_OSS_DEVNAME)) < 0) { - snd_printk(KERN_ERR "can't register device seq\n"); - mutex_unlock(®ister_mutex); - return rc; - } - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, - NULL, 0, - &seq_oss_f_ops, NULL, - SNDRV_SEQ_OSS_DEVNAME)) < 0) { - snd_printk(KERN_ERR "can't register device music\n"); - snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0); - mutex_unlock(®ister_mutex); - return rc; - } - debug_printk(("device registered\n")); - mutex_unlock(®ister_mutex); - return 0; -} - -static void -unregister_device(void) -{ - mutex_lock(®ister_mutex); - debug_printk(("device unregistered\n")); - if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0) - snd_printk(KERN_ERR "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"); - mutex_unlock(®ister_mutex); -} - -/* - * /proc interface - */ - -#ifdef CONFIG_PROC_FS - -static struct snd_info_entry *info_entry; - -static void -info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf) -{ - mutex_lock(®ister_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); - mutex_unlock(®ister_mutex); -} - - -static int __init -register_proc(void) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root); - if (entry == NULL) - return -ENOMEM; - - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = NULL; - entry->c.text.read = info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } - info_entry = entry; - return 0; -} - -static void -unregister_proc(void) -{ - snd_info_free_entry(info_entry); - info_entry = NULL; -} -#endif /* CONFIG_PROC_FS */ diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_device.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_device.h deleted file mode 100644 index c0154a95..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_device.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_DEVICE_H -#define __SEQ_OSS_DEVICE_H - -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <sound/core.h> -#include <sound/seq_oss.h> -#include <sound/rawmidi.h> -#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 -#define SNDRV_SEQ_OSS_MAX_MIDI_DEVS 32 - -/* version */ -#define SNDRV_SEQ_OSS_MAJOR_VERSION 0 -#define SNDRV_SEQ_OSS_MINOR_VERSION 1 -#define SNDRV_SEQ_OSS_TINY_VERSION 8 -#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" - - -/* - * type definitions - */ - -typedef unsigned int reltime_t; -typedef unsigned int abstime_t; - - -/* - * synthesizer channel information - */ -struct seq_oss_chinfo { - int note, vel; -}; - -/* - * synthesizer information - */ -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; - int midi_mapped; -}; - - -/* - * sequencer client information - */ - -struct seq_oss_devinfo { - - int index; /* application index */ - int cseq; /* sequencer client number */ - int port; /* sequencer port number */ - int queue; /* sequencer queue number */ - - struct snd_seq_addr addr; /* address of this device */ - - int seq_mode; /* sequencer mode */ - int file_mode; /* file access */ - - /* midi device table */ - int max_mididev; - - /* synth device table */ - int max_synthdev; - struct seq_oss_synthinfo synths[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS]; - int synth_opened; - - /* output queue */ - struct seq_oss_writeq *writeq; - - /* midi input queue */ - struct seq_oss_readq *readq; - - /* timer */ - struct seq_oss_timer *timer; -}; - - -/* - * function prototypes - */ - -/* create/delete OSS sequencer client */ -int snd_seq_oss_create_client(void); -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(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(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp); - -/* */ -void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); - - -/* proc interface */ -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) -#define is_write_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_WRITE) -#define is_nonblock_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_NONBLOCK) - -/* dispatch event */ -static inline int -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(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(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, - int dest_client, int dest_port) -{ - ev->queue = dp->queue; - ev->source = dp->addr; - ev->dest.client = dest_client; - ev->dest.port = dest_port; -} - - -/* 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_printd x; } while (0) -#else -#define debug_printk(x) /**/ -#endif - -#endif /* __SEQ_OSS_DEVICE_H */ diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.c deleted file mode 100644 index 066f5f3e..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_device.h" -#include "seq_oss_synth.h" -#include "seq_oss_midi.h" -#include "seq_oss_event.h" -#include "seq_oss_timer.h" -#include <sound/seq_oss_legacy.h> -#include "seq_oss_readq.h" -#include "seq_oss_writeq.h" - - -/* - * prototypes - */ -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); - - -/* - * convert an OSS event to ALSA event - * return 0 : enqueued - * non-zero : invalid - ignored - */ - -int -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: - return extended_event(dp, q, ev); - - case EV_CHN_VOICE: - return chn_voice_event(dp, q, ev); - - case EV_CHN_COMMON: - return chn_common_event(dp, q, ev); - - case EV_TIMING: - return timing_event(dp, q, ev); - - case EV_SEQ_LOCAL: - return local_event(dp, q, ev); - - case EV_SYSEX: - return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev); - - case SEQ_MIDIPUTC: - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - return -EINVAL; - /* put a midi byte */ - if (! is_write_mode(dp->file_mode)) - break; - if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE)) - break; - if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE) - return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev); - break; - - case SEQ_ECHO: - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - return -EINVAL; - return set_echo_event(dp, q, ev); - - case SEQ_PRIVATE: - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - return -EINVAL; - return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev); - - default: - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - return -EINVAL; - return old_event(dp, q, ev); - } - return -EINVAL; -} - -/* old type events: mode1 only */ -static int -old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev) -{ - switch (q->s.code) { - case SEQ_NOTEOFF: - return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev); - - case SEQ_NOTEON: - return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev); - - case SEQ_WAIT: - /* skip */ - break; - - case SEQ_PGMCHANGE: - return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE, - q->n.chn, 0, q->n.note, ev); - - case SEQ_SYNCTIMER: - return snd_seq_oss_timer_reset(dp->timer); - } - - return -EINVAL; -} - -/* 8bytes extended event: mode1 only */ -static int -extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev) -{ - int val; - - switch (q->e.cmd) { - case SEQ_NOTEOFF: - return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev); - - case SEQ_NOTEON: - return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev); - - case SEQ_PGMCHANGE: - return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE, - q->e.chn, 0, q->e.p1, ev); - - case SEQ_AFTERTOUCH: - return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS, - q->e.chn, 0, q->e.p1, ev); - - case SEQ_BALANCE: - /* convert -128:127 to 0:127 */ - val = (char)q->e.p1; - val = (val + 128) / 2; - return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER, - q->e.chn, CTL_PAN, val, ev); - - case SEQ_CONTROLLER: - val = ((short)q->e.p3 << 8) | (short)q->e.p2; - switch (q->e.p1) { - case CTRL_PITCH_BENDER: /* SEQ1 V2 control */ - /* -0x2000:0x1fff */ - return set_control_event(dp, q->e.dev, - SNDRV_SEQ_EVENT_PITCHBEND, - q->e.chn, 0, val, ev); - case CTRL_PITCH_BENDER_RANGE: - /* conversion: 100/semitone -> 128/semitone */ - return set_control_event(dp, q->e.dev, - SNDRV_SEQ_EVENT_REGPARAM, - q->e.chn, 0, val*128/100, ev); - default: - return set_control_event(dp, q->e.dev, - SNDRV_SEQ_EVENT_CONTROL14, - q->e.chn, q->e.p1, val, ev); - } - - case SEQ_VOLMODE: - return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev); - - } - return -EINVAL; -} - -/* channel voice events: mode1 and 2 */ -static int -chn_voice_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev) -{ - if (q->v.chn >= 32) - return -EINVAL; - switch (q->v.cmd) { - case MIDI_NOTEON: - return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev); - - case MIDI_NOTEOFF: - return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev); - - case MIDI_KEY_PRESSURE: - return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS, - q->v.chn, q->v.note, q->v.parm, ev); - - } - return -EINVAL; -} - -/* channel common events: mode1 and 2 */ -static int -chn_common_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev) -{ - if (q->l.chn >= 32) - return -EINVAL; - switch (q->l.cmd) { - case MIDI_PGM_CHANGE: - return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE, - q->l.chn, 0, q->l.p1, ev); - - case MIDI_CTL_CHANGE: - return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER, - q->l.chn, q->l.p1, q->l.val, ev); - - case MIDI_PITCH_BEND: - /* conversion: 0:0x3fff -> -0x2000:0x1fff */ - return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND, - q->l.chn, 0, q->l.val - 8192, ev); - - case MIDI_CHN_PRESSURE: - return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS, - q->l.chn, 0, q->l.val, ev); - } - return -EINVAL; -} - -/* timer events: mode1 and mode2 */ -static int -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 { - union evrec tmp; - memset(&tmp, 0, sizeof(tmp)); - /* XXX: only for little-endian! */ - tmp.echo = (q->t.time << 8) | SEQ_ECHO; - return set_echo_event(dp, &tmp, ev); - } - - case TMR_STOP: - if (dp->seq_mode) - return snd_seq_oss_timer_stop(dp->timer); - return 0; - - case TMR_CONTINUE: - if (dp->seq_mode) - return snd_seq_oss_timer_continue(dp->timer); - return 0; - - case TMR_TEMPO: - if (dp->seq_mode) - return snd_seq_oss_timer_tempo(dp->timer, q->t.time); - return 0; - } - - return -EINVAL; -} - -/* local events: mode1 and 2 */ -static int -local_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev) -{ - return -EINVAL; -} - -/* - * process note-on event for OSS synth - * three different modes are available: - * - SNDRV_SEQ_OSS_PROCESS_EVENTS (for one-voice per channel mode) - * Accept note 255 as volume change. - * - SNDRV_SEQ_OSS_PASS_EVENTS - * Pass all events to lowlevel driver anyway - * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS (mostly for Emu8000) - * Use key-pressure if note >= 128 - */ -static int -note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev) -{ - struct seq_oss_synthinfo *info = &dp->synths[dev]; - switch (info->arg.event_passing) { - case SNDRV_SEQ_OSS_PROCESS_EVENTS: - if (! info->ch || ch < 0 || ch >= info->nr_voices) { - /* pass directly */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); - } - - if (note == 255 && info->ch[ch].note >= 0) { - /* volume control */ - int type; - //if (! vel) - /* set volume to zero -- note off */ - // type = SNDRV_SEQ_EVENT_NOTEOFF; - //else - if (info->ch[ch].vel) - /* sample already started -- volume change */ - type = SNDRV_SEQ_EVENT_KEYPRESS; - else - /* sample not started -- start now */ - type = SNDRV_SEQ_EVENT_NOTEON; - info->ch[ch].vel = vel; - return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev); - } else if (note >= 128) - return -EINVAL; /* invalid */ - - if (note != info->ch[ch].note && info->ch[ch].note >= 0) - /* note changed - note off at beginning */ - set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev); - /* set current status */ - info->ch[ch].note = note; - info->ch[ch].vel = vel; - if (vel) /* non-zero velocity - start the note now */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); - return -EINVAL; - - case SNDRV_SEQ_OSS_PASS_EVENTS: - /* pass the event anyway */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); - - case SNDRV_SEQ_OSS_PROCESS_KEYPRESS: - if (note >= 128) /* key pressure: shifted by 128 */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev); - else /* normal note-on event */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); - } - return -EINVAL; -} - -/* - * process note-off event for OSS synth - */ -static int -note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev) -{ - struct seq_oss_synthinfo *info = &dp->synths[dev]; - switch (info->arg.event_passing) { - case SNDRV_SEQ_OSS_PROCESS_EVENTS: - if (! info->ch || ch < 0 || ch >= info->nr_voices) { - /* pass directly */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); - } - - if (info->ch[ch].note >= 0) { - note = info->ch[ch].note; - info->ch[ch].vel = 0; - info->ch[ch].note = -1; - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev); - } - return -EINVAL; /* invalid */ - - case SNDRV_SEQ_OSS_PASS_EVENTS: - case SNDRV_SEQ_OSS_PROCESS_KEYPRESS: - /* pass the event anyway */ - return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev); - - } - return -EINVAL; -} - -/* - * create a note event - */ -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) -{ - if (! snd_seq_oss_synth_is_valid(dp, dev)) - return -ENXIO; - - ev->type = type; - snd_seq_oss_synth_addr(dp, dev, ev); - ev->data.note.channel = ch; - ev->data.note.note = note; - ev->data.note.velocity = vel; - - return 0; -} - -/* - * create a control event - */ -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) -{ - if (! snd_seq_oss_synth_is_valid(dp, dev)) - return -ENXIO; - - ev->type = type; - snd_seq_oss_synth_addr(dp, dev, ev); - ev->data.control.channel = ch; - ev->data.control.param = param; - ev->data.control.value = val; - - return 0; -} - -/* - * create an echo event - */ -static int -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 */ - snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port); - memcpy(&ev->data, rec, LONG_EVENT_SIZE); - return 0; -} - -/* - * event input callback from ALSA sequencer: - * the echo event is processed here. - */ -int -snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data, - int atomic, int hop) -{ - 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); - - if (ev->source.client != dp->cseq) - return 0; /* ignored */ - - rec = (union evrec*)&ev->data; - if (rec->s.code == SEQ_SYNCTIMER) { - /* sync echo back */ - snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time); - - } else { - /* echo back event */ - if (dp->readq == NULL) - return 0; - snd_seq_oss_readq_put_event(dp->readq, rec); - } - return 0; -} - diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.h deleted file mode 100644 index 9a4d9adb..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_event.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * seq_oss_event.h - OSS event queue record - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_EVENT_H -#define __SEQ_OSS_EVENT_H - -#include "seq_oss_device.h" - -#define SHORT_EVENT_SIZE 4 -#define LONG_EVENT_SIZE 8 - -/* short event (4bytes) */ -struct evrec_short { - unsigned char code; - unsigned char parm1; - unsigned char dev; - unsigned char parm2; -}; - -/* short note events (4bytes) */ -struct evrec_note { - unsigned char code; - unsigned char chn; - unsigned char note; - unsigned char vel; -}; - -/* long timer events (8bytes) */ -struct evrec_timer { - unsigned char code; - unsigned char cmd; - unsigned char dummy1, dummy2; - unsigned int time; -}; - -/* long extended events (8bytes) */ -struct evrec_extended { - unsigned char code; - unsigned char cmd; - unsigned char dev; - unsigned char chn; - unsigned char p1, p2, p3, p4; -}; - -/* long channel events (8bytes) */ -struct evrec_long { - unsigned char code; - unsigned char dev; - unsigned char cmd; - unsigned char chn; - unsigned char p1, p2; - unsigned short val; -}; - -/* channel voice events (8bytes) */ -struct evrec_voice { - unsigned char code; - unsigned char dev; - unsigned char cmd; - unsigned char chn; - unsigned char note, parm; - unsigned short dummy; -}; - -/* sysex events (8bytes) */ -struct evrec_sysex { - unsigned char code; - unsigned char dev; - unsigned char buf[6]; -}; - -/* event record */ -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]; -}; - -#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(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/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_init.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_init.c deleted file mode 100644 index e3cb46fe..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_init.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * open/close and reset interface - * - * Copyright (C) 1998-1999 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. - * - * 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 "seq_oss_device.h" -#include "seq_oss_synth.h" -#include "seq_oss_midi.h" -#include "seq_oss_writeq.h" -#include "seq_oss_readq.h" -#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> - -/* - * common variables - */ -static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN; -module_param(maxqlen, int, 0444); -MODULE_PARM_DESC(maxqlen, "maximum queue length"); - -static int system_client = -1; /* ALSA sequencer client number */ -static int system_port = -1; - -static int num_clients; -static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS]; - - -/* - * prototypes - */ -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(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) - - -/* - * create sequencer client for OSS sequencer - */ -int __init -snd_seq_oss_create_client(void) -{ - int rc; - struct snd_seq_port_info *port; - struct snd_seq_port_callback port_callback; - - port = kmalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - rc = -ENOMEM; - goto __error; - } - - /* create ALSA client */ - 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)); - - /* look up midi devices */ - snd_seq_oss_midi_lookup_ports(system_client); - - /* create annoucement receiver port */ - memset(port, 0, sizeof(*port)); - strcpy(port->name, "Receiver"); - port->addr.client = system_client; - port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */ - port->type = 0; - - memset(&port_callback, 0, sizeof(port_callback)); - /* don't set port_callback.owner here. otherwise the module counter - * is incremented and we can no longer release the module.. - */ - port_callback.event_input = receive_announce; - port->kernel = &port_callback; - - call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port); - if ((system_port = port->addr.port) >= 0) { - struct snd_seq_port_subscribe subs; - - memset(&subs, 0, sizeof(subs)); - subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; - subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - subs.dest.client = system_client; - subs.dest.port = system_port; - call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs); - } - rc = 0; - - __error: - kfree(port); - return rc; -} - - -/* - * receive annoucement from system port, and check the midi device - */ -static int -receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop) -{ - struct snd_seq_port_info pinfo; - - if (atomic) - return 0; /* it must not happen */ - - switch (ev->type) { - case SNDRV_SEQ_EVENT_PORT_START: - case SNDRV_SEQ_EVENT_PORT_CHANGE: - if (ev->data.addr.client == system_client) - break; /* ignore myself */ - memset(&pinfo, 0, sizeof(pinfo)); - pinfo.addr = ev->data.addr; - if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0) - snd_seq_oss_midi_check_new_port(&pinfo); - break; - - case SNDRV_SEQ_EVENT_PORT_EXIT: - if (ev->data.addr.client == system_client) - break; /* ignore myself */ - snd_seq_oss_midi_check_exit_port(ev->data.addr.client, - ev->data.addr.port); - break; - } - return 0; -} - - -/* - * delete OSS sequencer client - */ -int -snd_seq_oss_delete_client(void) -{ - if (system_client >= 0) - snd_seq_delete_kernel_client(system_client); - - snd_seq_oss_midi_clear_all(); - - return 0; -} - - -/* - * open sequencer device - */ -int -snd_seq_oss_open(struct file *file, int level) -{ - int i, rc; - struct seq_oss_devinfo *dp; - - dp = kzalloc(sizeof(*dp), GFP_KERNEL); - if (!dp) { - snd_printk(KERN_ERR "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; - } - - dp->index = i; - if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { - snd_printk(KERN_ERR "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"); */ - rc = -ENODEV; - goto _error; - } - - /* create port */ - debug_printk(("create new port\n")); - rc = create_port(dp); - if (rc < 0) { - snd_printk(KERN_ERR "can't create port\n"); - goto _error; - } - - /* allocate queue */ - debug_printk(("allocate queue\n")); - rc = alloc_seq_queue(dp); - if (rc < 0) - goto _error; - - /* set address */ - dp->addr.client = dp->cseq; - dp->addr.port = dp->port; - /*dp->addr.queue = dp->queue;*/ - /*dp->addr.channel = 0;*/ - - dp->seq_mode = level; - - /* set up file mode */ - dp->file_mode = translate_mode(file); - - /* initialize read queue */ - debug_printk(("initialize read queue\n")); - if (is_read_mode(dp->file_mode)) { - 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) { - rc = -ENOMEM; - goto _error; - } - } - - /* initialize timer */ - debug_printk(("initialize timer\n")); - dp->timer = snd_seq_oss_timer_new(dp); - if (!dp->timer) { - snd_printk(KERN_ERR "can't alloc timer\n"); - rc = -ENOMEM; - goto _error; - } - debug_printk(("timer initialized\n")); - - /* set private data pointer */ - file->private_data = dp; - - /* set up for mode2 */ - if (level == SNDRV_SEQ_OSS_MODE_MUSIC) - snd_seq_oss_synth_setup_midi(dp); - else if (is_read_mode(dp->file_mode)) - snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ); - - 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); - delete_seq_queue(dp->queue); - delete_port(dp); - - return rc; -} - -/* - * translate file flags to private mode - */ -static int -translate_mode(struct file *file) -{ - int file_mode = 0; - if ((file->f_flags & O_ACCMODE) != O_RDONLY) - file_mode |= SNDRV_SEQ_OSS_FILE_WRITE; - if ((file->f_flags & O_ACCMODE) != O_WRONLY) - file_mode |= SNDRV_SEQ_OSS_FILE_READ; - if (file->f_flags & O_NONBLOCK) - file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK; - return file_mode; -} - - -/* - * create sequencer port - */ -static int -create_port(struct seq_oss_devinfo *dp) -{ - int rc; - struct snd_seq_port_info port; - struct snd_seq_port_callback callback; - - memset(&port, 0, sizeof(port)); - port.addr.client = dp->cseq; - sprintf(port.name, "Sequencer-%d", dp->index); - port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */ - port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC; - port.midi_channels = 128; - port.synth_voices = 128; - - memset(&callback, 0, sizeof(callback)); - callback.owner = THIS_MODULE; - callback.private_data = dp; - callback.event_input = snd_seq_oss_event_input; - callback.private_free = free_devinfo; - port.kernel = &callback; - - rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port); - if (rc < 0) - return rc; - - dp->port = port.addr.port; - debug_printk(("new port = %d\n", port.addr.port)); - - return 0; -} - -/* - * delete ALSA port - */ -static int -delete_port(struct seq_oss_devinfo *dp) -{ - 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); -} - -/* - * allocate a queue - */ -static int -alloc_seq_queue(struct seq_oss_devinfo *dp) -{ - struct snd_seq_queue_info qinfo; - int rc; - - memset(&qinfo, 0, sizeof(qinfo)); - qinfo.owner = system_client; - qinfo.locked = 1; - strcpy(qinfo.name, "OSS Sequencer Emulation"); - if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0) - return rc; - dp->queue = qinfo.queue; - return 0; -} - -/* - * release queue - */ -static int -delete_seq_queue(int queue) -{ - struct snd_seq_queue_info qinfo; - int rc; - - if (queue < 0) - return 0; - memset(&qinfo, 0, sizeof(qinfo)); - 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); - return rc; -} - - -/* - * free device informations - private_free callback of port - */ -static void -free_devinfo(void *private) -{ - struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private; - - if (dp->timer) - snd_seq_oss_timer_delete(dp->timer); - - if (dp->writeq) - snd_seq_oss_writeq_delete(dp->writeq); - - if (dp->readq) - snd_seq_oss_readq_delete(dp->readq); - - kfree(dp); -} - - -/* - * close sequencer device - */ -void -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")); -} - - -/* - * Wait until the queue is empty (if we don't have nonblock) - */ -void -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)) - ; - } -} - - -/* - * reset sequencer devices - */ -void -snd_seq_oss_reset(struct seq_oss_devinfo *dp) -{ - int i; - - /* reset all synth devices */ - for (i = 0; i < dp->max_synthdev; i++) - snd_seq_oss_synth_reset(dp, i); - - /* reset all midi devices */ - if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) { - for (i = 0; i < dp->max_mididev; i++) - snd_seq_oss_midi_reset(dp, i); - } - - /* remove queues */ - if (dp->readq) - snd_seq_oss_readq_clear(dp->readq); - if (dp->writeq) - snd_seq_oss_writeq_clear(dp->writeq); - - /* reset timer */ - snd_seq_oss_timer_stop(dp->timer); -} - - -#ifdef CONFIG_PROC_FS -/* - * misc. functions for proc interface - */ -char * -enabled_str(int bool) -{ - return bool ? "enabled" : "disabled"; -} - -static char * -filemode_str(int val) -{ - static char *str[] = { - "none", "read", "write", "read/write", - }; - return str[val & SNDRV_SEQ_OSS_FILE_ACMODE]; -} - - -/* - * proc interface - */ -void -snd_seq_oss_system_info_read(struct snd_info_buffer *buf) -{ - int i; - 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); - - snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients); - for (i = 0; i < num_clients; i++) { - snd_iprintf(buf, "\nApplication %d: ", i); - if ((dp = client_table[i]) == NULL) { - snd_iprintf(buf, "*empty*\n"); - continue; - } - snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue); - snd_iprintf(buf, " sequencer mode = %s : file open mode = %s\n", - (dp->seq_mode ? "music" : "synth"), - filemode_str(dp->file_mode)); - if (dp->seq_mode) - snd_iprintf(buf, " timer tempo = %d, timebase = %d\n", - dp->timer->oss_tempo, dp->timer->oss_timebase); - snd_iprintf(buf, " max queue length %d\n", maxqlen); - if (is_read_mode(dp->file_mode) && dp->readq) - snd_seq_oss_readq_info_read(dp->readq, buf); - } -} -#endif /* CONFIG_PROC_FS */ diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_ioctl.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_ioctl.c deleted file mode 100644 index 5ac701c9..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_ioctl.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * OSS compatible i/o control - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_device.h" -#include "seq_oss_readq.h" -#include "seq_oss_writeq.h" -#include "seq_oss_timer.h" -#include "seq_oss_synth.h" -#include "seq_oss_midi.h" -#include "seq_oss_event.h" - -static int snd_seq_oss_synth_info_user(struct seq_oss_devinfo *dp, void __user *arg) -{ - struct synth_info info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - if (snd_seq_oss_synth_make_info(dp, info.device, &info) < 0) - return -EINVAL; - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_seq_oss_midi_info_user(struct seq_oss_devinfo *dp, void __user *arg) -{ - struct midi_info info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - if (snd_seq_oss_midi_make_info(dp, info.device, &info) < 0) - return -EINVAL; - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg) -{ - unsigned char ev[8]; - 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, (union evrec *)ev, &tmpev)) { - snd_seq_oss_dispatch(dp, &tmpev, 0, 0); - } - return 0; -} - -int -snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg) -{ - int dev, val; - void __user *arg = (void __user *)carg; - int __user *p = arg; - - switch (cmd) { - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SOURCE: - case SNDCTL_TMR_SELECT: - case SNDCTL_SEQ_CTRLRATE: - 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)) - ; - if (signal_pending(current)) - return -ERESTARTSYS; - 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); - return 0; - - 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)) - return -EFAULT; - if (val < 1) - val = 1; - if (val >= dp->writeq->maxlen) - val = dp->writeq->maxlen - 1; - snd_seq_oss_writeq_set_output(dp->writeq, val); - 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)) - return -EFAULT; - if (val <= 0) - val = -1; - else - val = (HZ * val) / 10; - dp->readq->pre_event_timeout = val; - 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); - } - return 0; -} - diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.c deleted file mode 100644 index 677dc845..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * MIDI device handlers - * - * Copyright (C) 1998,99 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. - * - * 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/asoundef.h> -#include "seq_oss_midi.h" -#include "seq_oss_readq.h" -#include "seq_oss_timer.h" -#include "seq_oss_event.h" -#include <sound/seq_midi_event.h> -#include "../seq_lock.h" -#include <linux/init.h> -#include <linux/slab.h> - - -/* - * constants - */ -#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30 - -/* - * definition of midi device record - */ -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]; - struct snd_midi_event *coder; /* MIDI event coder */ - struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */ - snd_use_lock_t use_lock; -}; - - -/* - * midi device table - */ -static int max_midi_devs; -static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS]; - -static DEFINE_SPINLOCK(register_lock); - -/* - * prototypes - */ -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 -snd_seq_oss_midi_lookup_ports(int client) -{ - struct snd_seq_client_info *clinfo; - struct snd_seq_port_info *pinfo; - - clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); - if (! clinfo || ! pinfo) { - kfree(clinfo); - kfree(pinfo); - return -ENOMEM; - } - clinfo->client = -1; - while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) { - if (clinfo->client == client) - continue; /* ignore myself */ - pinfo->addr.client = clinfo->client; - pinfo->addr.port = -1; - while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0) - snd_seq_oss_midi_check_new_port(pinfo); - } - kfree(clinfo); - kfree(pinfo); - return 0; -} - - -/* - */ -static struct seq_oss_midi * -get_mdev(int dev) -{ - struct seq_oss_midi *mdev; - unsigned long flags; - - spin_lock_irqsave(®ister_lock, flags); - mdev = midi_devs[dev]; - if (mdev) - snd_use_lock_use(&mdev->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); - return mdev; -} - -/* - * look for the identical slot - */ -static struct seq_oss_midi * -find_slot(int client, int port) -{ - int i; - struct seq_oss_midi *mdev; - unsigned long flags; - - spin_lock_irqsave(®ister_lock, flags); - for (i = 0; i < max_midi_devs; i++) { - mdev = midi_devs[i]; - if (mdev && mdev->client == client && mdev->port == port) { - /* found! */ - snd_use_lock_use(&mdev->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); - return mdev; - } - } - spin_unlock_irqrestore(®ister_lock, flags); - return NULL; -} - - -#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE) -#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ) -/* - * register a new port if it doesn't exist yet - */ -int -snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) -{ - int i; - 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; - /* either read or write subscribable */ - if ((pinfo->capability & PERM_WRITE) != PERM_WRITE && - (pinfo->capability & PERM_READ) != PERM_READ) - return 0; - - /* - * look for the identical slot - */ - if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { - /* already exists */ - snd_use_lock_free(&mdev->use_lock); - return 0; - } - - /* - * allocate midi info record - */ - if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { - snd_printk(KERN_ERR "can't malloc midi info\n"); - return -ENOMEM; - } - - /* copy the port information */ - mdev->client = pinfo->addr.client; - mdev->port = pinfo->addr.port; - mdev->flags = pinfo->capability; - mdev->opened = 0; - snd_use_lock_init(&mdev->use_lock); - - /* copy and truncate the name of synth device */ - strlcpy(mdev->name, pinfo->name, sizeof(mdev->name)); - - /* 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"); - kfree(mdev); - return -ENOMEM; - } - /* OSS sequencer adds running status to all sequences */ - snd_midi_event_no_status(mdev->coder, 1); - - /* - * look for en empty slot - */ - spin_lock_irqsave(®ister_lock, flags); - for (i = 0; i < max_midi_devs; i++) { - if (midi_devs[i] == NULL) - break; - } - if (i >= max_midi_devs) { - if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) { - spin_unlock_irqrestore(®ister_lock, flags); - snd_midi_event_free(mdev->coder); - kfree(mdev); - return -ENOMEM; - } - max_midi_devs++; - } - mdev->seq_device = i; - midi_devs[mdev->seq_device] = mdev; - spin_unlock_irqrestore(®ister_lock, flags); - - return 0; -} - -/* - * release the midi device if it was registered - */ -int -snd_seq_oss_midi_check_exit_port(int client, int port) -{ - struct seq_oss_midi *mdev; - unsigned long flags; - int index; - - if ((mdev = find_slot(client, port)) != NULL) { - spin_lock_irqsave(®ister_lock, flags); - midi_devs[mdev->seq_device] = NULL; - spin_unlock_irqrestore(®ister_lock, flags); - snd_use_lock_free(&mdev->use_lock); - snd_use_lock_sync(&mdev->use_lock); - if (mdev->coder) - snd_midi_event_free(mdev->coder); - kfree(mdev); - } - spin_lock_irqsave(®ister_lock, flags); - for (index = max_midi_devs - 1; index >= 0; index--) { - if (midi_devs[index]) - break; - } - max_midi_devs = index + 1; - spin_unlock_irqrestore(®ister_lock, flags); - return 0; -} - - -/* - * release the midi device if it was registered - */ -void -snd_seq_oss_midi_clear_all(void) -{ - int i; - struct seq_oss_midi *mdev; - unsigned long flags; - - spin_lock_irqsave(®ister_lock, flags); - for (i = 0; i < max_midi_devs; i++) { - if ((mdev = midi_devs[i]) != NULL) { - if (mdev->coder) - snd_midi_event_free(mdev->coder); - kfree(mdev); - midi_devs[i] = NULL; - } - } - max_midi_devs = 0; - spin_unlock_irqrestore(®ister_lock, flags); -} - - -/* - * set up midi tables - */ -void -snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) -{ - dp->max_mididev = max_midi_devs; -} - -/* - * clean up midi tables - */ -void -snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp) -{ - int i; - for (i = 0; i < dp->max_mididev; i++) - snd_seq_oss_midi_close(dp, i); - dp->max_mididev = 0; -} - - -/* - * open all midi devices. ignore errors. - */ -void -snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode) -{ - int i; - for (i = 0; i < dp->max_mididev; i++) - snd_seq_oss_midi_open(dp, i, file_mode); -} - - -/* - * get the midi device information - */ -static struct seq_oss_midi * -get_mididev(struct seq_oss_devinfo *dp, int dev) -{ - if (dev < 0 || dev >= dp->max_mididev) - return NULL; - return get_mdev(dev); -} - - -/* - * open the midi device if not opened yet - */ -int -snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) -{ - int perm; - struct seq_oss_midi *mdev; - struct snd_seq_port_subscribe subs; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return -ENODEV; - - /* already used? */ - if (mdev->opened && mdev->devinfo != dp) { - snd_use_lock_free(&mdev->use_lock); - return -EBUSY; - } - - perm = 0; - if (is_write_mode(fmode)) - perm |= PERM_WRITE; - if (is_read_mode(fmode)) - perm |= PERM_READ; - perm &= mdev->flags; - if (perm == 0) { - snd_use_lock_free(&mdev->use_lock); - return -ENXIO; - } - - /* already opened? */ - if ((mdev->opened & perm) == perm) { - snd_use_lock_free(&mdev->use_lock); - return 0; - } - - perm &= ~mdev->opened; - - memset(&subs, 0, sizeof(subs)); - - if (perm & PERM_WRITE) { - subs.sender = dp->addr; - subs.dest.client = mdev->client; - subs.dest.port = mdev->port; - if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) - mdev->opened |= PERM_WRITE; - } - if (perm & PERM_READ) { - subs.sender.client = mdev->client; - subs.sender.port = mdev->port; - subs.dest = dp->addr; - subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP; - subs.queue = dp->queue; /* queue for timestamps */ - if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) - mdev->opened |= PERM_READ; - } - - if (! mdev->opened) { - snd_use_lock_free(&mdev->use_lock); - return -ENXIO; - } - - mdev->devinfo = dp; - snd_use_lock_free(&mdev->use_lock); - return 0; -} - -/* - * close the midi device if already opened - */ -int -snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_midi *mdev; - struct snd_seq_port_subscribe subs; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return -ENODEV; - if (! mdev->opened || mdev->devinfo != dp) { - snd_use_lock_free(&mdev->use_lock); - 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; - subs.dest.client = mdev->client; - subs.dest.port = mdev->port; - snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs); - } - if (mdev->opened & PERM_READ) { - subs.sender.client = mdev->client; - subs.sender.port = mdev->port; - subs.dest = dp->addr; - snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs); - } - - mdev->opened = 0; - mdev->devinfo = NULL; - - snd_use_lock_free(&mdev->use_lock); - return 0; -} - -/* - * change seq capability flags to file mode flags - */ -int -snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_midi *mdev; - int mode; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return 0; - - mode = 0; - if (mdev->opened & PERM_WRITE) - mode |= SNDRV_SEQ_OSS_FILE_WRITE; - if (mdev->opened & PERM_READ) - mode |= SNDRV_SEQ_OSS_FILE_READ; - - snd_use_lock_free(&mdev->use_lock); - return mode; -} - -/* - * reset the midi device and close it: - * so far, only close the device. - */ -void -snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_midi *mdev; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return; - if (! mdev->opened) { - snd_use_lock_free(&mdev->use_lock); - return; - } - - if (mdev->opened & PERM_WRITE) { - 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; - ev.queue = dp->queue; - 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); - } - for (c = 0; c < 16; c++) { - ev.type = SNDRV_SEQ_EVENT_CONTROLLER; - ev.data.control.channel = c; - 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 = - 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); - } - } - } - // snd_seq_oss_midi_close(dp, dev); - snd_use_lock_free(&mdev->use_lock); -} - - -/* - * get client/port of the specified MIDI device - */ -void -snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr) -{ - struct seq_oss_midi *mdev; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return; - addr->client = mdev->client; - addr->port = mdev->port; - snd_use_lock_free(&mdev->use_lock); -} - - -/* - * input callback - this can be atomic - */ -int -snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) -{ - struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data; - struct seq_oss_midi *mdev; - int rc; - - if (dp->readq == NULL) - return 0; - if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL) - return 0; - if (! (mdev->opened & PERM_READ)) { - snd_use_lock_free(&mdev->use_lock); - return 0; - } - - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) - rc = send_synth_event(dp, ev, mdev->seq_device); - else - rc = send_midi_event(dp, ev, mdev); - - snd_use_lock_free(&mdev->use_lock); - return rc; -} - -/* - * convert ALSA sequencer event to OSS synth event - */ -static int -send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev) -{ - union evrec ossev; - - memset(&ossev, 0, sizeof(ossev)); - - switch (ev->type) { - case SNDRV_SEQ_EVENT_NOTEON: - ossev.v.cmd = MIDI_NOTEON; break; - case SNDRV_SEQ_EVENT_NOTEOFF: - ossev.v.cmd = MIDI_NOTEOFF; break; - case SNDRV_SEQ_EVENT_KEYPRESS: - ossev.v.cmd = MIDI_KEY_PRESSURE; break; - case SNDRV_SEQ_EVENT_CONTROLLER: - ossev.l.cmd = MIDI_CTL_CHANGE; break; - case SNDRV_SEQ_EVENT_PGMCHANGE: - ossev.l.cmd = MIDI_PGM_CHANGE; break; - case SNDRV_SEQ_EVENT_CHANPRESS: - ossev.l.cmd = MIDI_CHN_PRESSURE; break; - case SNDRV_SEQ_EVENT_PITCHBEND: - ossev.l.cmd = MIDI_PITCH_BEND; break; - default: - return 0; /* not supported */ - } - - ossev.v.dev = dev; - - switch (ev->type) { - case SNDRV_SEQ_EVENT_NOTEON: - case SNDRV_SEQ_EVENT_NOTEOFF: - case SNDRV_SEQ_EVENT_KEYPRESS: - ossev.v.code = EV_CHN_VOICE; - ossev.v.note = ev->data.note.note; - ossev.v.parm = ev->data.note.velocity; - ossev.v.chn = ev->data.note.channel; - break; - case SNDRV_SEQ_EVENT_CONTROLLER: - case SNDRV_SEQ_EVENT_PGMCHANGE: - case SNDRV_SEQ_EVENT_CHANPRESS: - ossev.l.code = EV_CHN_COMMON; - ossev.l.p1 = ev->data.control.param; - ossev.l.val = ev->data.control.value; - ossev.l.chn = ev->data.control.channel; - break; - case SNDRV_SEQ_EVENT_PITCHBEND: - ossev.l.code = EV_CHN_COMMON; - ossev.l.val = ev->data.control.value + 8192; - ossev.l.chn = ev->data.control.channel; - break; - } - - snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode); - snd_seq_oss_readq_put_event(dp->readq, &ossev); - - return 0; -} - -/* - * decode event and send MIDI bytes to read queue - */ -static int -send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev) -{ - char msg[32]; - int len; - - snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode); - if (!dp->timer->running) - len = snd_seq_oss_timer_start(dp->timer); - if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { - if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) - snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, - ev->data.ext.ptr, ev->data.ext.len); - } else { - len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); - if (len > 0) - snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len); - } - - return 0; -} - - -/* - * dump midi data - * return 0 : enqueued - * non-zero : invalid - ignored - */ -int -snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev) -{ - struct seq_oss_midi *mdev; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return -ENODEV; - if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) { - snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); - snd_use_lock_free(&mdev->use_lock); - return 0; - } - snd_use_lock_free(&mdev->use_lock); - return -EINVAL; -} - -/* - * create OSS compatible midi_info record - */ -int -snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf) -{ - struct seq_oss_midi *mdev; - - if ((mdev = get_mididev(dp, dev)) == NULL) - return -ENXIO; - inf->device = dev; - inf->dev_type = 0; /* FIXME: ?? */ - inf->capabilities = 0; /* FIXME: ?? */ - strlcpy(inf->name, mdev->name, sizeof(inf->name)); - snd_use_lock_free(&mdev->use_lock); - return 0; -} - - -#ifdef CONFIG_PROC_FS -/* - * proc interface - */ -static char * -capmode_str(int val) -{ - val &= PERM_READ|PERM_WRITE; - if (val == (PERM_READ|PERM_WRITE)) - return "read/write"; - else if (val == PERM_READ) - return "read"; - else if (val == PERM_WRITE) - return "write"; - else - return "none"; -} - -void -snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) -{ - int i; - 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++) { - snd_iprintf(buf, "\nmidi %d: ", i); - mdev = get_mdev(i); - if (mdev == NULL) { - snd_iprintf(buf, "*empty*\n"); - continue; - } - snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name, - mdev->client, mdev->port); - snd_iprintf(buf, " capability %s / opened %s\n", - capmode_str(mdev->flags), - capmode_str(mdev->opened)); - snd_use_lock_free(&mdev->use_lock); - } -} -#endif /* CONFIG_PROC_FS */ diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.h deleted file mode 100644 index 84eb866b..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_midi.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * midi device information - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_MIDI_H -#define __SEQ_OSS_MIDI_H - -#include "seq_oss_device.h" -#include <sound/seq_oss_legacy.h> - -int snd_seq_oss_midi_lookup_ports(int client); -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(struct seq_oss_devinfo *dp); -void snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp); - -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/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.c deleted file mode 100644 index 73661c4a..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * seq_oss_readq.c - MIDI input queue - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_readq.h" -#include "seq_oss_event.h" -#include <sound/seq_oss_legacy.h> -#include "../seq_lock.h" -#include <linux/wait.h> -#include <linux/slab.h> - -/* - * constants - */ -//#define SNDRV_SEQ_OSS_MAX_TIMEOUT (unsigned long)(-1) -#define SNDRV_SEQ_OSS_MAX_TIMEOUT (HZ * 3600) - - -/* - * prototypes - */ - - -/* - * create a read queue - */ -struct seq_oss_readq * -snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen) -{ - struct seq_oss_readq *q; - - if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) { - snd_printk(KERN_ERR "can't malloc read queue\n"); - return NULL; - } - - if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) { - snd_printk(KERN_ERR "can't malloc read queue buffer\n"); - kfree(q); - return NULL; - } - - q->maxlen = maxlen; - q->qlen = 0; - q->head = q->tail = 0; - init_waitqueue_head(&q->midi_sleep); - spin_lock_init(&q->lock); - q->pre_event_timeout = SNDRV_SEQ_OSS_MAX_TIMEOUT; - q->input_time = (unsigned long)-1; - - return q; -} - -/* - * delete the read queue - */ -void -snd_seq_oss_readq_delete(struct seq_oss_readq *q) -{ - if (q) { - kfree(q->q); - kfree(q); - } -} - -/* - * reset the read queue - */ -void -snd_seq_oss_readq_clear(struct seq_oss_readq *q) -{ - if (q->qlen) { - q->qlen = 0; - q->head = q->tail = 0; - } - /* if someone sleeping, wake'em up */ - if (waitqueue_active(&q->midi_sleep)) - wake_up(&q->midi_sleep); - q->input_time = (unsigned long)-1; -} - -/* - * put a midi byte - */ -int -snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, int len) -{ - union evrec rec; - int result; - - memset(&rec, 0, sizeof(rec)); - rec.c[0] = SEQ_MIDIPUTC; - rec.c[2] = dev; - - while (len-- > 0) { - rec.c[1] = *data++; - result = snd_seq_oss_readq_put_event(q, &rec); - if (result < 0) - return result; - } - return 0; -} - -/* - * copy an event to input queue: - * return zero if enqueued - */ -int -snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev) -{ - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - if (q->qlen >= q->maxlen - 1) { - spin_unlock_irqrestore(&q->lock, flags); - return -ENOMEM; - } - - memcpy(&q->q[q->tail], ev, sizeof(*ev)); - q->tail = (q->tail + 1) % q->maxlen; - q->qlen++; - - /* wake up sleeper */ - if (waitqueue_active(&q->midi_sleep)) - wake_up(&q->midi_sleep); - - spin_unlock_irqrestore(&q->lock, flags); - - return 0; -} - - -/* - * pop queue - * caller must hold lock - */ -int -snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec) -{ - if (q->qlen == 0) - return -EAGAIN; - memcpy(rec, &q->q[q->head], sizeof(*rec)); - return 0; -} - -/* - * sleep until ready - */ -void -snd_seq_oss_readq_wait(struct seq_oss_readq *q) -{ - wait_event_interruptible_timeout(q->midi_sleep, - (q->qlen > 0 || q->head == q->tail), - q->pre_event_timeout); -} - -/* - * drain one record - * caller must hold lock - */ -void -snd_seq_oss_readq_free(struct seq_oss_readq *q) -{ - if (q->qlen > 0) { - q->head = (q->head + 1) % q->maxlen; - q->qlen--; - } -} - -/* - * polling/select: - * return non-zero if readq is not empty. - */ -unsigned int -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; -} - -/* - * put a timestamp - */ -int -snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode) -{ - if (curt != q->input_time) { - union evrec rec; - memset(&rec, 0, sizeof(rec)); - switch (seq_mode) { - case SNDRV_SEQ_OSS_MODE_SYNTH: - rec.echo = (curt << 8) | SEQ_WAIT; - snd_seq_oss_readq_put_event(q, &rec); - break; - case SNDRV_SEQ_OSS_MODE_MUSIC: - rec.t.code = EV_TIMING; - rec.t.cmd = TMR_WAIT_ABS; - rec.t.time = curt; - snd_seq_oss_readq_put_event(q, &rec); - break; - } - q->input_time = curt; - } - return 0; -} - - -#ifdef CONFIG_PROC_FS -/* - * proc interface - */ -void -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/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.h deleted file mode 100644 index f1463f1f..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_readq.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * OSS compatible sequencer driver - * read fifo queue - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_READQ_H -#define __SEQ_OSS_READQ_H - -#include "seq_oss_device.h" - - -/* - * definition of read queue - */ -struct seq_oss_readq { - union evrec *q; - int qlen; - int maxlen; - int head, tail; - unsigned long pre_event_timeout; - unsigned long input_time; - wait_queue_head_t midi_sleep; - spinlock_t lock; -}; - -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) - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_rw.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_rw.c deleted file mode 100644 index 6a7b6ace..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_rw.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * read/write/select interface to device file - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_device.h" -#include "seq_oss_readq.h" -#include "seq_oss_writeq.h" -#include "seq_oss_synth.h" -#include <sound/seq_oss_legacy.h> -#include "seq_oss_event.h" -#include "seq_oss_timer.h" -#include "../seq_clientmgr.h" - - -/* - * protoypes - */ -static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt); - - -/* - * read interface - */ - -int -snd_seq_oss_read(struct seq_oss_devinfo *dp, char __user *buf, int count) -{ - struct seq_oss_readq *readq = dp->readq; - int result = 0, err = 0; - int ev_len; - union evrec rec; - unsigned long flags; - - if (readq == NULL || ! is_read_mode(dp->file_mode)) - return -ENXIO; - - while (count >= SHORT_EVENT_SIZE) { - snd_seq_oss_readq_lock(readq, flags); - err = snd_seq_oss_readq_pick(readq, &rec); - if (err == -EAGAIN && - !is_nonblock_mode(dp->file_mode) && result == 0) { - snd_seq_oss_readq_unlock(readq, flags); - snd_seq_oss_readq_wait(readq); - snd_seq_oss_readq_lock(readq, flags); - if (signal_pending(current)) - err = -ERESTARTSYS; - else - err = snd_seq_oss_readq_pick(readq, &rec); - } - if (err < 0) { - snd_seq_oss_readq_unlock(readq, flags); - break; - } - ev_len = ev_length(&rec); - if (ev_len < count) { - snd_seq_oss_readq_unlock(readq, flags); - break; - } - snd_seq_oss_readq_free(readq); - snd_seq_oss_readq_unlock(readq, flags); - if (copy_to_user(buf, &rec, ev_len)) { - err = -EFAULT; - break; - } - result += ev_len; - buf += ev_len; - count -= ev_len; - } - return result > 0 ? result : err; -} - - -/* - * write interface - */ - -int -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; - union evrec rec; - - if (! is_write_mode(dp->file_mode) || dp->writeq == NULL) - return -ENXIO; - - while (count >= SHORT_EVENT_SIZE) { - if (copy_from_user(&rec, buf, SHORT_EVENT_SIZE)) { - err = -EFAULT; - break; - } - if (rec.s.code == SEQ_FULLSIZE) { - /* load patch */ - if (result > 0) { - err = -EINVAL; - break; - } - fmt = (*(unsigned short *)rec.c) & 0xffff; - /* FIXME the return value isn't correct */ - return snd_seq_oss_synth_load_patch(dp, rec.s.dev, - fmt, buf, 0, count); - } - if (ev_is_long(&rec)) { - /* extended code */ - if (rec.s.code == SEQ_EXTENDED && - dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { - err = -EINVAL; - break; - } - ev_size = LONG_EVENT_SIZE; - if (count < ev_size) - break; - /* copy the reset 4 bytes */ - if (copy_from_user(rec.c + SHORT_EVENT_SIZE, - buf + SHORT_EVENT_SIZE, - LONG_EVENT_SIZE - SHORT_EVENT_SIZE)) { - err = -EFAULT; - break; - } - } else { - /* old-type code */ - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { - err = -EINVAL; - break; - } - ev_size = SHORT_EVENT_SIZE; - } - - /* insert queue */ - if ((err = insert_queue(dp, &rec, opt)) < 0) - break; - - result += ev_size; - buf += ev_size; - count -= ev_size; - } - return result > 0 ? result : err; -} - - -/* - * insert event record to write queue - * return: 0 = OK, non-zero = NG - */ -static int -insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt) -{ - int rc = 0; - 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)) - return 0; /* no need to insert queue */ - - /* parse this event */ - memset(&event, 0, sizeof(event)); - /* set dummy -- to be sure */ - event.type = SNDRV_SEQ_EVENT_NOTEOFF; - snd_seq_oss_fill_addr(dp, &event, dp->addr.port, dp->addr.client); - - if (snd_seq_oss_process_event(dp, rec, &event)) - return 0; /* invalid event - no need to insert queue */ - - event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer); - if (dp->timer->realtime || !dp->timer->running) { - snd_seq_oss_dispatch(dp, &event, 0, 0); - } else { - if (is_nonblock_mode(dp->file_mode)) - rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0); - else - rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0); - } - return rc; -} - - -/* - * select / poll - */ - -unsigned int -snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait) -{ - unsigned int mask = 0; - - /* input */ - if (dp->readq && is_read_mode(dp->file_mode)) { - if (snd_seq_oss_readq_poll(dp->readq, file, wait)) - mask |= POLLIN | POLLRDNORM; - } - - /* output */ - if (dp->writeq && is_write_mode(dp->file_mode)) { - if (snd_seq_kernel_client_write_poll(dp->cseq, file, wait)) - mask |= POLLOUT | POLLWRNORM; - } - return mask; -} diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.c deleted file mode 100644 index c5b773a1..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * synth device handlers - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_synth.h" -#include "seq_oss_midi.h" -#include "../seq_lock.h" -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> - -/* - * constants - */ -#define SNDRV_SEQ_OSS_MAX_SYNTH_NAME 30 -#define MAX_SYSEX_BUFLEN 128 - - -/* - * definition of synth info records - */ - -/* sysex buffer */ -struct seq_oss_synth_sysex { - int len; - int skip; - unsigned char buf[MAX_SYSEX_BUFLEN]; -}; - -/* synth info */ -struct seq_oss_synth { - int seq_device; - - /* for synth_info */ - int synth_type; - int synth_subtype; - int nr_voices; - - char name[SNDRV_SEQ_OSS_MAX_SYNTH_NAME]; - struct snd_seq_oss_callback oper; - - int opened; - - void *private_data; - snd_use_lock_t use_lock; -}; - - -/* - * device table - */ -static int max_synth_devs; -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 */ - 16, /* nr_voices */ - "MIDI", /* name */ -}; - -static DEFINE_SPINLOCK(register_lock); - -/* - * prototypes - */ -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 - */ -void __init -snd_seq_oss_synth_init(void) -{ - snd_use_lock_init(&midi_synth_dev.use_lock); -} - -/* - * registration of the synth device - */ -int -snd_seq_oss_synth_register(struct snd_seq_device *dev) -{ - int i; - 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"); - return -ENOMEM; - } - rec->seq_device = -1; - rec->synth_type = reg->type; - rec->synth_subtype = reg->subtype; - rec->nr_voices = reg->nvoices; - rec->oper = reg->oper; - rec->private_data = reg->private_data; - rec->opened = 0; - snd_use_lock_init(&rec->use_lock); - - /* copy and truncate the name of synth device */ - strlcpy(rec->name, dev->name, sizeof(rec->name)); - - /* registration */ - spin_lock_irqsave(®ister_lock, flags); - for (i = 0; i < max_synth_devs; i++) { - if (synth_devs[i] == NULL) - break; - } - if (i >= max_synth_devs) { - if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) { - spin_unlock_irqrestore(®ister_lock, flags); - snd_printk(KERN_ERR "no more synth slot\n"); - kfree(rec); - return -ENOMEM; - } - max_synth_devs++; - } - rec->seq_device = i; - synth_devs[i] = rec; - debug_printk(("synth %s registered %d\n", rec->name, i)); - spin_unlock_irqrestore(®ister_lock, flags); - dev->driver_data = rec; -#ifdef SNDRV_OSS_INFO_DEV_SYNTH - if (i < SNDRV_CARDS) - snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name); -#endif - return 0; -} - - -int -snd_seq_oss_synth_unregister(struct snd_seq_device *dev) -{ - int index; - struct seq_oss_synth *rec = dev->driver_data; - unsigned long flags; - - spin_lock_irqsave(®ister_lock, flags); - for (index = 0; index < max_synth_devs; index++) { - if (synth_devs[index] == rec) - break; - } - if (index >= max_synth_devs) { - spin_unlock_irqrestore(®ister_lock, flags); - snd_printk(KERN_ERR "can't unregister synth\n"); - return -EINVAL; - } - synth_devs[index] = NULL; - if (index == max_synth_devs - 1) { - for (index--; index >= 0; index--) { - if (synth_devs[index]) - break; - } - max_synth_devs = index + 1; - } - spin_unlock_irqrestore(®ister_lock, flags); -#ifdef SNDRV_OSS_INFO_DEV_SYNTH - if (rec->seq_device < SNDRV_CARDS) - snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device); -#endif - - snd_use_lock_sync(&rec->use_lock); - kfree(rec); - - return 0; -} - - -/* - */ -static struct seq_oss_synth * -get_sdev(int dev) -{ - struct seq_oss_synth *rec; - unsigned long flags; - - spin_lock_irqsave(®ister_lock, flags); - rec = synth_devs[dev]; - if (rec) - snd_use_lock_use(&rec->use_lock); - spin_unlock_irqrestore(®ister_lock, flags); - return rec; -} - - -/* - * set up synth tables - */ - -void -snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) -{ - int i; - struct seq_oss_synth *rec; - struct seq_oss_synthinfo *info; - - dp->max_synthdev = max_synth_devs; - dp->synth_opened = 0; - memset(dp->synths, 0, sizeof(dp->synths)); - for (i = 0; i < dp->max_synthdev; i++) { - rec = get_sdev(i); - if (rec == NULL) - continue; - if (rec->oper.open == NULL || rec->oper.close == NULL) { - snd_use_lock_free(&rec->use_lock); - continue; - } - info = &dp->synths[i]; - info->arg.app_index = dp->port; - info->arg.file_mode = dp->file_mode; - info->arg.seq_mode = dp->seq_mode; - if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) - info->arg.event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS; - else - info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS; - info->opened = 0; - if (!try_module_get(rec->oper.owner)) { - snd_use_lock_free(&rec->use_lock); - continue; - } - if (rec->oper.open(&info->arg, rec->private_data) < 0) { - module_put(rec->oper.owner); - snd_use_lock_free(&rec->use_lock); - continue; - } - info->nr_voices = rec->nr_voices; - if (info->nr_voices > 0) { - info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL); - if (!info->ch) { - snd_printk(KERN_ERR "Cannot malloc\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++; - snd_use_lock_free(&rec->use_lock); - } -} - - -/* - * set up synth tables for MIDI emulation - /dev/music mode only - */ - -void -snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp) -{ - int i; - - if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) - return; - - for (i = 0; i < dp->max_mididev; i++) { - struct seq_oss_synthinfo *info; - info = &dp->synths[dp->max_synthdev]; - if (snd_seq_oss_midi_open(dp, i, dp->file_mode) < 0) - continue; - info->arg.app_index = dp->port; - info->arg.file_mode = dp->file_mode; - info->arg.seq_mode = dp->seq_mode; - info->arg.private_data = info; - info->is_midi = 1; - info->midi_mapped = i; - info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS; - snd_seq_oss_midi_get_addr(dp, i, &info->arg.addr); - info->opened = 1; - midi_synth_dev.opened++; - dp->max_synthdev++; - if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) - break; - } -} - - -/* - * clean up synth tables - */ - -void -snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) -{ - int i; - struct seq_oss_synth *rec; - struct seq_oss_synthinfo *info; - - 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) - continue; - if (info->is_midi) { - if (midi_synth_dev.opened > 0) { - snd_seq_oss_midi_close(dp, info->midi_mapped); - midi_synth_dev.opened--; - } - } else { - rec = get_sdev(i); - 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; - } - snd_use_lock_free(&rec->use_lock); - } - kfree(info->sysex); - info->sysex = NULL; - kfree(info->ch); - info->ch = NULL; - } - dp->synth_opened = 0; - dp->max_synthdev = 0; -} - -/* - * check if the specified device is MIDI mapped device - */ -static int -is_midi_dev(struct seq_oss_devinfo *dp, int dev) -{ - if (dev < 0 || dev >= dp->max_synthdev) - return 0; - if (dp->synths[dev].is_midi) - return 1; - return 0; -} - -/* - * return synth device information pointer - */ -static struct seq_oss_synth * -get_synthdev(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_synth *rec; - if (dev < 0 || dev >= dp->max_synthdev) - return NULL; - if (! dp->synths[dev].opened) - return NULL; - if (dp->synths[dev].is_midi) - return &midi_synth_dev; - if ((rec = get_sdev(dev)) == NULL) - return NULL; - if (! rec->opened) { - snd_use_lock_free(&rec->use_lock); - return NULL; - } - return rec; -} - - -/* - * reset note and velocity on each channel. - */ -static void -reset_channels(struct seq_oss_synthinfo *info) -{ - int i; - if (info->ch == NULL || ! info->nr_voices) - return; - for (i = 0; i < info->nr_voices; i++) { - info->ch[i].note = -1; - info->ch[i].vel = 0; - } -} - - -/* - * reset synth device: - * call reset callback. if no callback is defined, send a heartbeat - * event to the corresponding port. - */ -void -snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_synth *rec; - struct seq_oss_synthinfo *info; - - if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev)) - return; - info = &dp->synths[dev]; - if (! info->opened) - return; - if (info->sysex) - info->sysex->len = 0; /* reset sysex */ - reset_channels(info); - if (info->is_midi) { - if (midi_synth_dev.opened <= 0) - return; - snd_seq_oss_midi_reset(dp, info->midi_mapped); - /* reopen the device */ - snd_seq_oss_midi_close(dp, dev); - if (snd_seq_oss_midi_open(dp, info->midi_mapped, - dp->file_mode) < 0) { - midi_synth_dev.opened--; - info->opened = 0; - kfree(info->sysex); - info->sysex = NULL; - kfree(info->ch); - info->ch = NULL; - } - return; - } - - rec = get_sdev(dev); - if (rec == NULL) - return; - if (rec->oper.reset) { - rec->oper.reset(&info->arg); - } else { - 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); - ev.type = SNDRV_SEQ_EVENT_RESET; - snd_seq_oss_dispatch(dp, &ev, 0, 0); - } - snd_use_lock_free(&rec->use_lock); -} - - -/* - * load a patch record: - * call load_patch callback function - */ -int -snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, - const char __user *buf, int p, int c) -{ - struct seq_oss_synth *rec; - int rc; - - if (dev < 0 || dev >= dp->max_synthdev) - return -ENXIO; - - if (is_midi_dev(dp, dev)) - return 0; - if ((rec = get_synthdev(dp, dev)) == NULL) - return -ENXIO; - - if (rec->oper.load_patch == NULL) - rc = -ENXIO; - else - rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c); - snd_use_lock_free(&rec->use_lock); - return rc; -} - -/* - * check if the device is valid synth device - */ -int -snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev) -{ - struct seq_oss_synth *rec; - rec = get_synthdev(dp, dev); - if (rec) { - snd_use_lock_free(&rec->use_lock); - return 1; - } - return 0; -} - - -/* - * receive OSS 6 byte sysex packet: - * the full sysex message will be sent if it reaches to the end of data - * (0xff). - */ -int -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; - struct seq_oss_synth_sysex *sysex; - - if (! snd_seq_oss_synth_is_valid(dp, dev)) - return -ENXIO; - - sysex = dp->synths[dev].sysex; - if (sysex == NULL) { - sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); - if (sysex == NULL) - return -ENOMEM; - dp->synths[dev].sysex = sysex; - } - - send = 0; - dest = sysex->buf + sysex->len; - /* copy 6 byte packet to the buffer */ - for (i = 0; i < 6; i++) { - if (buf[i] == 0xff) { - send = 1; - break; - } - dest[i] = buf[i]; - sysex->len++; - if (sysex->len >= MAX_SYSEX_BUFLEN) { - sysex->len = 0; - sysex->skip = 1; - break; - } - } - - if (sysex->len && send) { - if (sysex->skip) { - sysex->skip = 0; - sysex->len = 0; - return -EINVAL; /* skip */ - } - /* copy the data to event record and send it */ - ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE; - if (snd_seq_oss_synth_addr(dp, dev, ev)) - return -EINVAL; - ev->data.ext.len = sysex->len; - ev->data.ext.ptr = sysex->buf; - sysex->len = 0; - return 0; - } - - return -EINVAL; /* skip */ -} - -/* - * fill the event source/destination addresses - */ -int -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; - snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, - dp->synths[dev].arg.addr.port); - return 0; -} - - -/* - * OSS compatible ioctl - */ -int -snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) -{ - struct seq_oss_synth *rec; - int rc; - - if (is_midi_dev(dp, dev)) - return -ENXIO; - if ((rec = get_synthdev(dp, dev)) == NULL) - return -ENXIO; - if (rec->oper.ioctl == NULL) - rc = -ENXIO; - else - rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr); - snd_use_lock_free(&rec->use_lock); - return rc; -} - - -/* - * send OSS raw events - SEQ_PRIVATE and SEQ_VOLUME - */ -int -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; - ev->type = SNDRV_SEQ_EVENT_OSS; - memcpy(ev->data.raw8.d, data, 8); - return snd_seq_oss_synth_addr(dp, dev, ev); -} - - -/* - * create OSS compatible synth_info record - */ -int -snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf) -{ - struct seq_oss_synth *rec; - - if (dev < 0 || dev >= dp->max_synthdev) - return -ENXIO; - - if (dp->synths[dev].is_midi) { - struct midi_info minf; - snd_seq_oss_midi_make_info(dp, dp->synths[dev].midi_mapped, &minf); - inf->synth_type = SYNTH_TYPE_MIDI; - inf->synth_subtype = 0; - inf->nr_voices = 16; - inf->device = dev; - strlcpy(inf->name, minf.name, sizeof(inf->name)); - } else { - if ((rec = get_synthdev(dp, dev)) == NULL) - return -ENXIO; - inf->synth_type = rec->synth_type; - inf->synth_subtype = rec->synth_subtype; - inf->nr_voices = rec->nr_voices; - inf->device = dev; - strlcpy(inf->name, rec->name, sizeof(inf->name)); - snd_use_lock_free(&rec->use_lock); - } - return 0; -} - - -#ifdef CONFIG_PROC_FS -/* - * proc interface - */ -void -snd_seq_oss_synth_info_read(struct snd_info_buffer *buf) -{ - int i; - 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++) { - snd_iprintf(buf, "\nsynth %d: ", i); - rec = get_sdev(i); - if (rec == NULL) { - snd_iprintf(buf, "*empty*\n"); - continue; - } - snd_iprintf(buf, "[%s]\n", rec->name); - snd_iprintf(buf, " type 0x%x : subtype 0x%x : voices %d\n", - rec->synth_type, rec->synth_subtype, - rec->nr_voices); - snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n", - enabled_str((long)rec->oper.ioctl), - enabled_str((long)rec->oper.load_patch)); - snd_use_lock_free(&rec->use_lock); - } -} -#endif /* CONFIG_PROC_FS */ diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.h deleted file mode 100644 index dbdfcbb8..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_synth.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * synth device information - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_SYNTH_H -#define __SEQ_OSS_SYNTH_H - -#include "seq_oss_device.h" -#include <sound/seq_oss_legacy.h> -#include <sound/seq_device.h> - -void snd_seq_oss_synth_init(void); -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(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(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf); - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.c deleted file mode 100644 index ab59cbfb..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * Timer control routines - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_timer.h" -#include "seq_oss_event.h" -#include <sound/seq_oss_legacy.h> -#include <linux/slab.h> - -/* - */ -#define MIN_OSS_TEMPO 8 -#define MAX_OSS_TEMPO 360 -#define MIN_OSS_TIMEBASE 1 -#define MAX_OSS_TIMEBASE 1000 - -/* - */ -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. - */ -struct seq_oss_timer * -snd_seq_oss_timer_new(struct seq_oss_devinfo *dp) -{ - struct seq_oss_timer *rec; - - rec = kzalloc(sizeof(*rec), GFP_KERNEL); - if (rec == NULL) - return NULL; - - rec->dp = dp; - rec->cur_tick = 0; - rec->realtime = 0; - rec->running = 0; - rec->oss_tempo = 60; - rec->oss_timebase = 100; - calc_alsa_tempo(rec); - - return rec; -} - - -/* - * delete timer. - * if no more timer exists, stop the queue. - */ -void -snd_seq_oss_timer_delete(struct seq_oss_timer *rec) -{ - if (rec) { - snd_seq_oss_timer_stop(rec); - kfree(rec); - } -} - - -/* - * process one timing event - * return 1 : event proceseed -- skip this event - * 0 : not a timer event -- enqueue this event - */ -int -snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev) -{ - abstime_t parm = ev->t.time; - - if (ev->t.code == EV_TIMING) { - switch (ev->t.cmd) { - case TMR_WAIT_REL: - parm += rec->cur_tick; - rec->realtime = 0; - /* continue to next */ - case TMR_WAIT_ABS: - if (parm == 0) { - rec->realtime = 1; - } else if (parm >= rec->cur_tick) { - rec->realtime = 0; - rec->cur_tick = parm; - } - return 1; /* skip this event */ - - case TMR_START: - snd_seq_oss_timer_start(rec); - return 1; - - } - } else if (ev->s.code == SEQ_WAIT) { - /* time = from 1 to 3 bytes */ - parm = (ev->echo >> 8) & 0xffffff; - if (parm > rec->cur_tick) { - /* set next event time */ - rec->cur_tick = parm; - rec->realtime = 0; - } - return 1; - } - - return 0; -} - - -/* - * convert tempo units - */ -static void -calc_alsa_tempo(struct seq_oss_timer *timer) -{ - timer->tempo = (60 * 1000000) / timer->oss_tempo; - timer->ppq = timer->oss_timebase; -} - - -/* - * dispatch a timer event - */ -static int -send_timer_event(struct seq_oss_devinfo *dp, int type, int value) -{ - struct snd_seq_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.type = type; - ev.source.client = dp->cseq; - ev.source.port = 0; - ev.dest.client = SNDRV_SEQ_CLIENT_SYSTEM; - ev.dest.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - ev.queue = dp->queue; - ev.data.queue.queue = dp->queue; - ev.data.queue.param.value = value; - return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0); -} - -/* - * set queue tempo and start queue - */ -int -snd_seq_oss_timer_start(struct seq_oss_timer *timer) -{ - struct seq_oss_devinfo *dp = timer->dp; - struct snd_seq_queue_tempo tmprec; - - if (timer->running) - snd_seq_oss_timer_stop(timer); - - memset(&tmprec, 0, sizeof(tmprec)); - tmprec.queue = dp->queue; - tmprec.ppq = timer->ppq; - tmprec.tempo = timer->tempo; - snd_seq_set_queue_tempo(dp->cseq, &tmprec); - - send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0); - timer->running = 1; - timer->cur_tick = 0; - return 0; -} - - -/* - * stop queue - */ -int -snd_seq_oss_timer_stop(struct seq_oss_timer *timer) -{ - if (! timer->running) - return 0; - send_timer_event(timer->dp, SNDRV_SEQ_EVENT_STOP, 0); - timer->running = 0; - return 0; -} - - -/* - * continue queue - */ -int -snd_seq_oss_timer_continue(struct seq_oss_timer *timer) -{ - if (timer->running) - return 0; - send_timer_event(timer->dp, SNDRV_SEQ_EVENT_CONTINUE, 0); - timer->running = 1; - return 0; -} - - -/* - * change queue tempo - */ -int -snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value) -{ - if (value < MIN_OSS_TEMPO) - value = MIN_OSS_TEMPO; - else if (value > MAX_OSS_TEMPO) - value = MAX_OSS_TEMPO; - timer->oss_tempo = value; - calc_alsa_tempo(timer); - if (timer->running) - send_timer_event(timer->dp, SNDRV_SEQ_EVENT_TEMPO, timer->tempo); - return 0; -} - - -/* - * ioctls - */ -int -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; - if (value) - return -EINVAL; - value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60; - return put_user(value, arg) ? -EFAULT : 0; - } - - if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) - return 0; - - 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) - value = MIN_OSS_TIMEBASE; - else if (value > MAX_OSS_TIMEBASE) - value = MAX_OSS_TIMEBASE; - timer->oss_timebase = value; - calc_alsa_tempo(timer); - return 0; - - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SELECT: - case SNDCTL_TMR_SOURCE: - debug_printk(("timer XXX\n")); - /* not supported */ - return 0; - } - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.h deleted file mode 100644 index b995bd68..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_timer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * OSS compatible sequencer driver - * timer handling routines - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_TIMER_H -#define __SEQ_OSS_TIMER_H - -#include "seq_oss_device.h" - -/* - * timer information definition - */ -struct seq_oss_timer { - struct seq_oss_devinfo *dp; - reltime_t cur_tick; - int realtime; - int running; - int tempo, ppq; /* ALSA queue */ - int oss_tempo, oss_timebase; -}; - - -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(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(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(struct seq_oss_timer *timer) -{ - return timer->cur_tick; -} - - -/* - * is realtime event? - */ -static inline int -snd_seq_oss_timer_is_realtime(struct seq_oss_timer *timer) -{ - return timer->realtime; -} - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.c b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.c deleted file mode 100644 index d50338bb..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * OSS compatible sequencer driver - * - * seq_oss_writeq.c - write queue and sync - * - * Copyright (C) 1998,99 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. - * - * 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 "seq_oss_writeq.h" -#include "seq_oss_event.h" -#include "seq_oss_timer.h" -#include <sound/seq_oss_legacy.h> -#include "../seq_lock.h" -#include "../seq_clientmgr.h" -#include <linux/wait.h> -#include <linux/slab.h> - - -/* - * create a write queue record - */ -struct seq_oss_writeq * -snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) -{ - struct seq_oss_writeq *q; - struct snd_seq_client_pool pool; - - if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) - return NULL; - q->dp = dp; - q->maxlen = maxlen; - spin_lock_init(&q->sync_lock); - q->sync_event_put = 0; - q->sync_time = 0; - init_waitqueue_head(&q->sync_sleep); - - memset(&pool, 0, sizeof(pool)); - pool.client = dp->cseq; - pool.output_pool = maxlen; - pool.output_room = maxlen / 2; - - snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); - - return q; -} - -/* - * delete the write queue - */ -void -snd_seq_oss_writeq_delete(struct seq_oss_writeq *q) -{ - if (q) { - snd_seq_oss_writeq_clear(q); /* to be sure */ - kfree(q); - } -} - - -/* - * reset the write queue - */ -void -snd_seq_oss_writeq_clear(struct seq_oss_writeq *q) -{ - struct snd_seq_remove_events reset; - - memset(&reset, 0, sizeof(reset)); - reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */ - snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset); - - /* wake up sleepers if any */ - snd_seq_oss_writeq_wakeup(q, 0); -} - -/* - * wait until the write buffer has enough room - */ -int -snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) -{ - struct seq_oss_devinfo *dp = q->dp; - abstime_t time; - - time = snd_seq_oss_timer_cur_tick(dp->timer); - if (q->sync_time >= time) - return 0; /* already finished */ - - if (! q->sync_event_put) { - struct snd_seq_event ev; - union evrec *rec; - - /* put echoback event */ - memset(&ev, 0, sizeof(ev)); - ev.flags = 0; - ev.type = SNDRV_SEQ_EVENT_ECHO; - ev.time.tick = time; - /* echo back to itself */ - snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port); - rec = (union evrec *)&ev.data; - rec->t.code = SEQ_SYNCTIMER; - rec->t.time = time; - q->sync_event_put = 1; - snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); - } - - wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); - if (signal_pending(current)) - /* interrupted - return 0 to finish sync */ - q->sync_event_put = 0; - if (! q->sync_event_put || q->sync_time >= time) - return 0; - return 1; -} - -/* - * wake up sync - echo event was catched - */ -void -snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time) -{ - unsigned long flags; - - spin_lock_irqsave(&q->sync_lock, flags); - q->sync_time = time; - q->sync_event_put = 0; - if (waitqueue_active(&q->sync_sleep)) { - wake_up(&q->sync_sleep); - } - spin_unlock_irqrestore(&q->sync_lock, flags); -} - - -/* - * return the unused pool size - */ -int -snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q) -{ - 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; -} - - -/* - * set output threshold size from ioctl - */ -void -snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val) -{ - 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; - snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); -} - diff --git a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.h b/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.h deleted file mode 100644 index c469d296..00000000 --- a/ANDROID_3.4.5/sound/core/seq/oss/seq_oss_writeq.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * OSS compatible sequencer driver - * write priority queue - * - * Copyright (C) 1998,99 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. - * - * 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 - */ - -#ifndef __SEQ_OSS_WRITEQ_H -#define __SEQ_OSS_WRITEQ_H - -#include "seq_oss_device.h" - - -struct seq_oss_writeq { - struct seq_oss_devinfo *dp; - int maxlen; - abstime_t sync_time; - int sync_event_put; - wait_queue_head_t sync_sleep; - spinlock_t sync_lock; -}; - - -/* - * seq_oss_writeq.c - */ -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/ANDROID_3.4.5/sound/core/seq/seq.c b/ANDROID_3.4.5/sound/core/seq/seq.c deleted file mode 100644 index 71211056..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ALSA sequencer main module - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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/module.h> -#include <linux/device.h> -#include <sound/core.h> -#include <sound/initval.h> - -#include <sound/seq_kernel.h> -#include "seq_clientmgr.h" -#include "seq_memory.h" -#include "seq_queue.h" -#include "seq_lock.h" -#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[15] = {[0] = SNDRV_SEQ_CLIENT_DUMMY, [1 ... 14] = -1}; -#else -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_HRTIMER_DEFAULT - SNDRV_TIMER_GLOBAL_HRTIMER -#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT) - SNDRV_TIMER_GLOBAL_RTC -#else - SNDRV_TIMER_GLOBAL_SYSTEM -#endif - ; -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@perex.cz>"); -MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer."); -MODULE_LICENSE("GPL"); - -module_param_array(seq_client_load, int, NULL, 0444); -MODULE_PARM_DESC(seq_client_load, "The numbers of global (system) clients to load through kmod."); -module_param(seq_default_timer_class, int, 0644); -MODULE_PARM_DESC(seq_default_timer_class, "The default timer class."); -module_param(seq_default_timer_sclass, int, 0644); -MODULE_PARM_DESC(seq_default_timer_sclass, "The default timer slave class."); -module_param(seq_default_timer_card, int, 0644); -MODULE_PARM_DESC(seq_default_timer_card, "The default timer card number."); -module_param(seq_default_timer_device, int, 0644); -MODULE_PARM_DESC(seq_default_timer_device, "The default timer device number."); -module_param(seq_default_timer_subdevice, int, 0644); -MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice number."); -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 - */ - -static int __init alsa_seq_init(void) -{ - int err; - - snd_seq_autoload_lock(); - if ((err = client_init_data()) < 0) - goto error; - - /* init memory, room for selected events */ - if ((err = snd_sequencer_memory_init()) < 0) - goto error; - - /* init event queues */ - if ((err = snd_seq_queues_init()) < 0) - goto error; - - /* register sequencer device */ - if ((err = snd_sequencer_device_init()) < 0) - goto error; - - /* register proc interface */ - if ((err = snd_seq_info_init()) < 0) - goto error; - - /* register our internal client */ - if ((err = snd_seq_system_client_init()) < 0) - goto error; - - error: - snd_seq_autoload_unlock(); - return err; -} - -static void __exit alsa_seq_exit(void) -{ - /* unregister our internal client */ - snd_seq_system_client_done(); - - /* unregister proc interface */ - snd_seq_info_done(); - - /* delete timing queues */ - snd_seq_queues_delete(); - - /* unregister sequencer device */ - snd_sequencer_device_done(); - - /* release event memory */ - snd_sequencer_memory_done(); -} - -module_init(alsa_seq_init) -module_exit(alsa_seq_exit) diff --git a/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.c b/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.c deleted file mode 100644 index 4dc6bae8..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.c +++ /dev/null @@ -1,2591 +0,0 @@ -/* - * ALSA sequencer Client Manager - * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@perex.cz> - * 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. - * - * 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/export.h> -#include <linux/slab.h> -#include <sound/core.h> -#include <sound/minors.h> -#include <linux/kmod.h> - -#include <sound/seq_kernel.h> -#include "seq_clientmgr.h" -#include "seq_memory.h" -#include "seq_queue.h" -#include "seq_timer.h" -#include "seq_info.h" -#include "seq_system.h" -#include <sound/seq_device.h> -#ifdef CONFIG_COMPAT -#include <linux/compat.h> -#endif - -/* Client Manager - - * this module handles the connections of userland and kernel clients - * - */ - -/* - * 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 DEFINE_MUTEX(register_mutex); - -/* - * client table - */ -static char clienttablock[SNDRV_SEQ_MAX_CLIENTS]; -static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS]; -static struct snd_seq_usage client_usage; - -/* - * prototypes - */ -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); - -/* - */ - -static inline mm_segment_t snd_enter_user(void) -{ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ - set_fs(fs); -} - -/* - */ -static inline unsigned short snd_seq_file_flags(struct file *file) -{ - switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { - case FMODE_WRITE: - return SNDRV_SEQ_LFLG_OUTPUT; - case FMODE_READ: - return SNDRV_SEQ_LFLG_INPUT; - default: - return SNDRV_SEQ_LFLG_OPEN; - } -} - -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 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); - return NULL; - } - return clienttab[clientid]; -} - -struct snd_seq_client *snd_seq_client_use_ptr(int clientid) -{ - unsigned long flags; - 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); - return NULL; - } - spin_lock_irqsave(&clients_lock, flags); - client = clientptr(clientid); - if (client) - goto __lock; - if (clienttablock[clientid]) { - spin_unlock_irqrestore(&clients_lock, flags); - return NULL; - } - spin_unlock_irqrestore(&clients_lock, flags); -#ifdef CONFIG_MODULES - if (!in_interrupt()) { - static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; - static char card_requested[SNDRV_CARDS]; - if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { - int idx; - - if (!client_requested[clientid]) { - client_requested[clientid] = 1; - 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); - break; - } - } - } - } 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; - snd_request_card(card); - } - snd_seq_device_load_drivers(); - } - } - spin_lock_irqsave(&clients_lock, flags); - client = clientptr(clientid); - if (client) - goto __lock; - spin_unlock_irqrestore(&clients_lock, flags); - } -#endif - return NULL; - - __lock: - snd_use_lock_use(&client->use_lock); - spin_unlock_irqrestore(&clients_lock, flags); - return client; -} - -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(struct snd_seq_usage *res, int num) -{ - res->cur -= num; -} - -/* initialise data structures */ -int __init client_init_data(void) -{ - /* zap out the client table */ - memset(&clienttablock, 0, sizeof(clienttablock)); - memset(&clienttab, 0, sizeof(clienttab)); - return 0; -} - - -static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) -{ - unsigned long flags; - int c; - struct snd_seq_client *client; - - /* init client data */ - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) - return NULL; - client->pool = snd_seq_pool_new(poolsize); - if (client->pool == NULL) { - kfree(client); - return NULL; - } - client->type = NO_CLIENT; - snd_use_lock_init(&client->use_lock); - rwlock_init(&client->ports_lock); - 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 = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; - c < SNDRV_SEQ_MAX_CLIENTS; - c++) { - if (clienttab[c] || clienttablock[c]) - continue; - clienttab[client->number = c] = client; - spin_unlock_irqrestore(&clients_lock, flags); - return client; - } - } else { - if (clienttab[client_index] == NULL && !clienttablock[client_index]) { - clienttab[client->number = client_index] = client; - spin_unlock_irqrestore(&clients_lock, flags); - return client; - } - } - spin_unlock_irqrestore(&clients_lock, flags); - snd_seq_pool_delete(&client->pool); - kfree(client); - return NULL; /* no free slot found or busy, return failure code */ -} - - -static int seq_free_client1(struct snd_seq_client *client) -{ - unsigned long flags; - - if (!client) - return 0; - snd_seq_delete_all_ports(client); - snd_seq_queue_client_leave(client->number); - spin_lock_irqsave(&clients_lock, flags); - clienttablock[client->number] = 1; - clienttab[client->number] = NULL; - spin_unlock_irqrestore(&clients_lock, flags); - snd_use_lock_sync(&client->use_lock); - snd_seq_queue_client_termination(client->number); - if (client->pool) - snd_seq_pool_delete(&client->pool); - spin_lock_irqsave(&clients_lock, flags); - clienttablock[client->number] = 0; - spin_unlock_irqrestore(&clients_lock, flags); - return 0; -} - - -static void seq_free_client(struct snd_seq_client * client) -{ - mutex_lock(®ister_mutex); - switch (client->type) { - case NO_CLIENT: - snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n", - client->number); - break; - case USER_CLIENT: - case KERNEL_CLIENT: - seq_free_client1(client); - usage_free(&client_usage, 1); - break; - - default: - snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n", - client->number, client->type); - } - mutex_unlock(®ister_mutex); - - snd_seq_system_client_ev_client_exit(client->number); -} - - - -/* -------------------------------------------------------- */ - -/* create a user client */ -static int snd_seq_open(struct inode *inode, struct file *file) -{ - int c, mode; /* client id */ - struct snd_seq_client *client; - struct snd_seq_user_client *user; - int err; - - err = nonseekable_open(inode, file); - if (err < 0) - return err; - - if (mutex_lock_interruptible(®ister_mutex)) - return -ERESTARTSYS; - client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS); - if (client == NULL) { - mutex_unlock(®ister_mutex); - return -ENOMEM; /* failure code */ - } - - mode = snd_seq_file_flags(file); - if (mode & SNDRV_SEQ_LFLG_INPUT) - client->accept_input = 1; - if (mode & SNDRV_SEQ_LFLG_OUTPUT) - client->accept_output = 1; - - user = &client->data.user; - user->fifo = NULL; - user->fifo_pool_size = 0; - - if (mode & SNDRV_SEQ_LFLG_INPUT) { - user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS; - user->fifo = snd_seq_fifo_new(user->fifo_pool_size); - if (user->fifo == NULL) { - seq_free_client1(client); - kfree(client); - mutex_unlock(®ister_mutex); - return -ENOMEM; - } - } - - usage_alloc(&client_usage, 1); - client->type = USER_CLIENT; - mutex_unlock(®ister_mutex); - - c = client->number; - file->private_data = client; - - /* fill client data */ - user->file = file; - sprintf(client->name, "Client-%d", c); - - /* make others aware this new client */ - snd_seq_system_client_ev_client_start(c); - - return 0; -} - -/* delete a user client */ -static int snd_seq_release(struct inode *inode, struct file *file) -{ - struct snd_seq_client *client = file->private_data; - - if (client) { - seq_free_client(client); - if (client->data.user.fifo) - snd_seq_fifo_delete(&client->data.user.fifo); - kfree(client); - } - - return 0; -} - - -/* handle client read() */ -/* possible error values: - * -ENXIO invalid client or file open mode - * -ENOSPC FIFO overflow (the flag is cleared after this error report) - * -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) -{ - struct snd_seq_client *client = file->private_data; - struct snd_seq_fifo *fifo; - int err; - long result = 0; - struct snd_seq_event_cell *cell; - - if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT)) - return -ENXIO; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - /* check client structures are in place */ - if (snd_BUG_ON(!client)) - return -ENXIO; - - if (!client->accept_input || (fifo = client->data.user.fifo) == NULL) - return -ENXIO; - - if (atomic_read(&fifo->overflow) > 0) { - /* buffer overflow is detected */ - snd_seq_fifo_clear(fifo); - /* return error code */ - return -ENOSPC; - } - - cell = NULL; - err = 0; - snd_seq_fifo_lock(fifo); - - /* while data available in queue */ - while (count >= sizeof(struct snd_seq_event)) { - int nonblock; - - nonblock = (file->f_flags & O_NONBLOCK) || result > 0; - if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) { - break; - } - if (snd_seq_ev_is_variable(&cell->event)) { - struct snd_seq_event tmpev; - tmpev = cell->event; - tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK; - if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) { - err = -EFAULT; - break; - } - 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(struct snd_seq_event)); - if (err < 0) - break; - result += err; - count -= err; - buf += err; - } else { - if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) { - err = -EFAULT; - break; - } - count -= sizeof(struct snd_seq_event); - buf += sizeof(struct snd_seq_event); - } - snd_seq_cell_free(cell); - cell = NULL; /* to be sure */ - result += sizeof(struct snd_seq_event); - } - - if (err < 0) { - if (cell) - snd_seq_fifo_cell_putback(fifo, cell); - if (err == -EAGAIN && result > 0) - err = 0; - } - snd_seq_fifo_unlock(fifo); - - return (err < 0) ? err : result; -} - - -/* - * check access permission to the port - */ -static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags) -{ - if ((port->capability & flags) != flags) - return 0; - return flags; -} - -/* - * check if the destination client is available, and return the pointer - * if filter is non-zero, client filter bitmap is tested. - */ -static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event, - int filter) -{ - struct snd_seq_client *dest; - - dest = snd_seq_client_use_ptr(event->dest.client); - if (dest == NULL) - return NULL; - if (! dest->accept_input) - goto __not_avail; - if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) && - ! test_bit(event->type, dest->event_filter)) - goto __not_avail; - if (filter && !(dest->filter & filter)) - goto __not_avail; - - return dest; /* ok - accessible */ -__not_avail: - snd_seq_client_unlock(dest); - return NULL; -} - - -/* - * Return the error event. - * - * If the receiver client is a user client, the original event is - * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If - * the original event is also variable length, the external data is - * copied after the event record. - * If the receiver client is a kernel client, the original event is - * quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra - * kmalloc. - */ -static int bounce_error_event(struct snd_seq_client *client, - struct snd_seq_event *event, - int err, int atomic, int hop) -{ - struct snd_seq_event bounce_ev; - int result; - - if (client == NULL || - ! (client->filter & SNDRV_SEQ_FILTER_BOUNCE) || - ! client->accept_input) - return 0; /* ignored */ - - /* set up quoted error */ - memset(&bounce_ev, 0, sizeof(bounce_ev)); - bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR; - bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; - bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT; - bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM; - bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - bounce_ev.dest.client = client->number; - bounce_ev.dest.port = event->source.port; - bounce_ev.data.quote.origin = event->dest; - bounce_ev.data.quote.event = event; - bounce_ev.data.quote.value = -err; /* use positive value */ - result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1); - if (result < 0) { - client->event_lost++; - return result; - } - - return result; -} - - -/* - * rewrite the time-stamp of the event record with the curren time - * of the given queue. - * return non-zero if updated. - */ -static int update_timestamp_of_queue(struct snd_seq_event *event, - int queue, int real_time) -{ - struct snd_seq_queue *q; - - q = queueptr(queue); - if (! q) - return 0; - event->queue = queue; - event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK; - if (real_time) { - event->time.time = snd_seq_timer_get_cur_time(q->timer); - event->flags |= SNDRV_SEQ_TIME_STAMP_REAL; - } else { - event->time.tick = snd_seq_timer_get_cur_tick(q->timer); - event->flags |= SNDRV_SEQ_TIME_STAMP_TICK; - } - queuefree(q); - return 1; -} - - -/* - * deliver an event to the specified destination. - * if filter is non-zero, client filter bitmap is tested. - * - * RETURN VALUE: 0 : if succeeded - * <0 : error - */ -static int snd_seq_deliver_single_event(struct snd_seq_client *client, - struct snd_seq_event *event, - int filter, int atomic, int hop) -{ - struct snd_seq_client *dest = NULL; - struct snd_seq_client_port *dest_port = NULL; - int result = -ENOENT; - int direct; - - direct = snd_seq_ev_is_direct(event); - - dest = get_event_dest_client(event, filter); - if (dest == NULL) - goto __skip; - dest_port = snd_seq_port_use_ptr(dest, event->dest.port); - if (dest_port == NULL) - goto __skip; - - /* check permission */ - if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) { - result = -EPERM; - goto __skip; - } - - if (dest_port->timestamping) - update_timestamp_of_queue(event, dest_port->time_queue, - dest_port->time_real); - - switch (dest->type) { - case USER_CLIENT: - if (dest->data.user.fifo) - result = snd_seq_fifo_event_in(dest->data.user.fifo, event); - break; - - case KERNEL_CLIENT: - if (dest_port->event_input == NULL) - break; - result = dest_port->event_input(event, direct, - dest_port->private_data, - atomic, hop); - break; - default: - break; - } - - __skip: - if (dest_port) - snd_seq_port_unlock(dest_port); - if (dest) - snd_seq_client_unlock(dest); - - if (result < 0 && !direct) { - result = bounce_error_event(client, event, result, atomic, hop); - } - return result; -} - - -/* - * send the event to all subscribers: - */ -static int deliver_to_subscribers(struct snd_seq_client *client, - struct snd_seq_event *event, - int atomic, int hop) -{ - struct snd_seq_subscribers *subs; - int err = 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) - return -EINVAL; /* invalid source port */ - /* save original event record */ - event_saved = *event; - grp = &src_port->c_src; - - /* lock list */ - if (atomic) - read_lock(&grp->list_lock); - else - down_read(&grp->list_mutex); - 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 */ - update_timestamp_of_queue(event, subs->info.queue, - subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL); - err = snd_seq_deliver_single_event(client, event, - 0, atomic, hop); - if (err < 0) - break; - num_ev++; - /* restore original event record */ - *event = event_saved; - } - if (atomic) - read_unlock(&grp->list_lock); - else - up_read(&grp->list_mutex); - *event = event_saved; /* restore */ - snd_seq_port_unlock(src_port); - return (err < 0) ? err : num_ev; -} - - -#ifdef SUPPORT_BROADCAST -/* - * broadcast to all ports: - */ -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; - 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_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; - 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; -} - -/* - * send the event to all clients: - * if destination port is also ADDRESS_BROADCAST, deliver to all ports. - */ -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 dest; - struct snd_seq_addr addr; - - addr = event->dest; /* save */ - - for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) { - /* don't send to itself */ - if (dest == client->number) - continue; - event->dest.client = dest; - event->dest.port = addr.port; - if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST) - err = port_broadcast_event(client, event, atomic, hop); - else - /* 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; - num_ev += err; - } - event->dest = addr; /* restore */ - return (err < 0) ? err : num_ev; -} - - -/* multicast - not supported yet */ -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"); - return 0; /* ignored */ -} -#endif /* SUPPORT_BROADCAST */ - - -/* deliver an event to the destination port(s). - * if the event is to subscribers or broadcast, the event is dispatched - * to multiple targets. - * - * RETURN VALUE: n > 0 : the number of delivered events. - * n == 0 : the event was not passed to any client. - * n < 0 : error - event was not processed. - */ -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", - event->source.client, event->source.port, - event->dest.client, event->dest.port); - return -EMLINK; - } - - if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS || - event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) - result = deliver_to_subscribers(client, event, atomic, hop); -#ifdef SUPPORT_BROADCAST - else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST || - event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST) - result = broadcast_event(client, event, atomic, hop); - else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS) - result = multicast_event(client, event, atomic, hop); - else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST) - result = port_broadcast_event(client, event, atomic, hop); -#endif - else - result = snd_seq_deliver_single_event(client, event, 0, atomic, hop); - - return result; -} - -/* - * dispatch an event cell: - * This function is called only from queue check routines in timer - * interrupts or after enqueued. - * The event cell shall be released or re-queued in this function. - * - * RETURN VALUE: n > 0 : the number of delivered events. - * n == 0 : the event was not passed to any client. - * n < 0 : error - event was not processed. - */ -int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) -{ - struct snd_seq_client *client; - int result; - - if (snd_BUG_ON(!cell)) - return -EINVAL; - - client = snd_seq_client_use_ptr(cell->event.source.client); - if (client == NULL) { - snd_seq_cell_free(cell); /* release this cell */ - return -EINVAL; - } - - if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) { - /* NOTE event: - * the event cell is re-used as a NOTE-OFF event and - * enqueued again. - */ - struct snd_seq_event tmpev, *ev; - - /* reserve this event to enqueue note-off later */ - tmpev = cell->event; - tmpev.type = SNDRV_SEQ_EVENT_NOTEON; - result = snd_seq_deliver_event(client, &tmpev, atomic, hop); - - /* - * This was originally a note event. We now re-use the - * cell for the note-off event. - */ - - ev = &cell->event; - ev->type = SNDRV_SEQ_EVENT_NOTEOFF; - ev->flags |= SNDRV_SEQ_PRIORITY_HIGH; - - /* add the duration time */ - switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) { - case SNDRV_SEQ_TIME_STAMP_TICK: - ev->time.tick += ev->data.note.duration; - break; - case SNDRV_SEQ_TIME_STAMP_REAL: - /* unit for duration is ms */ - ev->time.time.tv_nsec += 1000000 * (ev->data.note.duration % 1000); - ev->time.time.tv_sec += ev->data.note.duration / 1000 + - ev->time.time.tv_nsec / 1000000000; - ev->time.time.tv_nsec %= 1000000000; - break; - } - ev->data.note.velocity = ev->data.note.off_velocity; - - /* Now queue this cell as the note off event */ - if (snd_seq_enqueue_event(cell, atomic, hop) < 0) - snd_seq_cell_free(cell); /* release this cell */ - - } else { - /* Normal events: - * event cell is freed after processing the event - */ - - result = snd_seq_deliver_event(client, &cell->event, atomic, hop); - snd_seq_cell_free(cell); - } - - snd_seq_client_unlock(client); - return result; -} - - -/* Allocate a cell from client pool and enqueue it to queue: - * if pool is empty and blocking is TRUE, sleep until a new cell is - * available. - */ -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) -{ - struct snd_seq_event_cell *cell; - int err; - - /* special queue values - force direct passing */ - if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { - event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - event->queue = SNDRV_SEQ_QUEUE_DIRECT; - } else -#ifdef SUPPORT_BROADCAST - if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) { - event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST; - event->queue = SNDRV_SEQ_QUEUE_DIRECT; - } -#endif - if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { - /* check presence of 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); - } - - /* direct event processing without enqueued */ - if (snd_seq_ev_is_direct(event)) { - if (event->type == SNDRV_SEQ_EVENT_NOTE) - return -EINVAL; /* this event must be enqueued! */ - return snd_seq_deliver_event(client, event, atomic, hop); - } - - /* Not direct, normal queuing */ - if (snd_seq_queue_is_used(event->queue, client->number) <= 0) - return -EINVAL; /* invalid queue */ - if (! snd_seq_write_pool_allocated(client)) - return -ENXIO; /* queue is not allocated */ - - /* allocate an event cell */ - err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); - if (err < 0) - return err; - - /* we got a cell. enqueue it. */ - if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) { - snd_seq_cell_free(cell); - return err; - } - - return 0; -} - - -/* - * check validity of event type and data length. - * return non-zero if invalid. - */ -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: - if (snd_seq_ev_is_variable_type(ev)) - return -EINVAL; - break; - case SNDRV_SEQ_EVENT_LENGTH_VARIABLE: - if (! snd_seq_ev_is_variable_type(ev) || - (ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK) >= SNDRV_SEQ_MAX_EVENT_LEN) - return -EINVAL; - break; - case SNDRV_SEQ_EVENT_LENGTH_VARUSR: - if (! snd_seq_ev_is_direct(ev)) - return -EINVAL; - break; - } - return 0; -} - - -/* handle write() */ -/* possible error values: - * -ENXIO invalid client or file open mode - * -ENOMEM malloc failed - * -EFAULT seg. fault during copy from user space - * -EINVAL invalid event - * -EAGAIN no space in output pool - * -EINTR interrupts while sleep - * -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) -{ - struct snd_seq_client *client = file->private_data; - int written = 0, len; - int err = -EINVAL; - struct snd_seq_event event; - - if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT)) - return -ENXIO; - - /* check client structures are in place */ - if (snd_BUG_ON(!client)) - return -ENXIO; - - if (!client->accept_output || client->pool == NULL) - return -ENXIO; - - /* allocate the pool now if the pool is not allocated yet */ - if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { - if (snd_seq_pool_init(client->pool) < 0) - return -ENOMEM; - } - - /* only process whole events */ - 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)) { - err = -EFAULT; - break; - } - event.source.client = client->number; /* fill in client number */ - /* Check for extension data length */ - if (check_event_type_and_length(&event)) { - err = -EINVAL; - break; - } - - /* check for special events */ - if (event.type == SNDRV_SEQ_EVENT_NONE) - goto __skip_event; - else if (snd_seq_ev_is_reserved(&event)) { - err = -EINVAL; - break; - } - - if (snd_seq_ev_is_variable(&event)) { - int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK; - if ((size_t)(extlen + len) > count) { - /* back out, will get an error this time or next */ - err = -EINVAL; - break; - } - /* set user space pointer */ - event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; - event.data.ext.ptr = (char __force *)buf - + 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 = (void __force *)compat_ptr(event.data.raw32.d[1]); - event.data.ext.ptr = ptr; - } -#endif - } - - /* ok, enqueue it */ - err = snd_seq_client_enqueue_event(client, &event, file, - !(file->f_flags & O_NONBLOCK), - 0, 0); - if (err < 0) - break; - - __skip_event: - /* Update pointers and counts */ - count -= len; - buf += len; - written += len; - } - - return written ? written : err; -} - - -/* - * handle polling - */ -static unsigned int snd_seq_poll(struct file *file, poll_table * wait) -{ - struct snd_seq_client *client = file->private_data; - unsigned int mask = 0; - - /* check client structures are in place */ - if (snd_BUG_ON(!client)) - return -ENXIO; - - if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) && - client->data.user.fifo) { - - /* check if data is available in the outqueue */ - if (snd_seq_fifo_poll_wait(client->data.user.fifo, file, wait)) - mask |= POLLIN | POLLRDNORM; - } - - if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) { - - /* check if data is available in the pool */ - if (!snd_seq_write_pool_allocated(client) || - snd_seq_pool_poll_wait(client->pool, file, wait)) - mask |= POLLOUT | POLLWRNORM; - } - - return mask; -} - - -/*-----------------------------------------------------*/ - - -/* SYSTEM_INFO ioctl() */ -static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user *arg) -{ - struct snd_seq_system_info info; - - memset(&info, 0, sizeof(info)); - /* fill the info fields */ - info.queues = SNDRV_SEQ_MAX_QUEUES; - info.clients = SNDRV_SEQ_MAX_CLIENTS; - info.ports = 256; /* fixed limit */ - info.channels = 256; /* fixed limit */ - info.cur_clients = client_usage.cur; - info.cur_queues = snd_seq_queue_get_cur_queues(); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - - -/* RUNNING_MODE ioctl() */ -static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void __user *arg) -{ - struct snd_seq_running_info info; - struct snd_seq_client *cptr; - int err = 0; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - /* requested client number */ - cptr = snd_seq_client_use_ptr(info.client); - if (cptr == NULL) - return -ENOENT; /* don't change !!! */ - -#ifdef SNDRV_BIG_ENDIAN - if (! info.big_endian) { - err = -EINVAL; - goto __err; - } -#else - if (info.big_endian) { - err = -EINVAL; - goto __err; - } - -#endif - if (info.cpu_mode > sizeof(long)) { - err = -EINVAL; - goto __err; - } - cptr->convert32 = (info.cpu_mode < sizeof(long)); - __err: - snd_seq_client_unlock(cptr); - return err; -} - -/* CLIENT_INFO ioctl() */ -static void get_client_info(struct snd_seq_client *cptr, - struct snd_seq_client_info *info) -{ - info->client = cptr->number; - - /* fill the info fields */ - info->type = cptr->type; - strcpy(info->name, cptr->name); - info->filter = cptr->filter; - info->event_lost = cptr->event_lost; - memcpy(info->event_filter, cptr->event_filter, 32); - info->num_ports = cptr->num_ports; - memset(info->reserved, 0, sizeof(info->reserved)); -} - -static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client *cptr; - struct snd_seq_client_info client_info; - - if (copy_from_user(&client_info, arg, sizeof(client_info))) - return -EFAULT; - - /* requested client number */ - cptr = snd_seq_client_use_ptr(client_info.client); - if (cptr == NULL) - return -ENOENT; /* don't change !!! */ - - get_client_info(cptr, &client_info); - snd_seq_client_unlock(cptr); - - if (copy_to_user(arg, &client_info, sizeof(client_info))) - return -EFAULT; - return 0; -} - - -/* CLIENT_INFO ioctl() */ -static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client_info client_info; - - if (copy_from_user(&client_info, arg, sizeof(client_info))) - return -EFAULT; - - /* it is not allowed to set the info fields for an another client */ - if (client->number != client_info.client) - return -EPERM; - /* also client type must be set now */ - if (client->type != client_info.type) - return -EINVAL; - - /* fill the info fields */ - if (client_info.name[0]) - strlcpy(client->name, client_info.name, sizeof(client->name)); - - client->filter = client_info.filter; - client->event_lost = client_info.event_lost; - memcpy(client->event_filter, client_info.event_filter, 32); - - return 0; -} - - -/* - * CREATE PORT ioctl() - */ -static int snd_seq_ioctl_create_port(struct snd_seq_client *client, - void __user *arg) -{ - 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; - - /* it is not allowed to create the port for an another client */ - if (info.addr.client != client->number) - return -EPERM; - - port = snd_seq_create_port(client, (info.flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info.addr.port : -1); - if (port == NULL) - return -ENOMEM; - - if (client->type == USER_CLIENT && info.kernel) { - snd_seq_delete_port(client, port->addr.port); - return -EINVAL; - } - if (client->type == KERNEL_CLIENT) { - if ((callback = info.kernel) != NULL) { - if (callback->owner) - port->owner = callback->owner; - port->private_data = callback->private_data; - port->private_free = callback->private_free; - port->callback_all = callback->callback_all; - port->event_input = callback->event_input; - port->c_src.open = callback->subscribe; - port->c_src.close = callback->unsubscribe; - port->c_dest.open = callback->use; - port->c_dest.close = callback->unuse; - } - } - - info.addr = port->addr; - - snd_seq_set_port_info(port, &info); - snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -/* - * DELETE PORT ioctl() - */ -static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_port_info info; - int err; - - /* set passed parameters */ - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - /* it is not allowed to remove the port for an another client */ - if (info.addr.client != client->number) - return -EPERM; - - err = snd_seq_delete_port(client, info.addr.port); - if (err >= 0) - snd_seq_system_client_ev_port_exit(client->number, info.addr.port); - return err; -} - - -/* - * GET_PORT_INFO ioctl() (on any client) - */ -static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, - void __user *arg) -{ - 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; - cptr = snd_seq_client_use_ptr(info.addr.client); - if (cptr == NULL) - return -ENXIO; - - port = snd_seq_port_use_ptr(cptr, info.addr.port); - if (port == NULL) { - snd_seq_client_unlock(cptr); - return -ENOENT; /* don't change */ - } - - /* get port info */ - snd_seq_get_port_info(port, &info); - snd_seq_port_unlock(port); - snd_seq_client_unlock(cptr); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - - -/* - * SET_PORT_INFO ioctl() (only ports on this/own client) - */ -static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client_port *port; - struct snd_seq_port_info info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - if (info.addr.client != client->number) /* only set our own ports ! */ - return -EPERM; - port = snd_seq_port_use_ptr(client, info.addr.port); - if (port) { - snd_seq_set_port_info(port, &info); - snd_seq_port_unlock(port); - } - return 0; -} - - -/* - * port subscription (connection) - */ -#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(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) { - /* connection by third client - check export permission */ - if (check_port_perm(sport, SNDRV_SEQ_PORT_CAP_NO_EXPORT)) - return -EPERM; - if (check_port_perm(dport, SNDRV_SEQ_PORT_CAP_NO_EXPORT)) - return -EPERM; - } - - /* check read permission */ - /* if sender or receiver is the subscribing client itself, - * no permission check is necessary - */ - if (client->number != subs->sender.client) { - if (! check_port_perm(sport, PERM_RD)) - return -EPERM; - } - /* check write permission */ - if (client->number != subs->dest.client) { - if (! check_port_perm(dport, PERM_WR)) - return -EPERM; - } - return 0; -} - -/* - * send an subscription notify event to user client: - * client must be user client. - */ -int snd_seq_client_notify_subscription(int client, int port, - struct snd_seq_port_subscribe *info, - int evtype) -{ - struct snd_seq_event event; - - memset(&event, 0, sizeof(event)); - event.type = evtype; - event.data.connect.dest = info->dest; - event.data.connect.sender = info->sender; - - return snd_seq_system_notify(client, port, &event); /* non-atomic */ -} - - -/* - * add to port's subscription list IOCTL interface - */ -static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, - void __user *arg) -{ - int result = -EINVAL; - 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; - - if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL) - goto __end; - if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL) - goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL) - goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL) - goto __end; - - result = check_subscription_permission(client, sport, dport, &subs); - if (result < 0) - goto __end; - - /* connect them */ - result = snd_seq_port_connect(client, sender, sport, receiver, dport, &subs); - if (! result) /* broadcast announce */ - snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0, - &subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED); - __end: - if (sport) - snd_seq_port_unlock(sport); - if (dport) - snd_seq_port_unlock(dport); - if (sender) - snd_seq_client_unlock(sender); - if (receiver) - snd_seq_client_unlock(receiver); - return result; -} - - -/* - * remove from port's subscription list - */ -static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, - void __user *arg) -{ - int result = -ENXIO; - 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; - - if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL) - goto __end; - if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL) - goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL) - goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL) - goto __end; - - result = check_subscription_permission(client, sport, dport, &subs); - if (result < 0) - goto __end; - - result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, &subs); - if (! result) /* broadcast announce */ - snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0, - &subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED); - __end: - if (sport) - snd_seq_port_unlock(sport); - if (dport) - snd_seq_port_unlock(dport); - if (sender) - snd_seq_client_unlock(sender); - if (receiver) - snd_seq_client_unlock(receiver); - return result; -} - - -/* CREATE_QUEUE ioctl() */ -static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_queue_info info; - int result; - struct snd_seq_queue *q; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - result = snd_seq_queue_alloc(client->number, info.locked, info.flags); - if (result < 0) - return result; - - q = queueptr(result); - if (q == NULL) - return -EINVAL; - - info.queue = q->queue; - info.locked = q->locked; - info.owner = q->owner; - - /* set queue name */ - if (! info.name[0]) - snprintf(info.name, sizeof(info.name), "Queue-%d", q->queue); - strlcpy(q->name, info.name, sizeof(q->name)); - queuefree(q); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -/* DELETE_QUEUE ioctl() */ -static int snd_seq_ioctl_delete_queue(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_queue_info info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - return snd_seq_queue_delete(client->number, info.queue); -} - -/* GET_QUEUE_INFO ioctl() */ -static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_queue_info info; - struct snd_seq_queue *q; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - q = queueptr(info.queue); - if (q == NULL) - return -EINVAL; - - memset(&info, 0, sizeof(info)); - info.queue = q->queue; - info.owner = q->owner; - info.locked = q->locked; - strlcpy(info.name, q->name, sizeof(info.name)); - queuefree(q); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -/* SET_QUEUE_INFO ioctl() */ -static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_queue_info info; - struct snd_seq_queue *q; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - if (info.owner != client->number) - return -EINVAL; - - /* change owner/locked permission */ - if (snd_seq_queue_check_access(info.queue, client->number)) { - if (snd_seq_queue_set_owner(info.queue, client->number, info.locked) < 0) - return -EPERM; - if (info.locked) - snd_seq_queue_use(info.queue, client->number, 1); - } else { - return -EPERM; - } - - q = queueptr(info.queue); - if (! q) - return -EINVAL; - if (q->owner != client->number) { - queuefree(q); - return -EPERM; - } - strlcpy(q->name, info.name, sizeof(q->name)); - queuefree(q); - - return 0; -} - -/* GET_NAMED_QUEUE ioctl() */ -static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client, void __user *arg) -{ - struct snd_seq_queue_info info; - struct snd_seq_queue *q; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - q = snd_seq_queue_find_name(info.name); - if (q == NULL) - return -EINVAL; - info.queue = q->queue; - info.owner = q->owner; - info.locked = q->locked; - queuefree(q); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -/* GET_QUEUE_STATUS ioctl() */ -static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client, - void __user *arg) -{ - 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; - - queue = queueptr(status.queue); - if (queue == NULL) - return -EINVAL; - memset(&status, 0, sizeof(status)); - status.queue = queue->queue; - - tmr = queue->timer; - status.events = queue->tickq->cells + queue->timeq->cells; - - status.time = snd_seq_timer_get_cur_time(tmr); - status.tick = snd_seq_timer_get_cur_tick(tmr); - - status.running = tmr->running; - - status.flags = queue->flags; - queuefree(queue); - - if (copy_to_user(arg, &status, sizeof(status))) - return -EFAULT; - return 0; -} - - -/* GET_QUEUE_TEMPO ioctl() */ -static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, - void __user *arg) -{ - 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; - - queue = queueptr(tempo.queue); - if (queue == NULL) - return -EINVAL; - memset(&tempo, 0, sizeof(tempo)); - tempo.queue = queue->queue; - - tmr = queue->timer; - - tempo.tempo = tmr->tempo; - tempo.ppq = tmr->ppq; - tempo.skew_value = tmr->skew; - tempo.skew_base = tmr->skew_base; - queuefree(queue); - - if (copy_to_user(arg, &tempo, sizeof(tempo))) - return -EFAULT; - return 0; -} - - -/* SET_QUEUE_TEMPO ioctl() */ -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); -} - -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; - struct snd_seq_queue_tempo tempo; - - if (copy_from_user(&tempo, arg, sizeof(tempo))) - return -EFAULT; - - result = snd_seq_set_queue_tempo(client->number, &tempo); - return result < 0 ? result : 0; -} - - -/* GET_QUEUE_TIMER ioctl() */ -static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client, - void __user *arg) -{ - 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; - - queue = queueptr(timer.queue); - if (queue == NULL) - return -EINVAL; - - if (mutex_lock_interruptible(&queue->timer_mutex)) { - queuefree(queue); - return -ERESTARTSYS; - } - tmr = queue->timer; - memset(&timer, 0, sizeof(timer)); - timer.queue = queue->queue; - - timer.type = tmr->type; - if (tmr->type == SNDRV_SEQ_TIMER_ALSA) { - timer.u.alsa.id = tmr->alsa_id; - timer.u.alsa.resolution = tmr->preferred_resolution; - } - mutex_unlock(&queue->timer_mutex); - queuefree(queue); - - if (copy_to_user(arg, &timer, sizeof(timer))) - return -EFAULT; - return 0; -} - - -/* SET_QUEUE_TIMER ioctl() */ -static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client, - void __user *arg) -{ - int result = 0; - struct snd_seq_queue_timer timer; - - if (copy_from_user(&timer, arg, sizeof(timer))) - return -EFAULT; - - if (timer.type != SNDRV_SEQ_TIMER_ALSA) - return -EINVAL; - - if (snd_seq_queue_check_access(timer.queue, client->number)) { - struct snd_seq_queue *q; - struct snd_seq_timer *tmr; - - q = queueptr(timer.queue); - if (q == NULL) - return -ENXIO; - if (mutex_lock_interruptible(&q->timer_mutex)) { - queuefree(q); - return -ERESTARTSYS; - } - tmr = q->timer; - snd_seq_queue_timer_close(timer.queue); - tmr->type = timer.type; - if (tmr->type == SNDRV_SEQ_TIMER_ALSA) { - tmr->alsa_id = timer.u.alsa.id; - tmr->preferred_resolution = timer.u.alsa.resolution; - } - result = snd_seq_queue_timer_open(timer.queue); - mutex_unlock(&q->timer_mutex); - queuefree(q); - } else { - return -EPERM; - } - - return result; -} - - -/* GET_QUEUE_CLIENT ioctl() */ -static int snd_seq_ioctl_get_queue_client(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_queue_client info; - int used; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - used = snd_seq_queue_is_used(info.queue, client->number); - if (used < 0) - return -EINVAL; - info.used = used; - info.client = client->number; - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - - -/* SET_QUEUE_CLIENT ioctl() */ -static int snd_seq_ioctl_set_queue_client(struct snd_seq_client *client, - void __user *arg) -{ - int err; - struct snd_seq_queue_client info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - if (info.used >= 0) { - err = snd_seq_queue_use(info.queue, client->number, info.used); - if (err < 0) - return err; - } - - return snd_seq_ioctl_get_queue_client(client, arg); -} - - -/* GET_CLIENT_POOL ioctl() */ -static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client_pool info; - struct snd_seq_client *cptr; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - cptr = snd_seq_client_use_ptr(info.client); - if (cptr == NULL) - return -ENOENT; - memset(&info, 0, sizeof(info)); - info.output_pool = cptr->pool->size; - info.output_room = cptr->pool->room; - info.output_free = info.output_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; - if (cptr->data.user.fifo) - info.input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool); - } else { - info.input_pool = 0; - info.input_free = 0; - } - snd_seq_client_unlock(cptr); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -/* SET_CLIENT_POOL ioctl() */ -static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client_pool info; - int rc; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - if (client->number != info.client) - return -EINVAL; /* can't change other clients */ - - if (info.output_pool >= 1 && info.output_pool <= SNDRV_SEQ_MAX_EVENTS && - (! snd_seq_write_pool_allocated(client) || - info.output_pool != client->pool->size)) { - if (snd_seq_write_pool_allocated(client)) { - /* remove all existing cells */ - snd_seq_queue_client_leave_cells(client->number); - snd_seq_pool_done(client->pool); - } - client->pool->size = info.output_pool; - rc = snd_seq_pool_init(client->pool); - if (rc < 0) - return rc; - } - if (client->type == USER_CLIENT && client->data.user.fifo != NULL && - info.input_pool >= 1 && - info.input_pool <= SNDRV_SEQ_MAX_CLIENT_EVENTS && - info.input_pool != client->data.user.fifo_pool_size) { - /* change pool size */ - rc = snd_seq_fifo_resize(client->data.user.fifo, info.input_pool); - if (rc < 0) - return rc; - client->data.user.fifo_pool_size = info.input_pool; - } - if (info.output_room >= 1 && - info.output_room <= client->pool->size) { - client->pool->room = info.output_room; - } - - return snd_seq_ioctl_get_client_pool(client, arg); -} - - -/* REMOVE_EVENTS ioctl() */ -static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_remove_events info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - /* - * Input mostly not implemented XXX. - */ - if (info.remove_mode & SNDRV_SEQ_REMOVE_INPUT) { - /* - * No restrictions so for a user client we can clear - * the whole fifo - */ - if (client->type == USER_CLIENT) - snd_seq_fifo_clear(client->data.user.fifo); - } - - if (info.remove_mode & SNDRV_SEQ_REMOVE_OUTPUT) - snd_seq_queue_remove_cells(client->number, &info); - - return 0; -} - - -/* - * get subscription info - */ -static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, - void __user *arg) -{ - int result; - 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; - - result = -EINVAL; - if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL) - goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL) - goto __end; - p = snd_seq_port_get_subscription(&sport->c_src, &subs.dest); - if (p) { - result = 0; - subs = p->info; - } else - result = -ENOENT; - - __end: - if (sport) - snd_seq_port_unlock(sport); - if (sender) - snd_seq_client_unlock(sender); - if (result >= 0) { - if (copy_to_user(arg, &subs, sizeof(subs))) - return -EFAULT; - } - return result; -} - - -/* - * get subscription info - check only its presence - */ -static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, - void __user *arg) -{ - int result = -ENXIO; - 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; - - if (copy_from_user(&subs, arg, sizeof(subs))) - return -EFAULT; - - if ((cptr = snd_seq_client_use_ptr(subs.root.client)) == NULL) - goto __end; - if ((port = snd_seq_port_use_ptr(cptr, subs.root.port)) == NULL) - goto __end; - - switch (subs.type) { - case SNDRV_SEQ_QUERY_SUBS_READ: - group = &port->c_src; - break; - case SNDRV_SEQ_QUERY_SUBS_WRITE: - group = &port->c_dest; - break; - default: - goto __end; - } - - down_read(&group->list_mutex); - /* search for the subscriber */ - subs.num_subs = group->count; - i = 0; - result = -ENOENT; - list_for_each(p, &group->list_head) { - if (i++ == subs.index) { - /* found! */ - struct snd_seq_subscribers *s; - if (subs.type == SNDRV_SEQ_QUERY_SUBS_READ) { - s = list_entry(p, struct snd_seq_subscribers, src_list); - subs.addr = s->info.dest; - } else { - s = list_entry(p, struct snd_seq_subscribers, dest_list); - subs.addr = s->info.sender; - } - subs.flags = s->info.flags; - subs.queue = s->info.queue; - result = 0; - break; - } - } - up_read(&group->list_mutex); - - __end: - if (port) - snd_seq_port_unlock(port); - if (cptr) - snd_seq_client_unlock(cptr); - if (result >= 0) { - if (copy_to_user(arg, &subs, sizeof(subs))) - return -EFAULT; - } - return result; -} - - -/* - * query next client - */ -static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client, - void __user *arg) -{ - struct snd_seq_client *cptr = NULL; - struct snd_seq_client_info info; - - if (copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - /* search for next client */ - info.client++; - if (info.client < 0) - info.client = 0; - for (; info.client < SNDRV_SEQ_MAX_CLIENTS; info.client++) { - cptr = snd_seq_client_use_ptr(info.client); - if (cptr) - break; /* found */ - } - if (cptr == NULL) - return -ENOENT; - - get_client_info(cptr, &info); - snd_seq_client_unlock(cptr); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -/* - * query next port - */ -static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, - void __user *arg) -{ - 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; - cptr = snd_seq_client_use_ptr(info.addr.client); - if (cptr == NULL) - return -ENXIO; - - /* search for next port */ - info.addr.port++; - port = snd_seq_port_query_nearest(cptr, &info); - if (port == NULL) { - snd_seq_client_unlock(cptr); - return -ENOENT; - } - - /* get port info */ - info.addr = port->addr; - snd_seq_get_port_info(port, &info); - snd_seq_port_unlock(port); - snd_seq_client_unlock(cptr); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -/* -------------------------------------------------------- */ - -static struct seq_ioctl_table { - unsigned int cmd; - 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 }, - { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info }, - { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info }, - { SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port }, - { SNDRV_SEQ_IOCTL_DELETE_PORT, snd_seq_ioctl_delete_port }, - { SNDRV_SEQ_IOCTL_GET_PORT_INFO, snd_seq_ioctl_get_port_info }, - { SNDRV_SEQ_IOCTL_SET_PORT_INFO, snd_seq_ioctl_set_port_info }, - { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, snd_seq_ioctl_subscribe_port }, - { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, snd_seq_ioctl_unsubscribe_port }, - { SNDRV_SEQ_IOCTL_CREATE_QUEUE, snd_seq_ioctl_create_queue }, - { SNDRV_SEQ_IOCTL_DELETE_QUEUE, snd_seq_ioctl_delete_queue }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, snd_seq_ioctl_get_queue_info }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, snd_seq_ioctl_set_queue_info }, - { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, snd_seq_ioctl_get_named_queue }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, snd_seq_ioctl_get_queue_status }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, snd_seq_ioctl_get_queue_tempo }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, snd_seq_ioctl_set_queue_tempo }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, snd_seq_ioctl_get_queue_timer }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, snd_seq_ioctl_set_queue_timer }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, snd_seq_ioctl_get_queue_client }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, snd_seq_ioctl_set_queue_client }, - { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, snd_seq_ioctl_get_client_pool }, - { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, snd_seq_ioctl_set_client_pool }, - { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, snd_seq_ioctl_get_subscription }, - { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, snd_seq_ioctl_query_next_client }, - { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, snd_seq_ioctl_query_next_port }, - { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, snd_seq_ioctl_remove_events }, - { SNDRV_SEQ_IOCTL_QUERY_SUBS, snd_seq_ioctl_query_subs }, - { 0, NULL }, -}; - -static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, - void __user *arg) -{ - struct seq_ioctl_table *p; - - switch (cmd) { - case SNDRV_SEQ_IOCTL_PVERSION: - /* return sequencer version number */ - return put_user(SNDRV_SEQ_VERSION, (int __user *)arg) ? -EFAULT : 0; - case SNDRV_SEQ_IOCTL_CLIENT_ID: - /* return the id of this client */ - return put_user(client->number, (int __user *)arg) ? -EFAULT : 0; - } - - if (! arg) - return -EFAULT; - for (p = ioctl_tables; p->cmd; p++) { - if (p->cmd == cmd) - return p->func(client, arg); - } - snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", - cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); - return -ENOTTY; -} - - -static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct snd_seq_client *client = file->private_data; - - if (snd_BUG_ON(!client)) - return -ENXIO; - - return snd_seq_do_ioctl(client, cmd, (void __user *) arg); -} - -#ifdef CONFIG_COMPAT -#include "seq_compat.c" -#else -#define snd_seq_ioctl_compat NULL -#endif - -/* -------------------------------------------------------- */ - - -/* exported to kernel modules */ -int snd_seq_create_kernel_client(struct snd_card *card, int client_index, - const char *name_fmt, ...) -{ - struct snd_seq_client *client; - va_list args; - - if (snd_BUG_ON(in_interrupt())) - return -EBUSY; - - if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD) - return -EINVAL; - if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS) - return -EINVAL; - - if (mutex_lock_interruptible(®ister_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) { - mutex_unlock(®ister_mutex); - return -EBUSY; /* failure code */ - } - usage_alloc(&client_usage, 1); - - client->accept_input = 1; - client->accept_output = 1; - - va_start(args, name_fmt); - vsnprintf(client->name, sizeof(client->name), name_fmt, args); - va_end(args); - - client->type = KERNEL_CLIENT; - mutex_unlock(®ister_mutex); - - /* make others aware this new client */ - snd_seq_system_client_ev_client_start(client->number); - - /* return client number to caller */ - return client->number; -} - -EXPORT_SYMBOL(snd_seq_create_kernel_client); - -/* exported to kernel modules */ -int snd_seq_delete_kernel_client(int client) -{ - struct snd_seq_client *ptr; - - if (snd_BUG_ON(in_interrupt())) - return -EBUSY; - - ptr = clientptr(client); - if (ptr == NULL) - return -EINVAL; - - seq_free_client(ptr); - kfree(ptr); - 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, struct snd_seq_event *ev, - struct file *file, int blocking, - int atomic, int hop) -{ - struct snd_seq_client *cptr; - int result; - - if (snd_BUG_ON(!ev)) - return -EINVAL; - - if (ev->type == SNDRV_SEQ_EVENT_NONE) - return 0; /* ignore this */ - if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) - return -EINVAL; /* quoted events can't be enqueued */ - - /* fill in client number */ - ev->source.client = client; - - if (check_event_type_and_length(ev)) - return -EINVAL; - - cptr = snd_seq_client_use_ptr(client); - if (cptr == NULL) - return -EINVAL; - - if (! cptr->accept_output) - result = -EPERM; - else /* send it */ - result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); - - snd_seq_client_unlock(cptr); - return result; -} - -/* - * exported, called by kernel clients to enqueue events (w/o blocking) - * - * RETURN VALUE: zero if succeed, negative if error - */ -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, 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 - * clients, bypassing the queues. Event time-stamp will be updated. - * - * RETURN VALUE: negative = delivery failed, - * zero, or positive: the number of delivered events - */ -int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, - int atomic, int hop) -{ - struct snd_seq_client *cptr; - int result; - - if (snd_BUG_ON(!ev)) - return -EINVAL; - - /* fill in client number */ - ev->queue = SNDRV_SEQ_QUEUE_DIRECT; - ev->source.client = client; - - if (check_event_type_and_length(ev)) - return -EINVAL; - - cptr = snd_seq_client_use_ptr(client); - if (cptr == NULL) - return -EINVAL; - - if (!cptr->accept_output) - result = -EPERM; - else - result = snd_seq_deliver_event(cptr, ev, atomic, hop); - - snd_seq_client_unlock(cptr); - return result; -} - -EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); - -/* - * exported, called by kernel clients to perform same functions as with - * userland ioctl() - */ -int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) -{ - struct snd_seq_client *client; - mm_segment_t fs; - int result; - - client = clientptr(clientid); - if (client == NULL) - return -ENXIO; - fs = snd_enter_user(); - 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) -{ - struct snd_seq_client *client; - - client = clientptr(clientid); - if (client == NULL) - return -ENXIO; - - if (! snd_seq_write_pool_allocated(client)) - return 1; - if (snd_seq_pool_poll_wait(client->pool, file, wait)) - return 1; - return 0; -} - -EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); - -/*---------------------------------------------------------------------------*/ - -#ifdef CONFIG_PROC_FS -/* - * /proc interface - */ -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; - struct snd_seq_subscribers *s; - int count = 0; - - down_read(&group->list_mutex); - if (list_empty(&group->list_head)) { - up_read(&group->list_mutex); - return; - } - snd_iprintf(buffer, msg); - list_for_each(p, &group->list_head) { - if (is_src) - s = list_entry(p, struct snd_seq_subscribers, src_list); - else - s = list_entry(p, struct snd_seq_subscribers, dest_list); - if (count++) - snd_iprintf(buffer, ", "); - snd_iprintf(buffer, "%d:%d", - is_src ? s->info.dest.client : s->info.sender.client, - is_src ? s->info.dest.port : s->info.sender.port); - if (s->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) - snd_iprintf(buffer, "[%c:%d]", ((s->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 'r' : 't'), s->info.queue); - if (group->exclusive) - snd_iprintf(buffer, "[ex]"); - } - up_read(&group->list_mutex); - snd_iprintf(buffer, "\n"); -} - -#define FLAG_PERM_RD(perm) ((perm) & SNDRV_SEQ_PORT_CAP_READ ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_READ ? 'R' : 'r') : '-') -#define FLAG_PERM_WR(perm) ((perm) & SNDRV_SEQ_PORT_CAP_WRITE ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_WRITE ? 'W' : 'w') : '-') -#define FLAG_PERM_EX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_NO_EXPORT ? '-' : 'e') - -#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-') - -static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, - struct snd_seq_client *client) -{ - struct snd_seq_client_port *p; - - 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), - FLAG_PERM_WR(p->capability), - FLAG_PERM_EX(p->capability), - FLAG_PERM_DUPLEX(p->capability)); - snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: "); - snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: "); - } - mutex_unlock(&client->ports_mutex); -} - - -/* exported to seq_info.c */ -void snd_seq_info_clients_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - int c; - struct snd_seq_client *client; - - snd_iprintf(buffer, "Client info\n"); - snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur); - snd_iprintf(buffer, " peak clients : %d\n", client_usage.peak); - snd_iprintf(buffer, " max clients : %d\n", SNDRV_SEQ_MAX_CLIENTS); - snd_iprintf(buffer, "\n"); - - /* list the client table */ - for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) { - client = snd_seq_client_use_ptr(c); - if (client == NULL) - continue; - if (client->type == NO_CLIENT) { - snd_seq_client_unlock(client); - continue; - } - - snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n", - c, client->name, - client->type == USER_CLIENT ? "User" : "Kernel"); - snd_seq_info_dump_ports(buffer, client); - if (snd_seq_write_pool_allocated(client)) { - snd_iprintf(buffer, " Output pool :\n"); - snd_seq_info_pool(buffer, client->pool, " "); - } - if (client->type == USER_CLIENT && client->data.user.fifo && - client->data.user.fifo->pool) { - snd_iprintf(buffer, " Input pool :\n"); - snd_seq_info_pool(buffer, client->data.user.fifo->pool, " "); - } - snd_seq_client_unlock(client); - } -} -#endif /* CONFIG_PROC_FS */ - -/*---------------------------------------------------------------------------*/ - - -/* - * REGISTRATION PART - */ - -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, -}; - -/* - * register sequencer device - */ -int __init snd_sequencer_device_init(void) -{ - int err; - - if (mutex_lock_interruptible(®ister_mutex)) - return -ERESTARTSYS; - - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, - &snd_seq_f_ops, NULL, "seq")) < 0) { - mutex_unlock(®ister_mutex); - return err; - } - - mutex_unlock(®ister_mutex); - - return 0; -} - - - -/* - * unregister sequencer device - */ -void __exit snd_sequencer_device_done(void) -{ - snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0); -} diff --git a/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.h b/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.h deleted file mode 100644 index 20f0a725..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_clientmgr.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ALSA sequencer Client Manager - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_CLIENTMGR_H -#define __SND_SEQ_CLIENTMGR_H - -#include <sound/seq_kernel.h> -#include <linux/bitops.h> -#include "seq_fifo.h" -#include "seq_ports.h" -#include "seq_lock.h" - - -/* client manager */ - -struct snd_seq_user_client { - struct file *file; /* file struct of client */ - /* ... */ - - /* fifo */ - struct snd_seq_fifo *fifo; /* queue for incoming events */ - int fifo_pool_size; -}; - -struct snd_seq_kernel_client { - /* ... */ -}; - - -struct snd_seq_client { - snd_seq_client_type_t type; - unsigned int accept_input: 1, - accept_output: 1; - char name[64]; /* client name */ - int number; /* client number */ - unsigned int filter; /* filter flags */ - DECLARE_BITMAP(event_filter, 256); - snd_use_lock_t use_lock; - int event_lost; - /* ports */ - int num_ports; /* number of ports */ - struct list_head ports_list_head; - rwlock_t ports_lock; - struct mutex ports_mutex; - int convert32; /* convert 32->64bit */ - - /* output pool */ - struct snd_seq_pool *pool; /* memory pool for this client */ - - union { - struct snd_seq_user_client user; - struct snd_seq_kernel_client kernel; - } data; -}; - -/* usage statistics */ -struct snd_seq_usage { - int cur; - int peak; -}; - - -int client_init_data(void); -int snd_sequencer_device_init(void); -void snd_sequencer_device_done(void); - -/* get locked pointer to client */ -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) */ -int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop); - -/* exported to other modules */ -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, - struct snd_seq_port_subscribe *info, int evtype); - -extern int seq_client_load[15]; - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_compat.c b/ANDROID_3.4.5/sound/core/seq/seq_compat.c deleted file mode 100644 index 81f7c109..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_compat.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for sequencer API - * Copyright (c) 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; 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 - * - */ - -/* This file included from seq.c */ - -#include <linux/compat.h> -#include <linux/slab.h> - -struct snd_seq_port_info32 { - struct snd_seq_addr addr; /* client/port numbers */ - char name[64]; /* port name */ - - u32 capability; /* port capability bits */ - u32 type; /* port type bits */ - s32 midi_channels; /* channels per MIDI port */ - s32 midi_voices; /* voices per MIDI port */ - s32 synth_voices; /* voices per SYNTH port */ - - s32 read_use; /* R/O: subscribers for output (from this port) */ - s32 write_use; /* R/O: subscribers for input (to this port) */ - - u32 kernel; /* reserved for kernel use (must be NULL) */ - u32 flags; /* misc. conditioning */ - unsigned char time_queue; /* queue # for timestamping */ - char reserved[59]; /* for future use */ -}; - -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; - struct snd_seq_port_info *data; - mm_segment_t fs; - - data = memdup_user(data32, sizeof(*data32)); - if (IS_ERR(data)) - return PTR_ERR(data); - - if (get_user(data->flags, &data32->flags) || - get_user(data->time_queue, &data32->time_queue)) - goto error; - data->kernel = NULL; - - fs = snd_enter_user(); - err = snd_seq_do_ioctl(client, cmd, data); - snd_leave_user(fs); - if (err < 0) - goto error; - - if (copy_to_user(data32, data, sizeof(*data32)) || - put_user(data->flags, &data32->flags) || - put_user(data->time_queue, &data32->time_queue)) - err = -EFAULT; - - error: - kfree(data); - return err; -} - - - -/* - */ - -enum { - 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) -{ - struct snd_seq_client *client = file->private_data; - void __user *argp = compat_ptr(arg); - - if (snd_BUG_ON(!client)) - return -ENXIO; - - switch (cmd) { - case SNDRV_SEQ_IOCTL_PVERSION: - case SNDRV_SEQ_IOCTL_CLIENT_ID: - case SNDRV_SEQ_IOCTL_SYSTEM_INFO: - case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: - case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO: - case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT: - case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT: - case SNDRV_SEQ_IOCTL_CREATE_QUEUE: - case SNDRV_SEQ_IOCTL_DELETE_QUEUE: - case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO: - case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO: - case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE: - case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS: - case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO: - case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO: - case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER: - case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER: - case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT: - case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT: - case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL: - case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL: - case SNDRV_SEQ_IOCTL_REMOVE_EVENTS: - case SNDRV_SEQ_IOCTL_QUERY_SUBS: - case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION: - case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT: - case SNDRV_SEQ_IOCTL_RUNNING_MODE: - return snd_seq_do_ioctl(client, cmd, argp); - case SNDRV_SEQ_IOCTL_CREATE_PORT32: - return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp); - case SNDRV_SEQ_IOCTL_DELETE_PORT32: - return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp); - case SNDRV_SEQ_IOCTL_GET_PORT_INFO32: - return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp); - case SNDRV_SEQ_IOCTL_SET_PORT_INFO32: - return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp); - case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32: - return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp); - } - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/seq/seq_device.c b/ANDROID_3.4.5/sound/core/seq/seq_device.c deleted file mode 100644 index 5cf8d65e..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_device.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * ALSA sequencer device management - * Copyright (c) 1999 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; 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 - * - * - *---------------------------------------------------------------- - * - * This device handler separates the card driver module from sequencer - * stuff (sequencer core, synth drivers, etc), so that user can avoid - * to spend unnecessary resources e.g. if he needs only listening to - * MP3s. - * - * The card (or lowlevel) driver creates a sequencer device entry - * via snd_seq_device_new(). This is an entry pointer to communicate - * with the sequencer device "driver", which is involved with the - * actual part to communicate with the sequencer core. - * Each sequencer device entry has an id string and the corresponding - * driver with the same id is loaded when required. For example, - * lowlevel codes to access emu8000 chip on sbawe card are included in - * emu8000-synth module. To activate this module, the hardware - * resources like i/o port are passed via snd_seq_device argument. - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/info.h> -#include <sound/seq_device.h> -#include <sound/seq_kernel.h> -#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 state */ -#define DRIVER_EMPTY 0 -#define DRIVER_LOADED (1<<0) -#define DRIVER_REQUESTED (1<<1) -#define DRIVER_LOCKED (1<<2) - -struct ops_list { - char id[ID_LEN]; /* driver id */ - int driver; /* driver state */ - int used; /* reference counter */ - int argsize; /* argument size */ - - /* operators */ - struct snd_seq_dev_ops ops; - - /* registred 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 mutex reg_mutex; - - struct list_head list; /* next driver */ -}; - - -static LIST_HEAD(opslist); -static int num_ops; -static DEFINE_MUTEX(ops_mutex); -#ifdef CONFIG_PROC_FS -static struct snd_info_entry *info_entry; -#endif - -/* - * prototypes - */ -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 - */ - -#ifdef CONFIG_PROC_FS -static void snd_seq_device_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct ops_list *ops; - - 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" : ""), - ops->driver & DRIVER_REQUESTED ? ",requested" : "", - ops->driver & DRIVER_LOCKED ? ",locked" : "", - ops->num_devices); - } - mutex_unlock(&ops_mutex); -} -#endif - -/* - * load all registered drivers (called from seq_clientmgr.c) - */ - -#ifdef CONFIG_MODULES -/* avoid auto-loading during module_init() */ -static int snd_seq_in_init; -void snd_seq_autoload_lock(void) -{ - snd_seq_in_init++; -} - -void snd_seq_autoload_unlock(void) -{ - snd_seq_in_init--; -} -#endif - -void snd_seq_device_load_drivers(void) -{ -#ifdef CONFIG_MODULES - struct ops_list *ops; - - /* Calling request_module during module_init() - * may cause blocking. - */ - if (snd_seq_in_init) - return; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if (! (ops->driver & DRIVER_LOADED) && - ! (ops->driver & DRIVER_REQUESTED)) { - ops->used++; - mutex_unlock(&ops_mutex); - ops->driver |= DRIVER_REQUESTED; - request_module("snd-%s", ops->id); - mutex_lock(&ops_mutex); - ops->used--; - } - } - mutex_unlock(&ops_mutex); -#endif -} - -/* - * register a sequencer device - * card = card info (NULL allowed) - * device = device number (if any) - * id = id of driver - * result = return pointer (NULL allowed if unnecessary) - */ -int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, - struct snd_seq_device **result) -{ - struct snd_seq_device *dev; - struct ops_list *ops; - int err; - 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, - }; - - if (result) - *result = NULL; - - if (snd_BUG_ON(!id)) - return -EINVAL; - - ops = find_driver(id, 1); - if (ops == NULL) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); - if (dev == NULL) { - unlock_driver(ops); - return -ENOMEM; - } - - /* set up device info */ - dev->card = card; - dev->device = device; - strlcpy(dev->id, id, sizeof(dev->id)); - dev->argsize = argsize; - dev->status = SNDRV_SEQ_DEVICE_FREE; - - /* add this device to the list */ - mutex_lock(&ops->reg_mutex); - list_add_tail(&dev->list, &ops->dev_list); - ops->num_devices++; - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { - snd_seq_device_free(dev); - return err; - } - - if (result) - *result = dev; - - return 0; -} - -/* - * free the existing device - */ -static int snd_seq_device_free(struct snd_seq_device *dev) -{ - struct ops_list *ops; - - if (snd_BUG_ON(!dev)) - return -EINVAL; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENXIO; - - /* remove the device from the list */ - mutex_lock(&ops->reg_mutex); - list_del(&dev->list); - ops->num_devices--; - mutex_unlock(&ops->reg_mutex); - - free_device(dev, ops); - if (dev->private_free) - dev->private_free(dev); - kfree(dev); - - unlock_driver(ops); - - return 0; -} - -static int snd_seq_device_dev_free(struct snd_device *device) -{ - struct snd_seq_device *dev = device->device_data; - return snd_seq_device_free(dev); -} - -/* - * register the device - */ -static int snd_seq_device_dev_register(struct snd_device *device) -{ - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - /* initialize this device if the corresponding driver was - * already loaded - */ - if (ops->driver & DRIVER_LOADED) - init_device(dev, ops); - - unlock_driver(ops); - return 0; -} - -/* - * disconnect the device - */ -static int snd_seq_device_dev_disconnect(struct snd_device *device) -{ - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - free_device(dev, ops); - - unlock_driver(ops); - return 0; -} - -/* - * register device driver - * id = driver id - * entry = driver operators - duplicated to each instance - */ -int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, - int argsize) -{ - struct ops_list *ops; - struct snd_seq_device *dev; - - if (id == NULL || entry == NULL || - entry->init_device == NULL || entry->free_device == NULL) - return -EINVAL; - - snd_seq_autoload_lock(); - ops = find_driver(id, 1); - if (ops == NULL) { - snd_seq_autoload_unlock(); - return -ENOMEM; - } - if (ops->driver & DRIVER_LOADED) { - snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id); - unlock_driver(ops); - snd_seq_autoload_unlock(); - return -EBUSY; - } - - 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_entry(dev, &ops->dev_list, list) { - init_device(dev, ops); - } - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - snd_seq_autoload_unlock(); - - return 0; -} - - -/* - * create driver record - */ -static struct ops_list * create_driver(char *id) -{ - struct ops_list *ops; - - ops = kzalloc(sizeof(*ops), GFP_KERNEL); - if (ops == NULL) - return ops; - - /* set up driver entry */ - strlcpy(ops->id, id, sizeof(ops->id)); - 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 */ - mutex_lock(&ops_mutex); - list_add_tail(&ops->list, &opslist); - num_ops++; - mutex_unlock(&ops_mutex); - - return ops; -} - - -/* - * unregister the specified driver - */ -int snd_seq_device_unregister_driver(char *id) -{ - 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); - unlock_driver(ops); - return -EBUSY; - } - - /* close and release all devices associated with this driver */ - mutex_lock(&ops->reg_mutex); - ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ - 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); - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - /* remove empty driver entries */ - remove_drivers(); - - return 0; -} - - -/* - * remove empty driver entries - */ -static void remove_drivers(void) -{ - struct list_head *head; - - mutex_lock(&ops_mutex); - head = opslist.next; - while (head != &opslist) { - 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; - list_del(&ops->list); - kfree(ops); - num_ops--; - } else - head = head->next; - } - mutex_unlock(&ops_mutex); -} - -/* - * initialize the device - call init_device operator - */ -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); - 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); - } - - return 0; -} - -/* - * release the device - call free_device operator - */ -static int free_device(struct snd_seq_device *dev, struct ops_list *ops) -{ - int result; - - if (! (ops->driver & DRIVER_LOADED)) - return 0; /* driver is not loaded yet */ - 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); - return -EINVAL; - } - if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { - dev->status = SNDRV_SEQ_DEVICE_FREE; - dev->driver_data = NULL; - ops->num_init_devices--; - } else { - snd_printk(KERN_ERR "free_device failed: %s: %s\n", - dev->name, dev->id); - } - - return 0; -} - -/* - * find the matching driver with given id - */ -static struct ops_list * find_driver(char *id, int create_if_empty) -{ - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if (strcmp(ops->id, id) == 0) { - ops->used++; - mutex_unlock(&ops_mutex); - return ops; - } - } - mutex_unlock(&ops_mutex); - if (create_if_empty) - return create_driver(id); - return NULL; -} - -static void unlock_driver(struct ops_list *ops) -{ - mutex_lock(&ops_mutex); - ops->used--; - mutex_unlock(&ops_mutex); -} - - -/* - * module part - */ - -static int __init alsa_seq_device_init(void) -{ -#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 = 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(); -#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); -} - -module_init(alsa_seq_device_init) -module_exit(alsa_seq_device_exit) - -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); -EXPORT_SYMBOL(snd_seq_autoload_lock); -EXPORT_SYMBOL(snd_seq_autoload_unlock); diff --git a/ANDROID_3.4.5/sound/core/seq/seq_dummy.c b/ANDROID_3.4.5/sound/core/seq/seq_dummy.c deleted file mode 100644 index dbc55071..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_dummy.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * ALSA sequencer MIDI-through client - * Copyright (c) 1999-2000 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; 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 <sound/core.h> -#include "seq_clientmgr.h" -#include <sound/initval.h> -#include <sound/asoundef.h> - -/* - - Sequencer MIDI-through client - - This gives a simple midi-through client. All the normal input events - are redirected to output port immediately. - The routing can be done via aconnect program in alsa-utils. - - Each client has a static client number 62 (= SNDRV_SEQ_CLIENT_DUMMY). - If you want to auto-load this module, you may add the following alias - in your /etc/conf.modules file. - - alias snd-seq-client-62 snd-seq-dummy - - The module is loaded on demand for client 62, or /proc/asound/seq/ - is accessed. If you don't need this module to be loaded, alias - snd-seq-client-62 as "off". This will help modprobe. - - 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 a configuration file under /etc/modprobe.d/: - - option snd-seq-dummy ports=4 - - 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. - In duplex mode, each port has DUPLEX capability. - - */ - - -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); -MODULE_DESCRIPTION("ALSA sequencer MIDI-through client"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY)); - -static int ports = 1; -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"); - -struct snd_seq_dummy_port { - int client; - int port; - int duplex; - int connect; -}; - -static int my_client = -1; - -/* - * unuse callback - send ALL_SOUNDS_OFF and RESET_CONTROLLERS events - * to subscribers. - * Note: this callback is called only after all subscribers are removed. - */ -static int -dummy_unuse(void *private_data, struct snd_seq_port_subscribe *info) -{ - struct snd_seq_dummy_port *p; - int i; - struct snd_seq_event ev; - - p = private_data; - memset(&ev, 0, sizeof(ev)); - if (p->duplex) - ev.source.port = p->connect; - else - ev.source.port = p->port; - ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - ev.type = SNDRV_SEQ_EVENT_CONTROLLER; - for (i = 0; i < 16; i++) { - ev.data.control.channel = i; - ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF; - snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0); - ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS; - snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0); - } - return 0; -} - -/* - * event input callback - just redirect events to subscribers - */ -static int -dummy_input(struct snd_seq_event *ev, int direct, void *private_data, - int atomic, int hop) -{ - struct snd_seq_dummy_port *p; - struct snd_seq_event tmpev; - - p = private_data; - if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM || - ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) - return 0; /* ignore system messages */ - tmpev = *ev; - if (p->duplex) - tmpev.source.port = p->connect; - else - tmpev.source.port = p->port; - tmpev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - return snd_seq_kernel_client_dispatch(p->client, &tmpev, atomic, hop); -} - -/* - * free_private callback - */ -static void -dummy_free(void *private_data) -{ - kfree(private_data); -} - -/* - * create a port - */ -static struct snd_seq_dummy_port __init * -create_port(int idx, int type) -{ - 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; - - rec->client = my_client; - rec->duplex = duplex; - rec->connect = 0; - memset(&pinfo, 0, sizeof(pinfo)); - pinfo.addr.client = my_client; - if (duplex) - sprintf(pinfo.name, "Midi Through Port-%d:%c", idx, - (type ? 'B' : 'A')); - else - sprintf(pinfo.name, "Midi Through Port-%d", idx); - pinfo.capability = SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; - 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 - | SNDRV_SEQ_PORT_TYPE_SOFTWARE - | SNDRV_SEQ_PORT_TYPE_PORT; - memset(&pcb, 0, sizeof(pcb)); - pcb.owner = THIS_MODULE; - pcb.unuse = dummy_unuse; - pcb.event_input = dummy_input; - pcb.private_free = dummy_free; - pcb.private_data = rec; - pinfo.kernel = &pcb; - if (snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo) < 0) { - kfree(rec); - return NULL; - } - rec->port = pinfo.addr.port; - return rec; -} - -/* - * register client and create ports - */ -static int __init -register_client(void) -{ - struct snd_seq_dummy_port *rec1, *rec2; - int i; - - if (ports < 1) { - snd_printk(KERN_ERR "invalid number of ports %d\n", ports); - return -EINVAL; - } - - /* create client */ - my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY, - "Midi Through"); - if (my_client < 0) - return my_client; - - /* create ports */ - for (i = 0; i < ports; i++) { - rec1 = create_port(i, 0); - if (rec1 == NULL) { - snd_seq_delete_kernel_client(my_client); - return -ENOMEM; - } - if (duplex) { - rec2 = create_port(i, 1); - if (rec2 == NULL) { - snd_seq_delete_kernel_client(my_client); - return -ENOMEM; - } - rec1->connect = rec2->port; - rec2->connect = rec1->port; - } - } - - return 0; -} - -/* - * delete client if exists - */ -static void __exit -delete_client(void) -{ - if (my_client >= 0) - snd_seq_delete_kernel_client(my_client); -} - -/* - * Init part - */ - -static int __init alsa_seq_dummy_init(void) -{ - int err; - snd_seq_autoload_lock(); - err = register_client(); - snd_seq_autoload_unlock(); - return err; -} - -static void __exit alsa_seq_dummy_exit(void) -{ - delete_client(); -} - -module_init(alsa_seq_dummy_init) -module_exit(alsa_seq_dummy_exit) diff --git a/ANDROID_3.4.5/sound/core/seq/seq_fifo.c b/ANDROID_3.4.5/sound/core/seq/seq_fifo.c deleted file mode 100644 index 0d75afa7..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_fifo.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * ALSA sequencer FIFO - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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/core.h> -#include <linux/slab.h> -#include "seq_fifo.h" -#include "seq_lock.h" - - -/* FIFO */ - -/* create new fifo */ -struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) -{ - struct snd_seq_fifo *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (f == NULL) { - snd_printd("malloc failed for snd_seq_fifo_new() \n"); - return NULL; - } - - f->pool = snd_seq_pool_new(poolsize); - if (f->pool == NULL) { - kfree(f); - return NULL; - } - if (snd_seq_pool_init(f->pool) < 0) { - snd_seq_pool_delete(&f->pool); - kfree(f); - return NULL; - } - - spin_lock_init(&f->lock); - snd_use_lock_init(&f->use_lock); - init_waitqueue_head(&f->input_sleep); - atomic_set(&f->overflow, 0); - - f->head = NULL; - f->tail = NULL; - f->cells = 0; - - return f; -} - -void snd_seq_fifo_delete(struct snd_seq_fifo **fifo) -{ - struct snd_seq_fifo *f; - - if (snd_BUG_ON(!fifo)) - return; - f = *fifo; - if (snd_BUG_ON(!f)) - return; - *fifo = NULL; - - snd_seq_fifo_clear(f); - - /* wake up clients if any */ - if (waitqueue_active(&f->input_sleep)) - wake_up(&f->input_sleep); - - /* release resources...*/ - /*....................*/ - - if (f->pool) { - snd_seq_pool_done(f->pool); - snd_seq_pool_delete(&f->pool); - } - - kfree(f); -} - -static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f); - -/* clear queue */ -void snd_seq_fifo_clear(struct snd_seq_fifo *f) -{ - struct snd_seq_event_cell *cell; - unsigned long flags; - - /* clear overflow flag */ - atomic_set(&f->overflow, 0); - - snd_use_lock_sync(&f->use_lock); - spin_lock_irqsave(&f->lock, flags); - /* drain the fifo */ - while ((cell = fifo_cell_out(f)) != NULL) { - snd_seq_cell_free(cell); - } - spin_unlock_irqrestore(&f->lock, flags); -} - - -/* enqueue event to fifo */ -int snd_seq_fifo_event_in(struct snd_seq_fifo *f, - struct snd_seq_event *event) -{ - struct snd_seq_event_cell *cell; - unsigned long flags; - int err; - - 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) - atomic_inc(&f->overflow); - snd_use_lock_free(&f->use_lock); - return err; - } - - /* append new cells to fifo */ - spin_lock_irqsave(&f->lock, flags); - if (f->tail != NULL) - f->tail->next = cell; - f->tail = cell; - if (f->head == NULL) - f->head = cell; - f->cells++; - spin_unlock_irqrestore(&f->lock, flags); - - /* wakeup client */ - if (waitqueue_active(&f->input_sleep)) - wake_up(&f->input_sleep); - - snd_use_lock_free(&f->use_lock); - - return 0; /* success */ - -} - -/* dequeue cell from fifo */ -static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f) -{ - struct snd_seq_event_cell *cell; - - if ((cell = f->head) != NULL) { - f->head = cell->next; - - /* reset tail if this was the last element */ - if (f->tail == cell) - f->tail = NULL; - - cell->next = NULL; - f->cells--; - } - - return cell; -} - -/* dequeue cell from fifo and copy on user space */ -int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, - struct snd_seq_event_cell **cellp, int nonblock) -{ - struct snd_seq_event_cell *cell; - unsigned long flags; - wait_queue_t wait; - - if (snd_BUG_ON(!f)) - return -EINVAL; - - *cellp = NULL; - init_waitqueue_entry(&wait, current); - spin_lock_irqsave(&f->lock, flags); - while ((cell = fifo_cell_out(f)) == NULL) { - if (nonblock) { - /* non-blocking - return immediately */ - spin_unlock_irqrestore(&f->lock, flags); - return -EAGAIN; - } - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&f->input_sleep, &wait); - spin_unlock_irq(&f->lock); - schedule(); - spin_lock_irq(&f->lock); - remove_wait_queue(&f->input_sleep, &wait); - if (signal_pending(current)) { - spin_unlock_irqrestore(&f->lock, flags); - return -ERESTARTSYS; - } - } - spin_unlock_irqrestore(&f->lock, flags); - *cellp = cell; - - return 0; -} - - -void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, - struct snd_seq_event_cell *cell) -{ - unsigned long flags; - - if (cell) { - spin_lock_irqsave(&f->lock, flags); - cell->next = f->head; - f->head = cell; - f->cells++; - spin_unlock_irqrestore(&f->lock, flags); - } -} - - -/* polling; return non-zero if queue is available */ -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(struct snd_seq_fifo *f, int poolsize) -{ - unsigned long flags; - struct snd_seq_pool *newpool, *oldpool; - struct snd_seq_event_cell *cell, *next, *oldhead; - - if (snd_BUG_ON(!f || !f->pool)) - return -EINVAL; - - /* allocate new pool */ - newpool = snd_seq_pool_new(poolsize); - if (newpool == NULL) - return -ENOMEM; - if (snd_seq_pool_init(newpool) < 0) { - snd_seq_pool_delete(&newpool); - return -ENOMEM; - } - - spin_lock_irqsave(&f->lock, flags); - /* remember old pool */ - oldpool = f->pool; - oldhead = f->head; - /* exchange pools */ - f->pool = newpool; - f->head = NULL; - f->tail = NULL; - f->cells = 0; - /* NOTE: overflow flag is not cleared */ - spin_unlock_irqrestore(&f->lock, flags); - - /* release cells in old pool */ - for (cell = oldhead; cell; cell = next) { - next = cell->next; - snd_seq_cell_free(cell); - } - snd_seq_pool_delete(&oldpool); - - return 0; -} diff --git a/ANDROID_3.4.5/sound/core/seq/seq_fifo.h b/ANDROID_3.4.5/sound/core/seq/seq_fifo.h deleted file mode 100644 index 062c446e..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_fifo.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ALSA sequencer FIFO - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_FIFO_H -#define __SND_SEQ_FIFO_H - -#include "seq_memory.h" -#include "seq_lock.h" - - -/* === 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; - -}; - -/* create new fifo (constructor) */ -struct snd_seq_fifo *snd_seq_fifo_new(int poolsize); - -/* delete fifo (destructor) */ -void snd_seq_fifo_delete(struct snd_seq_fifo **f); - - -/* enqueue event to fifo */ -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(struct snd_seq_fifo *f, struct snd_seq_event_cell **cellp, int nonblock); - -/* free dequeued cell - fifo should be locked */ -void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, struct snd_seq_event_cell *cell); - -/* clean up queue */ -void snd_seq_fifo_clear(struct snd_seq_fifo *f); - -/* polling */ -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(struct snd_seq_fifo *f, int poolsize); - - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_info.c b/ANDROID_3.4.5/sound/core/seq/seq_info.c deleted file mode 100644 index acf77694..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_info.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ALSA sequencer /proc interface - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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/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 struct snd_info_entry * __init -create_info_entry(char *name, void (*read)(struct snd_info_entry *, - struct snd_info_buffer *)) -{ - 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 = read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return NULL; - } - return entry; -} - -/* create all our /proc entries */ -int __init snd_seq_info_init(void) -{ - queues_entry = create_info_entry("queues", - snd_seq_info_queues_read); - clients_entry = create_info_entry("clients", - snd_seq_info_clients_read); - timer_entry = create_info_entry("timer", snd_seq_info_timer_read); - return 0; -} - -int __exit snd_seq_info_done(void) -{ - snd_info_free_entry(queues_entry); - snd_info_free_entry(clients_entry); - snd_info_free_entry(timer_entry); - return 0; -} -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_info.h b/ANDROID_3.4.5/sound/core/seq/seq_info.h deleted file mode 100644 index 4892a7f3..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_info.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ALSA sequencer /proc info - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_INFO_H -#define __SND_SEQ_INFO_H - -#include <sound/info.h> -#include <sound/seq_kernel.h> - -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/ANDROID_3.4.5/sound/core/seq/seq_lock.c b/ANDROID_3.4.5/sound/core/seq/seq_lock.c deleted file mode 100644 index 2cfe50c7..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_lock.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Do sleep inside a spin-lock - * Copyright (c) 1999 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; 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/export.h> -#include <sound/core.h> -#include "seq_lock.h" - -#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG) - -/* wait until all locks are released */ -void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) -{ - 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); - 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); - break; - } - schedule_timeout_uninterruptible(1); - max_count--; - } -} - -EXPORT_SYMBOL(snd_use_lock_sync_helper); - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_lock.h b/ANDROID_3.4.5/sound/core/seq/seq_lock.h deleted file mode 100644 index 54044bc2..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_lock.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __SND_SEQ_LOCK_H -#define __SND_SEQ_LOCK_H - -#include <linux/sched.h> - -#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG) - -typedef atomic_t snd_use_lock_t; - -/* initialize lock */ -#define snd_use_lock_init(lockp) atomic_set(lockp, 0) - -/* increment lock */ -#define snd_use_lock_use(lockp) atomic_inc(lockp) - -/* release lock */ -#define snd_use_lock_free(lockp) atomic_dec(lockp) - -/* wait until all locks are released */ -void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line); -#define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__) - -#else /* SMP || CONFIG_SND_DEBUG */ - -typedef spinlock_t snd_use_lock_t; /* dummy */ -#define snd_use_lock_init(lockp) /**/ -#define snd_use_lock_use(lockp) /**/ -#define snd_use_lock_free(lockp) /**/ -#define snd_use_lock_sync(lockp) /**/ - -#endif /* SMP || CONFIG_SND_DEBUG */ - -#endif /* __SND_SEQ_LOCK_H */ diff --git a/ANDROID_3.4.5/sound/core/seq/seq_memory.c b/ANDROID_3.4.5/sound/core/seq/seq_memory.c deleted file mode 100644 index f478f770..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_memory.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * ALSA sequencer Memory Manager - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@perex.cz> - * 2000 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; 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/export.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <sound/core.h> - -#include <sound/seq_kernel.h> -#include "seq_memory.h" -#include "seq_queue.h" -#include "seq_info.h" -#include "seq_lock.h" - -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(struct snd_seq_pool *pool) -{ - return snd_seq_pool_available(pool) >= pool->room; -} - -/* - * Variable length event: - * The event like sysex uses variable length type. - * The external data may be stored in three different formats. - * 1) kernel space - * This is the normal case. - * ext.data.len = length - * ext.data.ptr = buffer pointer - * 2) user space - * When an event is generated via read(), the external data is - * kept in user space until expanded. - * ext.data.len = length | SNDRV_SEQ_EXT_USRPTR - * ext.data.ptr = userspace pointer - * 3) chained cells - * When the variable length event is enqueued (in prioq or fifo), - * the external data is decomposed to several cells. - * ext.data.len = length | SNDRV_SEQ_EXT_CHAINED - * ext.data.ptr = the additiona cell head - * -> cell.next -> cell.next -> .. - */ - -/* - * exported: - * call dump function to expand external data. - */ - -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; - - return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; -} - -int snd_seq_dump_var_event(const struct snd_seq_event *event, - snd_seq_dump_func_t func, void *private_data) -{ - int len, err; - 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 __force __user *)event->data.ext.ptr; - while (len > 0) { - int size = sizeof(buf); - if (len < size) - size = len; - if (copy_from_user(buf, curptr, size)) - return -EFAULT; - err = func(private_data, buf, size); - if (err < 0) - return err; - curptr += size; - len -= size; - } - return 0; - } if (! (event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) { - return func(private_data, event->data.ext.ptr, len); - } - - cell = (struct snd_seq_event_cell *)event->data.ext.ptr; - for (; len > 0 && cell; cell = cell->next) { - int size = sizeof(struct snd_seq_event); - if (len < size) - size = len; - err = func(private_data, &cell->event, size); - if (err < 0) - return err; - len -= size; - } - return 0; -} - -EXPORT_SYMBOL(snd_seq_dump_var_event); - - -/* - * exported: - * expand the variable length event to linear buffer space. - */ - -static int seq_copy_in_kernel(char **bufptr, const void *src, int size) -{ - memcpy(*bufptr, src, size); - *bufptr += size; - return 0; -} - -static int seq_copy_in_user(char __user **bufptr, const void *src, int size) -{ - if (copy_to_user(*bufptr, src, size)) - return -EFAULT; - *bufptr += size; - return 0; -} - -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; - - if ((len = get_var_len(event)) < 0) - return len; - newlen = len; - if (size_aligned > 0) - 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 __force __user *)event->data.ext.ptr, len)) - return -EFAULT; - return newlen; - } - err = snd_seq_dump_var_event(event, - in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel : - (snd_seq_dump_func_t)seq_copy_in_user, - &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(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(struct snd_seq_event_cell * cell) -{ - unsigned long flags; - struct snd_seq_pool *pool; - - if (snd_BUG_ON(!cell)) - return; - pool = cell->pool; - 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) { - struct snd_seq_event_cell *curp, *nextptr; - curp = cell->event.data.ext.ptr; - for (; curp; curp = nextptr) { - nextptr = curp->next; - curp->next = pool->free; - free_cell(pool, curp); - } - } - } - if (waitqueue_active(&pool->output_sleep)) { - /* has enough space now? */ - if (snd_seq_output_ok(pool)) - wake_up(&pool->output_sleep); - } - spin_unlock_irqrestore(&pool->lock, flags); -} - - -/* - * allocate an event cell. - */ -static int snd_seq_cell_alloc(struct snd_seq_pool *pool, - struct snd_seq_event_cell **cellp, - int nonblock, struct file *file) -{ - struct snd_seq_event_cell *cell; - unsigned long flags; - int err = -EAGAIN; - wait_queue_t wait; - - if (pool == NULL) - return -EINVAL; - - *cellp = NULL; - - 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"); - err = -EINVAL; - goto __error; - } - while (pool->free == NULL && ! nonblock && ! pool->closing) { - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&pool->output_sleep, &wait); - spin_unlock_irq(&pool->lock); - schedule(); - spin_lock_irq(&pool->lock); - remove_wait_queue(&pool->output_sleep, &wait); - /* interrupted? */ - if (signal_pending(current)) { - err = -ERESTARTSYS; - goto __error; - } - } - if (pool->closing) { /* closing.. */ - err = -ENOMEM; - goto __error; - } - - cell = pool->free; - if (cell) { - int used; - pool->free = cell->next; - atomic_inc(&pool->counter); - used = atomic_read(&pool->counter); - if (pool->max_used < used) - pool->max_used = used; - pool->event_alloc_success++; - /* clear cell pointers */ - cell->next = NULL; - err = 0; - } else - pool->event_alloc_failures++; - *cellp = cell; - -__error: - spin_unlock_irqrestore(&pool->lock, flags); - return err; -} - - -/* - * duplicate the event to a cell. - * if the event has external data, the data is decomposed to additional - * cells. - */ -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; - struct snd_seq_event_cell *cell; - - *cellp = NULL; - - ncells = 0; - extlen = 0; - if (snd_seq_ev_is_variable(event)) { - extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; - ncells = (extlen + sizeof(struct snd_seq_event) - 1) / sizeof(struct snd_seq_event); - } - if (ncells >= pool->total_elements) - return -ENOMEM; - - err = snd_seq_cell_alloc(pool, &cell, nonblock, file); - if (err < 0) - return err; - - /* copy the event */ - cell->event = *event; - - /* decompose */ - if (snd_seq_ev_is_variable(event)) { - 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; - 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 = (struct snd_seq_event_cell *)event->data.ext.ptr; - buf = (char *)event->data.ext.ptr; - tail = NULL; - - while (ncells-- > 0) { - int size = sizeof(struct snd_seq_event); - if (len < size) - size = len; - err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); - if (err < 0) - goto __error; - if (cell->event.data.ext.ptr == NULL) - cell->event.data.ext.ptr = tmp; - if (tail) - tail->next = tmp; - tail = tmp; - /* copy chunk */ - if (is_chained && src) { - tmp->event = src->event; - src = src->next; - } else if (is_usrptr) { - if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) { - err = -EFAULT; - goto __error; - } - } else { - memcpy(&tmp->event, buf, size); - } - buf += size; - len -= size; - } - } - - *cellp = cell; - return 0; - -__error: - snd_seq_cell_free(cell); - return err; -} - - -/* poll 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); -} - - -/* allocate room specified number of events */ -int snd_seq_pool_init(struct snd_seq_pool *pool) -{ - int cell; - struct snd_seq_event_cell *cellptr; - unsigned long flags; - - if (snd_BUG_ON(!pool)) - return -EINVAL; - if (pool->ptr) /* should be atomic? */ - return 0; - - pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); - if (pool->ptr == NULL) { - snd_printd("seq: malloc for sequencer events failed\n"); - return -ENOMEM; - } - - /* add new cells to the free cell list */ - spin_lock_irqsave(&pool->lock, flags); - pool->free = NULL; - - for (cell = 0; cell < pool->size; cell++) { - cellptr = pool->ptr + cell; - cellptr->pool = pool; - cellptr->next = pool->free; - pool->free = cellptr; - } - pool->room = (pool->size + 1) / 2; - - /* init statistics */ - pool->max_used = 0; - pool->total_elements = pool->size; - spin_unlock_irqrestore(&pool->lock, flags); - return 0; -} - -/* remove events */ -int snd_seq_pool_done(struct snd_seq_pool *pool) -{ - unsigned long flags; - struct snd_seq_event_cell *ptr; - int max_count = 5 * HZ; - - if (snd_BUG_ON(!pool)) - return -EINVAL; - - /* wait for closing all threads */ - spin_lock_irqsave(&pool->lock, flags); - pool->closing = 1; - spin_unlock_irqrestore(&pool->lock, flags); - - if (waitqueue_active(&pool->output_sleep)) - wake_up(&pool->output_sleep); - - 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)); - break; - } - schedule_timeout_uninterruptible(1); - max_count--; - } - - /* release all resources */ - spin_lock_irqsave(&pool->lock, flags); - ptr = pool->ptr; - pool->ptr = NULL; - pool->free = NULL; - pool->total_elements = 0; - spin_unlock_irqrestore(&pool->lock, flags); - - vfree(ptr); - - spin_lock_irqsave(&pool->lock, flags); - pool->closing = 0; - spin_unlock_irqrestore(&pool->lock, flags); - - return 0; -} - - -/* init new memory pool */ -struct snd_seq_pool *snd_seq_pool_new(int poolsize) -{ - 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"); - return NULL; - } - spin_lock_init(&pool->lock); - pool->ptr = NULL; - pool->free = NULL; - pool->total_elements = 0; - atomic_set(&pool->counter, 0); - pool->closing = 0; - init_waitqueue_head(&pool->output_sleep); - - pool->size = poolsize; - - /* init statistics */ - pool->max_used = 0; - return pool; -} - -/* remove memory pool */ -int snd_seq_pool_delete(struct snd_seq_pool **ppool) -{ - struct snd_seq_pool *pool = *ppool; - - *ppool = NULL; - if (pool == NULL) - return 0; - snd_seq_pool_done(pool); - kfree(pool); - return 0; -} - -/* initialize sequencer memory */ -int __init snd_sequencer_memory_init(void) -{ - return 0; -} - -/* release sequencer memory */ -void __exit snd_sequencer_memory_done(void) -{ -} - - -/* exported to seq_clientmgr.c */ -void snd_seq_info_pool(struct snd_info_buffer *buffer, - struct snd_seq_pool *pool, char *space) -{ - if (pool == NULL) - return; - snd_iprintf(buffer, "%sPool size : %d\n", space, pool->total_elements); - snd_iprintf(buffer, "%sCells in use : %d\n", space, atomic_read(&pool->counter)); - snd_iprintf(buffer, "%sPeak cells in use : %d\n", space, pool->max_used); - snd_iprintf(buffer, "%sAlloc success : %d\n", space, pool->event_alloc_success); - snd_iprintf(buffer, "%sAlloc failures : %d\n", space, pool->event_alloc_failures); -} diff --git a/ANDROID_3.4.5/sound/core/seq/seq_memory.h b/ANDROID_3.4.5/sound/core/seq/seq_memory.h deleted file mode 100644 index 4a2ec779..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_memory.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ALSA sequencer Memory Manager - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_MEMORYMGR_H -#define __SND_SEQ_MEMORYMGR_H - -#include <sound/seq_kernel.h> -#include <linux/poll.h> - -struct snd_info_buffer; - -/* container for sequencer event (internal use) */ -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 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 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 */ - - int size; /* pool size to be allocated */ - int room; /* watermark for sleep/wakeup */ - - int closing; - - /* statistics */ - int max_used; - int event_alloc_nopool; - int event_alloc_failures; - int event_alloc_success; - - /* Write locking */ - wait_queue_head_t output_sleep; - - /* Pool lock */ - spinlock_t lock; -}; - -void snd_seq_cell_free(struct snd_seq_event_cell *cell); - -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(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(struct snd_seq_pool *pool) -{ - return pool ? pool->total_elements : 0; -} - -/* init pool - allocate events */ -int snd_seq_pool_init(struct snd_seq_pool *pool); - -/* done pool - free events */ -int snd_seq_pool_done(struct snd_seq_pool *pool); - -/* create pool */ -struct snd_seq_pool *snd_seq_pool_new(int poolsize); - -/* remove pool */ -int snd_seq_pool_delete(struct snd_seq_pool **pool); - -/* init memory */ -int snd_sequencer_memory_init(void); - -/* release event memory */ -void snd_sequencer_memory_done(void); - -/* polling */ -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/ANDROID_3.4.5/sound/core/seq/seq_midi.c b/ANDROID_3.4.5/sound/core/seq/seq_midi.c deleted file mode 100644 index 64069dbf..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_midi.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Generic MIDI synth driver for ALSA sequencer - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@perex.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* -Possible options for midisynth module: - - automatic opening of midi ports on first received event or subscription - (close will be performed when client leaves) -*/ - - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <sound/core.h> -#include <sound/rawmidi.h> -#include <sound/seq_kernel.h> -#include <sound/seq_device.h> -#include <sound/seq_midi_event.h> -#include <sound/initval.h> - -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; -module_param(output_buffer_size, int, 0644); -MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes."); -static int input_buffer_size = PAGE_SIZE; -module_param(input_buffer_size, int, 0644); -MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes."); - -/* data for this midi synth driver */ -struct seq_midisynth { - struct snd_card *card; - int device; - int subdevice; - struct snd_rawmidi_file input_rfile; - struct snd_rawmidi_file output_rfile; - int seq_client; - int seq_port; - struct snd_midi_event *parser; -}; - -struct seq_midisynth_client { - int seq_client; - int num_ports; - int ports_per_device[SNDRV_RAWMIDI_DEVICES]; - struct seq_midisynth *ports[SNDRV_RAWMIDI_DEVICES]; -}; - -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(struct snd_rawmidi_substream *substream) -{ - 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 = runtime->private_data; - if (msynth == NULL) - return; - memset(&ev, 0, sizeof(ev)); - while (runtime->avail > 0) { - res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf)); - if (res <= 0) - continue; - if (msynth->parser == NULL) - continue; - pbuf = buf; - while (res > 0) { - count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev); - if (count < 0) - break; - pbuf += count; - res -= count; - if (ev.type != SNDRV_SEQ_EVENT_NONE) { - ev.source.port = msynth->seq_port; - ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0); - /* clear event and reset header */ - memset(&ev, 0, sizeof(ev)); - } - } - } -} - -static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count) -{ - struct snd_rawmidi_runtime *runtime; - int tmp; - - if (snd_BUG_ON(!substream || !buf)) - return -EINVAL; - runtime = substream->runtime; - if ((tmp = runtime->avail) < count) { - if (printk_ratelimit()) - snd_printk(KERN_ERR "MIDI output buffer overrun\n"); - return -ENOMEM; - } - if (snd_rawmidi_kernel_write(substream, buf, count) < count) - return -EINVAL; - return 0; -} - -static int event_process_midi(struct snd_seq_event *ev, int direct, - void *private_data, int atomic, int hop) -{ - struct seq_midisynth *msynth = private_data; - unsigned char msg[10]; /* buffer for constructing midi messages */ - struct snd_rawmidi_substream *substream; - int len; - - 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); - return 0; - } - snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); - snd_midi_event_reset_decode(msynth->parser); - } else { - if (msynth->parser == NULL) - return -EIO; - len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev); - if (len < 0) - return 0; - if (dump_midi(substream, msg, len) < 0) - snd_midi_event_reset_decode(msynth->parser); - } - return 0; -} - - -static int snd_seq_midisynth_new(struct seq_midisynth *msynth, - struct snd_card *card, - int device, - int subdevice) -{ - if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &msynth->parser) < 0) - return -ENOMEM; - msynth->card = card; - msynth->device = device; - msynth->subdevice = subdevice; - return 0; -} - -/* open associated midi device for input */ -static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe *info) -{ - int err; - 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, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_INPUT, - &msynth->input_rfile)) < 0) { - snd_printd("midi input open failed!!!\n"); - return err; - } - runtime = msynth->input_rfile.input->runtime; - memset(¶ms, 0, sizeof(params)); - params.avail_min = 1; - params.buffer_size = input_buffer_size; - if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, ¶ms)) < 0) { - snd_rawmidi_kernel_release(&msynth->input_rfile); - return err; - } - snd_midi_event_reset_encode(msynth->parser); - runtime->event = snd_midi_input_event; - runtime->private_data = msynth; - snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0); - return 0; -} - -/* close associated midi device for input */ -static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscribe *info) -{ - int err; - struct seq_midisynth *msynth = private_data; - - 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, struct snd_seq_port_subscribe *info) -{ - int err; - struct seq_midisynth *msynth = private_data; - struct snd_rawmidi_params params; - - /* open midi port */ - if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_OUTPUT, - &msynth->output_rfile)) < 0) { - snd_printd("midi output open failed!!!\n"); - return err; - } - memset(¶ms, 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, ¶ms)) < 0) { - snd_rawmidi_kernel_release(&msynth->output_rfile); - return err; - } - snd_midi_event_reset_decode(msynth->parser); - return 0; -} - -/* close associated midi device for output */ -static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info) -{ - struct seq_midisynth *msynth = private_data; - - 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(struct seq_midisynth *msynth) -{ - if (msynth == NULL) - return; - - if (msynth->seq_client > 0) { - /* delete port */ - snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port); - } - - if (msynth->parser) - snd_midi_event_free(msynth->parser); -} - -/* register new midi synth port */ -static int -snd_seq_midisynth_register_port(struct snd_seq_device *dev) -{ - 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; - struct snd_seq_port_callback pcallbacks; - struct snd_card *card = dev->card; - int device = dev->device; - unsigned int input_count = 0, output_count = 0; - - if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES)) - return -EINVAL; - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) - return -ENOMEM; - info->device = device; - info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - info->subdevice = 0; - if (snd_rawmidi_info_select(card, info) >= 0) - output_count = info->subdevices_count; - info->stream = SNDRV_RAWMIDI_STREAM_INPUT; - if (snd_rawmidi_info_select(card, info) >= 0) { - input_count = info->subdevices_count; - } - ports = output_count; - if (ports < input_count) - ports = input_count; - if (ports == 0) { - kfree(info); - return -ENODEV; - } - if (ports > (256 / SNDRV_RAWMIDI_DEVICES)) - ports = 256 / SNDRV_RAWMIDI_DEVICES; - - mutex_lock(®ister_mutex); - client = synths[card->number]; - if (client == NULL) { - newclient = 1; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) { - mutex_unlock(®ister_mutex); - kfree(info); - return -ENOMEM; - } - 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); - mutex_unlock(®ister_mutex); - kfree(info); - return -ENOMEM; - } - } - - msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL); - port = kmalloc(sizeof(*port), GFP_KERNEL); - if (msynth == NULL || port == NULL) - goto __nomem; - - for (p = 0; p < ports; p++) { - ms = &msynth[p]; - - if (snd_seq_midisynth_new(ms, card, device, p) < 0) - goto __nomem; - - /* declare port */ - memset(port, 0, sizeof(*port)); - port->addr.client = client->seq_client; - port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p; - port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; - memset(info, 0, sizeof(*info)); - info->device = device; - if (p < output_count) - info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - else - info->stream = SNDRV_RAWMIDI_STREAM_INPUT; - info->subdevice = p; - if (snd_rawmidi_info_select(card, info) >= 0) - strcpy(port->name, info->subname); - if (! port->name[0]) { - if (info->name[0]) { - if (ports > 1) - snprintf(port->name, sizeof(port->name), "%s-%d", 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); - else - sprintf(port->name, "MIDI %d-%d", card->number, device); - } - } - if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count) - port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; - if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count) - port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; - 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 - | SNDRV_SEQ_PORT_TYPE_HARDWARE - | SNDRV_SEQ_PORT_TYPE_PORT; - port->midi_channels = 16; - memset(&pcallbacks, 0, sizeof(pcallbacks)); - pcallbacks.owner = THIS_MODULE; - pcallbacks.private_data = ms; - pcallbacks.subscribe = midisynth_subscribe; - pcallbacks.unsubscribe = midisynth_unsubscribe; - pcallbacks.use = midisynth_use; - 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; - ms->seq_port = port->addr.port; - } - client->ports_per_device[device] = ports; - client->ports[device] = msynth; - client->num_ports++; - if (newclient) - synths[card->number] = client; - mutex_unlock(®ister_mutex); - kfree(info); - kfree(port); - return 0; /* success */ - - __nomem: - if (msynth != NULL) { - for (p = 0; p < ports; p++) - snd_seq_midisynth_delete(&msynth[p]); - kfree(msynth); - } - if (newclient) { - snd_seq_delete_kernel_client(client->seq_client); - kfree(client); - } - kfree(info); - kfree(port); - mutex_unlock(®ister_mutex); - return -ENOMEM; -} - -/* release midi synth port */ -static int -snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) -{ - struct seq_midisynth_client *client; - struct seq_midisynth *msynth; - struct snd_card *card = dev->card; - int device = dev->device, p, ports; - - mutex_lock(®ister_mutex); - client = synths[card->number]; - if (client == NULL || client->ports[device] == NULL) { - mutex_unlock(®ister_mutex); - return -ENODEV; - } - ports = client->ports_per_device[device]; - client->ports_per_device[device] = 0; - msynth = client->ports[device]; - client->ports[device] = NULL; - for (p = 0; p < ports; p++) - snd_seq_midisynth_delete(&msynth[p]); - kfree(msynth); - client->num_ports--; - if (client->num_ports <= 0) { - snd_seq_delete_kernel_client(client->seq_client); - synths[card->number] = NULL; - kfree(client); - } - mutex_unlock(®ister_mutex); - return 0; -} - - -static int __init alsa_seq_midi_init(void) -{ - static struct snd_seq_dev_ops ops = { - snd_seq_midisynth_register_port, - snd_seq_midisynth_unregister_port, - }; - memset(&synths, 0, sizeof(synths)); - snd_seq_autoload_lock(); - snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0); - snd_seq_autoload_unlock(); - return 0; -} - -static void __exit alsa_seq_midi_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH); -} - -module_init(alsa_seq_midi_init) -module_exit(alsa_seq_midi_exit) diff --git a/ANDROID_3.4.5/sound/core/seq/seq_midi_emul.c b/ANDROID_3.4.5/sound/core/seq/seq_midi_emul.c deleted file mode 100644 index 6f64471d..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_midi_emul.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * GM/GS/XG midi module. - * - * Copyright (C) 1999 Steve Ratcliffe - * - * Based on awe_wave.c by 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 - * - */ -/* - * This module is used to keep track of the current midi state. - * It can be used for drivers that are required to emulate midi when - * the hardware doesn't. - * - * It was written for a AWE64 driver, but there should be no AWE specific - * code in here. If there is it should be reported as a bug. - */ - -#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> -#include <sound/initval.h> -#include <sound/asoundef.h> - -MODULE_AUTHOR("Takashi Iwai / Steve Ratcliffe"); -MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI emulation."); -MODULE_LICENSE("GPL"); - -/* Prototypes for static functions */ -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(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); - - -/* - * Process an event in a driver independent way. This means dealing - * with RPN, NRPN, SysEx etc that are defined for common midi applications - * 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 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 - * interpreted. - * XG - You can use all xg_ prefixed elements of chan. Codes for XG will - * be interpreted. - */ -void -snd_midi_process_event(struct snd_midi_op *ops, - struct snd_seq_event *ev, - struct snd_midi_channel_set *chanset) -{ - 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"); - return; - } - if (chanset->channels == NULL) - return; - - 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); - return; - } - } - - chan = chanset->channels + dest_channel; - drv = chanset->private_data; - - /* EVENT_NOTE should be processed before queued */ - if (ev->type == SNDRV_SEQ_EVENT_NOTE) - return; - - /* Make sure that we don't have a note on that should really be - * a note off */ - if (ev->type == SNDRV_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) - ev->type = SNDRV_SEQ_EVENT_NOTEOFF; - - /* Make sure the note is within array range */ - if (ev->type == SNDRV_SEQ_EVENT_NOTEON || - ev->type == SNDRV_SEQ_EVENT_NOTEOFF || - ev->type == SNDRV_SEQ_EVENT_KEYPRESS) { - if (ev->data.note.note >= 128) - return; - } - - switch (ev->type) { - case SNDRV_SEQ_EVENT_NOTEON: - if (chan->note[ev->data.note.note] & SNDRV_MIDI_NOTE_ON) { - if (ops->note_off) - ops->note_off(drv, ev->data.note.note, 0, chan); - } - chan->note[ev->data.note.note] = SNDRV_MIDI_NOTE_ON; - if (ops->note_on) - ops->note_on(drv, ev->data.note.note, ev->data.note.velocity, chan); - break; - case SNDRV_SEQ_EVENT_NOTEOFF: - if (! (chan->note[ev->data.note.note] & SNDRV_MIDI_NOTE_ON)) - break; - if (ops->note_off) - note_off(ops, drv, chan, ev->data.note.note, ev->data.note.velocity); - break; - case SNDRV_SEQ_EVENT_KEYPRESS: - if (ops->key_press) - ops->key_press(drv, ev->data.note.note, ev->data.note.velocity, chan); - break; - case SNDRV_SEQ_EVENT_CONTROLLER: - do_control(ops, drv, chanset, chan, - ev->data.control.param, ev->data.control.value); - break; - case SNDRV_SEQ_EVENT_PGMCHANGE: - chan->midi_program = ev->data.control.value; - break; - case SNDRV_SEQ_EVENT_PITCHBEND: - chan->midi_pitchbend = ev->data.control.value; - if (ops->control) - ops->control(drv, MIDI_CTL_PITCHBEND, chan); - break; - case SNDRV_SEQ_EVENT_CHANPRESS: - chan->midi_pressure = ev->data.control.value; - if (ops->control) - ops->control(drv, MIDI_CTL_CHAN_PRESSURE, chan); - break; - case SNDRV_SEQ_EVENT_CONTROL14: - /* Best guess is that this is any of the 14 bit controller values */ - if (ev->data.control.param < 32) { - /* set low part first */ - chan->control[ev->data.control.param + 32] = - ev->data.control.value & 0x7f; - do_control(ops, drv, chanset, chan, - ev->data.control.param, - ((ev->data.control.value>>7) & 0x7f)); - } else - do_control(ops, drv, chanset, chan, - ev->data.control.param, - ev->data.control.value); - break; - case SNDRV_SEQ_EVENT_NONREGPARAM: - /* 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; - chan->control[MIDI_CTL_LSB_DATA_ENTRY] - = ev->data.control.value & 0x7f; - chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB] - = (ev->data.control.param >> 7) & 0x7f; - chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB] - = ev->data.control.param & 0x7f; - nrpn(ops, drv, chan, chanset); - break; - case SNDRV_SEQ_EVENT_REGPARAM: - /* 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; - chan->control[MIDI_CTL_LSB_DATA_ENTRY] - = ev->data.control.value & 0x7f; - chan->control[MIDI_CTL_REGIST_PARM_NUM_MSB] - = (ev->data.control.param >> 7) & 0x7f; - chan->control[MIDI_CTL_REGIST_PARM_NUM_LSB] - = ev->data.control.param & 0x7f; - rpn(ops, drv, chan, chanset); - break; - case SNDRV_SEQ_EVENT_SYSEX: - if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) { - unsigned char sysexbuf[64]; - int len; - len = snd_seq_expand_var_event(ev, sizeof(sysexbuf), sysexbuf, 1, 0); - if (len > 0) - sysex(ops, drv, sysexbuf, len, chanset); - } - break; - case SNDRV_SEQ_EVENT_SONGPOS: - case SNDRV_SEQ_EVENT_SONGSEL: - case SNDRV_SEQ_EVENT_CLOCK: - case SNDRV_SEQ_EVENT_START: - case SNDRV_SEQ_EVENT_CONTINUE: - case SNDRV_SEQ_EVENT_STOP: - case SNDRV_SEQ_EVENT_QFRAME: - case SNDRV_SEQ_EVENT_TEMPO: - case SNDRV_SEQ_EVENT_TIMESIGN: - case SNDRV_SEQ_EVENT_KEYSIGN: - goto not_yet; - case SNDRV_SEQ_EVENT_SENSING: - break; - case SNDRV_SEQ_EVENT_CLIENT_START: - case SNDRV_SEQ_EVENT_CLIENT_EXIT: - case SNDRV_SEQ_EVENT_CLIENT_CHANGE: - case SNDRV_SEQ_EVENT_PORT_START: - case SNDRV_SEQ_EVENT_PORT_EXIT: - case SNDRV_SEQ_EVENT_PORT_CHANGE: - case SNDRV_SEQ_EVENT_ECHO: - not_yet: - default: - /*snd_printd("Unimplemented event %d\n", ev->type);*/ - break; - } -} - - -/* - * release note - */ -static void -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 */ - chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED; - } else if (chan->note[note] & SNDRV_MIDI_NOTE_SOSTENUTO) { - /* Mark this note as release; it will be turned off when sostenuto - * is turned off */ - chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED; - } else { - chan->note[note] = 0; - if (ops->note_off) - ops->note_off(drv, note, vel, chan); - } -} - -/* - * Do all driver independent operations for this controller and pass - * events that need to take place immediately to the driver. - */ -static void -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; - - /* Switches */ - if ((control >=64 && control <=69) || (control >= 80 && control <= 83)) { - /* These are all switches; either off or on so set to 0 or 127 */ - value = (value >= 64)? 127: 0; - } - chan->control[control] = value; - - switch (control) { - case MIDI_CTL_SUSTAIN: - if (value == 0) { - /* Sustain has been released, turn off held notes */ - for (i = 0; i < 128; i++) { - if (chan->note[i] & SNDRV_MIDI_NOTE_RELEASED) { - chan->note[i] = SNDRV_MIDI_NOTE_OFF; - if (ops->note_off) - ops->note_off(drv, i, 0, chan); - } - } - } - break; - case MIDI_CTL_PORTAMENTO: - break; - case MIDI_CTL_SOSTENUTO: - if (value) { - /* Mark each note that is currently held down */ - for (i = 0; i < 128; i++) { - if (chan->note[i] & SNDRV_MIDI_NOTE_ON) - chan->note[i] |= SNDRV_MIDI_NOTE_SOSTENUTO; - } - } else { - /* release all notes that were held */ - for (i = 0; i < 128; i++) { - if (chan->note[i] & SNDRV_MIDI_NOTE_SOSTENUTO) { - chan->note[i] &= ~SNDRV_MIDI_NOTE_SOSTENUTO; - if (chan->note[i] & SNDRV_MIDI_NOTE_RELEASED) { - chan->note[i] = SNDRV_MIDI_NOTE_OFF; - if (ops->note_off) - ops->note_off(drv, i, 0, chan); - } - } - } - } - break; - case MIDI_CTL_MSB_DATA_ENTRY: - chan->control[MIDI_CTL_LSB_DATA_ENTRY] = 0; - /* go through here */ - case MIDI_CTL_LSB_DATA_ENTRY: - if (chan->param_type == SNDRV_MIDI_PARAM_TYPE_REGISTERED) - rpn(ops, drv, chan, chset); - else - nrpn(ops, drv, chan, chset); - break; - case MIDI_CTL_REGIST_PARM_NUM_LSB: - case MIDI_CTL_REGIST_PARM_NUM_MSB: - chan->param_type = SNDRV_MIDI_PARAM_TYPE_REGISTERED; - break; - case MIDI_CTL_NONREG_PARM_NUM_LSB: - case MIDI_CTL_NONREG_PARM_NUM_MSB: - chan->param_type = SNDRV_MIDI_PARAM_TYPE_NONREGISTERED; - break; - - case MIDI_CTL_ALL_SOUNDS_OFF: - all_sounds_off(ops, drv, chan); - break; - - case MIDI_CTL_ALL_NOTES_OFF: - all_notes_off(ops, drv, chan); - break; - - case MIDI_CTL_MSB_BANK: - if (chset->midi_mode == SNDRV_MIDI_MODE_XG) { - if (value == 127) - chan->drum_channel = 1; - else - chan->drum_channel = 0; - } - break; - case MIDI_CTL_LSB_BANK: - break; - - case MIDI_CTL_RESET_CONTROLLERS: - snd_midi_reset_controllers(chan); - break; - - case MIDI_CTL_SOFT_PEDAL: - case MIDI_CTL_LEGATO_FOOTSWITCH: - case MIDI_CTL_HOLD2: - case MIDI_CTL_SC1_SOUND_VARIATION: - case MIDI_CTL_SC2_TIMBRE: - case MIDI_CTL_SC3_RELEASE_TIME: - case MIDI_CTL_SC4_ATTACK_TIME: - case MIDI_CTL_SC5_BRIGHTNESS: - case MIDI_CTL_E1_REVERB_DEPTH: - case MIDI_CTL_E2_TREMOLO_DEPTH: - case MIDI_CTL_E3_CHORUS_DEPTH: - case MIDI_CTL_E4_DETUNE_DEPTH: - case MIDI_CTL_E5_PHASER_DEPTH: - goto notyet; - notyet: - default: - if (ops->control) - ops->control(drv, control, chan); - break; - } -} - - -/* - * initialize the MIDI status - */ -void -snd_midi_channel_set_clear(struct snd_midi_channel_set *chset) -{ - int i; - - chset->midi_mode = SNDRV_MIDI_MODE_GM; - chset->gs_master_volume = 127; - - for (i = 0; i < chset->max_channels; i++) { - struct snd_midi_channel *chan = chset->channels + i; - memset(chan->note, 0, sizeof(chan->note)); - - chan->midi_aftertouch = 0; - chan->midi_pressure = 0; - chan->midi_program = 0; - chan->midi_pitchbend = 0; - snd_midi_reset_controllers(chan); - chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */ - chan->gm_rpn_fine_tuning = 0; - chan->gm_rpn_coarse_tuning = 0; - - if (i == 9) - chan->drum_channel = 1; - else - chan->drum_channel = 0; - } -} - -/* - * Process a rpn message. - */ -static void -rpn(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan, - struct snd_midi_channel_set *chset) -{ - int type; - int val; - - if (chset->midi_mode != SNDRV_MIDI_MODE_NONE) { - type = (chan->control[MIDI_CTL_REGIST_PARM_NUM_MSB] << 8) | - chan->control[MIDI_CTL_REGIST_PARM_NUM_LSB]; - val = (chan->control[MIDI_CTL_MSB_DATA_ENTRY] << 7) | - chan->control[MIDI_CTL_LSB_DATA_ENTRY]; - - switch (type) { - case 0x0000: /* Pitch bend sensitivity */ - /* MSB only / 1 semitone per 128 */ - chan->gm_rpn_pitch_bend_range = val; - break; - - case 0x0001: /* fine tuning: */ - /* MSB/LSB, 8192=center, 100/8192 cent step */ - chan->gm_rpn_fine_tuning = val - 8192; - break; - - case 0x0002: /* coarse tuning */ - /* MSB only / 8192=center, 1 semitone per 128 */ - chan->gm_rpn_coarse_tuning = val - 8192; - break; - - case 0x7F7F: /* "lock-in" RPN */ - /* ignored */ - break; - } - } - /* should call nrpn or rpn callback here.. */ -} - -/* - * Process an nrpn message. - */ -static void -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) - ops->nrpn(drv, chan, chset); -} - - -/* - * convert channel parameter in GS sysex - */ -static int -get_channel(unsigned char cmd) -{ - int p = cmd & 0x0f; - if (p == 0) - p = 9; - else if (p < 10) - p--; - return p; -} - - -/* - * Process a sysex message. - */ -static void -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[] = { - 0x7e,0x7f,0x09,0x01, - }; - /* XG on */ - static unsigned char xg_on_macro[] = { - 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, - }; - /* GS prefix - * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off - * reverb mode: XX=0x01, YY=0x30, ZZ=0-7 - * chorus mode: XX=0x01, YY=0x38, ZZ=0-7 - * master vol: XX=0x00, YY=0x04, ZZ=0-127 - */ - static unsigned char gs_pfx_macro[] = { - 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ - }; - - int parsed = SNDRV_MIDI_SYSEX_NOT_PARSED; - - if (len <= 0 || buf[0] != 0xf0) - return; - /* skip first byte */ - buf++; - len--; - - /* GM on */ - if (len >= (int)sizeof(gm_on_macro) && - memcmp(buf, gm_on_macro, sizeof(gm_on_macro)) == 0) { - if (chset->midi_mode != SNDRV_MIDI_MODE_GS && - chset->midi_mode != SNDRV_MIDI_MODE_XG) { - chset->midi_mode = SNDRV_MIDI_MODE_GM; - reset_all_channels(chset); - parsed = SNDRV_MIDI_SYSEX_GM_ON; - } - } - - /* GS macros */ - else if (len >= 8 && - memcmp(buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) { - if (chset->midi_mode != SNDRV_MIDI_MODE_GS && - chset->midi_mode != SNDRV_MIDI_MODE_XG) - chset->midi_mode = SNDRV_MIDI_MODE_GS; - - if (buf[5] == 0x00 && buf[6] == 0x7f && buf[7] == 0x00) { - /* GS reset */ - parsed = SNDRV_MIDI_SYSEX_GS_RESET; - reset_all_channels(chset); - } - - else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x15) { - /* drum pattern */ - int p = get_channel(buf[5]); - if (p < chset->max_channels) { - parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL; - if (buf[7]) - chset->channels[p].drum_channel = 1; - else - chset->channels[p].drum_channel = 0; - } - - } else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x21) { - /* program */ - int p = get_channel(buf[5]); - if (p < chset->max_channels && - ! chset->channels[p].drum_channel) { - parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL; - chset->channels[p].midi_program = buf[7]; - } - - } else if (buf[5] == 0x01 && buf[6] == 0x30) { - /* reverb mode */ - parsed = SNDRV_MIDI_SYSEX_GS_REVERB_MODE; - chset->gs_reverb_mode = buf[7]; - - } else if (buf[5] == 0x01 && buf[6] == 0x38) { - /* chorus mode */ - parsed = SNDRV_MIDI_SYSEX_GS_CHORUS_MODE; - chset->gs_chorus_mode = buf[7]; - - } else if (buf[5] == 0x00 && buf[6] == 0x04) { - /* master volume */ - parsed = SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME; - chset->gs_master_volume = buf[7]; - - } - } - - /* XG on */ - else if (len >= (int)sizeof(xg_on_macro) && - memcmp(buf, xg_on_macro, sizeof(xg_on_macro)) == 0) { - int i; - chset->midi_mode = SNDRV_MIDI_MODE_XG; - parsed = SNDRV_MIDI_SYSEX_XG_ON; - /* reset CC#0 for drums */ - for (i = 0; i < chset->max_channels; i++) { - if (chset->channels[i].drum_channel) - chset->channels[i].control[MIDI_CTL_MSB_BANK] = 127; - else - chset->channels[i].control[MIDI_CTL_MSB_BANK] = 0; - } - } - - if (ops->sysex) - ops->sysex(private, buf - 1, len + 1, parsed, chset); -} - -/* - * all sound off - */ -static void -all_sounds_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan) -{ - int n; - - if (! ops->note_terminate) - return; - for (n = 0; n < 128; n++) { - if (chan->note[n]) { - ops->note_terminate(drv, n, chan); - chan->note[n] = 0; - } - } -} - -/* - * all notes off - */ -static void -all_notes_off(struct snd_midi_op *ops, void *drv, struct snd_midi_channel *chan) -{ - int n; - - if (! ops->note_off) - return; - for (n = 0; n < 128; n++) { - if (chan->note[n] == SNDRV_MIDI_NOTE_ON) - note_off(ops, drv, chan, n, 0); - } -} - -/* - * Initialise a single midi channel control block. - */ -static void snd_midi_channel_init(struct snd_midi_channel *p, int n) -{ - if (p == NULL) - return; - - memset(p, 0, sizeof(struct snd_midi_channel)); - p->private = NULL; - p->number = n; - - snd_midi_reset_controllers(p); - p->gm_rpn_pitch_bend_range = 256; /* 2 semitones */ - p->gm_rpn_fine_tuning = 0; - p->gm_rpn_coarse_tuning = 0; - - if (n == 9) - p->drum_channel = 1; /* Default ch 10 as drums */ -} - -/* - * Allocate and initialise a set of midi channel control blocks. - */ -static struct snd_midi_channel *snd_midi_channel_init_set(int n) -{ - struct snd_midi_channel *chan; - int i; - - 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); - } - - return chan; -} - -/* - * reset all midi channels - */ -static void -reset_all_channels(struct snd_midi_channel_set *chset) -{ - int ch; - for (ch = 0; ch < chset->max_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; - chan->gm_rpn_coarse_tuning = 0; - - if (ch == 9) - chan->drum_channel = 1; - else - chan->drum_channel = 0; - } -} - - -/* - * Allocate and initialise a midi channel set. - */ -struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n) -{ - struct snd_midi_channel_set *chset; - - chset = kmalloc(sizeof(*chset), GFP_KERNEL); - if (chset) { - chset->channels = snd_midi_channel_init_set(n); - chset->private_data = NULL; - chset->max_channels = n; - } - return chset; -} - -/* - * Reset the midi controllers on a particular channel to default values. - */ -static void snd_midi_reset_controllers(struct snd_midi_channel *chan) -{ - memset(chan->control, 0, sizeof(chan->control)); - chan->gm_volume = 127; - chan->gm_expression = 127; - chan->gm_pan = 64; -} - - -/* - * Free a midi channel set. - */ -void snd_midi_channel_free_set(struct snd_midi_channel_set *chset) -{ - if (chset == NULL) - return; - kfree(chset->channels); - kfree(chset); -} - -static int __init alsa_seq_midi_emul_init(void) -{ - return 0; -} - -static void __exit alsa_seq_midi_emul_exit(void) -{ -} - -module_init(alsa_seq_midi_emul_init) -module_exit(alsa_seq_midi_emul_exit) - -EXPORT_SYMBOL(snd_midi_process_event); -EXPORT_SYMBOL(snd_midi_channel_set_clear); -EXPORT_SYMBOL(snd_midi_channel_alloc_set); -EXPORT_SYMBOL(snd_midi_channel_free_set); diff --git a/ANDROID_3.4.5/sound/core/seq/seq_midi_event.c b/ANDROID_3.4.5/sound/core/seq/seq_midi_event.c deleted file mode 100644 index 37db7ba4..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_midi_event.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * MIDI byte <-> sequencer event coder - * - * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>, - * Jaroslav Kysela <perex@perex.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/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@perex.cz>"); -MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder"); -MODULE_LICENSE("GPL"); - -/* 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 */ - - -/* - * prototypes - */ -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 { - int event; - int qlen; - 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 - 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, -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(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 { - int event; - 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}, - {SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn}, -}; - -/* - * new/delete record - */ - -int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) -{ - struct snd_midi_event *dev; - - *rdev = NULL; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - if (bufsize > 0) { - dev->buf = kmalloc(bufsize, GFP_KERNEL); - if (dev->buf == NULL) { - kfree(dev); - return -ENOMEM; - } - } - dev->bufsize = bufsize; - dev->lastcmd = 0xff; - dev->type = ST_INVALID; - spin_lock_init(&dev->lock); - *rdev = dev; - return 0; -} - -void snd_midi_event_free(struct snd_midi_event *dev) -{ - if (dev != NULL) { - kfree(dev->buf); - kfree(dev); - } -} - -/* - * initialize record - */ -static inline void reset_encode(struct snd_midi_event *dev) -{ - dev->read = 0; - dev->qlen = 0; - dev->type = ST_INVALID; -} - -void snd_midi_event_reset_encode(struct snd_midi_event *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - reset_encode(dev); - spin_unlock_irqrestore(&dev->lock, flags); -} - -void snd_midi_event_reset_decode(struct snd_midi_event *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - dev->lastcmd = 0xff; - spin_unlock_irqrestore(&dev->lock, flags); -} - -#if 0 -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(struct snd_midi_event *dev, int on) -{ - dev->nostat = on ? 1 : 0; -} - -/* - * resize buffer - */ -#if 0 -int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize) -{ - unsigned char *new_buf, *old_buf; - unsigned long flags; - - if (bufsize == dev->bufsize) - return 0; - new_buf = kmalloc(bufsize, GFP_KERNEL); - if (new_buf == NULL) - return -ENOMEM; - spin_lock_irqsave(&dev->lock, flags); - old_buf = dev->buf; - dev->buf = new_buf; - dev->bufsize = bufsize; - reset_encode(dev); - spin_unlock_irqrestore(&dev->lock, flags); - kfree(old_buf); - return 0; -} -#endif /* 0 */ - -/* - * read bytes and encode to sequencer event if finished - * return the size of encoded bytes - */ -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; - - ev->type = SNDRV_SEQ_EVENT_NONE; - - while (count-- > 0) { - rc = snd_midi_event_encode_byte(dev, *buf++, ev); - result++; - if (rc < 0) - return rc; - else if (rc > 0) - return result; - } - - return result; -} - -/* - * read one byte and encode to sequencer event: - * return 1 if MIDI bytes are encoded to an event - * 0 data is not finished - * negative for error - */ -int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, - struct snd_seq_event *ev) -{ - int rc = 0; - unsigned long flags; - - c &= 0xff; - - if (c >= MIDI_CMD_COMMON_CLOCK) { - /* real-time event */ - ev->type = status_event[ST_SPECIAL + c - 0xf0].event; - ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; - ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; - return ev->type != SNDRV_SEQ_EVENT_NONE; - } - - spin_lock_irqsave(&dev->lock, flags); - 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; - 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) { - ev->type = status_event[dev->type].event; - ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; - 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 || - dev->read >= dev->bufsize) { - ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; - ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE; - ev->type = SNDRV_SEQ_EVENT_SYSEX; - ev->data.ext.len = dev->read; - ev->data.ext.ptr = dev->buf; - if (c != MIDI_CMD_COMMON_SYSEX_END) - dev->read = 0; /* continue to parse */ - else - reset_encode(dev); /* all parsed */ - rc = 1; - } - } - - spin_unlock_irqrestore(&dev->lock, flags); - return rc; -} - -/* encode note event */ -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]; - ev->data.note.velocity = dev->buf[2]; -} - -/* encode one parameter controls */ -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(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(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]; - ev->data.control.value = dev->buf[2]; -} - -/* encode one parameter value*/ -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(struct snd_midi_event *dev, struct snd_seq_event *ev) -{ - ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1]; -} - -/* - * decode from a sequencer event to midi bytes - * return the size of decoded midi events - */ -long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count, - struct snd_seq_event *ev) -{ - unsigned int cmd, type; - - if (ev->type == SNDRV_SEQ_EVENT_NONE) - return -ENOENT; - - for (type = 0; type < ARRAY_SIZE(status_event); type++) { - if (ev->type == status_event[type].event) - goto __found; - } - for (type = 0; type < ARRAY_SIZE(extra_event); type++) { - if (ev->type == extra_event[type].event) - return extra_event[type].decode(dev, buf, count, ev); - } - return -ENOENT; - - __found: - if (type >= ST_SPECIAL) - cmd = 0xf0 + (type - ST_SPECIAL); - else - /* data.note.channel and data.control.channel is identical */ - cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f); - - - if (cmd == MIDI_CMD_COMMON_SYSEX) { - snd_midi_event_reset_decode(dev); - return snd_seq_expand_var_event(ev, count, buf, 1, 0); - } else { - int qlen; - unsigned char xbuf[4]; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) { - dev->lastcmd = cmd; - spin_unlock_irqrestore(&dev->lock, flags); - xbuf[0] = cmd; - if (status_event[type].decode) - status_event[type].decode(ev, xbuf + 1); - qlen = status_event[type].qlen + 1; - } else { - spin_unlock_irqrestore(&dev->lock, flags); - if (status_event[type].decode) - status_event[type].decode(ev, xbuf + 0); - qlen = status_event[type].qlen; - } - if (count < qlen) - return -ENOMEM; - memcpy(buf, xbuf, qlen); - return qlen; - } -} - - -/* decode note event */ -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(struct snd_seq_event *ev, unsigned char *buf) -{ - buf[0] = ev->data.control.value & 0x7f; -} - -/* decode pitch wheel change */ -static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf) -{ - int value = ev->data.control.value + 8192; - buf[0] = value & 0x7f; - buf[1] = (value >> 7) & 0x7f; -} - -/* decode midi control change */ -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(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(struct snd_midi_event *dev, unsigned char *buf, - int count, struct snd_seq_event *ev) -{ - unsigned char cmd; - int idx = 0; - - cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); - if (ev->data.control.param < 0x20) { - if (count < 4) - return -ENOMEM; - if (dev->nostat && count < 6) - return -ENOMEM; - if (cmd != dev->lastcmd || dev->nostat) { - if (count < 5) - return -ENOMEM; - buf[idx++] = dev->lastcmd = cmd; - } - buf[idx++] = ev->data.control.param; - buf[idx++] = (ev->data.control.value >> 7) & 0x7f; - if (dev->nostat) - buf[idx++] = cmd; - buf[idx++] = ev->data.control.param + 0x20; - buf[idx++] = ev->data.control.value & 0x7f; - } else { - if (count < 2) - return -ENOMEM; - if (cmd != dev->lastcmd || dev->nostat) { - if (count < 3) - return -ENOMEM; - buf[idx++] = dev->lastcmd = cmd; - } - buf[idx++] = ev->data.control.param & 0x7f; - buf[idx++] = ev->data.control.value & 0x7f; - } - return idx; -} - -/* decode reg/nonreg param */ -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; - static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, - MIDI_CTL_NONREG_PARM_NUM_LSB, - MIDI_CTL_MSB_DATA_ENTRY, - MIDI_CTL_LSB_DATA_ENTRY }; - static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, - MIDI_CTL_REGIST_PARM_NUM_LSB, - MIDI_CTL_MSB_DATA_ENTRY, - MIDI_CTL_LSB_DATA_ENTRY }; - unsigned char bytes[4]; - int idx = 0, i; - - if (count < 8) - return -ENOMEM; - if (dev->nostat && count < 12) - return -ENOMEM; - cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); - 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; - buf[idx++] = dev->lastcmd = cmd; - } - cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn; - for (i = 0; i < 4; i++) { - if (dev->nostat) - buf[idx++] = dev->lastcmd = cmd; - buf[idx++] = cbytes[i]; - buf[idx++] = bytes[i]; - } - return idx; -} - -/* - * exports - */ - -EXPORT_SYMBOL(snd_midi_event_new); -EXPORT_SYMBOL(snd_midi_event_free); -EXPORT_SYMBOL(snd_midi_event_reset_encode); -EXPORT_SYMBOL(snd_midi_event_reset_decode); -EXPORT_SYMBOL(snd_midi_event_no_status); -EXPORT_SYMBOL(snd_midi_event_encode); -EXPORT_SYMBOL(snd_midi_event_encode_byte); -EXPORT_SYMBOL(snd_midi_event_decode); - -static int __init alsa_seq_midi_event_init(void) -{ - return 0; -} - -static void __exit alsa_seq_midi_event_exit(void) -{ -} - -module_init(alsa_seq_midi_event_init) -module_exit(alsa_seq_midi_event_exit) diff --git a/ANDROID_3.4.5/sound/core/seq/seq_ports.c b/ANDROID_3.4.5/sound/core/seq/seq_ports.c deleted file mode 100644 index 9516e5ce..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_ports.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * ALSA sequencer Ports - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <sound/core.h> -#include <linux/slab.h> -#include <linux/module.h> -#include "seq_system.h" -#include "seq_ports.h" -#include "seq_clientmgr.h" - -/* - - registration of client ports - - */ - - -/* - -NOTE: the current implementation of the port structure as a linked list is -not optimal for clients that have many ports. For sending messages to all -subscribers of a port we first need to find the address of the port -structure, which means we have to traverse the list. A direct access table -(array) would be better, but big preallocated arrays waste memory. - -Possible actions: - -1) leave it this way, a client does normaly does not have more than a few -ports - -2) replace the linked list of ports by a array of pointers which is -dynamicly kmalloced. When a port is added or deleted we can simply allocate -a new array, copy the corresponding pointers, and delete the old one. We -then only need a pointer to this array, and an integer that tells us how -much elements are in array. - -*/ - -/* return pointer to port structure - port is locked if found */ -struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, - int num) -{ - struct snd_seq_client_port *port; - - if (client == NULL) - return NULL; - read_lock(&client->ports_lock); - list_for_each_entry(port, &client->ports_list_head, list) { - if (port->addr.port == num) { - if (port->closing) - break; /* deleting now */ - snd_use_lock_use(&port->use_lock); - read_unlock(&client->ports_lock); - return port; - } - } - read_unlock(&client->ports_lock); - return NULL; /* not found */ -} - - -/* search for the next port - port is locked if found */ -struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *client, - struct snd_seq_port_info *pinfo) -{ - int num; - struct snd_seq_client_port *port, *found; - - num = pinfo->addr.port; - found = NULL; - read_lock(&client->ports_lock); - list_for_each_entry(port, &client->ports_list_head, list) { - if (port->addr.port < num) - continue; - if (port->addr.port == num) { - found = port; - break; - } - if (found == NULL || port->addr.port < found->addr.port) - found = port; - } - if (found) { - if (found->closing) - found = NULL; - else - snd_use_lock_use(&found->use_lock); - } - read_unlock(&client->ports_lock); - return found; -} - - -/* 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; - grp->exclusive = 0; - rwlock_init(&grp->list_lock); - init_rwsem(&grp->list_mutex); - grp->open = NULL; - grp->close = NULL; -} - - -/* create a port, port number is returned (-1 on failure) */ -struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, - int port) -{ - unsigned long flags; - struct snd_seq_client_port *new_port, *p; - int num = -1; - - /* sanity check */ - 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); - 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"); - return NULL; /* failure, out of memory */ - } - /* init port data */ - new_port->addr.client = client->number; - new_port->addr.port = -1; - new_port->owner = THIS_MODULE; - sprintf(new_port->name, "port-%d", num); - snd_use_lock_init(&new_port->use_lock); - port_subs_info_init(&new_port->c_src); - port_subs_info_init(&new_port->c_dest); - - num = port >= 0 ? port : 0; - mutex_lock(&client->ports_mutex); - write_lock_irqsave(&client->ports_lock, flags); - 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, &p->list); - client->num_ports++; - new_port->addr.port = num; /* store the port number in the port */ - write_unlock_irqrestore(&client->ports_lock, flags); - mutex_unlock(&client->ports_mutex); - sprintf(new_port->name, "port-%d", num); - - return new_port; -} - -/* */ -enum group_type { - SRC_LIST, DEST_LIST -}; - -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 struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, - struct snd_seq_client **cp) -{ - 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); - if (! p) { - snd_seq_client_unlock(*cp); - *cp = NULL; - } - return p; - } - return NULL; -} - -/* - * remove all subscribers on the list - * this is called from port_delete, for each src and dest list. - */ -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; - - list_for_each_safe(p, n, &grp->list_head) { - struct snd_seq_subscribers *subs; - struct snd_seq_client *c; - struct snd_seq_client_port *aport; - - if (grptype == 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, struct snd_seq_subscribers, dest_list); - aport = get_client_port(&subs->info.sender, &c); - } - list_del(p); - unsubscribe_port(client, port, grp, &subs->info, 0); - if (!aport) { - /* looks like the connected port is being deleted. - * we decrease the counter, and when both ports are deleted - * remove the subscriber info - */ - if (atomic_dec_and_test(&subs->ref_count)) - kfree(subs); - } else { - /* ok we got the connected port */ - 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); - snd_seq_port_unlock(aport); - snd_seq_client_unlock(c); - } - } -} - -/* delete port data */ -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; - snd_use_lock_sync(&port->use_lock); - - /* clear subscribers info */ - clear_subscriber_list(client, port, &port->c_src, SRC_LIST); - clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); - - if (port->private_free) - port->private_free(port->private_data); - - snd_BUG_ON(port->c_src.count != 0); - snd_BUG_ON(port->c_dest.count != 0); - - kfree(port); - return 0; -} - - -/* delete a port with the given port id */ -int snd_seq_delete_port(struct snd_seq_client *client, int port) -{ - unsigned long flags; - struct snd_seq_client_port *found = NULL, *p; - - mutex_lock(&client->ports_mutex); - write_lock_irqsave(&client->ports_lock, flags); - 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(&p->list); - client->num_ports--; - found = p; - break; - } - } - write_unlock_irqrestore(&client->ports_lock, flags); - mutex_unlock(&client->ports_mutex); - if (found) - return port_delete(client, found); - else - return -ENOENT; -} - -/* delete the all ports belonging to the given client */ -int snd_seq_delete_all_ports(struct snd_seq_client *client) -{ - unsigned long flags; - 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. - */ - 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); - list_del_init(&client->ports_list_head); - } else { - INIT_LIST_HEAD(&deleted_list); - } - client->num_ports = 0; - write_unlock_irqrestore(&client->ports_lock, flags); - - /* remove each port in deleted_list */ - 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); - } - mutex_unlock(&client->ports_mutex); - return 0; -} - -/* set port info fields */ -int snd_seq_set_port_info(struct snd_seq_client_port * port, - struct snd_seq_port_info * info) -{ - if (snd_BUG_ON(!port || !info)) - return -EINVAL; - - /* set port name */ - if (info->name[0]) - strlcpy(port->name, info->name, sizeof(port->name)); - - /* set capabilities */ - port->capability = info->capability; - - /* get port type */ - port->type = info->type; - - /* information about supported channels/voices */ - port->midi_channels = info->midi_channels; - port->midi_voices = info->midi_voices; - port->synth_voices = info->synth_voices; - - /* timestamping */ - port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0; - port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0; - port->time_queue = info->time_queue; - - return 0; -} - -/* get port info fields */ -int snd_seq_get_port_info(struct snd_seq_client_port * port, - struct snd_seq_port_info * info) -{ - if (snd_BUG_ON(!port || !info)) - return -EINVAL; - - /* get port name */ - strlcpy(info->name, port->name, sizeof(info->name)); - - /* get capabilities */ - info->capability = port->capability; - - /* get port type */ - info->type = port->type; - - /* information about supported channels/voices */ - info->midi_channels = port->midi_channels; - info->midi_voices = port->midi_voices; - info->synth_voices = port->synth_voices; - - /* get subscriber counts */ - info->read_use = port->c_src.count; - info->write_use = port->c_dest.count; - - /* timestamping */ - info->flags = 0; - if (port->timestamping) { - info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP; - if (port->time_real) - info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL; - info->time_queue = port->time_queue; - } - - return 0; -} - - - -/* - * call callback functions (if any): - * the callbacks are invoked only when the first (for connection) or - * the last subscription (for disconnection) is done. Second or later - * subscription results in increment of counter, but no callback is - * invoked. - * This feature is useful if these callbacks are associated with - * initialization or termination of devices (see seq_midi.c). - * - * If callback_all option is set, the callback function is invoked - * at each connection/disconnection. - */ - -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; - - if (!try_module_get(port->owner)) - return -EFAULT; - grp->count++; - if (grp->open && (port->callback_all || grp->count == 1)) { - err = grp->open(port->private_data, info); - if (err < 0) { - module_put(port->owner); - grp->count--; - } - } - if (err >= 0 && send_ack && client->type == USER_CLIENT) - snd_seq_client_notify_subscription(port->addr.client, port->addr.port, - info, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED); - - return err; -} - -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; - - if (! grp->count) - return -EINVAL; - grp->count--; - if (grp->close && (port->callback_all || grp->count == 0)) - err = grp->close(port->private_data, info); - if (send_ack && client->type == USER_CLIENT) - snd_seq_client_notify_subscription(port->addr.client, port->addr.port, - info, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED); - module_put(port->owner); - return err; -} - - - -/* check if both addresses are identical */ -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(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)) { - if (r->flags && r->flags == s->flags) - return r->queue == s->queue; - else if (! r->flags) - return 1; - } - return 0; -} - - -/* connect two ports */ -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) -{ - 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; - - subs = kzalloc(sizeof(*subs), GFP_KERNEL); - if (! subs) - return -ENOMEM; - - subs->info = *info; - atomic_set(&subs->ref_count, 2); - - down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - - exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; - err = -EBUSY; - if (exclusive) { - if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) - goto __error; - } else { - if (src->exclusive || dest->exclusive) - goto __error; - /* check whether already exists */ - list_for_each_entry(s, &src->list_head, src_list) { - if (match_subs_info(info, &s->info)) - goto __error; - } - list_for_each_entry(s, &dest->list_head, dest_list) { - if (match_subs_info(info, &s->info)) - goto __error; - } - } - - if ((err = subscribe_port(src_client, src_port, src, info, - connector->number != src_client->number)) < 0) - goto __error; - src_called = 1; - - if ((err = subscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number)) < 0) - goto __error; - - /* add to list */ - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no other lock yet - list_add_tail(&subs->src_list, &src->list_head); - list_add_tail(&subs->dest_list, &dest->list_head); - // write_unlock(&dest->list_lock); // no other lock yet - write_unlock_irqrestore(&src->list_lock, flags); - - src->exclusive = dest->exclusive = exclusive; - - up_write(&dest->list_mutex); - up_write(&src->list_mutex); - return 0; - - __error: - if (src_called) - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); - kfree(subs); - up_write(&dest->list_mutex); - up_write(&src->list_mutex); - return err; -} - - -/* remove the connection */ -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) -{ - 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_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - - /* look for the connection */ - 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 - list_del(&subs->src_list); - list_del(&subs->dest_list); - // write_unlock(&dest->list_lock); - write_unlock_irqrestore(&src->list_lock, flags); - src->exclusive = dest->exclusive = 0; - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); - unsubscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number); - kfree(subs); - err = 0; - break; - } - } - - up_write(&dest->list_mutex); - up_write(&src->list_mutex); - return err; -} - - -/* get matched subscriber */ -struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, - struct snd_seq_addr *dest_addr) -{ - struct snd_seq_subscribers *s, *found = NULL; - - down_read(&src_grp->list_mutex); - list_for_each_entry(s, &src_grp->list_head, src_list) { - if (addr_match(dest_addr, &s->info.dest)) { - found = s; - break; - } - } - up_read(&src_grp->list_mutex); - return found; -} - -/* - * Attach a device driver that wants to receive events from the - * sequencer. Returns the new port number on success. - * A driver that wants to receive the events converted to midi, will - * use snd_seq_midisynth_register_port(). - */ -/* exported */ -int snd_seq_event_port_attach(int client, - struct snd_seq_port_callback *pcbp, - int cap, int type, int midi_channels, - int midi_voices, char *portname) -{ - struct snd_seq_port_info portinfo; - int ret; - - /* Set up the port */ - memset(&portinfo, 0, sizeof(portinfo)); - portinfo.addr.client = client; - strlcpy(portinfo.name, portname ? portname : "Unamed port", - sizeof(portinfo.name)); - - portinfo.capability = cap; - portinfo.type = type; - portinfo.kernel = pcbp; - portinfo.midi_channels = midi_channels; - portinfo.midi_voices = midi_voices; - - /* Create it */ - ret = snd_seq_kernel_client_ctl(client, - SNDRV_SEQ_IOCTL_CREATE_PORT, - &portinfo); - - if (ret >= 0) - ret = portinfo.addr.port; - - return ret; -} - -EXPORT_SYMBOL(snd_seq_event_port_attach); - -/* - * Detach the driver from a port. - */ -/* exported */ -int snd_seq_event_port_detach(int client, int port) -{ - struct snd_seq_port_info portinfo; - int err; - - memset(&portinfo, 0, sizeof(portinfo)); - portinfo.addr.client = client; - portinfo.addr.port = port; - err = snd_seq_kernel_client_ctl(client, - SNDRV_SEQ_IOCTL_DELETE_PORT, - &portinfo); - - return err; -} - -EXPORT_SYMBOL(snd_seq_event_port_detach); diff --git a/ANDROID_3.4.5/sound/core/seq/seq_ports.h b/ANDROID_3.4.5/sound/core/seq/seq_ports.h deleted file mode 100644 index 9d711711..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_ports.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * ALSA sequencer Ports - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_PORTS_H -#define __SND_SEQ_PORTS_H - -#include <sound/seq_kernel.h> -#include "seq_lock.h" - -/* list of 'exported' ports */ - -/* Client ports that are not exported are still accessible, but are - anonymous ports. - - If a port supports SUBSCRIPTION, that port can send events to all - subscribersto a special address, with address - (queue==SNDRV_SEQ_ADDRESS_SUBSCRIBERS). The message is then send to all - recipients that are registered in the subscription list. A typical - application for these SUBSCRIPTION events is handling of incoming MIDI - data. The port doesn't 'know' what other clients are interested in this - message. If for instance a MIDI recording application would like to receive - the events from that port, it will first have to subscribe with that port. - -*/ - -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; -}; - -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; - int (*open)(void *private_data, struct snd_seq_port_subscribe *info); - int (*close)(void *private_data, struct snd_seq_port_subscribe *info); -}; - -struct snd_seq_client_port { - - 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 */ - struct snd_seq_port_subs_info c_src; /* read (sender) list */ - struct snd_seq_port_subs_info c_dest; /* write (dest) list */ - - 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; - unsigned int timestamping: 1; - unsigned int time_real: 1; - int time_queue; - - /* capability, inport, output, sync */ - unsigned int capability; /* port capability bits */ - unsigned int type; /* port type bits */ - - /* supported channels */ - int midi_channels; - int midi_voices; - int synth_voices; - -}; - -struct snd_seq_client; - -/* return pointer to port structure and lock port */ -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 */ -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) */ -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(struct snd_seq_client *client, int port); - -/* delete all ports */ -int snd_seq_delete_all_ports(struct snd_seq_client *client); - -/* set port info fields */ -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(struct snd_seq_client_port *port, - struct snd_seq_port_info *info); - -/* add subscriber to subscription list */ -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(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(struct snd_seq_client_port *port, - struct snd_seq_port_subscribe *info); - -/* get matched subscriber */ -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/ANDROID_3.4.5/sound/core/seq/seq_prioq.c b/ANDROID_3.4.5/sound/core/seq/seq_prioq.c deleted file mode 100644 index 29896ab2..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_prioq.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * ALSA sequencer Priority Queue - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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/time.h> -#include <linux/slab.h> -#include <sound/core.h> -#include "seq_timer.h" -#include "seq_prioq.h" - - -/* Implementation is a simple linked list for now... - - This priority queue orders the events on timestamp. For events with an - equeal timestamp the queue behaves as a FIFO. - - * - * +-------+ - * Head --> | first | - * +-------+ - * |next - * +-----v-+ - * | | - * +-------+ - * | - * +-----v-+ - * | | - * +-------+ - * | - * +-----v-+ - * Tail --> | last | - * +-------+ - * - - */ - - - -/* create new prioq (constructor) */ -struct snd_seq_prioq *snd_seq_prioq_new(void) -{ - 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"); - return NULL; - } - - spin_lock_init(&f->lock); - f->head = NULL; - f->tail = NULL; - f->cells = 0; - - return f; -} - -/* delete prioq (destructor) */ -void snd_seq_prioq_delete(struct snd_seq_prioq **fifo) -{ - struct snd_seq_prioq *f = *fifo; - *fifo = NULL; - - if (f == NULL) { - snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n"); - return; - } - - /* release resources...*/ - /*....................*/ - - if (f->cells > 0) { - /* drain prioQ */ - while (f->cells > 0) - snd_seq_cell_free(snd_seq_prioq_cell_out(f)); - } - - kfree(f); -} - - - - -/* compare timestamp between events */ -/* return 1 if a >= b; 0 */ -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 */ - return (snd_seq_compare_tick_time(&a->time.tick, &b->time.tick)); - } else { - /* compare real time */ - return (snd_seq_compare_real_time(&a->time.time, &b->time.time)); - } -} - -/* compare timestamp between events */ -/* return negative if a < b; - * zero if a = b; - * positive if a > 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 */ - if (a->time.tick > b->time.tick) - return 1; - else if (a->time.tick == b->time.tick) - return 0; - else - return -1; - } else { - /* compare real time */ - if (a->time.time.tv_sec > b->time.time.tv_sec) - return 1; - else if (a->time.time.tv_sec == b->time.time.tv_sec) { - if (a->time.time.tv_nsec > b->time.time.tv_nsec) - return 1; - else if (a->time.time.tv_nsec == b->time.time.tv_nsec) - return 0; - else - return -1; - } else - return -1; - } -} - -/* enqueue cell to prioq */ -int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, - struct snd_seq_event_cell * cell) -{ - struct snd_seq_event_cell *cur, *prev; - unsigned long flags; - int count; - int prior; - - if (snd_BUG_ON(!f || !cell)) - return -EINVAL; - - /* check flags */ - prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK); - - spin_lock_irqsave(&f->lock, flags); - - /* check if this element needs to inserted at the end (ie. ordered - data is inserted) This will be very likeley if a sequencer - application or midi file player is feeding us (sequential) data */ - if (f->tail && !prior) { - if (compare_timestamp(&cell->event, &f->tail->event)) { - /* add new cell to tail of the fifo */ - f->tail->next = cell; - f->tail = cell; - cell->next = NULL; - f->cells++; - spin_unlock_irqrestore(&f->lock, flags); - return 0; - } - } - /* traverse list of elements to find the place where the new cell is - to be inserted... Note that this is a order n process ! */ - - prev = NULL; /* previous cell */ - cur = f->head; /* cursor */ - - count = 10000; /* FIXME: enough big, isn't it? */ - while (cur != NULL) { - /* compare timestamps */ - int rel = compare_timestamp_rel(&cell->event, &cur->event); - if (rel < 0) - /* new cell has earlier schedule time, */ - break; - else if (rel == 0 && prior) - /* equal schedule time and prior to others */ - break; - /* new cell has equal or larger schedule time, */ - /* move cursor to next cell */ - prev = cur; - cur = cur->next; - if (! --count) { - spin_unlock_irqrestore(&f->lock, flags); - snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n"); - return -EINVAL; - } - } - - /* insert it before cursor */ - if (prev != NULL) - prev->next = cell; - cell->next = cur; - - if (f->head == cur) /* this is the first cell, set head to it */ - f->head = cell; - if (cur == NULL) /* reached end of the list */ - f->tail = cell; - f->cells++; - spin_unlock_irqrestore(&f->lock, flags); - return 0; -} - -/* dequeue cell from prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f) -{ - 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"); - return NULL; - } - spin_lock_irqsave(&f->lock, flags); - - cell = f->head; - if (cell) { - f->head = cell->next; - - /* reset tail if this was the last element */ - if (f->tail == cell) - f->tail = NULL; - - cell->next = NULL; - f->cells--; - } - - spin_unlock_irqrestore(&f->lock, flags); - return cell; -} - -/* return number of events available in prioq */ -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"); - return 0; - } - return f->cells; -} - - -/* peek at cell at the head of the prioq */ -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"); - return NULL; - } - return f->head; -} - - -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) - return 1; - if (!timestamp) - return 0; - switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { - case SNDRV_SEQ_TIME_STAMP_TICK: - if (cell->event.time.tick) - return 1; - break; - case SNDRV_SEQ_TIME_STAMP_REAL: - if (cell->event.time.time.tv_sec || - cell->event.time.time.tv_nsec) - return 1; - break; - } - return 0; -} - -/* remove cells for left client */ -void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) -{ - register struct snd_seq_event_cell *cell, *next; - unsigned long flags; - 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); - cell = f->head; - while (cell) { - next = cell->next; - if (prioq_match(cell, client, timestamp)) { - /* remove cell from prioq */ - if (cell == f->head) { - f->head = cell->next; - } else { - prev->next = cell->next; - } - if (cell == f->tail) - f->tail = cell->next; - f->cells--; - /* add cell to free list */ - cell->next = NULL; - if (freefirst == NULL) { - freefirst = cell; - } else { - freeprev->next = cell; - } - freeprev = cell; - } else { -#if 0 - printk(KERN_DEBUG "type = %i, source = %i, dest = %i, " - "client = %i\n", - cell->event.type, - cell->event.source.client, - cell->event.dest.client, - client); -#endif - prev = cell; - } - cell = next; - } - spin_unlock_irqrestore(&f->lock, flags); - - /* remove selected cells */ - while (freefirst) { - freenext = freefirst->next; - snd_seq_cell_free(freefirst); - freefirst = freenext; - } -} - -static int prioq_remove_match(struct snd_seq_remove_events *info, - struct snd_seq_event *ev) -{ - int res; - - if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) { - if (ev->dest.client != info->dest.client || - ev->dest.port != info->dest.port) - return 0; - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) { - if (! snd_seq_ev_is_channel_type(ev)) - return 0; - /* data.note.channel and data.control.channel are identical */ - if (ev->data.note.channel != info->channel) - return 0; - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) { - if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) - res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick); - else - res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); - if (!res) - return 0; - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) { - if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) - res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick); - else - res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); - if (res) - return 0; - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) { - if (ev->type != info->type) - return 0; - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) { - /* Do not remove off events */ - switch (ev->type) { - case SNDRV_SEQ_EVENT_NOTEOFF: - /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */ - return 0; - default: - break; - } - } - if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) { - if (info->tag != ev->tag) - return 0; - } - - return 1; -} - -/* remove cells matching remove criteria */ -void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client, - struct snd_seq_remove_events *info) -{ - struct snd_seq_event_cell *cell, *next; - unsigned long flags; - 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); - cell = f->head; - - while (cell) { - next = cell->next; - if (cell->event.source.client == client && - prioq_remove_match(info, &cell->event)) { - - /* remove cell from prioq */ - if (cell == f->head) { - f->head = cell->next; - } else { - prev->next = cell->next; - } - - if (cell == f->tail) - f->tail = cell->next; - f->cells--; - - /* add cell to free list */ - cell->next = NULL; - if (freefirst == NULL) { - freefirst = cell; - } else { - freeprev->next = cell; - } - - freeprev = cell; - } else { - prev = cell; - } - cell = next; - } - spin_unlock_irqrestore(&f->lock, flags); - - /* remove selected cells */ - while (freefirst) { - freenext = freefirst->next; - snd_seq_cell_free(freefirst); - freefirst = freenext; - } -} - - diff --git a/ANDROID_3.4.5/sound/core/seq/seq_prioq.h b/ANDROID_3.4.5/sound/core/seq/seq_prioq.h deleted file mode 100644 index d38bb78d..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_prioq.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ALSA sequencer Priority Queue - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_PRIOQ_H -#define __SND_SEQ_PRIOQ_H - -#include "seq_memory.h" - - -/* === 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; -}; - - -/* create new prioq (constructor) */ -struct snd_seq_prioq *snd_seq_prioq_new(void); - -/* delete prioq (destructor) */ -void snd_seq_prioq_delete(struct snd_seq_prioq **fifo); - -/* enqueue cell to prioq */ -int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell); - -/* dequeue cell from prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f); - -/* return number of events available in prioq */ -int snd_seq_prioq_avail(struct snd_seq_prioq *f); - -/* peek at cell at the head of the prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f); - -/* client left queue */ -void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp); - -/* Remove events */ -void snd_seq_prioq_remove_events(struct snd_seq_prioq *f, int client, - struct snd_seq_remove_events *info); - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_queue.c b/ANDROID_3.4.5/sound/core/seq/seq_queue.c deleted file mode 100644 index f9077361..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_queue.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * ALSA sequencer Timing queue handling - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * 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 - * - * MAJOR CHANGES - * Nov. 13, 1999 Takashi Iwai <iwai@ww.uni-erlangen.de> - * - Queues are allocated dynamically via ioctl. - * - When owner client is deleted, all owned queues are deleted, too. - * - Owner of unlocked queue is kept unmodified even if it is - * manipulated by other clients. - * - Owner field in SET_QUEUE_OWNER ioctl must be identical with the - * caller client. i.e. Changing owner to a third client is not - * allowed. - * - * 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 struct snd_seq_queue pointer is returned via - * queueptr(). This pointer *MUST* be released afterward by - * queuefree(ptr). - * - Addition of experimental sync support. - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <sound/core.h> - -#include "seq_memory.h" -#include "seq_queue.h" -#include "seq_clientmgr.h" -#include "seq_fifo.h" -#include "seq_timer.h" -#include "seq_info.h" - -/* list of allocated 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; - -int snd_seq_queue_get_cur_queues(void) -{ - return num_queues; -} - -/*----------------------------------------------------------------*/ - -/* assign queue id and insert to list */ -static int queue_list_add(struct snd_seq_queue *q) -{ - int i; - unsigned long flags; - - spin_lock_irqsave(&queue_list_lock, flags); - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if (! queue_list[i]) { - queue_list[i] = q; - q->queue = i; - num_queues++; - spin_unlock_irqrestore(&queue_list_lock, flags); - return i; - } - } - spin_unlock_irqrestore(&queue_list_lock, flags); - return -1; -} - -static struct snd_seq_queue *queue_list_remove(int id, int client) -{ - struct snd_seq_queue *q; - unsigned long flags; - - spin_lock_irqsave(&queue_list_lock, flags); - q = queue_list[id]; - if (q) { - spin_lock(&q->owner_lock); - if (q->owner == client) { - /* found */ - q->klocked = 1; - spin_unlock(&q->owner_lock); - queue_list[id] = NULL; - num_queues--; - spin_unlock_irqrestore(&queue_list_lock, flags); - return q; - } - spin_unlock(&q->owner_lock); - } - spin_unlock_irqrestore(&queue_list_lock, flags); - return NULL; -} - -/*----------------------------------------------------------------*/ - -/* create new queue (constructor) */ -static struct snd_seq_queue *queue_new(int owner, int locked) -{ - struct snd_seq_queue *q; - - q = kzalloc(sizeof(*q), GFP_KERNEL); - if (q == NULL) { - snd_printd("malloc failed for snd_seq_queue_new()\n"); - return NULL; - } - - spin_lock_init(&q->owner_lock); - spin_lock_init(&q->check_lock); - mutex_init(&q->timer_mutex); - snd_use_lock_init(&q->use_lock); - q->queue = -1; - - q->tickq = snd_seq_prioq_new(); - q->timeq = snd_seq_prioq_new(); - q->timer = snd_seq_timer_new(); - if (q->tickq == NULL || q->timeq == NULL || q->timer == NULL) { - snd_seq_prioq_delete(&q->tickq); - snd_seq_prioq_delete(&q->timeq); - snd_seq_timer_delete(&q->timer); - kfree(q); - return NULL; - } - - q->owner = owner; - q->locked = locked; - q->klocked = 0; - - return q; -} - -/* delete queue (destructor) */ -static void queue_delete(struct snd_seq_queue *q) -{ - /* stop and release the timer */ - snd_seq_timer_stop(q->timer); - snd_seq_timer_close(q); - /* wait until access free */ - snd_use_lock_sync(&q->use_lock); - /* release resources... */ - snd_seq_prioq_delete(&q->tickq); - snd_seq_prioq_delete(&q->timeq); - snd_seq_timer_delete(&q->timer); - - kfree(q); -} - - -/*----------------------------------------------------------------*/ - -/* setup queues */ -int __init snd_seq_queues_init(void) -{ - /* - memset(queue_list, 0, sizeof(queue_list)); - num_queues = 0; - */ - return 0; -} - -/* delete all existing queues */ -void __exit snd_seq_queues_delete(void) -{ - int i; - - /* clear list */ - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if (queue_list[i]) - queue_delete(queue_list[i]); - } -} - -/* allocate a new queue - - * return queue index value or negative value for error - */ -int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags) -{ - struct snd_seq_queue *q; - - q = queue_new(client, locked); - if (q == NULL) - return -ENOMEM; - q->info_flags = info_flags; - if (queue_list_add(q) < 0) { - queue_delete(q); - return -ENOMEM; - } - snd_seq_queue_use(q->queue, client, 1); /* use this queue */ - return q->queue; -} - -/* delete a queue - queue must be owned by the client */ -int snd_seq_queue_delete(int client, int queueid) -{ - struct snd_seq_queue *q; - - if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) - return -EINVAL; - q = queue_list_remove(queueid, client); - if (q == NULL) - return -EINVAL; - queue_delete(q); - - return 0; -} - - -/* return pointer to queue structure for specified id */ -struct snd_seq_queue *queueptr(int queueid) -{ - struct snd_seq_queue *q; - unsigned long flags; - - if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) - return NULL; - spin_lock_irqsave(&queue_list_lock, flags); - q = queue_list[queueid]; - if (q) - snd_use_lock_use(&q->use_lock); - spin_unlock_irqrestore(&queue_list_lock, flags); - return q; -} - -/* return the (first) queue matching with the specified name */ -struct snd_seq_queue *snd_seq_queue_find_name(char *name) -{ - int i; - struct snd_seq_queue *q; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) != NULL) { - if (strncmp(q->name, name, sizeof(q->name)) == 0) - return q; - queuefree(q); - } - } - return NULL; -} - - -/* -------------------------------------------------------- */ - -void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) -{ - unsigned long flags; - struct snd_seq_event_cell *cell; - - if (q == NULL) - return; - - /* make this function non-reentrant */ - spin_lock_irqsave(&q->check_lock, flags); - if (q->check_blocked) { - q->check_again = 1; - spin_unlock_irqrestore(&q->check_lock, flags); - return; /* other thread is already checking queues */ - } - q->check_blocked = 1; - spin_unlock_irqrestore(&q->check_lock, flags); - - __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)) { - cell = snd_seq_prioq_cell_out(q->tickq); - if (cell) - snd_seq_dispatch_event(cell, atomic, hop); - } else { - /* event remains in the queue */ - break; - } - } - - - /* 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)) { - cell = snd_seq_prioq_cell_out(q->timeq); - if (cell) - snd_seq_dispatch_event(cell, atomic, hop); - } else { - /* event remains in the queue */ - break; - } - } - - /* free lock */ - spin_lock_irqsave(&q->check_lock, flags); - if (q->check_again) { - q->check_again = 0; - spin_unlock_irqrestore(&q->check_lock, flags); - goto __again; - } - q->check_blocked = 0; - spin_unlock_irqrestore(&q->check_lock, flags); -} - - -/* enqueue a event to singe queue */ -int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop) -{ - int dest, err; - struct snd_seq_queue *q; - - if (snd_BUG_ON(!cell)) - return -EINVAL; - dest = cell->event.queue; /* destination queue */ - q = queueptr(dest); - if (q == NULL) - return -EINVAL; - /* handle relative time stamps, convert them into absolute */ - if ((cell->event.flags & SNDRV_SEQ_TIME_MODE_MASK) == SNDRV_SEQ_TIME_MODE_REL) { - switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { - case SNDRV_SEQ_TIME_STAMP_TICK: - cell->event.time.tick += q->timer->tick.cur_tick; - break; - - case SNDRV_SEQ_TIME_STAMP_REAL: - snd_seq_inc_real_time(&cell->event.time.time, - &q->timer->cur_time); - break; - } - cell->event.flags &= ~SNDRV_SEQ_TIME_MODE_MASK; - cell->event.flags |= SNDRV_SEQ_TIME_MODE_ABS; - } - /* enqueue event in the real-time or midi queue */ - switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { - case SNDRV_SEQ_TIME_STAMP_TICK: - err = snd_seq_prioq_cell_in(q->tickq, cell); - break; - - case SNDRV_SEQ_TIME_STAMP_REAL: - default: - err = snd_seq_prioq_cell_in(q->timeq, cell); - break; - } - - if (err < 0) { - queuefree(q); /* unlock */ - return err; - } - - /* trigger dispatching */ - snd_seq_check_queue(q, atomic, hop); - - queuefree(q); /* unlock */ - - return 0; -} - - -/*----------------------------------------------------------------*/ - -static inline int check_access(struct snd_seq_queue *q, int client) -{ - return (q->owner == client) || (!q->locked && !q->klocked); -} - -/* check if the client has permission to modify queue parameters. - * if it does, lock the queue - */ -static int queue_access_lock(struct snd_seq_queue *q, int client) -{ - unsigned long flags; - int access_ok; - - spin_lock_irqsave(&q->owner_lock, flags); - access_ok = check_access(q, client); - if (access_ok) - q->klocked = 1; - spin_unlock_irqrestore(&q->owner_lock, flags); - return access_ok; -} - -/* unlock the queue */ -static inline void queue_access_unlock(struct snd_seq_queue *q) -{ - unsigned long flags; - - spin_lock_irqsave(&q->owner_lock, flags); - q->klocked = 0; - spin_unlock_irqrestore(&q->owner_lock, flags); -} - -/* exported - only checking permission */ -int snd_seq_queue_check_access(int queueid, int client) -{ - struct snd_seq_queue *q = queueptr(queueid); - int access_ok; - unsigned long flags; - - if (! q) - return 0; - spin_lock_irqsave(&q->owner_lock, flags); - access_ok = check_access(q, client); - spin_unlock_irqrestore(&q->owner_lock, flags); - queuefree(q); - return access_ok; -} - -/*----------------------------------------------------------------*/ - -/* - * change queue's owner and permission - */ -int snd_seq_queue_set_owner(int queueid, int client, int locked) -{ - struct snd_seq_queue *q = queueptr(queueid); - - if (q == NULL) - return -EINVAL; - - if (! queue_access_lock(q, client)) { - queuefree(q); - return -EPERM; - } - - q->locked = locked ? 1 : 0; - q->owner = client; - queue_access_unlock(q); - queuefree(q); - - return 0; -} - - -/*----------------------------------------------------------------*/ - -/* open timer - - * q->use mutex should be down before calling this function to avoid - * confliction with snd_seq_queue_use() - */ -int snd_seq_queue_timer_open(int queueid) -{ - int result = 0; - struct snd_seq_queue *queue; - struct snd_seq_timer *tmr; - - queue = queueptr(queueid); - if (queue == NULL) - return -EINVAL; - tmr = queue->timer; - if ((result = snd_seq_timer_open(queue)) < 0) { - snd_seq_timer_defaults(tmr); - result = snd_seq_timer_open(queue); - } - queuefree(queue); - return result; -} - -/* close timer - - * q->use mutex should be down before calling this function - */ -int snd_seq_queue_timer_close(int queueid) -{ - struct snd_seq_queue *queue; - int result = 0; - - queue = queueptr(queueid); - if (queue == NULL) - return -EINVAL; - 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, - struct snd_seq_queue_tempo *info) -{ - struct snd_seq_queue *q = queueptr(queueid); - int result; - - if (q == NULL) - return -EINVAL; - if (! queue_access_lock(q, client)) { - queuefree(q); - return -EPERM; - } - - result = snd_seq_timer_set_tempo(q->timer, info->tempo); - 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); - queue_access_unlock(q); - queuefree(q); - return result; -} - - -/* use or unuse this queue - - * if it is the first client, starts the timer. - * if it is not longer used by any clients, stop the timer. - */ -int snd_seq_queue_use(int queueid, int client, int use) -{ - struct snd_seq_queue *queue; - - queue = queueptr(queueid); - if (queue == NULL) - return -EINVAL; - mutex_lock(&queue->timer_mutex); - if (use) { - if (!test_and_set_bit(client, queue->clients_bitmap)) - queue->clients++; - } else { - if (test_and_clear_bit(client, queue->clients_bitmap)) - queue->clients--; - } - if (queue->clients) { - if (use && queue->clients == 1) - snd_seq_timer_defaults(queue->timer); - snd_seq_timer_open(queue); - } else { - snd_seq_timer_close(queue); - } - mutex_unlock(&queue->timer_mutex); - queuefree(queue); - return 0; -} - -/* - * check if queue is used by the client - * return negative value if the queue is invalid. - * return 0 if not used, 1 if used. - */ -int snd_seq_queue_is_used(int queueid, int client) -{ - struct snd_seq_queue *q; - int result; - - q = queueptr(queueid); - if (q == NULL) - return -EINVAL; /* invalid queue */ - result = test_bit(client, q->clients_bitmap) ? 1 : 0; - queuefree(q); - return result; -} - - -/*----------------------------------------------------------------*/ - -/* notification that client has left the system - - * stop the timer on all queues owned by this client - */ -void snd_seq_queue_client_termination(int client) -{ - unsigned long flags; - int i; - struct snd_seq_queue *q; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - spin_lock_irqsave(&q->owner_lock, flags); - if (q->owner == client) - q->klocked = 1; - spin_unlock_irqrestore(&q->owner_lock, flags); - if (q->owner == client) { - if (q->timer->running) - snd_seq_timer_stop(q->timer); - snd_seq_timer_reset(q->timer); - } - queuefree(q); - } -} - -/* final stage notification - - * remove cells for no longer exist client (for non-owned queue) - * or delete this queue (for owned queue) - */ -void snd_seq_queue_client_leave(int client) -{ - int i; - struct snd_seq_queue *q; - - /* delete own queues from queue list */ - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queue_list_remove(i, client)) != NULL) - queue_delete(q); - } - - /* remove cells from existing queues - - * they are not owned by this client - */ - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - if (test_bit(client, q->clients_bitmap)) { - snd_seq_prioq_leave(q->tickq, client, 0); - snd_seq_prioq_leave(q->timeq, client, 0); - snd_seq_queue_use(q->queue, client, 0); - } - queuefree(q); - } -} - - - -/*----------------------------------------------------------------*/ - -/* remove cells from all queues */ -void snd_seq_queue_client_leave_cells(int client) -{ - int i; - struct snd_seq_queue *q; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - snd_seq_prioq_leave(q->tickq, client, 0); - snd_seq_prioq_leave(q->timeq, client, 0); - queuefree(q); - } -} - -/* remove cells based on flush criteria */ -void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) -{ - int i; - struct snd_seq_queue *q; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - if (test_bit(client, q->clients_bitmap) && - (! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) || - q->queue == info->queue)) { - snd_seq_prioq_remove_events(q->tickq, client, info); - snd_seq_prioq_remove_events(q->timeq, client, info); - } - queuefree(q); - } -} - -/*----------------------------------------------------------------*/ - -/* - * send events to all subscribed ports - */ -static void queue_broadcast_event(struct snd_seq_queue *q, struct snd_seq_event *ev, - int atomic, int hop) -{ - struct snd_seq_event sev; - - sev = *ev; - - sev.flags = SNDRV_SEQ_TIME_STAMP_TICK|SNDRV_SEQ_TIME_MODE_ABS; - sev.time.tick = q->timer->tick.cur_tick; - sev.queue = q->queue; - sev.data.queue.queue = q->queue; - - /* broadcast events from Timer port */ - sev.source.client = SNDRV_SEQ_CLIENT_SYSTEM; - sev.source.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - sev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - snd_seq_kernel_client_dispatch(SNDRV_SEQ_CLIENT_SYSTEM, &sev, atomic, hop); -} - -/* - * process a received queue-control event. - * this function is exported for seq_sync.c. - */ -static void snd_seq_queue_process_event(struct snd_seq_queue *q, - struct snd_seq_event *ev, - int atomic, int hop) -{ - switch (ev->type) { - case SNDRV_SEQ_EVENT_START: - snd_seq_prioq_leave(q->tickq, ev->source.client, 1); - snd_seq_prioq_leave(q->timeq, ev->source.client, 1); - if (! snd_seq_timer_start(q->timer)) - queue_broadcast_event(q, ev, atomic, hop); - break; - - case SNDRV_SEQ_EVENT_CONTINUE: - if (! snd_seq_timer_continue(q->timer)) - queue_broadcast_event(q, ev, atomic, hop); - break; - - case SNDRV_SEQ_EVENT_STOP: - snd_seq_timer_stop(q->timer); - queue_broadcast_event(q, ev, atomic, hop); - break; - - case SNDRV_SEQ_EVENT_TEMPO: - snd_seq_timer_set_tempo(q->timer, ev->data.queue.param.value); - queue_broadcast_event(q, ev, atomic, hop); - break; - - case SNDRV_SEQ_EVENT_SETPOS_TICK: - if (snd_seq_timer_set_position_tick(q->timer, ev->data.queue.param.time.tick) == 0) { - queue_broadcast_event(q, ev, atomic, hop); - } - break; - - case SNDRV_SEQ_EVENT_SETPOS_TIME: - if (snd_seq_timer_set_position_time(q->timer, ev->data.queue.param.time.time) == 0) { - queue_broadcast_event(q, ev, atomic, hop); - } - break; - case SNDRV_SEQ_EVENT_QUEUE_SKEW: - if (snd_seq_timer_set_skew(q->timer, - ev->data.queue.param.skew.value, - ev->data.queue.param.skew.base) == 0) { - queue_broadcast_event(q, ev, atomic, hop); - } - break; - } -} - - -/* - * Queue control via timer control port: - * this function is exported as a callback of timer port. - */ -int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) -{ - struct snd_seq_queue *q; - - if (snd_BUG_ON(!ev)) - return -EINVAL; - q = queueptr(ev->data.queue.queue); - - if (q == NULL) - return -EINVAL; - - if (! queue_access_lock(q, ev->source.client)) { - queuefree(q); - return -EPERM; - } - - snd_seq_queue_process_event(q, ev, atomic, hop); - - queue_access_unlock(q); - queuefree(q); - return 0; -} - - -/*----------------------------------------------------------------*/ - -#ifdef CONFIG_PROC_FS -/* exported to seq_info.c */ -void snd_seq_info_queues_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - int i, bpm; - struct snd_seq_queue *q; - struct snd_seq_timer *tmr; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - - tmr = q->timer; - if (tmr->tempo) - bpm = 60000000 / tmr->tempo; - else - bpm = 0; - - snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name); - snd_iprintf(buffer, "owned by client : %d\n", q->owner); - snd_iprintf(buffer, "lock status : %s\n", q->locked ? "Locked" : "Free"); - snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq)); - snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq)); - snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped"); - snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq); - snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo); - snd_iprintf(buffer, "current BPM : %d\n", bpm); - snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec); - snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick); - snd_iprintf(buffer, "\n"); - queuefree(q); - } -} -#endif /* CONFIG_PROC_FS */ - diff --git a/ANDROID_3.4.5/sound/core/seq/seq_queue.h b/ANDROID_3.4.5/sound/core/seq/seq_queue.h deleted file mode 100644 index 30c81114..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_queue.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ALSA sequencer Queue handling - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * 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 - * - */ -#ifndef __SND_SEQ_QUEUE_H -#define __SND_SEQ_QUEUE_H - -#include "seq_memory.h" -#include "seq_prioq.h" -#include "seq_timer.h" -#include "seq_lock.h" -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/bitops.h> - -#define SEQ_QUEUE_NO_OWNER (-1) - -struct snd_seq_queue { - int queue; /* queue number */ - - char name[64]; /* name of this queue */ - - struct snd_seq_prioq *tickq; /* midi tick event queue */ - struct snd_seq_prioq *timeq; /* real-time event 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) */ - check_again:1, - check_blocked:1; - - unsigned int flags; /* status flags */ - unsigned int info_flags; /* info for sync */ - - spinlock_t owner_lock; - spinlock_t check_lock; - - /* clients which uses this queue (bitmap) */ - DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS); - unsigned int clients; /* users of this queue */ - struct mutex timer_mutex; - - snd_use_lock_t use_lock; -}; - - -/* get the number of current queues */ -int snd_seq_queue_get_cur_queues(void); - -/* init queues structure */ -int snd_seq_queues_init(void); - -/* delete queues */ -void snd_seq_queues_delete(void); - - -/* create new queue (constructor) */ -int snd_seq_queue_alloc(int client, int locked, unsigned int flags); - -/* delete queue (destructor) */ -int snd_seq_queue_delete(int client, int queueid); - -/* notification that client has left the system */ -void snd_seq_queue_client_termination(int client); - -/* final stage */ -void snd_seq_queue_client_leave(int client); - -/* enqueue a event received from one the clients */ -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, struct snd_seq_remove_events *info); - -/* return pointer to queue structure for specified id */ -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 */ -struct snd_seq_queue *snd_seq_queue_find_name(char *name); - -/* check single queue and dispatch events */ -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, 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); -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(struct snd_seq_event *ev, int atomic, int hop); - -/* - * 64bit division - for sync stuff.. - */ -#if defined(i386) || defined(i486) - -#define udiv_qrnnd(q, r, n1, n0, d) \ - __asm__ ("divl %4" \ - : "=a" ((u32)(q)), \ - "=d" ((u32)(r)) \ - : "0" ((u32)(n0)), \ - "1" ((u32)(n1)), \ - "rm" ((u32)(d))) - -#define u64_div(x,y,q) do {u32 __tmp; udiv_qrnnd(q, __tmp, (x)>>32, x, y);} while (0) -#define u64_mod(x,y,r) do {u32 __tmp; udiv_qrnnd(__tmp, q, (x)>>32, x, y);} while (0) -#define u64_divmod(x,y,q,r) udiv_qrnnd(q, r, (x)>>32, x, y) - -#else -#define u64_div(x,y,q) ((q) = (u32)((u64)(x) / (u64)(y))) -#define u64_mod(x,y,r) ((r) = (u32)((u64)(x) % (u64)(y))) -#define u64_divmod(x,y,q,r) (u64_div(x,y,q), u64_mod(x,y,r)) -#endif - - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_system.c b/ANDROID_3.4.5/sound/core/seq/seq_system.c deleted file mode 100644 index 8ce1d0b4..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_system.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * ALSA sequencer System services Client - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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/export.h> -#include <linux/slab.h> -#include <sound/core.h> -#include "seq_system.h" -#include "seq_timer.h" -#include "seq_queue.h" - -/* internal client that provide system services, access to timer etc. */ - -/* - * Port "Timer" - * - send tempo /start/stop etc. events to this port to manipulate the - * queue's timer. The queue address is specified in - * data.queue.queue. - * - this port supports subscription. The received timer events are - * broadcasted to all subscribed clients. The modified tempo - * value is stored on data.queue.value. - * The modifier client/port is not send. - * - * Port "Announce" - * - does not receive message - * - supports supscription. For each client or port attaching to or - * detaching from the system an announcement is send to the subscribed - * clients. - * - * Idea: the subscription mechanism might also work handy for distributing - * synchronisation and timing information. In this case we would ideally have - * a list of subscribers for each type of sync (time, tick), for each timing - * queue. - * - * NOTE: the queue to be started, stopped, etc. must be specified - * in data.queue.addr.queue field. queue is used only for - * scheduling, and no longer referred as affected queue. - * They are used only for timer broadcast (see above). - * -- iwai - */ - - -/* client id of our system client */ -static int sysclient = -1; - -/* port id numbers for this client */ -static int announce_port = -1; - - - -/* fill standard header data, source port & channel are filled in */ -static int setheader(struct snd_seq_event * ev, int client, int port) -{ - if (announce_port < 0) - return -ENODEV; - - memset(ev, 0, sizeof(struct snd_seq_event)); - - ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; - ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; - - ev->source.client = sysclient; - ev->source.port = announce_port; - ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - - /* fill data */ - /*ev->data.addr.queue = SNDRV_SEQ_ADDRESS_UNKNOWN;*/ - ev->data.addr.client = client; - ev->data.addr.port = port; - - return 0; -} - - -/* entry points for broadcasting system events */ -void snd_seq_system_broadcast(int client, int port, int type) -{ - struct snd_seq_event ev; - - if (setheader(&ev, client, port) < 0) - return; - ev.type = type; - snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0); -} - -/* entry points for broadcasting system events */ -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; - ev->source.port = announce_port; - ev->dest.client = client; - ev->dest.port = port; - return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0); -} - -/* call-back handler for timer events */ -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); -} - -/* register our internal client */ -int __init snd_seq_system_client_init(void) -{ - struct snd_seq_port_callback pcallbacks; - struct snd_seq_port_info *port; - - port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) - return -ENOMEM; - - memset(&pcallbacks, 0, sizeof(pcallbacks)); - pcallbacks.owner = THIS_MODULE; - pcallbacks.event_input = event_input_timer; - - /* register client */ - sysclient = snd_seq_create_kernel_client(NULL, 0, "System"); - - /* register timer */ - strcpy(port->name, "Timer"); - port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */ - port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */ - port->kernel = &pcallbacks; - port->type = 0; - port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; - port->addr.client = sysclient; - port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); - - /* register announcement port */ - strcpy(port->name, "Announce"); - port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */ - port->kernel = NULL; - port->type = 0; - port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; - port->addr.client = sysclient; - port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); - announce_port = port->addr.port; - - kfree(port); - return 0; -} - - -/* unregister our internal client */ -void __exit snd_seq_system_client_done(void) -{ - int oldsysclient = sysclient; - - if (oldsysclient >= 0) { - sysclient = -1; - announce_port = -1; - snd_seq_delete_kernel_client(oldsysclient); - } -} diff --git a/ANDROID_3.4.5/sound/core/seq/seq_system.h b/ANDROID_3.4.5/sound/core/seq/seq_system.h deleted file mode 100644 index cf2cfa23..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_system.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ALSA sequencer System Client - * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_SYSTEM_H -#define __SND_SEQ_SYSTEM_H - -#include <sound/seq_kernel.h> - - -/* entry points for broadcasting system events */ -void snd_seq_system_broadcast(int client, int port, int type); - -#define snd_seq_system_client_ev_client_start(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_START) -#define snd_seq_system_client_ev_client_exit(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_EXIT) -#define snd_seq_system_client_ev_client_change(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_CHANGE) -#define snd_seq_system_client_ev_port_start(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_START) -#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, struct snd_seq_event *ev); - -/* register our internal client */ -int snd_seq_system_client_init(void); - -/* unregister our internal client */ -void snd_seq_system_client_done(void); - - -#endif diff --git a/ANDROID_3.4.5/sound/core/seq/seq_timer.c b/ANDROID_3.4.5/sound/core/seq/seq_timer.c deleted file mode 100644 index 160b1bd0..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_timer.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * ALSA sequencer Timer - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <sound/core.h> -#include <linux/slab.h> -#include "seq_timer.h" -#include "seq_queue.h" -#include "seq_info.h" - -/* 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(struct snd_seq_timer *tmr) -{ - if (tmr->tempo < 1000000) - tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; - else { - /* might overflow.. */ - unsigned int s; - s = tmr->tempo % tmr->ppq; - s = (s * 1000) / tmr->ppq; - tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; - tmr->tick.resolution += s; - } - if (tmr->tick.resolution <= 0) - tmr->tick.resolution = 1; - snd_seq_timer_update_tick(&tmr->tick, 0); -} - -/* create new timer (constructor) */ -struct snd_seq_timer *snd_seq_timer_new(void) -{ - struct snd_seq_timer *tmr; - - tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); - if (tmr == NULL) { - snd_printd("malloc failed for snd_seq_timer_new() \n"); - return NULL; - } - spin_lock_init(&tmr->lock); - - /* reset setup to defaults */ - snd_seq_timer_defaults(tmr); - - /* reset time */ - snd_seq_timer_reset(tmr); - - return tmr; -} - -/* delete timer (destructor) */ -void snd_seq_timer_delete(struct snd_seq_timer **tmr) -{ - struct snd_seq_timer *t = *tmr; - *tmr = NULL; - - if (t == NULL) { - snd_printd("oops: snd_seq_timer_delete() called with NULL timer\n"); - return; - } - t->running = 0; - - /* reset time */ - snd_seq_timer_stop(t); - snd_seq_timer_reset(t); - - kfree(t); -} - -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); - tmr->running = 0; - - tmr->type = SNDRV_SEQ_TIMER_ALSA; - tmr->alsa_id.dev_class = seq_default_timer_class; - tmr->alsa_id.dev_sclass = seq_default_timer_sclass; - tmr->alsa_id.card = seq_default_timer_card; - tmr->alsa_id.device = seq_default_timer_device; - tmr->alsa_id.subdevice = seq_default_timer_subdevice; - tmr->preferred_resolution = seq_default_timer_resolution; - - tmr->skew = tmr->skew_base = SKEW_BASE; -} - -void snd_seq_timer_reset(struct snd_seq_timer * tmr) -{ - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); - - /* reset time & songposition */ - tmr->cur_time.tv_sec = 0; - tmr->cur_time.tv_nsec = 0; - - tmr->tick.cur_tick = 0; - tmr->tick.fraction = 0; - - spin_unlock_irqrestore(&tmr->lock, flags); -} - - -/* called by timer interrupt routine. the period time since previous invocation is passed */ -static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, - unsigned long resolution, - unsigned long ticks) -{ - unsigned long flags; - struct snd_seq_queue *q = timeri->callback_data; - struct snd_seq_timer *tmr; - - if (q == NULL) - return; - tmr = q->timer; - if (tmr == NULL) - return; - if (!tmr->running) - return; - - resolution *= ticks; - if (tmr->skew != tmr->skew_base) { - /* FIXME: assuming skew_base = 0x10000 */ - resolution = (resolution >> 16) * tmr->skew + - (((resolution & 0xffff) * tmr->skew) >> 16); - } - - spin_lock_irqsave(&tmr->lock, flags); - - /* update timer */ - snd_seq_inc_time_nsec(&tmr->cur_time, resolution); - - /* calculate current tick */ - snd_seq_timer_update_tick(&tmr->tick, resolution); - - /* register actual time of this timer update */ - do_gettimeofday(&tmr->last_update); - - spin_unlock_irqrestore(&tmr->lock, flags); - - /* check queues and dispatch events */ - snd_seq_check_queue(q, 1, 0); -} - -/* set current tempo */ -int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) -{ - unsigned long flags; - - 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); - } - spin_unlock_irqrestore(&tmr->lock, flags); - return 0; -} - -/* set current ppq */ -int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) -{ - unsigned long flags; - - if (snd_BUG_ON(!tmr)) - return -EINVAL; - if (ppq <= 0) - return -EINVAL; - spin_lock_irqsave(&tmr->lock, flags); - if (tmr->running && (ppq != tmr->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"); - return -EBUSY; - } - - tmr->ppq = ppq; - 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(struct snd_seq_timer *tmr, - snd_seq_tick_time_t position) -{ - unsigned long flags; - - if (snd_BUG_ON(!tmr)) - return -EINVAL; - - spin_lock_irqsave(&tmr->lock, flags); - tmr->tick.cur_tick = position; - tmr->tick.fraction = 0; - spin_unlock_irqrestore(&tmr->lock, flags); - return 0; -} - -/* set current real-time position */ -int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, - snd_seq_real_time_t position) -{ - unsigned long flags; - - if (snd_BUG_ON(!tmr)) - return -EINVAL; - - snd_seq_sanity_real_time(&position); - spin_lock_irqsave(&tmr->lock, flags); - tmr->cur_time = position; - spin_unlock_irqrestore(&tmr->lock, flags); - return 0; -} - -/* set timer skew */ -int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, - unsigned int base) -{ - unsigned long flags; - - if (snd_BUG_ON(!tmr)) - return -EINVAL; - - /* FIXME */ - if (base != SKEW_BASE) { - snd_printd("invalid skew base 0x%x\n", base); - return -EINVAL; - } - spin_lock_irqsave(&tmr->lock, flags); - tmr->skew = skew; - spin_unlock_irqrestore(&tmr->lock, flags); - return 0; -} - -int snd_seq_timer_open(struct snd_seq_queue *q) -{ - struct snd_timer_instance *t; - struct snd_seq_timer *tmr; - char str[32]; - int err; - - tmr = q->timer; - if (snd_BUG_ON(!tmr)) - return -EINVAL; - if (tmr->timeri) - return -EBUSY; - sprintf(str, "sequencer queue %i", q->queue); - if (tmr->type != SNDRV_SEQ_TIMER_ALSA) /* standard ALSA timer */ - return -EINVAL; - if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) - tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER; - err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue); - 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) { - struct snd_timer_id tid; - memset(&tid, 0, sizeof(tid)); - tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; - tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER; - tid.card = -1; - 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; - } - } - t->callback = snd_seq_timer_interrupt; - t->callback_data = q; - t->flags |= SNDRV_TIMER_IFLG_AUTO; - tmr->timeri = t; - return 0; -} - -int snd_seq_timer_close(struct snd_seq_queue *q) -{ - struct snd_seq_timer *tmr; - - tmr = q->timer; - if (snd_BUG_ON(!tmr)) - return -EINVAL; - if (tmr->timeri) { - snd_timer_stop(tmr->timeri); - snd_timer_close(tmr->timeri); - tmr->timeri = NULL; - } - return 0; -} - -int snd_seq_timer_stop(struct snd_seq_timer * tmr) -{ - if (! tmr->timeri) - return -EINVAL; - if (!tmr->running) - return 0; - tmr->running = 0; - snd_timer_pause(tmr->timeri); - return 0; -} - -static int initialize_timer(struct snd_seq_timer *tmr) -{ - struct snd_timer *t; - unsigned long freq; - - t = tmr->timeri->timer; - 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 (!(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 * freq)); - if (! tmr->ticks) - tmr->ticks = 1; - } - } - tmr->initialized = 1; - return 0; -} - -int snd_seq_timer_start(struct snd_seq_timer * tmr) -{ - if (! tmr->timeri) - return -EINVAL; - if (tmr->running) - snd_seq_timer_stop(tmr); - snd_seq_timer_reset(tmr); - if (initialize_timer(tmr) < 0) - return -EINVAL; - snd_timer_start(tmr->timeri, tmr->ticks); - tmr->running = 1; - do_gettimeofday(&tmr->last_update); - return 0; -} - -int snd_seq_timer_continue(struct snd_seq_timer * tmr) -{ - if (! tmr->timeri) - return -EINVAL; - if (tmr->running) - return -EBUSY; - if (! tmr->initialized) { - snd_seq_timer_reset(tmr); - if (initialize_timer(tmr) < 0) - return -EINVAL; - } - snd_timer_start(tmr->timeri, tmr->ticks); - tmr->running = 1; - do_gettimeofday(&tmr->last_update); - return 0; -} - -/* return current 'real' time. use timeofday() to get better granularity. */ -snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) -{ - snd_seq_real_time_t cur_time; - - cur_time = tmr->cur_time; - if (tmr->running) { - struct timeval tm; - int usec; - do_gettimeofday(&tm); - usec = (int)(tm.tv_usec - tmr->last_update.tv_usec); - if (usec < 0) { - cur_time.tv_nsec += (1000000 + usec) * 1000; - cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1; - } else { - cur_time.tv_nsec += usec * 1000; - cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec; - } - snd_seq_sanity_real_time(&cur_time); - } - - return cur_time; -} - -/* 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(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(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - int idx; - 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++) { - q = queueptr(idx); - if (q == NULL) - continue; - if ((tmr = q->timer) == NULL || - (ti = tmr->timeri) == NULL) { - queuefree(q); - continue; - } - snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); - resolution = snd_timer_resolution(ti) * tmr->ticks; - snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); - snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); - queuefree(q); - } -} -#endif /* CONFIG_PROC_FS */ - diff --git a/ANDROID_3.4.5/sound/core/seq/seq_timer.h b/ANDROID_3.4.5/sound/core/seq/seq_timer.h deleted file mode 100644 index 88dfb718..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_timer.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * ALSA sequencer Timer - * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * - * - * 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 - * - */ -#ifndef __SND_SEQ_TIMER_H -#define __SND_SEQ_TIMER_H - -#include <sound/timer.h> -#include <sound/seq_kernel.h> - -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 */ -}; - -struct snd_seq_timer { - /* ... tempo / offset / running state */ - - unsigned int running:1, /* running state of queue */ - initialized:1; /* timer is initialized */ - - unsigned int tempo; /* current tempo, us/tick */ - int ppq; /* time resolution, ticks/quarter */ - - snd_seq_real_time_t cur_time; /* current time */ - struct snd_seq_timer_tick tick; /* current tick */ - int tick_updated; - - int type; /* timer type */ - 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 */ - - unsigned int skew; - unsigned int skew_base; - - struct timeval last_update; /* time of last clock update, used for interpolation */ - - spinlock_t lock; -}; - - -/* create new timer (constructor) */ -struct snd_seq_timer *snd_seq_timer_new(void); - -/* delete timer (destructor) */ -void snd_seq_timer_delete(struct snd_seq_timer **tmr); - -/* */ -static inline void snd_seq_timer_update_tick(struct snd_seq_timer_tick *tick, - unsigned long resolution) -{ - if (tick->resolution > 0) { - tick->fraction += resolution; - tick->cur_tick += (unsigned int)(tick->fraction / tick->resolution); - tick->fraction %= tick->resolution; - } -} - - -/* compare timestamp between events */ -/* return 1 if a >= b; otherwise return 0 */ -static inline int snd_seq_compare_tick_time(snd_seq_tick_time_t *a, snd_seq_tick_time_t *b) -{ - /* compare ticks */ - return (*a >= *b); -} - -static inline int snd_seq_compare_real_time(snd_seq_real_time_t *a, snd_seq_real_time_t *b) -{ - /* compare real time */ - if (a->tv_sec > b->tv_sec) - return 1; - if ((a->tv_sec == b->tv_sec) && (a->tv_nsec >= b->tv_nsec)) - return 1; - return 0; -} - - -static inline void snd_seq_sanity_real_time(snd_seq_real_time_t *tm) -{ - while (tm->tv_nsec >= 1000000000) { - /* roll-over */ - tm->tv_nsec -= 1000000000; - tm->tv_sec++; - } -} - - -/* increment timestamp */ -static inline void snd_seq_inc_real_time(snd_seq_real_time_t *tm, snd_seq_real_time_t *inc) -{ - tm->tv_sec += inc->tv_sec; - tm->tv_nsec += inc->tv_nsec; - snd_seq_sanity_real_time(tm); -} - -static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long nsec) -{ - tm->tv_nsec += nsec; - snd_seq_sanity_real_time(tm); -} - -/* called by timer isr */ -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/ANDROID_3.4.5/sound/core/seq/seq_virmidi.c b/ANDROID_3.4.5/sound/core/seq/seq_virmidi.c deleted file mode 100644 index 4b50e604..00000000 --- a/ANDROID_3.4.5/sound/core/seq/seq_virmidi.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Virtual Raw MIDI client on Sequencer - * - * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de>, - * Jaroslav Kysela <perex@perex.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Virtual Raw MIDI client - * - * The virtual rawmidi client is a sequencer client which associate - * a rawmidi device file. The created rawmidi device file can be - * accessed as a normal raw midi, but its MIDI source and destination - * are arbitrary. For example, a user-client software synth connected - * to this port can be used as a normal midi device as well. - * - * The virtual rawmidi device accepts also multiple opens. Each file - * has its own input buffer, so that no conflict would occur. The drain - * of input/output buffer acts only to the local buffer. - * - */ - -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <sound/core.h> -#include <sound/rawmidi.h> -#include <sound/info.h> -#include <sound/control.h> -#include <sound/minors.h> -#include <sound/seq_kernel.h> -#include <sound/seq_midi_event.h> -#include <sound/seq_virmidi.h> - -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); -MODULE_DESCRIPTION("Virtual Raw MIDI client on Sequencer"); -MODULE_LICENSE("GPL"); - -/* - * initialize an event record - */ -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; - switch (vmidi->seq_mode) { - case SNDRV_VIRMIDI_SEQ_DISPATCH: - ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - break; - case SNDRV_VIRMIDI_SEQ_ATTACH: - /* FIXME: source and destination are same - not good.. */ - ev->dest.client = vmidi->client; - ev->dest.port = vmidi->port; - break; - } - ev->type = SNDRV_SEQ_EVENT_NONE; -} - -/* - * decode input event and put to read buffer of each opened file - */ -static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, - struct snd_seq_event *ev) -{ - struct snd_virmidi *vmidi; - unsigned char msg[4]; - int len; - - read_lock(&rdev->filelist_lock); - list_for_each_entry(vmidi, &rdev->filelist, list) { - if (!vmidi->trigger) - continue; - if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { - if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) - continue; - snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); - } else { - len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); - if (len > 0) - snd_rawmidi_receive(vmidi->substream, msg, len); - } - } - read_unlock(&rdev->filelist_lock); - - return 0; -} - -/* - * receive an event from the remote virmidi port - * - * for rawmidi inputs, you can call this function from the event - * handler of a remote port which is attached to the virmidi via - * SNDRV_VIRMIDI_SEQ_ATTACH. - */ -#if 0 -int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev) -{ - struct snd_virmidi_dev *rdev; - - rdev = rmidi->private_data; - return snd_virmidi_dev_receive_event(rdev, ev); -} -#endif /* 0 */ - -/* - * event handler of virmidi port - */ -static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct, - void *private_data, int atomic, int hop) -{ - struct snd_virmidi_dev *rdev; - - rdev = private_data; - if (!(rdev->flags & SNDRV_VIRMIDI_USE)) - return 0; /* ignored */ - return snd_virmidi_dev_receive_event(rdev, ev); -} - -/* - * trigger rawmidi stream for input - */ -static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct snd_virmidi *vmidi = substream->runtime->private_data; - - if (up) { - vmidi->trigger = 1; - } else { - vmidi->trigger = 0; - } -} - -/* - * trigger rawmidi stream for output - */ -static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct snd_virmidi *vmidi = substream->runtime->private_data; - int count, res; - unsigned char buf[32], *pbuf; - - if (up) { - vmidi->trigger = 1; - if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && - !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); - return; /* ignored */ - } - if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; - vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - while (1) { - count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); - if (count <= 0) - break; - pbuf = buf; - while (count > 0) { - res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event); - if (res < 0) { - snd_midi_event_reset_encode(vmidi->parser); - continue; - } - snd_rawmidi_transmit_ack(substream, res); - pbuf += res; - count -= res; - if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; - vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - } - } - } else { - vmidi->trigger = 0; - } -} - -/* - * open rawmidi handle for input - */ -static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) -{ - struct snd_virmidi_dev *rdev = substream->rmidi->private_data; - struct snd_rawmidi_runtime *runtime = substream->runtime; - struct snd_virmidi *vmidi; - unsigned long flags; - - vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); - if (vmidi == NULL) - return -ENOMEM; - vmidi->substream = substream; - if (snd_midi_event_new(0, &vmidi->parser) < 0) { - kfree(vmidi); - return -ENOMEM; - } - vmidi->seq_mode = rdev->seq_mode; - vmidi->client = rdev->client; - vmidi->port = rdev->port; - runtime->private_data = vmidi; - write_lock_irqsave(&rdev->filelist_lock, flags); - list_add_tail(&vmidi->list, &rdev->filelist); - write_unlock_irqrestore(&rdev->filelist_lock, flags); - vmidi->rdev = rdev; - return 0; -} - -/* - * open rawmidi handle for output - */ -static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) -{ - struct snd_virmidi_dev *rdev = substream->rmidi->private_data; - struct snd_rawmidi_runtime *runtime = substream->runtime; - struct snd_virmidi *vmidi; - - vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); - if (vmidi == NULL) - return -ENOMEM; - vmidi->substream = substream; - if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &vmidi->parser) < 0) { - kfree(vmidi); - return -ENOMEM; - } - vmidi->seq_mode = rdev->seq_mode; - vmidi->client = rdev->client; - vmidi->port = rdev->port; - snd_virmidi_init_event(vmidi, &vmidi->event); - vmidi->rdev = rdev; - runtime->private_data = vmidi; - return 0; -} - -/* - * close rawmidi handle for input - */ -static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) -{ - struct snd_virmidi *vmidi = substream->runtime->private_data; - snd_midi_event_free(vmidi->parser); - list_del(&vmidi->list); - substream->runtime->private_data = NULL; - kfree(vmidi); - return 0; -} - -/* - * close rawmidi handle for output - */ -static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) -{ - struct snd_virmidi *vmidi = substream->runtime->private_data; - snd_midi_event_free(vmidi->parser); - substream->runtime->private_data = NULL; - kfree(vmidi); - return 0; -} - -/* - * subscribe callback - allow output to rawmidi device - */ -static int snd_virmidi_subscribe(void *private_data, - struct snd_seq_port_subscribe *info) -{ - struct snd_virmidi_dev *rdev; - - rdev = private_data; - if (!try_module_get(rdev->card->module)) - return -EFAULT; - rdev->flags |= SNDRV_VIRMIDI_SUBSCRIBE; - return 0; -} - -/* - * unsubscribe callback - disallow output to rawmidi device - */ -static int snd_virmidi_unsubscribe(void *private_data, - struct snd_seq_port_subscribe *info) -{ - struct snd_virmidi_dev *rdev; - - rdev = private_data; - rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE; - module_put(rdev->card->module); - return 0; -} - - -/* - * use callback - allow input to rawmidi device - */ -static int snd_virmidi_use(void *private_data, - struct snd_seq_port_subscribe *info) -{ - struct snd_virmidi_dev *rdev; - - rdev = private_data; - if (!try_module_get(rdev->card->module)) - return -EFAULT; - rdev->flags |= SNDRV_VIRMIDI_USE; - return 0; -} - -/* - * unuse callback - disallow input to rawmidi device - */ -static int snd_virmidi_unuse(void *private_data, - struct snd_seq_port_subscribe *info) -{ - struct snd_virmidi_dev *rdev; - - rdev = private_data; - rdev->flags &= ~SNDRV_VIRMIDI_USE; - module_put(rdev->card->module); - return 0; -} - - -/* - * Register functions - */ - -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 struct snd_rawmidi_ops snd_virmidi_output_ops = { - .open = snd_virmidi_output_open, - .close = snd_virmidi_output_close, - .trigger = snd_virmidi_output_trigger, -}; - -/* - * create a sequencer client and a port - */ -static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) -{ - int client; - struct snd_seq_port_callback pcallbacks; - struct snd_seq_port_info *pinfo; - int err; - - if (rdev->client >= 0) - return 0; - - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) { - err = -ENOMEM; - goto __error; - } - - 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; - - /* create a port */ - 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 - | SNDRV_SEQ_PORT_TYPE_SOFTWARE - | SNDRV_SEQ_PORT_TYPE_PORT; - pinfo->midi_channels = 16; - memset(&pcallbacks, 0, sizeof(pcallbacks)); - pcallbacks.owner = THIS_MODULE; - pcallbacks.private_data = rdev; - pcallbacks.subscribe = snd_virmidi_subscribe; - pcallbacks.unsubscribe = snd_virmidi_unsubscribe; - pcallbacks.use = snd_virmidi_use; - pcallbacks.unuse = snd_virmidi_unuse; - pcallbacks.event_input = snd_virmidi_event_input; - pinfo->kernel = &pcallbacks; - err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo); - if (err < 0) { - snd_seq_delete_kernel_client(client); - rdev->client = -1; - goto __error; - } - - rdev->port = pinfo->addr.port; - err = 0; /* success */ - - __error: - kfree(pinfo); - return err; -} - - -/* - * release the sequencer client - */ -static void snd_virmidi_dev_detach_seq(struct snd_virmidi_dev *rdev) -{ - if (rdev->client >= 0) { - snd_seq_delete_kernel_client(rdev->client); - rdev->client = -1; - } -} - -/* - * register the device - */ -static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi) -{ - struct snd_virmidi_dev *rdev = rmidi->private_data; - int err; - - switch (rdev->seq_mode) { - case SNDRV_VIRMIDI_SEQ_DISPATCH: - err = snd_virmidi_dev_attach_seq(rdev); - if (err < 0) - return err; - break; - case SNDRV_VIRMIDI_SEQ_ATTACH: - if (rdev->client == 0) - return -EINVAL; - /* should check presence of port more strictly.. */ - break; - default: - snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode); - return -EINVAL; - } - return 0; -} - - -/* - * unregister the device - */ -static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi) -{ - struct snd_virmidi_dev *rdev = rmidi->private_data; - - if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH) - snd_virmidi_dev_detach_seq(rdev); - return 0; -} - -/* - * - */ -static struct snd_rawmidi_global_ops snd_virmidi_global_ops = { - .dev_register = snd_virmidi_dev_register, - .dev_unregister = snd_virmidi_dev_unregister, -}; - -/* - * free device - */ -static void snd_virmidi_free(struct snd_rawmidi *rmidi) -{ - struct snd_virmidi_dev *rdev = rmidi->private_data; - kfree(rdev); -} - -/* - * create a new device - * - */ -/* exported */ -int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmidi) -{ - struct snd_rawmidi *rmidi; - struct snd_virmidi_dev *rdev; - int err; - - *rrmidi = NULL; - if ((err = snd_rawmidi_new(card, "VirMidi", device, - 16, /* may be configurable */ - 16, /* may be configurable */ - &rmidi)) < 0) - return err; - strcpy(rmidi->name, rmidi->id); - rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); - if (rdev == NULL) { - snd_device_free(card, rmidi); - return -ENOMEM; - } - rdev->card = card; - rdev->rmidi = rmidi; - rdev->device = device; - rdev->client = -1; - rwlock_init(&rdev->filelist_lock); - INIT_LIST_HEAD(&rdev->filelist); - rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; - rmidi->private_data = rdev; - rmidi->private_free = snd_virmidi_free; - rmidi->ops = &snd_virmidi_global_ops; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_virmidi_input_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_virmidi_output_ops); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - *rrmidi = rmidi; - return 0; -} - -/* - * ENTRY functions - */ - -static int __init alsa_virmidi_init(void) -{ - return 0; -} - -static void __exit alsa_virmidi_exit(void) -{ -} - -module_init(alsa_virmidi_init) -module_exit(alsa_virmidi_exit) - -EXPORT_SYMBOL(snd_virmidi_new); diff --git a/ANDROID_3.4.5/sound/core/sgbuf.c b/ANDROID_3.4.5/sound/core/sgbuf.c deleted file mode 100644 index 4e7ec2b4..00000000 --- a/ANDROID_3.4.5/sound/core/sgbuf.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Scatter-Gather buffer - * - * Copyright (c) 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; 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/slab.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <sound/memalloc.h> - - -/* table entries are align to 32 */ -#define SGBUF_TBL_ALIGN 32 -#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN) - -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) -{ - struct snd_sg_buf *sgbuf = dmab->private_data; - struct snd_dma_buffer tmpb; - int i; - - 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 & PAGE_MASK; - tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT; - snd_dma_free_pages(&tmpb); - } - - kfree(sgbuf->table); - kfree(sgbuf->page_table); - kfree(sgbuf); - dmab->private_data = NULL; - - 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, 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 = kzalloc(sizeof(*sgbuf), GFP_KERNEL); - if (! sgbuf) - return NULL; - sgbuf->dev = device; - pages = snd_sgbuf_aligned_pages(size); - sgbuf->tblsize = sgbuf_align_table(pages); - table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL); - if (!table) - goto _failed; - sgbuf->table = table; - pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL); - if (!pgtable) - goto _failed; - sgbuf->page_table = pgtable; - - /* 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) - return NULL; - if (!res_size) - goto _failed; - size = sgbuf->pages * PAGE_SIZE; - break; - } - 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; -} diff --git a/ANDROID_3.4.5/sound/core/sound.c b/ANDROID_3.4.5/sound/core/sound.c deleted file mode 100644 index 3700d96f..00000000 --- a/ANDROID_3.4.5/sound/core/sound.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Advanced Linux Sound Architecture - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/time.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/mutex.h> - -static int major = CONFIG_SND_MAJOR; -int snd_major; -EXPORT_SYMBOL(snd_major); - -static int cards_limit = 1; - -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."); -MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); - -/* this one holds the actual max. card number currently available. - * as default, it's identical with cards_limit option. when more - * modules are loaded manually, this limit number increases, too. - */ -int snd_ecards_limit; -EXPORT_SYMBOL(snd_ecards_limit); - -static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; -static DEFINE_MUTEX(sound_mutex); - -#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 request_module. Returns immediately if already loaded. - */ -void snd_request_card(int card) -{ - 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; - - switch (minor) { - case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; - case SNDRV_MINOR_TIMER: str = "snd-timer"; break; - default: return; - } - request_module(str); -} - -#endif /* modular kernel */ - -/** - * 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. - */ -void *snd_lookup_minor_data(unsigned int minor, int type) -{ - 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) - atomic_inc(&mreg->card_ptr->refcount); - } else - private_data = NULL; - mutex_unlock(&sound_mutex); - return private_data; -} - -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); - } - 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) -{ - unsigned int minor = iminor(inode); - struct snd_minor *mptr = NULL; - const struct file_operations *old_fops; - int err = 0; - - 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; - } - } - old_fops = file->f_op; - file->f_op = fops_get(mptr->f_ops); - if (file->f_op == NULL) { - file->f_op = old_fops; - err = -ENODEV; - } - mutex_unlock(&sound_mutex); - if (err < 0) - return err; - - 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 const struct file_operations snd_fops = -{ - .owner = THIS_MODULE, - .open = snd_open, - .llseek = noop_llseek, -}; - -#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; - - switch (type) { - case SNDRV_DEVICE_TYPE_SEQUENCER: - case SNDRV_DEVICE_TYPE_TIMER: - minor = type; - break; - case SNDRV_DEVICE_TYPE_CONTROL: - 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: - case SNDRV_DEVICE_TYPE_COMPRESS: - if (snd_BUG_ON(!card)) - return -EINVAL; - minor = SNDRV_MINOR(card->number, type + dev); - break; - default: - return -EINVAL; - } - if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) - return -EINVAL; - return minor; -} -#endif - -/** - * 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 - * @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. - * - * Returns zero if successful, or a negative error code on failure. - */ -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; - struct snd_minor *preg; - - if (snd_BUG_ON(!name)) - return -EINVAL; - preg = kmalloc(sizeof *preg, GFP_KERNEL); - if (preg == NULL) - return -ENOMEM; - preg->type = type; - preg->card = card ? card->number : -1; - preg->device = dev; - 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 minor; - } - 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 - * @card: the card instance - * @dev: the device index - * - * Unregisters the device file already registered via - * snd_register_device(). - * - * Returns zero if sucecessful, or a negative error code on failure - */ -int snd_unregister_device(int type, struct snd_card *card, int dev) -{ - int minor; - - mutex_lock(&sound_mutex); - minor = find_snd_minor(type, card, dev); - if (minor < 0) { - mutex_unlock(&sound_mutex); - return -EINVAL; - } - - device_destroy(sound_class, MKDEV(major, minor)); - - kfree(snd_minors[minor]); - snd_minors[minor] = NULL; - mutex_unlock(&sound_mutex); - return 0; -} - -EXPORT_SYMBOL(snd_unregister_device); - -int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, - struct device_attribute *attr) -{ - int minor, ret = -EINVAL; - struct device *d; - - mutex_lock(&sound_mutex); - minor = find_snd_minor(type, card, dev); - if (minor >= 0 && (d = snd_minors[minor]->dev) != NULL) - ret = device_create_file(d, attr); - mutex_unlock(&sound_mutex); - return ret; - -} - -EXPORT_SYMBOL(snd_add_device_sysfs_file); - -#ifdef CONFIG_PROC_FS -/* - * INFO PART - */ - -static struct snd_info_entry *snd_minor_info_entry; - -static const char *snd_device_type_name(int type) -{ - 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 "?"; - } -} - -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) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); - if (entry) { - entry->c.text.read = snd_minor_info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - snd_minor_info_entry = entry; - return 0; -} - -int __exit snd_minor_info_done(void) -{ - snd_info_free_entry(snd_minor_info_entry); - return 0; -} -#endif /* CONFIG_PROC_FS */ - -/* - * INIT PART - */ - -static int __init alsa_sound_init(void) -{ - snd_major = major; - snd_ecards_limit = cards_limit; - if (register_chrdev(major, "alsa", &snd_fops)) { - snd_printk(KERN_ERR "unable to register native major device number %d\n", major); - return -EIO; - } - if (snd_info_init() < 0) { - unregister_chrdev(major, "alsa"); - return -ENOMEM; - } - snd_info_minor_register(); -#ifndef MODULE - printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); -#endif - return 0; -} - -static void __exit alsa_sound_exit(void) -{ - snd_info_minor_unregister(); - snd_info_done(); - unregister_chrdev(major, "alsa"); -} - -subsys_initcall(alsa_sound_init); -module_exit(alsa_sound_exit); diff --git a/ANDROID_3.4.5/sound/core/sound_oss.c b/ANDROID_3.4.5/sound/core/sound_oss.c deleted file mode 100644 index ec860091..00000000 --- a/ANDROID_3.4.5/sound/core/sound_oss.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Advanced Linux Sound Architecture - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifdef CONFIG_SND_OSSEMUL - -#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE)) -#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_OSS_MINORS 128 - -static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; -static DEFINE_MUTEX(sound_oss_mutex); - -/* 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 snd_minor *mreg; - void *private_data; - - 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) - atomic_inc(&mreg->card_ptr->refcount); - } else - private_data = NULL; - mutex_unlock(&sound_oss_mutex); - return private_data; -} - -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: - 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: - minor = SNDRV_MINOR_OSS_SEQUENCER; - break; - case SNDRV_OSS_DEVICE_TYPE_MUSIC: - minor = SNDRV_MINOR_OSS_MUSIC; - break; - case SNDRV_OSS_DEVICE_TYPE_PCM: - 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: - 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: - minor = SNDRV_MINOR_OSS(card->number, SNDRV_MINOR_OSS_DMFM); - break; - case SNDRV_OSS_DEVICE_TYPE_SNDSTAT: - minor = SNDRV_MINOR_OSS_SNDSTAT; - break; - default: - return -EINVAL; - } - if (minor < 0 || minor >= SNDRV_OSS_MINORS) - return -EINVAL; - return minor; -} - -int snd_register_oss_device(int type, struct snd_card *card, int dev, - const struct file_operations *f_ops, void *private_data, - const char *name) -{ - int minor = snd_oss_kernel_minor(type, card, dev); - int minor_unit; - struct snd_minor *preg; - int cidx = SNDRV_MINOR_OSS_CARD(minor); - int track2 = -1; - int register1 = -1, register2 = -1; - struct device *carddev = snd_card_get_device_link(card); - - if (card && card->number >= 8) - return 0; /* ignore silently */ - if (minor < 0) - return minor; - preg = kmalloc(sizeof(struct snd_minor), GFP_KERNEL); - if (preg == NULL) - return -ENOMEM; - preg->type = type; - preg->card = card ? card->number : -1; - preg->device = dev; - 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: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO); - break; - case SNDRV_MINOR_OSS_MIDI: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI); - break; - case SNDRV_MINOR_OSS_MIDI1: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1); - break; - } - register1 = register_sound_special_device(f_ops, minor, carddev); - if (register1 != minor) - goto __end; - if (track2 >= 0) { - register2 = register_sound_special_device(f_ops, track2, - carddev); - if (register2 != track2) - goto __end; - snd_oss_minors[track2] = preg; - } - mutex_unlock(&sound_oss_mutex); - return 0; - - __end: - if (register2 >= 0) - unregister_sound_special(register2); - if (register1 >= 0) - unregister_sound_special(register1); - snd_oss_minors[minor] = NULL; - mutex_unlock(&sound_oss_mutex); - kfree(preg); - return -EBUSY; -} - -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; - struct snd_minor *mptr; - - if (card && card->number >= 8) - return 0; - if (minor < 0) - return minor; - mutex_lock(&sound_oss_mutex); - mptr = snd_oss_minors[minor]; - if (mptr == NULL) { - mutex_unlock(&sound_oss_mutex); - return -ENOENT; - } - unregister_sound_special(minor); - switch (SNDRV_MINOR_OSS_DEVICE(minor)) { - case SNDRV_MINOR_OSS_PCM: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO); - break; - case SNDRV_MINOR_OSS_MIDI: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI); - break; - case SNDRV_MINOR_OSS_MIDI1: - track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1); - break; - } - if (track2 >= 0) { - unregister_sound_special(track2); - 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 struct snd_info_entry *snd_minor_info_oss_entry; - -static const char *snd_oss_device_type_name(int type) -{ - 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 "?"; - } -} - -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) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); - if (entry) { - entry->c.text.read = snd_minor_info_oss_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - snd_minor_info_oss_entry = entry; - return 0; -} - -int __exit snd_minor_info_oss_done(void) -{ - snd_info_free_entry(snd_minor_info_oss_entry); - return 0; -} -#endif /* CONFIG_PROC_FS */ - -#endif /* CONFIG_SND_OSSEMUL */ diff --git a/ANDROID_3.4.5/sound/core/timer.c b/ANDROID_3.4.5/sound/core/timer.c deleted file mode 100644 index 6ddcf06f..00000000 --- a/ANDROID_3.4.5/sound/core/timer.c +++ /dev/null @@ -1,1999 +0,0 @@ -/* - * Timers abstract layer - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/time.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> -#include <sound/control.h> -#include <sound/info.h> -#include <sound/minors.h> -#include <sound/initval.h> -#include <linux/kmod.h> - -#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE) -#define DEFAULT_TIMER_LIMIT 4 -#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) -#define DEFAULT_TIMER_LIMIT 2 -#else -#define DEFAULT_TIMER_LIMIT 1 -#endif - -static int timer_limit = DEFAULT_TIMER_LIMIT; -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"); - -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; - 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 mutex tread_sem; -}; - -/* list of timers */ -static LIST_HEAD(snd_timer_list); - -/* list of slave instances */ -static LIST_HEAD(snd_timer_slave_list); - -/* lock for slave active lists */ -static DEFINE_SPINLOCK(slave_active_lock); - -static DEFINE_MUTEX(register_mutex); - -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(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 struct snd_timer_instance *snd_timer_instance_new(char *owner, - struct snd_timer *timer) -{ - struct snd_timer_instance *timeri; - timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); - if (timeri == NULL) - return NULL; - timeri->owner = kstrdup(owner, GFP_KERNEL); - if (! timeri->owner) { - kfree(timeri); - return NULL; - } - INIT_LIST_HEAD(&timeri->open_list); - INIT_LIST_HEAD(&timeri->active_list); - INIT_LIST_HEAD(&timeri->ack_list); - INIT_LIST_HEAD(&timeri->slave_list_head); - INIT_LIST_HEAD(&timeri->slave_active_head); - - timeri->timer = timer; - if (timer && !try_module_get(timer->module)) { - kfree(timeri->owner); - kfree(timeri); - return NULL; - } - - return timeri; -} - -/* - * find a timer instance from the given timer id - */ -static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) -{ - 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 || - timer->tmr_class == SNDRV_TIMER_CLASS_PCM) && - (timer->card == NULL || - timer->card->number != tid->card)) - continue; - if (timer->tmr_device != tid->device) - continue; - if (timer->tmr_subdevice != tid->subdevice) - continue; - return timer; - } - return NULL; -} - -#ifdef CONFIG_MODULES - -static void snd_timer_request(struct snd_timer_id *tid) -{ - switch (tid->dev_class) { - case SNDRV_TIMER_CLASS_GLOBAL: - if (tid->device < timer_limit) - request_module("snd-timer-%i", tid->device); - break; - case SNDRV_TIMER_CLASS_CARD: - case SNDRV_TIMER_CLASS_PCM: - if (tid->card < snd_ecards_limit) - request_module("snd-card-%i", tid->card); - break; - default: - break; - } -} - -#endif - -/* - * look for a master instance matching with the slave id of the given slave. - * when found, relink the open_link of the slave. - * - * call this with register_mutex down. - */ -static void snd_timer_check_slave(struct snd_timer_instance *slave) -{ - struct snd_timer *timer; - struct snd_timer_instance *master; - - /* FIXME: it's really dumb to look up all entries.. */ - 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_move_tail(&slave->open_list, - &master->slave_list_head); - spin_lock_irq(&slave_active_lock); - slave->master = master; - slave->timer = master->timer; - spin_unlock_irq(&slave_active_lock); - return; - } - } - } -} - -/* - * look for slave instances matching with the slave id of the given master. - * when found, relink the open_link of slaves. - * - * call this with register_mutex down. - */ -static void snd_timer_check_master(struct snd_timer_instance *master) -{ - struct snd_timer_instance *slave, *tmp; - - /* check all pending slaves */ - 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_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); - spin_unlock_irq(&slave_active_lock); - } - } -} - -/* - * open a timer instance - * when opening a master, the slave id must be here given. - */ -int snd_timer_open(struct snd_timer_instance **ti, - char *owner, struct snd_timer_id *tid, - unsigned int slave_id) -{ - 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); - return -EINVAL; - } - mutex_lock(®ister_mutex); - timeri = snd_timer_instance_new(owner, NULL); - if (!timeri) { - mutex_unlock(®ister_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); - mutex_unlock(®ister_mutex); - *ti = timeri; - return 0; - } - - /* open a master instance */ - mutex_lock(®ister_mutex); - timer = snd_timer_find(tid); -#ifdef CONFIG_MODULES - if (!timer) { - mutex_unlock(®ister_mutex); - snd_timer_request(tid); - mutex_lock(®ister_mutex); - timer = snd_timer_find(tid); - } -#endif - if (!timer) { - mutex_unlock(®ister_mutex); - return -ENODEV; - } - 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(®ister_mutex); - return -EBUSY; - } - } - timeri = snd_timer_instance_new(owner, timer); - if (!timeri) { - mutex_unlock(®ister_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(®ister_mutex); - *ti = timeri; - return 0; -} - -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); - -/* - * close a timer instance - */ -int snd_timer_close(struct snd_timer_instance *timeri) -{ - struct snd_timer *timer = NULL; - struct snd_timer_instance *slave, *tmp; - - if (snd_BUG_ON(!timeri)) - return -ENXIO; - - /* force to stop the timer */ - snd_timer_stop(timeri); - - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - /* wait, until the active callback is finished */ - spin_lock_irq(&slave_active_lock); - while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { - spin_unlock_irq(&slave_active_lock); - udelay(10); - spin_lock_irq(&slave_active_lock); - } - spin_unlock_irq(&slave_active_lock); - mutex_lock(®ister_mutex); - list_del(&timeri->open_list); - mutex_unlock(®ister_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) { - spin_unlock_irq(&timer->lock); - udelay(10); - spin_lock_irq(&timer->lock); - } - spin_unlock_irq(&timer->lock); - mutex_lock(®ister_mutex); - list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && - timer->hw.close) - timer->hw.close(timer); - /* remove slave links */ - 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_move_tail(&slave->open_list, &snd_timer_slave_list); - slave->master = NULL; - slave->timer = NULL; - spin_unlock_irq(&slave_active_lock); - } - mutex_unlock(®ister_mutex); - } - out: - if (timeri->private_free) - timeri->private_free(timeri); - kfree(timeri->owner); - kfree(timeri); - if (timer) - module_put(timer->module); - return 0; -} - -unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) -{ - struct snd_timer * timer; - - if (timeri == NULL) - return 0; - if ((timer = timeri->timer) != NULL) { - if (timer->hw.c_resolution) - return timer->hw.c_resolution(timer); - return timer->hw.resolution; - } - return 0; -} - -static void snd_timer_notify1(struct snd_timer_instance *ti, int event) -{ - struct snd_timer *timer; - unsigned long flags; - unsigned long resolution = 0; - struct snd_timer_instance *ts; - struct timespec tstamp; - - if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&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, event, &tstamp, resolution); - if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) - return; - timer = ti->timer; - if (timer == NULL) - return; - if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) - return; - spin_lock_irqsave(&timer->lock, flags); - 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(struct snd_timer *timer, struct snd_timer_instance *timeri, - unsigned long sticks) -{ - list_move_tail(&timeri->active_list, &timer->active_list_head); - if (timer->running) { - if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) - goto __start_now; - timer->flags |= SNDRV_TIMER_FLG_RESCHED; - timeri->flags |= SNDRV_TIMER_IFLG_START; - return 1; /* delayed start */ - } else { - timer->sticks = sticks; - timer->hw.start(timer); - __start_now: - timer->running++; - timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - return 0; - } -} - -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); - spin_unlock_irqrestore(&slave_active_lock, flags); - return 1; /* delayed start */ -} - -/* - * start the timer instance - */ -int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) -{ - struct snd_timer *timer; - int result = -EINVAL; - unsigned long flags; - - if (timeri == NULL || ticks < 1) - return -EINVAL; - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - result = snd_timer_start_slave(timeri); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); - return result; - } - timer = timeri->timer; - if (timer == NULL) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - timeri->ticks = timeri->cticks = ticks; - timeri->pticks = 0; - result = snd_timer_start1(timer, timeri, ticks); - spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); - return result; -} - -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) -{ - struct snd_timer *timer; - unsigned long flags; - - if (snd_BUG_ON(!timeri)) - return -ENXIO; - - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - spin_unlock_irqrestore(&slave_active_lock, flags); - } - goto __end; - } - timer = timeri->timer; - if (!timer) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - list_del_init(&timeri->ack_list); - list_del_init(&timeri->active_list); - if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && - !(--timer->running)) { - timer->hw.stop(timer); - if (timer->flags & SNDRV_TIMER_FLG_RESCHED) { - timer->flags &= ~SNDRV_TIMER_FLG_RESCHED; - snd_timer_reschedule(timer, 0); - if (timer->flags & SNDRV_TIMER_FLG_CHANGE) { - timer->flags &= ~SNDRV_TIMER_FLG_CHANGE; - timer->hw.start(timer); - } - } - } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); - spin_unlock_irqrestore(&timer->lock, flags); - __end: - if (event != SNDRV_TIMER_EVENT_RESOLUTION) - snd_timer_notify1(timeri, event); - return 0; -} - -/* - * stop the timer instance. - * - * do not call this from the timer callback! - */ -int snd_timer_stop(struct snd_timer_instance *timeri) -{ - struct snd_timer *timer; - unsigned long flags; - int err; - - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); - 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; - spin_unlock_irqrestore(&timer->lock, flags); - return 0; -} - -/* - * start again.. the tick is kept. - */ -int snd_timer_continue(struct snd_timer_instance *timeri) -{ - struct snd_timer *timer; - int result = -EINVAL; - unsigned long flags; - - if (timeri == NULL) - return result; - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) - return snd_timer_start_slave(timeri); - timer = timeri->timer; - if (! timer) - return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - if (!timeri->cticks) - timeri->cticks = 1; - timeri->pticks = 0; - result = snd_timer_start1(timer, timeri, timer->sticks); - spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); - return result; -} - -/* - * pause.. remember the ticks left - */ -int snd_timer_pause(struct snd_timer_instance * timeri) -{ - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); -} - -/* - * reschedule the timer - * - * 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(struct snd_timer * timer, unsigned long ticks_left) -{ - struct snd_timer_instance *ti; - unsigned long ticks = ~0UL; - - 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; - timer->running++; - } - if (ti->flags & SNDRV_TIMER_IFLG_RUNNING) { - if (ticks > ti->cticks) - ticks = ti->cticks; - } - } - if (ticks == ~0UL) { - timer->flags &= ~SNDRV_TIMER_FLG_RESCHED; - return; - } - if (ticks > timer->hw.ticks) - ticks = timer->hw.ticks; - if (ticks_left != ticks) - timer->flags |= SNDRV_TIMER_FLG_CHANGE; - timer->sticks = ticks; -} - -/* - * timer tasklet - * - */ -static void snd_timer_tasklet(unsigned long arg) -{ - 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_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 = 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; - - ti->flags |= SNDRV_TIMER_IFLG_CALLBACK; - spin_unlock(&timer->lock); - if (ti->callback) - ti->callback(ti, resolution, ticks); - spin_lock(&timer->lock); - ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; - } - spin_unlock_irqrestore(&timer->lock, flags); -} - -/* - * timer interrupt - * - * ticks_left is usually equal to timer->sticks. - * - */ -void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) -{ - struct snd_timer_instance *ti, *ts, *tmp; - unsigned long resolution, ticks; - struct list_head *p, *ack_list_head; - unsigned long flags; - int use_tasklet = 0; - - if (timer == NULL) - return; - - spin_lock_irqsave(&timer->lock, flags); - - /* remember the current resolution */ - if (timer->hw.c_resolution) - resolution = timer->hw.c_resolution(timer); - else - resolution = timer->hw.resolution; - - /* loop for all active instances - * 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_entry_safe(ti, tmp, &timer->active_list_head, - active_list) { - if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) - continue; - ti->pticks += ticks_left; - ti->resolution = resolution; - if (ti->cticks < ticks_left) - ti->cticks = 0; - else - ti->cticks -= ticks_left; - if (ti->cticks) /* not expired */ - continue; - if (ti->flags & SNDRV_TIMER_IFLG_AUTO) { - ti->cticks = ti->ticks; - } else { - ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - if (--timer->running) - list_del(&ti->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)) - list_add_tail(&ts->ack_list, ack_list_head); - } - } - if (timer->flags & SNDRV_TIMER_FLG_RESCHED) - snd_timer_reschedule(timer, timer->sticks); - if (timer->running) { - if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { - timer->hw.stop(timer); - timer->flags |= SNDRV_TIMER_FLG_CHANGE; - } - if (!(timer->hw.flags & SNDRV_TIMER_HW_AUTO) || - (timer->flags & SNDRV_TIMER_FLG_CHANGE)) { - /* restart timer */ - timer->flags &= ~SNDRV_TIMER_FLG_CHANGE; - timer->hw.start(timer); - } - } else { - timer->hw.stop(timer); - } - - /* now process all fast callbacks */ - while (!list_empty(&timer->ack_list_head)) { - p = timer->ack_list_head.next; /* get first item */ - 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; - - ti->flags |= SNDRV_TIMER_IFLG_CALLBACK; - spin_unlock(&timer->lock); - if (ti->callback) - ti->callback(ti, resolution, ticks); - spin_lock(&timer->lock); - ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; - } - - /* do we have any slow callbacks? */ - use_tasklet = !list_empty(&timer->sack_list_head); - spin_unlock_irqrestore(&timer->lock, flags); - - if (use_tasklet) - tasklet_schedule(&timer->task_queue); -} - -/* - - */ - -int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, - struct snd_timer **rtimer) -{ - struct snd_timer *timer; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_timer_dev_free, - .dev_register = snd_timer_dev_register, - .dev_disconnect = snd_timer_dev_disconnect, - }; - - if (snd_BUG_ON(!tid)) - return -EINVAL; - if (rtimer) - *rtimer = NULL; - timer = kzalloc(sizeof(*timer), GFP_KERNEL); - if (timer == NULL) { - snd_printk(KERN_ERR "timer: cannot allocate\n"); - return -ENOMEM; - } - timer->tmr_class = tid->dev_class; - timer->card = card; - timer->tmr_device = tid->device; - timer->tmr_subdevice = tid->subdevice; - if (id) - strlcpy(timer->id, id, sizeof(timer->id)); - INIT_LIST_HEAD(&timer->device_list); - INIT_LIST_HEAD(&timer->open_list_head); - INIT_LIST_HEAD(&timer->active_list_head); - 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); - if (card != NULL) { - timer->module = card->module; - err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); - if (err < 0) { - snd_timer_free(timer); - return err; - } - } - if (rtimer) - *rtimer = timer; - return 0; -} - -static int snd_timer_free(struct snd_timer *timer) -{ - if (!timer) - return 0; - - mutex_lock(®ister_mutex); - if (! list_empty(&timer->open_list_head)) { - struct list_head *p, *n; - struct snd_timer_instance *ti; - snd_printk(KERN_WARNING "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(®ister_mutex); - - if (timer->private_free) - timer->private_free(timer); - kfree(timer); - return 0; -} - -static int snd_timer_dev_free(struct snd_device *device) -{ - struct snd_timer *timer = device->device_data; - return snd_timer_free(timer); -} - -static int snd_timer_dev_register(struct snd_device *dev) -{ - struct snd_timer *timer = dev->device_data; - struct snd_timer *timer1; - - 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; - - mutex_lock(®ister_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) - continue; - if (timer1->card && timer->card) { - if (timer1->card->number > timer->card->number) - break; - if (timer1->card->number < timer->card->number) - continue; - } - if (timer1->tmr_device > timer->tmr_device) - break; - if (timer1->tmr_device < timer->tmr_device) - continue; - if (timer1->tmr_subdevice > timer->tmr_subdevice) - break; - if (timer1->tmr_subdevice < timer->tmr_subdevice) - continue; - /* conflicts.. */ - mutex_unlock(®ister_mutex); - return -EBUSY; - } - list_add_tail(&timer->device_list, &timer1->device_list); - mutex_unlock(®ister_mutex); - return 0; -} - -static int snd_timer_dev_disconnect(struct snd_device *device) -{ - struct snd_timer *timer = device->device_data; - mutex_lock(®ister_mutex); - list_del_init(&timer->device_list); - mutex_unlock(®ister_mutex); - return 0; -} - -void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) -{ - unsigned long flags; - unsigned long resolution = 0; - struct snd_timer_instance *ti, *ts; - - 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 || - event == SNDRV_TIMER_EVENT_MRESUME) { - if (timer->hw.c_resolution) - resolution = timer->hw.c_resolution(timer); - else - resolution = timer->hw.resolution; - } - list_for_each_entry(ti, &timer->active_list_head, active_list) { - if (ti->ccallback) - ti->ccallback(ti, event, tstamp, resolution); - 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); -} - -/* - * exported functions for global timers - */ -int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) -{ - struct snd_timer_id tid; - - tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; - tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; - tid.card = -1; - tid.device = device; - tid.subdevice = 0; - return snd_timer_new(NULL, id, &tid, rtimer); -} - -int snd_timer_global_free(struct snd_timer *timer) -{ - return snd_timer_free(timer); -} - -int snd_timer_global_register(struct snd_timer *timer) -{ - struct snd_device dev; - - memset(&dev, 0, sizeof(dev)); - dev.device_data = timer; - return snd_timer_dev_register(&dev); -} - -/* - * System timer - */ - -struct snd_timer_system_private { - struct timer_list tlist; - unsigned long last_expires; - unsigned long last_jiffies; - unsigned long correction; -}; - -static void snd_timer_s_function(unsigned long 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; - snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); -} - -static int snd_timer_s_start(struct snd_timer * timer) -{ - struct snd_timer_system_private *priv; - unsigned long njiff; - - priv = (struct snd_timer_system_private *) timer->private_data; - njiff = (priv->last_jiffies = jiffies); - if (priv->correction > timer->sticks - 1) { - priv->correction -= timer->sticks - 1; - njiff++; - } else { - njiff += timer->sticks - priv->correction; - priv->correction = 0; - } - priv->last_expires = priv->tlist.expires = njiff; - add_timer(&priv->tlist); - return 0; -} - -static int snd_timer_s_stop(struct snd_timer * timer) -{ - struct snd_timer_system_private *priv; - unsigned long jiff; - - priv = (struct snd_timer_system_private *) timer->private_data; - del_timer(&priv->tlist); - jiff = jiffies; - if (time_before(jiff, priv->last_expires)) - timer->sticks = priv->last_expires - jiff; - else - timer->sticks = 1; - priv->correction = 0; - return 0; -} - -static struct snd_timer_hardware snd_timer_system = -{ - .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, - .resolution = 1000000000L / HZ, - .ticks = 10000000L, - .start = snd_timer_s_start, - .stop = snd_timer_s_stop -}; - -static void snd_timer_free_system(struct snd_timer *timer) -{ - kfree(timer->private_data); -} - -static int snd_timer_register_system(void) -{ - struct snd_timer *timer; - struct snd_timer_system_private *priv; - int err; - - 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; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - snd_timer_free(timer); - return -ENOMEM; - } - init_timer(&priv->tlist); - priv->tlist.function = snd_timer_s_function; - priv->tlist.data = (unsigned long) timer; - timer->private_data = priv; - timer->private_free = snd_timer_free_system; - return snd_timer_global_register(timer); -} - -#ifdef CONFIG_PROC_FS -/* - * Info interface - */ - -static void snd_timer_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_timer *timer; - struct snd_timer_instance *ti; - - mutex_lock(®ister_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); - break; - case SNDRV_TIMER_CLASS_PCM: - 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, "%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); - if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) - snd_iprintf(buffer, " SLAVE"); - snd_iprintf(buffer, "\n"); - 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(®ister_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; - } - } - 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(struct snd_timer_instance *timeri, - unsigned long resolution, - unsigned long ticks) -{ - 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; - r = &tu->queue[prev]; - if (r->resolution == resolution) { - r->ticks += ticks; - goto __wake; - } - } - if (tu->qused >= tu->queue_size) { - tu->overrun++; - } else { - r = &tu->queue[tu->qtail++]; - tu->qtail %= tu->queue_size; - r->resolution = resolution; - r->ticks = ticks; - tu->qused++; - } - __wake: - spin_unlock(&tu->qlock); - kill_fasync(&tu->fasync, SIGIO, POLL_IN); - wake_up(&tu->qchange_sleep); -} - -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++; - } else { - memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread)); - tu->qtail %= tu->queue_size; - tu->qused++; - } -} - -static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, - int event, - struct timespec *tstamp, - unsigned long resolution) -{ - 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) - tu->tstamp = *tstamp; - if ((tu->filter & (1 << event)) == 0 || !tu->tread) - return; - r1.event = event; - r1.tstamp = *tstamp; - r1.val = resolution; - spin_lock_irqsave(&tu->qlock, flags); - snd_timer_user_append_to_tqueue(tu, &r1); - spin_unlock_irqrestore(&tu->qlock, flags); - kill_fasync(&tu->fasync, SIGIO, POLL_IN); - wake_up(&tu->qchange_sleep); -} - -static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, - unsigned long resolution, - unsigned long ticks) -{ - struct snd_timer_user *tu = timeri->callback_data; - struct snd_timer_tread *r, r1; - struct timespec tstamp; - int prev, append = 0; - - memset(&tstamp, 0, sizeof(tstamp)); - spin_lock(&tu->qlock); - 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) { - if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&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; - snd_timer_user_append_to_tqueue(tu, &r1); - tu->last_resolution = resolution; - append++; - } - if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0) - goto __wake; - if (ticks == 0) - goto __wake; - if (tu->qused > 0) { - prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; - r = &tu->tqueue[prev]; - if (r->event == SNDRV_TIMER_EVENT_TICK) { - r->tstamp = tstamp; - r->val += ticks; - append++; - goto __wake; - } - } - r1.event = SNDRV_TIMER_EVENT_TICK; - r1.tstamp = tstamp; - r1.val = ticks; - snd_timer_user_append_to_tqueue(tu, &r1); - append++; - __wake: - spin_unlock(&tu->qlock); - if (append == 0) - return; - kill_fasync(&tu->fasync, SIGIO, POLL_IN); - wake_up(&tu->qchange_sleep); -} - -static int snd_timer_user_open(struct inode *inode, struct file *file) -{ - 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); - mutex_init(&tu->tread_sem); - tu->ticks = 1; - tu->queue_size = 128; - tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), - GFP_KERNEL); - if (tu->queue == NULL) { - kfree(tu); - return -ENOMEM; - } - file->private_data = tu; - return 0; -} - -static int snd_timer_user_release(struct inode *inode, struct file *file) -{ - struct snd_timer_user *tu; - - if (file->private_data) { - tu = file->private_data; - file->private_data = NULL; - if (tu->timeri) - snd_timer_close(tu->timeri); - kfree(tu->queue); - kfree(tu->tqueue); - kfree(tu); - } - return 0; -} - -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; - id->card = -1; - id->device = -1; - id->subdevice = -1; -} - -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; - id->card = timer->card ? timer->card->number : -1; - id->device = timer->tmr_device; - id->subdevice = timer->tmr_subdevice; -} - -static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) -{ - struct snd_timer_id id; - struct snd_timer *timer; - struct list_head *p; - - if (copy_from_user(&id, _tid, sizeof(id))) - return -EFAULT; - mutex_lock(®ister_mutex); - if (id.dev_class < 0) { /* first item */ - if (list_empty(&snd_timer_list)) - snd_timer_user_zero_id(&id); - else { - timer = list_entry(snd_timer_list.next, - struct snd_timer, device_list); - snd_timer_user_copy_id(&id, timer); - } - } else { - switch (id.dev_class) { - case SNDRV_TIMER_CLASS_GLOBAL: - id.device = id.device < 0 ? 0 : id.device + 1; - list_for_each(p, &snd_timer_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; - } - if (timer->tmr_device >= id.device) { - snd_timer_user_copy_id(&id, timer); - break; - } - } - if (p == &snd_timer_list) - snd_timer_user_zero_id(&id); - break; - case SNDRV_TIMER_CLASS_CARD: - case SNDRV_TIMER_CLASS_PCM: - if (id.card < 0) { - id.card = 0; - } else { - if (id.card < 0) { - id.card = 0; - } else { - if (id.device < 0) { - id.device = 0; - } else { - if (id.subdevice < 0) { - id.subdevice = 0; - } else { - id.subdevice++; - } - } - } - } - list_for_each(p, &snd_timer_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; - } - if (timer->tmr_class < id.dev_class) - continue; - if (timer->card->number > id.card) { - snd_timer_user_copy_id(&id, timer); - break; - } - if (timer->card->number < id.card) - continue; - if (timer->tmr_device > id.device) { - snd_timer_user_copy_id(&id, timer); - break; - } - if (timer->tmr_device < id.device) - continue; - if (timer->tmr_subdevice > id.subdevice) { - snd_timer_user_copy_id(&id, timer); - break; - } - if (timer->tmr_subdevice < id.subdevice) - continue; - snd_timer_user_copy_id(&id, timer); - break; - } - if (p == &snd_timer_list) - snd_timer_user_zero_id(&id); - break; - default: - snd_timer_user_zero_id(&id); - } - } - mutex_unlock(®ister_mutex); - if (copy_to_user(_tid, &id, sizeof(*_tid))) - return -EFAULT; - return 0; -} - -static int snd_timer_user_ginfo(struct file *file, - struct snd_timer_ginfo __user *_ginfo) -{ - struct snd_timer_ginfo *ginfo; - struct snd_timer_id tid; - struct snd_timer *t; - struct list_head *p; - int err = 0; - - 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; - mutex_lock(®ister_mutex); - t = snd_timer_find(&tid); - if (t != NULL) { - ginfo->card = t->card ? t->card->number : -1; - if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) - ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; - strlcpy(ginfo->id, t->id, sizeof(ginfo->id)); - strlcpy(ginfo->name, t->name, sizeof(ginfo->name)); - ginfo->resolution = t->hw.resolution; - if (t->hw.resolution_min > 0) { - ginfo->resolution_min = t->hw.resolution_min; - ginfo->resolution_max = t->hw.resolution_max; - } - list_for_each(p, &t->open_list_head) { - ginfo->clients++; - } - } else { - err = -ENODEV; - } - mutex_unlock(®ister_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, - struct snd_timer_gparams __user *_gparams) -{ - struct snd_timer_gparams gparams; - struct snd_timer *t; - int err; - - if (copy_from_user(&gparams, _gparams, sizeof(gparams))) - return -EFAULT; - mutex_lock(®ister_mutex); - t = snd_timer_find(&gparams.tid); - if (!t) { - err = -ENODEV; - goto _error; - } - 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(®ister_mutex); - return err; -} - -static int snd_timer_user_gstatus(struct file *file, - struct snd_timer_gstatus __user *_gstatus) -{ - 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))) - return -EFAULT; - tid = gstatus.tid; - memset(&gstatus, 0, sizeof(gstatus)); - gstatus.tid = tid; - mutex_lock(®ister_mutex); - t = snd_timer_find(&tid); - if (t != NULL) { - if (t->hw.c_resolution) - gstatus.resolution = t->hw.c_resolution(t); - else - gstatus.resolution = t->hw.resolution; - if (t->hw.precise_resolution) { - t->hw.precise_resolution(t, &gstatus.resolution_num, - &gstatus.resolution_den); - } else { - gstatus.resolution_num = gstatus.resolution; - gstatus.resolution_den = 1000000000uL; - } - } else { - err = -ENODEV; - } - mutex_unlock(®ister_mutex); - if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) - err = -EFAULT; - return err; -} - -static int snd_timer_user_tselect(struct file *file, - struct snd_timer_select __user *_tselect) -{ - struct snd_timer_user *tu; - struct snd_timer_select tselect; - char str[32]; - int err = 0; - - tu = file->private_data; - mutex_lock(&tu->tread_sem); - if (tu->timeri) { - snd_timer_close(tu->timeri); - tu->timeri = NULL; - } - if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { - err = -EFAULT; - goto __err; - } - sprintf(str, "application %i", current->pid); - if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) - tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; - err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid); - if (err < 0) - goto __err; - - kfree(tu->queue); - tu->queue = NULL; - kfree(tu->tqueue); - tu->tqueue = NULL; - if (tu->tread) { - tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), - GFP_KERNEL); - if (tu->tqueue == NULL) - err = -ENOMEM; - } else { - 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->ccallback = snd_timer_user_ccallback; - tu->timeri->callback_data = (void *)tu; - } - - __err: - mutex_unlock(&tu->tread_sem); - return err; -} - -static int snd_timer_user_info(struct file *file, - struct snd_timer_info __user *_info) -{ - struct snd_timer_user *tu; - struct snd_timer_info *info; - struct snd_timer *t; - int err = 0; - - tu = file->private_data; - if (!tu->timeri) - return -EBADFD; - t = tu->timeri->timer; - if (!t) - return -EBADFD; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (! info) - return -ENOMEM; - info->card = t->card ? t->card->number : -1; - if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) - info->flags |= SNDRV_TIMER_FLG_SLAVE; - strlcpy(info->id, t->id, sizeof(info->id)); - strlcpy(info->name, t->name, sizeof(info->name)); - info->resolution = t->hw.resolution; - if (copy_to_user(_info, info, sizeof(*_info))) - err = -EFAULT; - kfree(info); - return err; -} - -static int snd_timer_user_params(struct file *file, - struct snd_timer_params __user *_params) -{ - 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; - if (!tu->timeri) - return -EBADFD; - t = tu->timeri->timer; - if (!t) - return -EBADFD; - if (copy_from_user(¶ms, _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)) { - err = -EINVAL; - goto _end; - } - if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)| - (1<<SNDRV_TIMER_EVENT_TICK)| - (1<<SNDRV_TIMER_EVENT_START)| - (1<<SNDRV_TIMER_EVENT_STOP)| - (1<<SNDRV_TIMER_EVENT_CONTINUE)| - (1<<SNDRV_TIMER_EVENT_PAUSE)| - (1<<SNDRV_TIMER_EVENT_SUSPEND)| - (1<<SNDRV_TIMER_EVENT_RESUME)| - (1<<SNDRV_TIMER_EVENT_MSTART)| - (1<<SNDRV_TIMER_EVENT_MSTOP)| - (1<<SNDRV_TIMER_EVENT_MCONTINUE)| - (1<<SNDRV_TIMER_EVENT_MPAUSE)| - (1<<SNDRV_TIMER_EVENT_MSUSPEND)| - (1<<SNDRV_TIMER_EVENT_MRESUME))) { - err = -EINVAL; - goto _end; - } - snd_timer_stop(tu->timeri); - spin_lock_irq(&t->lock); - tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO| - SNDRV_TIMER_IFLG_EXCLUSIVE| - SNDRV_TIMER_IFLG_EARLY_EVENT); - if (params.flags & SNDRV_TIMER_PSFLG_AUTO) - tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO; - if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) - tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE; - 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 (tu->tread) { - 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 = kmalloc(params.queue_size * sizeof(*tr), - GFP_KERNEL); - if (tr) { - kfree(tu->queue); - tu->queue_size = params.queue_size; - tu->queue = tr; - } - } - } - tu->qhead = tu->qtail = tu->qused = 0; - if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { - if (tu->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 { - 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; - err = 0; - _end: - if (copy_to_user(_params, ¶ms, sizeof(params))) - return -EFAULT; - return err; -} - -static int snd_timer_user_status(struct file *file, - struct snd_timer_status __user *_status) -{ - struct snd_timer_user *tu; - struct snd_timer_status status; - - tu = file->private_data; - if (!tu->timeri) - return -EBADFD; - memset(&status, 0, sizeof(status)); - status.tstamp = tu->tstamp; - status.resolution = snd_timer_resolution(tu->timeri); - status.lost = tu->timeri->lost; - status.overrun = tu->overrun; - spin_lock_irq(&tu->qlock); - status.queue = tu->qused; - spin_unlock_irq(&tu->qlock); - if (copy_to_user(_status, &status, sizeof(status))) - return -EFAULT; - return 0; -} - -static int snd_timer_user_start(struct file *file) -{ - int err; - struct snd_timer_user *tu; - - tu = file->private_data; - if (!tu->timeri) - return -EBADFD; - snd_timer_stop(tu->timeri); - tu->timeri->lost = 0; - tu->last_resolution = 0; - return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0; -} - -static int snd_timer_user_stop(struct file *file) -{ - int err; - struct snd_timer_user *tu; - - tu = file->private_data; - 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; - struct snd_timer_user *tu; - - tu = file->private_data; - if (!tu->timeri) - return -EBADFD; - tu->timeri->lost = 0; - return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; -} - -static int snd_timer_user_pause(struct file *file) -{ - int err; - struct snd_timer_user *tu; - - tu = file->private_data; - if (!tu->timeri) - return -EBADFD; - return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; -} - -enum { - SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), - SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), - SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), - SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), -}; - -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - 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: - return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; - case SNDRV_TIMER_IOCTL_NEXT_DEVICE: - return snd_timer_user_next_device(argp); - case SNDRV_TIMER_IOCTL_TREAD: - { - int xarg; - - mutex_lock(&tu->tread_sem); - if (tu->timeri) { /* too late */ - mutex_unlock(&tu->tread_sem); - return -EBUSY; - } - if (get_user(xarg, p)) { - mutex_unlock(&tu->tread_sem); - return -EFAULT; - } - tu->tread = xarg ? 1 : 0; - mutex_unlock(&tu->tread_sem); - return 0; - } - case SNDRV_TIMER_IOCTL_GINFO: - return snd_timer_user_ginfo(file, argp); - case SNDRV_TIMER_IOCTL_GPARAMS: - return snd_timer_user_gparams(file, argp); - case SNDRV_TIMER_IOCTL_GSTATUS: - return snd_timer_user_gstatus(file, argp); - case SNDRV_TIMER_IOCTL_SELECT: - return snd_timer_user_tselect(file, argp); - case SNDRV_TIMER_IOCTL_INFO: - return snd_timer_user_info(file, argp); - case SNDRV_TIMER_IOCTL_PARAMS: - return snd_timer_user_params(file, argp); - case SNDRV_TIMER_IOCTL_STATUS: - return snd_timer_user_status(file, argp); - case SNDRV_TIMER_IOCTL_START: - case SNDRV_TIMER_IOCTL_START_OLD: - return snd_timer_user_start(file); - case SNDRV_TIMER_IOCTL_STOP: - case SNDRV_TIMER_IOCTL_STOP_OLD: - return snd_timer_user_stop(file); - case SNDRV_TIMER_IOCTL_CONTINUE: - case SNDRV_TIMER_IOCTL_CONTINUE_OLD: - return snd_timer_user_continue(file); - case SNDRV_TIMER_IOCTL_PAUSE: - case SNDRV_TIMER_IOCTL_PAUSE_OLD: - return snd_timer_user_pause(file); - } - return -ENOTTY; -} - -static int snd_timer_user_fasync(int fd, struct file * file, int on) -{ - struct snd_timer_user *tu; - - tu = file->private_data; - 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) -{ - struct snd_timer_user *tu; - long result = 0, unit; - int err = 0; - - tu = file->private_data; - 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) { - wait_queue_t wait; - - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - err = -EAGAIN; - break; - } - - set_current_state(TASK_INTERRUPTIBLE); - init_waitqueue_entry(&wait, current); - add_wait_queue(&tu->qchange_sleep, &wait); - - spin_unlock_irq(&tu->qlock); - schedule(); - spin_lock_irq(&tu->qlock); - - remove_wait_queue(&tu->qchange_sleep, &wait); - - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - } - - spin_unlock_irq(&tu->qlock); - if (err < 0) - goto _error; - - if (tu->tread) { - 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(struct snd_timer_read))) { - err = -EFAULT; - goto _error; - } - } - - tu->qhead %= tu->queue_size; - - result += unit; - buffer += unit; - - spin_lock_irq(&tu->qlock); - tu->qused--; - } - spin_unlock_irq(&tu->qlock); - _error: - return result > 0 ? result : err; -} - -static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - struct snd_timer_user *tu; - - tu = file->private_data; - - poll_wait(file, &tu->qchange_sleep, wait); - - mask = 0; - if (tu->qused) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - -#ifdef CONFIG_COMPAT -#include "timer_compat.c" -#else -#define snd_timer_user_ioctl_compat NULL -#endif - -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, -}; - -/* - * ENTRY functions - */ - -static int __init alsa_timer_init(void) -{ - int err; - -#ifdef SNDRV_OSS_INFO_DEV_TIMERS - snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, - "system timer"); -#endif - - 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_f_ops, NULL, "timer")) < 0) - snd_printk(KERN_ERR "unable to register timer device (%i)\n", - err); - snd_timer_proc_init(); - return 0; -} - -static void __exit alsa_timer_exit(void) -{ - struct list_head *p, *n; - - snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0); - /* unregister the system timer */ - list_for_each_safe(p, n, &snd_timer_list) { - 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 -} - -module_init(alsa_timer_init) -module_exit(alsa_timer_exit) - -EXPORT_SYMBOL(snd_timer_open); -EXPORT_SYMBOL(snd_timer_close); -EXPORT_SYMBOL(snd_timer_resolution); -EXPORT_SYMBOL(snd_timer_start); -EXPORT_SYMBOL(snd_timer_stop); -EXPORT_SYMBOL(snd_timer_continue); -EXPORT_SYMBOL(snd_timer_pause); -EXPORT_SYMBOL(snd_timer_new); -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_interrupt); diff --git a/ANDROID_3.4.5/sound/core/timer_compat.c b/ANDROID_3.4.5/sound/core/timer_compat.c deleted file mode 100644 index e05802ae..00000000 --- a/ANDROID_3.4.5/sound/core/timer_compat.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 32bit -> 64bit ioctl wrapper for timer API - * Copyright (c) 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; 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 - * - */ - -/* This file included from timer.c */ - -#include <linux/compat.h> - -struct snd_timer_info32 { - u32 flags; - s32 card; - unsigned char id[64]; - unsigned char name[80]; - u32 reserved0; - u32 resolution; - unsigned char reserved[64]; -}; - -static int snd_timer_user_info_compat(struct file *file, - struct snd_timer_info32 __user *_info) -{ - struct snd_timer_user *tu; - struct snd_timer_info32 info; - struct snd_timer *t; - - tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; - t = tu->timeri->timer; - 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) - info.flags |= SNDRV_TIMER_FLG_SLAVE; - strlcpy(info.id, t->id, sizeof(info.id)); - strlcpy(info.name, t->name, sizeof(info.name)); - info.resolution = t->hw.resolution; - if (copy_to_user(_info, &info, sizeof(*_info))) - return -EFAULT; - return 0; -} - -struct snd_timer_status32 { - struct compat_timespec tstamp; - u32 resolution; - u32 lost; - u32 overrun; - u32 queue; - unsigned char reserved[64]; -}; - -static int snd_timer_user_status_compat(struct file *file, - struct snd_timer_status32 __user *_status) -{ - struct snd_timer_user *tu; - struct snd_timer_status status; - - tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; - memset(&status, 0, sizeof(status)); - status.tstamp = tu->tstamp; - status.resolution = snd_timer_resolution(tu->timeri); - status.lost = tu->timeri->lost; - status.overrun = tu->overrun; - spin_lock_irq(&tu->qlock); - status.queue = tu->qused; - spin_unlock_irq(&tu->qlock); - if (copy_to_user(_status, &status, sizeof(status))) - return -EFAULT; - return 0; -} - -/* - */ - -enum { - 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) -{ - void __user *argp = compat_ptr(arg); - - switch (cmd) { - case SNDRV_TIMER_IOCTL_PVERSION: - case SNDRV_TIMER_IOCTL_TREAD: - case SNDRV_TIMER_IOCTL_GINFO: - case SNDRV_TIMER_IOCTL_GPARAMS: - case SNDRV_TIMER_IOCTL_GSTATUS: - case SNDRV_TIMER_IOCTL_SELECT: - case SNDRV_TIMER_IOCTL_PARAMS: - case SNDRV_TIMER_IOCTL_START: - case SNDRV_TIMER_IOCTL_START_OLD: - case SNDRV_TIMER_IOCTL_STOP: - case SNDRV_TIMER_IOCTL_STOP_OLD: - case SNDRV_TIMER_IOCTL_CONTINUE: - case SNDRV_TIMER_IOCTL_CONTINUE_OLD: - case SNDRV_TIMER_IOCTL_PAUSE: - case SNDRV_TIMER_IOCTL_PAUSE_OLD: - case SNDRV_TIMER_IOCTL_NEXT_DEVICE: - return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); - case SNDRV_TIMER_IOCTL_INFO32: - return snd_timer_user_info_compat(file, argp); - case SNDRV_TIMER_IOCTL_STATUS32: - return snd_timer_user_status_compat(file, argp); - } - return -ENOIOCTLCMD; -} diff --git a/ANDROID_3.4.5/sound/core/vmaster.c b/ANDROID_3.4.5/sound/core/vmaster.c deleted file mode 100644 index 85758613..00000000 --- a/ANDROID_3.4.5/sound/core/vmaster.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * 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)) { - snd_printk(KERN_ERR "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; - return slave_put_val(slave, ucontrol); -} - -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 master_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct link_master *master = snd_kcontrol_chip(kcontrol); - struct link_slave *slave; - struct snd_ctl_elem_value *uval; - int err, old_val; - - err = master_init(master); - if (err < 0) - return err; - old_val = master->val; - if (ucontrol->value.integer.value[0] == old_val) - return 0; - - 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 = ucontrol->value.integer.value[0]; - slave_put_val(slave, uval); - } - kfree(uval); - if (master->hook && !err) - 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 matster control with the given name string. - * Returns the created control element, or NULL for errors (ENOMEM). - * - * 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. - */ -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. - */ -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_hook - Sync the vmaster hook - * @kcontrol: vmaster kctl element - * - * Call the hook function to synchronize with the current value of the given - * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't - * exist. - */ -void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol) -{ - struct link_master *master; - if (!kcontrol) - return; - master = snd_kcontrol_chip(kcontrol); - if (master->hook) - master->hook(master->hook_private_data, master->val); -} -EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook); |