diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /attic/drv/oss_s3vibes | |
download | oss4-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/.config | 1 | ||||
-rw-r--r-- | attic/drv/oss_s3vibes/.devices | 1 | ||||
-rw-r--r-- | attic/drv/oss_s3vibes/.name | 1 | ||||
-rw-r--r-- | attic/drv/oss_s3vibes/oss_s3vibes.c | 931 | ||||
-rw-r--r-- | attic/drv/oss_s3vibes/oss_s3vibes.man | 19 |
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 + |