summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/sound/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/sound/audio.c')
-rw-r--r--sys/i386/isa/sound/audio.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
new file mode 100644
index 0000000..f27f9d5
--- /dev/null
+++ b/sys/i386/isa/sound/audio.c
@@ -0,0 +1,356 @@
+/*
+ * sound/audio.c
+ *
+ * Device file manager for /dev/audio
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+#ifndef EXCLUDE_AUDIO
+
+#include "ulaw.h"
+
+#define ON 1
+#define OFF 0
+
+static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
+
+ * incomplete output block */
+static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+
+static int audio_mode[MAX_DSP_DEV];
+
+#define AM_NONE 0
+#define AM_WRITE 1
+#define AM_READ 2
+
+static char *wr_dma_buf[MAX_DSP_DEV];
+
+int
+audio_open (int dev, struct fileinfo *file)
+{
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ if (dev_type == SND_DEV_DSP16)
+ bits = 16;
+ else
+ bits = 8;
+
+ if ((ret = DMAbuf_open (dev, mode)) < 0)
+ return ret;
+
+ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+ {
+ audio_release (dev, file);
+ return RET_ERROR (ENXIO);
+ }
+
+ wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+
+ return ret;
+}
+
+void
+audio_release (int dev, struct fileinfo *file)
+{
+ int mode;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+
+ DMAbuf_release (dev, mode);
+}
+
+#ifdef NO_INLINE_ASM
+static void
+translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
+{
+ unsigned long i;
+
+ for (i = 0; i < n; ++i)
+ buff[i] = table[buff[i]];
+}
+
+#else
+extern inline void
+translate_bytes (const void *table, void *buff, unsigned long n)
+{
+ __asm__ ("cld\n"
+ "1:\tlodsb\n\t"
+ "xlatb\n\t"
+ "stosb\n\t"
+ "loop 1b\n\t":
+ :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
+ :"bx", "cx", "di", "si", "ax");
+}
+
+#endif
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c, p, l;
+ int err;
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+
+ p = 0;
+ c = count;
+
+ if (audio_mode[dev] == AM_READ) /* Direction changed */
+ {
+ wr_buff_no[dev] = -1;
+ }
+
+ audio_mode[dev] = AM_WRITE;
+
+ if (!count) /* Flush output */
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ }
+
+ while (c)
+ { /* Perform output blocking */
+ if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */
+ {
+ if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
+ return wr_buff_no[dev];
+ wr_buff_ptr[dev] = 0;
+ }
+
+ l = c;
+ if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
+ l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+
+ if (!dsp_devs[dev]->copy_from_user)
+ { /* No device specific copy routine */
+ COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+ }
+ else
+ dsp_devs[dev]->copy_from_user (dev,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
+
+
+ /* Insert local processing here */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
+#ifdef linux
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
+#endif
+ translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
+
+ c -= l;
+ p += l;
+ wr_buff_ptr[dev] += l;
+
+ if (wr_buff_ptr[dev] >= wr_buff_size[dev])
+ {
+ if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
+ return err;
+
+ wr_buff_no[dev] = -1;
+ }
+
+ }
+
+ return count;
+}
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c, p, l;
+ char *dmabuf;
+ int buff_no;
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+ p = 0;
+ c = count;
+
+ if (audio_mode[dev] == AM_WRITE)
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ }
+
+ audio_mode[dev] = AM_READ;
+
+ while (c)
+ {
+ if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
+ return buff_no;
+
+ if (l > c)
+ l = c;
+
+ /* Insert any local processing here. */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
+#ifdef linux
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
+#endif
+
+ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
+
+ COPY_TO_USER (buf, p, dmabuf, l);
+
+ DMAbuf_rmchars (dev, buff_no, l);
+
+ p += l;
+ c -= l;
+ }
+
+ return count - c;
+}
+
+int
+audio_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_SYNC:
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ break;
+
+ case SNDCTL_DSP_POST:
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ break;
+
+ case SNDCTL_DSP_RESET:
+ wr_buff_no[dev] = -1;
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ break;
+
+ default:
+ if (dev_type == SND_DEV_AUDIO)
+ return RET_ERROR (EIO);
+
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ }
+}
+
+long
+audio_init (long mem_start)
+{
+ return mem_start;
+}
+
+#else
+/* Stub versions */
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_open (int dev, struct fileinfo *file)
+{
+ return RET_ERROR (ENXIO);
+}
+
+void
+audio_release (int dev, struct fileinfo *file)
+{
+};
+int
+audio_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
+{
+ return RET_ERROR (EIO);
+}
+
+long
+audio_init (long mem_start)
+{
+ return mem_start;
+}
+
+#endif
+
+#endif
OpenPOWER on IntegriCloud