summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_envy24/envy24_direct.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_envy24/envy24_direct.c
downloadoss4-upstream.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_envy24/envy24_direct.c')
-rw-r--r--kernel/drv/oss_envy24/envy24_direct.c415
1 files changed, 415 insertions, 0 deletions
diff --git a/kernel/drv/oss_envy24/envy24_direct.c b/kernel/drv/oss_envy24/envy24_direct.c
new file mode 100644
index 0000000..9448c6c
--- /dev/null
+++ b/kernel/drv/oss_envy24/envy24_direct.c
@@ -0,0 +1,415 @@
+/*
+ * Purpose: Direct 24 bit multich driver for Envy24.
+ *
+ * This driver implements the all inputs and all outputs audio devices for
+ * envy24. Unlike the ordinary driver this one doesn't use additional buffering.
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#include "oss_config.h"
+#include "ac97.h"
+
+#ifdef USE_LICENSING
+#include "private/licensing/licensing.h"
+#endif
+
+#include "envy24.h"
+
+#define OUTCH_NAMES "CH1/2 CH3/4 CH5/6 CH7/8 digital"
+#define INCH_NAMES "CH1/2 CH3/4 CH5/6 CH7/8 digital monitor_mix"
+
+/*
+ * Audio routines
+ */
+extern int envy24_audio_set_rate (int dev, int arg);
+int envy24d_get_buffer_pointer (int dev, dmap_t * dmap, int direction);
+
+void
+envy24d_playintr (envy24_devc * devc)
+{
+ oss_audio_outputintr (devc->direct_portc_out.audio_dev, 0);
+}
+
+void
+envy24d_recintr (envy24_devc * devc)
+{
+ oss_audio_inputintr (devc->direct_portc_in.audio_dev, 0);
+}
+
+/*ARGSUSED*/
+static short
+envy24d_audio_set_channels (int dev, short arg)
+{
+ envy24d_portc *portc = audio_engines[dev]->portc;
+ return portc->channels;
+}
+
+/*ARGSUSED*/
+static unsigned int
+envy24d_audio_set_format (int dev, unsigned int arg)
+{
+ return AFMT_S32_LE;
+}
+
+/*ARGSUSED*/
+static int
+envy24d_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
+{
+ return OSS_EINVAL;
+}
+
+static void envy24d_audio_trigger (int dev, int state);
+
+static void
+envy24d_audio_reset (int dev)
+{
+ envy24d_audio_trigger (dev, 0);
+}
+
+/*ARGSUSED*/
+static int
+envy24d_audio_open (int dev, int mode, int open_flags)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+ envy24d_portc *portc = audio_engines[dev]->portc;
+ oss_native_word flags;
+
+ if (!(mode & portc->direction))
+ return OSS_EINVAL;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ if (portc->open_mode != 0 || (devc->direct_audio_opened & mode))
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+
+ if (mode == OPEN_WRITE && (devc->play_channel_mask != 0))
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+
+ if (mode == OPEN_READ && (devc->rec_channel_mask != 0))
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+
+ portc->open_mode = mode;
+ devc->direct_audio_opened |= mode;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+static void
+envy24d_audio_close (int dev, int mode)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+ envy24d_portc *portc = audio_engines[dev]->portc;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ portc->open_mode = 0;
+ devc->direct_audio_opened &= ~mode;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+/*ARGSUSED*/
+static void
+envy24d_audio_output_block (int dev, oss_native_word buf, int count,
+ int fragsize, int intrflag)
+{
+}
+
+/*ARGSUSED*/
+static void
+envy24d_audio_start_input (int dev, oss_native_word buf, int count,
+ int fragsize, int intrflag)
+{
+}
+
+static void
+envy24d_audio_trigger (int dev, int state)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+ envy24d_portc *portc = audio_engines[dev]->portc;
+ int changed;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ changed = state ^ portc->trigger_bits;
+
+ if (portc->direction == OPEN_WRITE && (changed & PCM_ENABLE_OUTPUT))
+ {
+ if (state & PCM_ENABLE_OUTPUT)
+ {
+#ifdef DO_TIMINGS
+ oss_do_timing ("Envy24d: Trigger start output");
+#endif
+ portc->trigger_bits = state;
+ envy24_launch_play_engine (devc);
+ }
+ else
+ {
+#ifdef DO_TIMINGS
+ oss_do_timing ("Envy24d: Trigger stop output");
+#endif
+ portc->trigger_bits = state;
+ envy24_stop_playback (devc);
+ }
+ }
+
+ if (portc->direction == OPEN_READ && (changed & PCM_ENABLE_INPUT))
+ {
+ if (state & PCM_ENABLE_INPUT)
+ {
+#ifdef DO_TIMINGS
+ oss_do_timing ("Envy24d: Trigger start input");
+#endif
+ portc->trigger_bits = state;
+ envy24_launch_recording (devc);
+ }
+ else
+ {
+#ifdef DO_TIMINGS
+ oss_do_timing ("Envy24d: Trigger stop input");
+#endif
+ portc->trigger_bits = state;
+ envy24_stop_recording (devc);
+ }
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+/*ARGSUSED*/
+static int
+envy24d_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+ envy24_start_recording (devc);
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+envy24d_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+
+ envy24_prepare_play_engine (devc);
+ return 0;
+}
+
+static int
+envy24d_alloc_buffer (int dev, dmap_t * dmap, int direction)
+{
+ envy24_devc *devc = audio_engines[dev]->devc;
+
+ if (direction == OPEN_WRITE)
+ {
+ if (devc->playbuf == NULL)
+ {
+ cmn_err (CE_CONT, "Envy24: No playback DMA buffer available\n");
+ return OSS_ENOSPC;
+ }
+
+ dmap->dmabuf = devc->playbuf;
+ dmap->buffsize = devc->playbuffsize;
+ dmap->dmabuf_phys = devc->playbuf_phys;
+ return 0;
+ }
+
+ if (direction == OPEN_READ)
+ {
+ if (devc->recbuf == NULL)
+ {
+ cmn_err (CE_CONT, "Envy24: No recording DMA buffer available\n");
+ return OSS_ENOSPC;
+ }
+
+ dmap->dmabuf = devc->recbuf;
+ dmap->buffsize = devc->recbuffsize;
+ dmap->dmabuf_phys = devc->recbuf_phys;
+ return 0;
+ }
+
+ return OSS_EIO;
+}
+
+/*ARGSUSED*/
+static int
+envy24d_free_buffer (int dev, dmap_t * dmap, int direction)
+{
+ dmap->dmabuf = NULL;
+ dmap->dmabuf_phys = 0;
+ dmap->buffsize = 0;
+ return 0;
+}
+
+int
+envy24d_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
+{
+
+ envy24_devc *devc = audio_engines[dev]->devc;
+ int pos;
+
+ if (direction == PCM_ENABLE_OUTPUT)
+ {
+ pos = INW (devc->osdev, devc->mt_base + 0x14);
+ pos = (pos + 1) * 4;
+ pos = dmap->bytes_in_use - pos;
+
+ return pos;
+ }
+
+ if (direction == PCM_ENABLE_INPUT)
+ {
+ pos = INW (devc->osdev, devc->mt_base + 0x24);
+ pos = (pos + 1) * 4;
+ pos = dmap->bytes_in_use - pos;
+
+ return pos;
+ }
+
+ return OSS_EIO;
+}
+
+/*ARGSUSED*/
+static int
+envy24d_check_input (int dev)
+{
+ cmn_err (CE_WARN, "Envy24d: Input timed out.\n");
+ return OSS_EIO;
+}
+
+/*ARGSUSED*/
+static int
+envy24d_check_output (int dev)
+{
+ cmn_err (CE_WARN, "Envy24d: Output timed out (%d)\n", GET_JIFFIES ());
+ return OSS_EIO;
+}
+
+static const audiodrv_t envy24d_audio_driver = {
+ envy24d_audio_open,
+ envy24d_audio_close,
+ envy24d_audio_output_block,
+ envy24d_audio_start_input,
+ envy24d_audio_ioctl,
+ envy24d_audio_prepare_for_input,
+ envy24d_audio_prepare_for_output,
+ envy24d_audio_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ envy24d_audio_trigger,
+ envy24_audio_set_rate,
+ envy24d_audio_set_format,
+ envy24d_audio_set_channels,
+ NULL,
+ NULL,
+ envy24d_check_input,
+ envy24d_check_output,
+ envy24d_alloc_buffer,
+ envy24d_free_buffer,
+ NULL,
+ NULL,
+ envy24d_get_buffer_pointer
+};
+
+void
+envy24d_install (envy24_devc * devc)
+{
+
+ int adev, out_dev, in_dev;
+ char tmpname[128];
+ envy24d_portc *portc;
+
+ /*
+ * Output device
+ */
+ sprintf (tmpname, "%s (all outputs)", devc->model_data->product);
+
+ if ((out_dev = adev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ tmpname,
+ &envy24d_audio_driver,
+ sizeof (audiodrv_t),
+ ADEV_NOVIRTUAL | ADEV_NOINPUT | ADEV_COLD
+ | ADEV_SPECIAL | ADEV_32BITONLY,
+ AFMT_S32_LE, devc, -1,
+ "10ch_out")) >= 0)
+ {
+ portc = &devc->direct_portc_out;
+ audio_engines[adev]->portc = portc;
+ audio_engines[adev]->rate_source = devc->first_dev;
+ audio_engines[adev]->caps |= DSP_CH_MULTI;
+ audio_engines[adev]->min_channels = 10;
+ audio_engines[adev]->max_channels = 10;
+ audio_engines[adev]->outch_names = OUTCH_NAMES;
+ audio_engines[adev]->min_block = devc->hw_pfragsize;
+ audio_engines[adev]->max_block = devc->hw_pfragsize;
+ audio_engines[adev]->min_rate = 8000;
+ audio_engines[adev]->max_rate = 96000;
+
+ audio_engines[adev]->mixer_dev = devc->mixer_dev;
+ devc->direct_audio_opened = 0;
+ portc->open_mode = 0;
+ portc->audio_dev = adev;
+ portc->channels = 10;
+ portc->direction = OPEN_WRITE;
+ audio_engines[adev]->port_number = 0; /* First output channel */
+ }
+
+ /*
+ * Input device
+ */
+ sprintf (tmpname, "%s (all inputs)", devc->model_data->product);
+
+ if ((adev = in_dev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ tmpname,
+ &envy24d_audio_driver,
+ sizeof (audiodrv_t),
+ ADEV_NOVIRTUAL | ADEV_NOOUTPUT | ADEV_COLD
+ | ADEV_SPECIAL | ADEV_32BITONLY,
+ AFMT_S32_LE, devc, -1,
+ "12ch_in")) >= 0)
+ {
+ portc = &devc->direct_portc_in;
+ audio_engines[adev]->portc = portc;
+ audio_engines[adev]->rate_source = devc->first_dev;
+ audio_engines[adev]->caps |= DSP_CH_MULTI;
+ audio_engines[adev]->min_channels = 12;
+ audio_engines[adev]->max_channels = 12;
+ audio_engines[adev]->inch_names = INCH_NAMES;
+ audio_engines[adev]->min_rate = 8000;
+ audio_engines[adev]->max_rate = 96000;
+
+ audio_engines[adev]->mixer_dev = devc->mixer_dev;
+ devc->direct_audio_opened = 0;
+ portc->open_mode = 0;
+ portc->audio_dev = adev;
+ audio_engines[adev]->min_block = devc->hw_pfragsize;
+ audio_engines[adev]->max_block = devc->hw_pfragsize;
+ portc->channels = 12;
+ portc->direction = OPEN_READ;
+ audio_engines[adev]->port_number = 10; /* First input channel */
+ }
+}