summaryrefslogtreecommitdiff
path: root/attic/drv/oss_s3vibes
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 /attic/drv/oss_s3vibes
downloadoss4-upstream.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'attic/drv/oss_s3vibes')
-rw-r--r--attic/drv/oss_s3vibes/.config1
-rw-r--r--attic/drv/oss_s3vibes/.devices1
-rw-r--r--attic/drv/oss_s3vibes/.name1
-rw-r--r--attic/drv/oss_s3vibes/oss_s3vibes.c931
-rw-r--r--attic/drv/oss_s3vibes/oss_s3vibes.man19
5 files changed, 953 insertions, 0 deletions
diff --git a/attic/drv/oss_s3vibes/.config b/attic/drv/oss_s3vibes/.config
new file mode 100644
index 0000000..5280084
--- /dev/null
+++ b/attic/drv/oss_s3vibes/.config
@@ -0,0 +1 @@
+platform=i86pc
diff --git a/attic/drv/oss_s3vibes/.devices b/attic/drv/oss_s3vibes/.devices
new file mode 100644
index 0000000..cc530e0
--- /dev/null
+++ b/attic/drv/oss_s3vibes/.devices
@@ -0,0 +1 @@
+oss_s3vibes pci5333,ca00 S3 Sonic Vibes
diff --git a/attic/drv/oss_s3vibes/.name b/attic/drv/oss_s3vibes/.name
new file mode 100644
index 0000000..7906362
--- /dev/null
+++ b/attic/drv/oss_s3vibes/.name
@@ -0,0 +1 @@
+S3 Sonic Vibes
diff --git a/attic/drv/oss_s3vibes/oss_s3vibes.c b/attic/drv/oss_s3vibes/oss_s3vibes.c
new file mode 100644
index 0000000..076988d
--- /dev/null
+++ b/attic/drv/oss_s3vibes/oss_s3vibes.c
@@ -0,0 +1,931 @@
+
+/*
+ * Purpose: Driver for S3 SonicVibes PCI audio controller.
+ */
+/*
+ *
+ * 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_s3vibes_cfg.h"
+#include "oss_pci.h"
+
+#ifdef USE_LICENSING
+#include "private/licensing/licensing.h"
+#endif
+
+#define S3_VENDOR_ID 0x5333
+#define S3_SONICVIBES 0xca00
+
+#define MIXER_DEVS (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \
+ SOUND_MASK_MIC | SOUND_MASK_VOLUME | \
+ SOUND_MASK_CD | SOUND_MASK_LINE | \
+ SOUND_MASK_PCM | SOUND_MASK_SYNTH | \
+ SOUND_MASK_RECLEV|SOUND_MASK_DEPTH )
+
+#define REC_DEVS (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \
+ SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_LINE)
+
+#define STEREO_DEVS (SOUND_MASK_LINE1 | SOUND_MASK_LINE | \
+ SOUND_MASK_VOLUME | \
+ SOUND_MASK_CD | SOUND_MASK_LINE | \
+ SOUND_MASK_PCM | SOUND_MASK_RECLEV)
+
+#define LEFT_CHN 0
+#define RIGHT_CHN 1
+
+static int default_mixer_levels[32] = {
+ 0x3232, /* Master Volume */
+ 0x3232, /* Bass */
+ 0x3232, /* Treble */
+ 0x4b4b, /* FM */
+ 0x3232, /* PCM */
+ 0x1515, /* PC Speaker */
+ 0x2020, /* Ext Line */
+ 0x1010, /* Mic */
+ 0x4b4b, /* CD */
+ 0x0000, /* Recording monitor */
+ 0x4b4b, /* Second PCM */
+ 0x4b4b, /* Recording level */
+ 0x4b4b, /* Input gain */
+ 0x4b4b, /* Output gain */
+ 0x2020, /* Line1 */
+ 0x2020, /* Line2 */
+ 0x1515 /* Line3 (usually line in) */
+};
+
+#define MAX_PORTC 2
+
+typedef struct vibes_portc
+{
+ int audio_dev;
+ int open_mode;
+ int channels;
+ int bits;
+ int speed;
+ int trigger_bits;
+ int audio_enabled;
+}
+vibes_portc;
+
+typedef struct vibes_devc
+{
+ oss_device_t *osdev;
+ int sb_base;
+ int enh_base;
+ int fm_base;
+ int mpu_base;
+ int game_base;
+ int dmaa_base;
+ int dmac_base;
+ int irq;
+ oss_mutex_t mutex;
+ oss_mutex_t low_mutex;
+
+ /* Mixer parameters */
+ int my_mixer;
+ int *levels;
+ int recdevs;
+
+ /* Audio parameters */
+ int audio_open_mode;
+ vibes_portc portc[MAX_PORTC];
+}
+vibes_devc;
+
+
+static int
+vibesintr (oss_device_t * osdev)
+{
+ vibes_devc *devc = (vibes_devc *) osdev->devc;
+ vibes_portc *portc;
+ unsigned char stat;
+ int serviced = 0;
+ int i;
+
+ stat = INB (devc->osdev, devc->enh_base + 0x02);
+
+ for (i = 0; i < MAX_PORTC; i++)
+ {
+ portc = &devc->portc[i];
+ if ((stat & 0x01) && (portc->trigger_bits & PCM_ENABLE_OUTPUT))
+ {
+ serviced = 1;
+ oss_audio_outputintr (portc->audio_dev, 1);
+ }
+
+ if ((stat & 0x04) && (portc->trigger_bits & PCM_ENABLE_INPUT))
+ {
+ serviced = 1;
+ oss_audio_inputintr (portc->audio_dev, 0);
+ }
+ }
+ return serviced;
+}
+
+static unsigned char
+vibes_mixer_read (vibes_devc * devc, int reg)
+{
+ oss_native_word flags;
+ unsigned char data, tmp;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ /* Select register index */
+ tmp = INB (devc->osdev, devc->enh_base + 4) & 0xc0;
+ OUTB (devc->osdev, tmp | (reg & 0x3f), devc->enh_base + 4);
+ oss_udelay (10);
+ /* Read the register */
+ data = INB (devc->osdev, devc->enh_base + 5);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+ return data;
+}
+
+static void
+vibes_mixer_write (vibes_devc * devc, int reg, unsigned char data)
+{
+ oss_native_word flags;
+ unsigned char tmp;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ /* Select register index */
+ tmp = INB (devc->osdev, devc->enh_base + 0x04) & 0xc0;
+ OUTB (devc->osdev, tmp | (reg & 0x3f), devc->enh_base + 4);
+ oss_udelay (10);
+ /* Write the register */
+ OUTB (devc->osdev, data, devc->enh_base + 0x05);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+}
+
+static int
+vibes_set_recmask (vibes_devc * devc, int mask)
+{
+ unsigned char bits = 0, tmp;
+ oss_native_word flags;
+ mask &= REC_DEVS;
+
+ if (mask & (mask - 1)) /* More than one bits selected */
+ mask = mask & (devc->recdevs ^ mask); /* Pick the one recently turned on */
+
+ switch (mask)
+ {
+ case SOUND_MASK_CD:
+ bits = 0;
+ break;
+ case SOUND_MASK_LINE2:
+ bits = 3;
+ break;
+ case SOUND_MASK_LINE:
+ bits = 4;
+ break;
+ case SOUND_MASK_LINE1:
+ bits = 5;
+ break;
+ case SOUND_MASK_MIC:
+ bits = 6;
+ break;
+
+ default: /* Unknown bit (combination) */
+ mask = SOUND_MASK_MIC;
+ bits = 6;
+ }
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ tmp = vibes_mixer_read (devc, 0x00) & 0x1f; /* Left ADC source */
+ vibes_mixer_write (devc, 0x00, tmp | (bits << 5));
+ tmp = vibes_mixer_read (devc, 0x01) & 0x1f; /* Right ADC source */
+ vibes_mixer_write (devc, 0x01, tmp | (bits << 5));
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return devc->recdevs = mask;
+}
+
+static int
+vibes_mixer_get (vibes_devc * devc, int dev)
+{
+ if (!((1 << dev) & MIXER_DEVS))
+ return OSS_EINVAL;
+
+ return devc->levels[dev];
+}
+
+static void
+set_volume (vibes_devc * devc, int reg, int level, int width)
+{
+ unsigned char tmp, bits;
+ int scale = (1 << width) - 1;
+
+ tmp = vibes_mixer_read (devc, reg) & ~(0x80 | scale);
+
+ if (level == 0)
+ bits = 0x80;
+ else
+ {
+ bits = (scale * level) / 100;
+ bits = scale - bits; /* Reverse */
+ }
+
+ vibes_mixer_write (devc, reg, tmp | bits);
+}
+
+static int
+vibes_mixer_set (vibes_devc * devc, int dev, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ switch (dev)
+ {
+ case SOUND_MIXER_LINE1:
+ set_volume (devc, 0x02, left, 5);
+ set_volume (devc, 0x03, right, 5);
+ break;
+
+ case SOUND_MIXER_CD:
+ set_volume (devc, 0x04, left, 5);
+ set_volume (devc, 0x05, right, 5);
+ break;
+
+ case SOUND_MIXER_LINE:
+ set_volume (devc, 0x06, left, 5);
+ set_volume (devc, 0x07, right, 5);
+ break;
+
+ case SOUND_MIXER_MIC:
+ set_volume (devc, 0x08, left, 4); /* Mono control with just 4 bits */
+ right = left;
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ set_volume (devc, 0x0a, left, 5);
+ set_volume (devc, 0x0b, right, 5);
+ break;
+
+ case SOUND_MIXER_LINE2:
+ set_volume (devc, 0x0c, left, 5);
+ set_volume (devc, 0x0d, right, 5);
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ set_volume (devc, 0x0e, left, 6);
+ set_volume (devc, 0x0f, right, 6);
+ break;
+
+ case SOUND_MIXER_PCM:
+ set_volume (devc, 0x10, left, 5);
+ set_volume (devc, 0x11, right, 5);
+ break;
+
+ case SOUND_MIXER_RECLEV:
+ {
+ int tmp, bits;
+
+ bits = (15 * left) / 100;
+ bits = 15 - bits; /* Reverse */
+ tmp = vibes_mixer_read (devc, 0x00) & ~15;
+ vibes_mixer_write (devc, 0x00, tmp | bits);
+
+ bits = (15 * right) / 100;
+ bits = 15 - bits; /* Reverse */
+ tmp = vibes_mixer_read (devc, 0x01) & ~15;
+ vibes_mixer_write (devc, 0x01, tmp | bits);
+ }
+ break;
+
+ case SOUND_MIXER_DEPTH:
+ set_volume (devc, 0x2c, left, 3);
+ right = left;
+ break;
+#if 0
+ case SOUND_MIXER_CENTER:
+ set_volume (devc, 0x2d, left, 3);
+ right = left;
+ break;
+#endif
+ }
+
+ value = left | (right << 8);
+
+ return devc->levels[dev] = value;
+}
+
+static void
+vibes_mixer_reset (vibes_devc * devc)
+{
+ int i;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (MIXER_DEVS & (1 << i))
+ vibes_mixer_set (devc, i, devc->levels[i]);
+ vibes_set_recmask (devc, SOUND_MASK_MIC);
+}
+
+/*ARGSUSED*/
+static int
+vibes_mixer_ioctl (int dev, int audiodev, unsigned int cmd, ioctl_arg arg)
+{
+ vibes_devc *devc = mixer_devs[dev]->devc;
+
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ int val;
+
+ if (IOC_IS_OUTPUT (cmd))
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ val = *arg;
+ return *arg = vibes_set_recmask (devc, val);
+ break;
+
+ default:
+ val = *arg;
+ return *arg = vibes_mixer_set (devc, cmd & 0xff, val);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return *arg = devc->recdevs;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *arg = MIXER_DEVS;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *arg = STEREO_DEVS;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *arg = REC_DEVS;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *arg = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default:
+ return *arg = vibes_mixer_get (devc, cmd & 0xff);
+ }
+ }
+ else
+ return OSS_EINVAL;
+}
+
+static mixer_driver_t vibes_mixer_driver = {
+ vibes_mixer_ioctl
+};
+
+static int
+vibes_audio_set_rate (int dev, int arg)
+{
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ if (arg == 0)
+ return portc->speed;
+
+ if (arg > 48000)
+ arg = 48000;
+ if (arg < 5000)
+ arg = 5000;
+ portc->speed = arg;
+ return portc->speed;
+}
+
+static short
+vibes_audio_set_channels (int dev, short arg)
+{
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ if ((arg != 1) && (arg != 2))
+ return portc->channels;
+ portc->channels = arg;
+
+ return portc->channels;
+}
+
+static unsigned int
+vibes_audio_set_format (int dev, unsigned int arg)
+{
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ if (arg == 0)
+ return portc->bits;
+
+ if (!(arg & (AFMT_U8 | AFMT_S16_LE)))
+ return portc->bits;
+ portc->bits = arg;
+
+ return portc->bits;
+}
+
+/*ARGSUSED*/
+static int
+vibes_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
+{
+ return OSS_EINVAL;
+}
+
+static void
+vibes_halt_output (int dev)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ unsigned char tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ tmp = vibes_mixer_read (devc, 0x13) & ~0x01;
+ vibes_mixer_write (devc, 0x13, tmp);
+ OUTB (devc->osdev, 0xff, devc->dmaa_base + 0x0d);
+ portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+static void
+vibes_halt_input (int dev)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ unsigned char tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ tmp = vibes_mixer_read (devc, 0x13) & ~0x02;
+ vibes_mixer_write (devc, 0x13, tmp);
+ OUTB (devc->osdev, 0xff, devc->dmac_base + 0x0d);
+ portc->trigger_bits &= ~PCM_ENABLE_INPUT;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+static void
+vibes_audio_reset (int dev)
+{
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ if (portc->open_mode & OPEN_WRITE)
+ vibes_halt_output (dev);
+ if (portc->open_mode & OPEN_READ)
+ vibes_halt_input (dev);
+}
+
+/*ARGSUSED*/
+static int
+vibes_audio_open (int dev, int mode, int open_flags)
+{
+ oss_native_word flags;
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ if (devc->audio_open_mode & mode)
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+
+ devc->audio_open_mode |= mode;
+ portc->open_mode = mode;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+static void
+vibes_audio_close (int dev, int mode)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+
+ vibes_audio_reset (dev);
+ devc->audio_open_mode &= ~mode;
+ portc->open_mode = 0;
+}
+
+/*ARGSUSED*/
+static void
+vibes_audio_output_block (int dev, oss_native_word buf, int count,
+ int fragsize, int intrflag)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ oss_native_word flags;
+ int c = fragsize - 1;
+ int dma_base = devc->dmaa_base;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ vibes_mixer_write (devc, 0x18, (c >> 8) & 0xff);
+ vibes_mixer_write (devc, 0x19, c & 0xff);
+
+ /* Setup DMA_A registers */
+ count = count - 1;
+ OUTB (devc->osdev, 0xff, dma_base + 0x0d);
+ OUTB (devc->osdev, 0x01, dma_base + 0x0f);
+ OUTB (devc->osdev, (buf) & 0xff, dma_base + 0x00);
+ OUTB (devc->osdev, (buf >> 8) & 0xff, dma_base + 0x01);
+ OUTB (devc->osdev, (buf >> 16) & 0xff, dma_base + 0x02);
+ OUTB (devc->osdev, (buf >> 24) & 0xff, dma_base + 0x03);
+ OUTB (devc->osdev, (count) & 0xff, dma_base + 0x04);
+ OUTB (devc->osdev, (count >> 8) & 0xff, dma_base + 0x05);
+ OUTB (devc->osdev, (count >> 16) & 0xff, dma_base + 0x06);
+ OUTB (devc->osdev, 0x18, dma_base + 0x0b);
+ OUTB (devc->osdev, 0x00, dma_base + 0x0f);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+/*ARGSUSED*/
+static void
+vibes_audio_start_input (int dev, oss_native_word buf, int count,
+ int fragsize, int intrflag)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ oss_native_word flags;
+ int c = (fragsize >> 1) - 1;
+ int dma_base = devc->dmac_base;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ vibes_mixer_write (devc, 0x1c, (c >> 8) & 0xff);
+ vibes_mixer_write (devc, 0x1d, c & 0xff);
+
+ /* Setup DMA_C registers */
+ count = count / 2 - 1; /* Word count */
+ OUTB (devc->osdev, 0xff, dma_base + 0x0d);
+ OUTB (devc->osdev, (buf) & 0xff, dma_base + 0x00);
+ OUTB (devc->osdev, (buf >> 8) & 0xff, dma_base + 0x01);
+ OUTB (devc->osdev, (buf >> 16) & 0xff, dma_base + 0x02);
+ OUTB (devc->osdev, (buf >> 24) & 0xff, dma_base + 0x03);
+ OUTB (devc->osdev, (count) & 0xff, dma_base + 0x04);
+ OUTB (devc->osdev, (count >> 8) & 0xff, dma_base + 0x05);
+ OUTB (devc->osdev, (count >> 16) & 0xff, dma_base + 0x06);
+ OUTB (devc->osdev, 0x14, dma_base + 0x0b);
+ OUTB (devc->osdev, 0x00, dma_base + 0x0f);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+/*ARGSUSED*/
+static void
+vibes_audio_trigger (int dev, int state)
+{
+ vibes_portc *portc = audio_engines[dev]->portc;
+ vibes_devc *devc = audio_engines[dev]->devc;
+
+ unsigned char tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ tmp = vibes_mixer_read (devc, 0x13) & ~0x07;
+ if (portc->open_mode & OPEN_WRITE)
+ {
+ tmp |= 0x01;
+ portc->trigger_bits |= PCM_ENABLE_OUTPUT;
+ }
+ if (portc->open_mode & OPEN_READ)
+ {
+ tmp |= 0x02;
+ portc->trigger_bits |= PCM_ENABLE_INPUT;
+ }
+ vibes_mixer_write (devc, 0x13, tmp);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+static void
+setup_output_rate (vibes_devc * devc, vibes_portc * portc)
+{
+ unsigned int p = portc->speed;
+
+ p = (p * 65536) / 48000;
+ p = (p - 1) & 0xffff;
+
+ if (p <= 1)
+ p = 1;
+ if (p > 0xffff)
+ p = 0xffff;
+
+ vibes_mixer_write (devc, 0x1e, (p) & 0xff);
+ vibes_mixer_write (devc, 0x1f, (p >> 8) & 0xff);
+}
+
+static void
+setup_input_rate (vibes_devc * devc, vibes_portc * portc)
+{
+ unsigned char tmp;
+
+ /* Use separate sampling rate for ADC and DAC */
+
+ tmp = vibes_mixer_read (devc, 0x22) | 0x10;
+ vibes_mixer_write (devc, 0x22, tmp); /* Use alternate sampling rate */
+ vibes_mixer_write (devc, 0x23, ((48000 / portc->speed) - 1) << 4);
+}
+
+/*ARGSUSED*/
+static int
+vibes_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+ unsigned char tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ OUTB (devc->osdev, 0x40, devc->enh_base + 0x04); /* Set MCE */
+ tmp = vibes_mixer_read (devc, 0x12) & ~0x30;
+ if (portc->channels != 1)
+ tmp |= 0x10;
+ if (portc->bits != 8)
+ tmp |= 0x20;
+ vibes_mixer_write (devc, 0x12, tmp);
+ setup_input_rate (devc, portc);
+ OUTB (devc->osdev, 0x00, devc->enh_base + 0x04); /* Clear MCE */
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+vibes_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ vibes_portc *portc = audio_engines[dev]->portc;
+ unsigned char tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ tmp = vibes_mixer_read (devc, 0x12) & ~0x03;
+ if (portc->channels != 1)
+ tmp |= 0x01;
+ if (portc->bits != 8)
+ tmp |= 0x02;
+
+ OUTB (devc->osdev, 0x40, devc->enh_base + 0x04); /* Set MCE */
+ vibes_mixer_write (devc, 0x12, tmp);
+ setup_output_rate (devc, portc);
+ OUTB (devc->osdev, 0x00, devc->enh_base + 0x04); /* Clear MCE */
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+#if 0
+static int
+vibes_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
+{
+ vibes_devc *devc = audio_engines[dev]->devc;
+ /* vibes_portc *portc = audio_engines[dev]->portc; */
+ unsigned int tmp = 0;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ if (direction == DMODE_OUTPUT)
+ {
+ tmp = INB (devc->osdev, devc->dmaa_base + 0x04);
+ tmp |= INB (devc->osdev, devc->dmaa_base + 0x05) << 8;
+ tmp |= INB (devc->osdev, devc->dmaa_base + 0x06) << 16;
+
+ tmp = dmap->bytes_in_use % tmp;
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+ return tmp;
+}
+#endif
+
+static audiodrv_t vibes_audio_driver = {
+ vibes_audio_open,
+ vibes_audio_close,
+ vibes_audio_output_block,
+ vibes_audio_start_input,
+ vibes_audio_ioctl,
+ vibes_audio_prepare_for_input,
+ vibes_audio_prepare_for_output,
+ vibes_audio_reset,
+ NULL,
+ NULL,
+ vibes_halt_input,
+ vibes_halt_output,
+ vibes_audio_trigger,
+ vibes_audio_set_rate,
+ vibes_audio_set_format,
+ vibes_audio_set_channels,
+ NULL,
+ NULL,
+ NULL, /* vibes_check_input, */
+ NULL, /* vibes_check_output, */
+ NULL, /*vibes_alloc_buffer, */
+ NULL, /* vibes_free_buffer, */
+ NULL,
+ NULL,
+ NULL /* vibes_get_buffer_pointer */
+};
+
+static int
+init_vibes (vibes_devc * devc)
+{
+ int my_mixer, adev;
+ int i;
+ unsigned char tmp;
+ vibes_portc *portc;
+
+
+ /* Setup CM00 */
+ tmp = INB (devc->osdev, devc->enh_base + 0x00);
+ OUTB (devc->osdev, tmp | 0x01, devc->enh_base + 0x00); /* Enhanced mode on */
+
+ my_mixer = 0;
+ if ((my_mixer = oss_install_mixer (OSS_MIXER_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ "S3 SonicVibes",
+ &vibes_mixer_driver,
+ sizeof (mixer_driver_t), devc)) < 0)
+ {
+ my_mixer = -1;
+ return 0;
+ }
+ else
+ {
+ devc->my_mixer = my_mixer;
+ devc->recdevs = 0;
+ vibes_set_recmask (devc, SOUND_MASK_MIC);
+ devc->levels = load_mixer_volumes ("S3VIBES", default_mixer_levels, 1);
+ vibes_mixer_reset (devc);
+ }
+
+ for (i = 0; i < MAX_PORTC; i++)
+ {
+ int flags = ADEV_AUTOMODE | ADEV_DUPLEX;
+
+ portc = &devc->portc[i];
+
+ if (i > 0)
+ flags |= ADEV_SHADOW;
+
+ if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ "S3 SonicVibes",
+ &vibes_audio_driver,
+ sizeof (audiodrv_t),
+ flags,
+ AFMT_U8 | AFMT_S16_LE, devc, -1)) < 0)
+ {
+ return 0;
+ }
+
+ audio_engines[adev]->mixer_dev = devc->my_mixer;
+ audio_engines[adev]->portc = portc;
+ audio_engines[adev]->dmabuf_maxaddr = MEMLIMIT_ISA;
+ portc->open_mode = 0;
+ portc->channels = 1;
+ portc->bits = 8;
+ portc->audio_dev = adev;
+ portc->open_mode = 0;
+ portc->trigger_bits = 0;
+ portc->audio_enabled = 0;
+#ifdef CONFIG_OSS_VMIX
+ if (i == 0)
+ vmix_attach_audiodev(devc->osdev, adev, -1, 0);
+#endif
+ }
+ return 1;
+}
+
+int
+oss_s3vibes_attach (oss_device_t * osdev)
+{
+ unsigned int dmaa_base, dmac_base;
+ unsigned char pci_irq_line, pci_revision;
+ unsigned short pci_command, vendor, device;
+ unsigned int pci_ioaddr0, pci_ioaddr1, pci_ioaddr2, pci_ioaddr3,
+ pci_ioaddr4;
+ vibes_devc *devc;
+
+ DDB (cmn_err (CE_WARN, "Entered S3 SonicVibes probe routine\n"));
+
+ pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
+ pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
+ pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
+ pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr0);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
+ pci_read_config_dword (osdev, 0x40, &dmaa_base);
+ pci_read_config_dword (osdev, 0x48, &dmac_base);
+
+ if (vendor != S3_VENDOR_ID || device != S3_SONICVIBES)
+ return 0;
+
+ if (pci_ioaddr0 == 0)
+ {
+ cmn_err (CE_WARN, "I/O address not assigned by BIOS.\n");
+ return 0;
+ }
+
+ if (pci_irq_line == 0)
+ {
+ cmn_err (CE_WARN, "IRQ not assigned by BIOS (%d).\n", pci_irq_line);
+ return 0;
+ }
+
+ if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
+ {
+ cmn_err (CE_WARN, "Out of memory\n");
+ return 0;
+ }
+
+ devc->osdev = osdev;
+ osdev->devc = devc;
+ devc->irq = pci_irq_line;
+
+ devc->sb_base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr0);
+ devc->enh_base = MAP_PCI_IOADDR (devc->osdev, 1, pci_ioaddr1);
+ devc->fm_base = MAP_PCI_IOADDR (devc->osdev, 2, pci_ioaddr2);
+ devc->mpu_base = MAP_PCI_IOADDR (devc->osdev, 3, pci_ioaddr3);
+ devc->game_base = MAP_PCI_IOADDR (devc->osdev, 4, pci_ioaddr4);
+
+ /* Remove I/O space marker in bit 0. */
+ devc->sb_base &= ~3;
+ devc->enh_base &= ~3;
+ devc->fm_base &= ~3;
+ devc->mpu_base &= ~3;
+ devc->game_base &= ~3;
+
+ DDB (cmn_err (CE_WARN, "SB compatibility base %04x\n", devc->sb_base));
+ DDB (cmn_err (CE_WARN, "Enhanced base %04x\n", devc->enh_base));
+ DDB (cmn_err (CE_WARN, "FM base %04x\n", devc->fm_base));
+ DDB (cmn_err (CE_WARN, "MIDI base %04x\n", devc->mpu_base));
+ DDB (cmn_err (CE_WARN, "Game port base %04x\n", devc->game_base));
+ DDB (cmn_err (CE_WARN, "DMA_A port base %04x\n", dmaa_base));
+ DDB (cmn_err (CE_WARN, "DMA_C port base %04x\n", dmac_base));
+
+ dmaa_base = (dmaa_base & 0x000f) + devc->sb_base;
+ dmac_base = (dmac_base & 0x000f) + devc->sb_base + 16;
+
+ dmaa_base |= 0x09; /* Enable. Allow 32 bit addressing */
+ dmac_base |= 0x01; /* Enable */
+
+ pci_write_config_dword (osdev, 0x40, dmaa_base);
+ pci_write_config_dword (osdev, 0x48, dmac_base);
+ DDB (cmn_err (CE_WARN, "DMA_A port base relocated to %04x\n", dmaa_base));
+ DDB (cmn_err (CE_WARN, "DMA_C port base relocated to %04x\n", dmac_base));
+
+ devc->dmaa_base = dmaa_base & ~0x000f;
+ devc->dmac_base = dmac_base & ~0x000f;
+
+ pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ pci_write_config_word (osdev, PCI_COMMAND, pci_command);
+
+ MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
+ MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1);
+
+ oss_register_device (osdev, "S3 Sonic Vibes");
+
+ if (oss_register_interrupts (devc->osdev, 0, vibesintr, NULL) < 0)
+ {
+ cmn_err (CE_WARN, "Can't allocate IRQ%d\n", pci_irq_line);
+ return 0;
+ }
+
+ return init_vibes (devc); /* Detected */
+}
+
+int
+oss_s3vibes_detach (oss_device_t * osdev)
+{
+ vibes_devc *devc = (vibes_devc *) osdev->devc;
+
+ if (oss_disable_device (osdev) < 0)
+ return 0;
+
+ oss_unregister_interrupts (devc->osdev);
+
+ MUTEX_CLEANUP (devc->mutex);
+ MUTEX_CLEANUP (devc->low_mutex);
+ UNMAP_PCI_IOADDR (devc->osdev, 0);
+ UNMAP_PCI_IOADDR (devc->osdev, 1);
+ UNMAP_PCI_IOADDR (devc->osdev, 2);
+ UNMAP_PCI_IOADDR (devc->osdev, 3);
+ UNMAP_PCI_IOADDR (devc->osdev, 4);
+
+ oss_unregister_device (devc->osdev);
+ return 1;
+
+}
diff --git a/attic/drv/oss_s3vibes/oss_s3vibes.man b/attic/drv/oss_s3vibes/oss_s3vibes.man
new file mode 100644
index 0000000..9949d94
--- /dev/null
+++ b/attic/drv/oss_s3vibes/oss_s3vibes.man
@@ -0,0 +1,19 @@
+NAME
+oss_s3vibes - S3 Sonic Vibes audio driver
+
+DESCRIPTION
+Open Sound System driver for S3 Sonic Vibes audio controller.
+S3Vibes device characteristics:
+ o 8/16 bit playback/record
+ o mono/stereo playback/recording
+ o 8KHz to 44.1Khz sample rate.
+
+OPTIONS
+None
+
+FILES
+CONFIGFILEPATH/oss_s3vibes.conf Device configuration file
+
+AUTHOR
+4Front Technologies
+