From 0de88b4ec377e3929ed43c78ca3c34c6292171d7 Mon Sep 17 00:00:00 2001 From: deraadt Date: Sat, 4 May 1996 13:29:31 +0000 Subject: [PATCH] Driver for Aria-based sound cards; netbsd pr#2122; from roland@imrryr.org --- share/man/man4/man4.i386/Makefile | 4 +- share/man/man4/man4.i386/aria.4 | 83 ++ sys/dev/isa/aria.c | 1766 +++++++++++++++++++++++++++++ sys/dev/isa/ariareg.h | 138 +++ sys/dev/isa/files.isa | 9 +- 5 files changed, 1997 insertions(+), 3 deletions(-) create mode 100644 share/man/man4/man4.i386/aria.4 create mode 100644 sys/dev/isa/aria.c create mode 100644 sys/dev/isa/ariareg.h diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index 21def2659db..d8546921f46 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.5 1996/04/19 05:48:09 mickey Exp $ +# $OpenBSD: Makefile,v 1.6 1996/05/04 13:29:44 deraadt Exp $ # from: @(#)Makefile 5.1 (Berkeley) 2/12/91 # Id: Makefile,v 1.4 1995/12/14 05:41:38 deraadt Exp $ -MAN= intro.4 aha.4 ahb.4 aic.4 ast.4 autoconf.4 boca.4 bt.4 +MAN= intro.4 aha.4 ahb.4 aic.4 aria.4 ast.4 autoconf.4 boca.4 bt.4 MAN+= com.4 cy.4 ed.4 ep.4 lms.4 lpt.4 mcd.4 mem.4 mms.4 ncr.4 npx.4 pms.4 MAN+= rtfps.4 scd.4 sea.4 speaker.4 uha.4 wd.4 MAN+= eg.4 el.4 ie.4 joy.4 le.4 wt.4 diff --git a/share/man/man4/man4.i386/aria.4 b/share/man/man4/man4.i386/aria.4 new file mode 100644 index 00000000000..2a17fac542b --- /dev/null +++ b/share/man/man4/man4.i386/aria.4 @@ -0,0 +1,83 @@ +.\" $OpenBSD: aria.4,v 1.1 1996/05/04 13:29:46 deraadt Exp $ +.\" aria.4 +.\" Copyright (c) 1996 Roland C. Dowdeswell +.\" All rights reserved. +.\" +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Roland C. Dowdeswell. +.\" 4. The name of the authors may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 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. +.\" +.\" +.Dd January 21, 1996 +.Dt ARIA 4 i386 +.Os +.Sh NAME +.Nm aria +.Nd +Aria 16 device driver +.Sh SYNOPSIS +.Cd "aria0 at isa? port 0xPPP irq X drq Y flags Z" +.Sh DESCRIPTION +The +.Nm aria +driver provides support for sound cards based on Sierra Semiconductor's +Aria chipset. Cards based on this chipset are capable of recording and +play 8- or 16-bit samples in mono or stereo up to 44.1KHz. Some chipsets +only play linear or ADCPM, but others will also play Mu-law and A-law +sounds. Three different mixer configurations are available. +.Pp +The I/O Port Base is selected from 0x280, 0x290, 0x2a0 and 0x2b0. The +selection method depends on the board. The Aria takes 8 ports. +.Pp +The IRQ is selected from 10, 11, or 12. +.Pp +The DRQ line is chosen from 5 or 6, this driver will work with or without +a DRQ. If no DRQ is given, then the +.Nm aria +driver will simply use Direct I/O. +.Pp +The flags currently supported are 0x1, for the Prometheus Aria 16/Aria 16se. +This flag tells the driver to initialise the card. It is a weird undocumented +piece of horribleness, but the card will not respond until you twiddle with +the joystick port... +.Sh BUGS +The driver has only been tested on a Prometheus Aria 16. +.Pp +No DMA support, yet, so don't bother setting a DRQ. +.Pp +The full-duplex features are horribly inconsistent. (i.e. unusable.) +.Pp +The card sometimes drops out, and needs to be reset. This can be +accomplished by opening and closing /dev/audio, e.g. + echo -n >/dev/audio +.Pp +The joystick and MIDI port interfaces are not supported. +.Sh SEE ALSO +.Xr audio 4 +.Sh HISTORY +The +.Nm aria +device driver appeared in +.Nx 1.1 . diff --git a/sys/dev/isa/aria.c b/sys/dev/isa/aria.c new file mode 100644 index 00000000000..d8e514cca20 --- /dev/null +++ b/sys/dev/isa/aria.c @@ -0,0 +1,1766 @@ +/* $OpenBSD: aria.c,v 1.1 1996/05/04 13:29:32 deraadt Exp $ */ + +/* + * Copyright (c) 1995, 1996 Roland C. Dowdeswell. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Roland C. Dowdeswell. + * 4. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * TODO: + * o Test the driver on cards other than a single + * Prometheus Aria 16. + * o Look into where aria_prometheus_kludge() belongs. + * o Add some dma code. It accomplishes its goal by + * direct IO at the moment. + * o Look into return values on aria_set_sr(), if there is + * no matching rate. (I think that this behaves in the + * same way as sbdsp.c) + * o Different programs should be able to open the device + * with O_RDONLY and O_WRONLY at the same time. But I + * do not see support for this in /sys/dev/audio.c, so + * I cannot effectively code it. + * o Separate the debugging code, with a #define. + * Write more into aria_printsc(). + * o Rework the mixer interface. + * o Deal with the lvls better. We need to do better mapping + * between logarithmic scales and the one byte that + * we are passed. + * o Deal better with cards that have no mixer. + */ + +#include "aria.h" +#if NARIA > 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#define FREAD 1 +#define FWRITE 2 + +#ifdef AUDIO_DEBUG +extern void Dprintf __P((const char *, ...)); +#define DPRINTF(x) if (ariadebug) Dprintf x +int ariadebug = 0; +#else +#define DPRINTF(x) +#endif + +struct aria_mixdev_info { + u_char num_channels; + u_char level[2]; + u_char mute; +}; + +struct aria_mixmaster { + u_char num_channels; + u_char level[2]; + u_char treble[2]; + u_char bass[2]; +}; + +struct aria_softc { + struct device sc_dev; /* base device */ + struct isadev sc_id; /* ISA device */ + void *sc_ih; /* interrupt vectoring */ + + u_short sc_iobase; /* I/O port base address */ + u_short sc_irq; /* interrupt */ + u_short sc_drq; /* dma chan */ + + u_short sc_open; /* reference count of open calls */ + u_short sc_play; /* non-paused play chans 2**chan */ + u_short sc_record; /* non-paused record chans 2**chan */ + u_short sc_change; /* to keep track of changes of a type */ + u_short gain[2]; /* left/right gain (play) */ + u_int spkr_state; /* non-null is on */ + + u_long sc_rate; /* Sample rate for input and output */ + u_int encoding; /* audio encoding -- ulaw/linear */ + int sc_chans; /* # of channels */ + int sc_precision; /* # bits per sample */ + + u_long sc_interrupts; /* number of interrupts taken */ + void (*sc_rintr)(void*); /* record transfer completion intr handler */ + void (*sc_pintr)(void*); /* play transfer completion intr handler */ + void *sc_rarg; /* arg for sc_rintr() */ + void *sc_parg; /* arg for sc_pintr() */ + + int sc_blocksize; /* literal dio block size */ + void *sc_rdiobuffer; /* record: where the next samples should be */ + void *sc_pdiobuffer; /* play: where the next samples are */ + + u_short sc_hardware; /* bit field of hardware present */ +#define ARIA_TELEPHONE 0x0001 /* has telephone input */ +#define ARIA_MIXER 0x0002 /* has SC18075 digital mixer */ +#define ARIA_MODEL 0x0004 /* is SC18025 (=0) or SC18026 (=1) */ + + struct aria_mixdev_info aria_mix[6]; + struct aria_mixmaster ariamix_master; + u_char aria_mix_source; +}; + +struct { + int sendcmd; + int wmidi; +} ariaerr; + + + +int ariaprobe(); +void ariaattach __P((struct device *, struct device *, void *)); +void ariaclose __P((void *)); +int ariaopen __P((dev_t, int)); +int aria_getdev __P((void *, struct audio_device *)); + +void aria_do_kludge __P((u_short, u_short, u_short, u_short, u_short)); +void aria_prometheus_kludge __P((struct isa_attach_args *)); + +int aria_set_sr __P((void *, u_long)); +u_long aria_get_sr __P((void *)); +int aria_query_encoding __P((void *, struct audio_encoding *)); +int aria_set_encoding __P((void *, u_int)); +int aria_get_encoding __P((void *)); +int aria_set_precision __P((void *, u_int)); +int aria_get_precision __P((void *)); +int aria_set_channels __P((void *, int)); +int aria_get_channels __P((void *)); +int aria_round_blocksize __P((void *, int)); +int aria_set_out_port __P((void *, int)); +int aria_get_out_port __P((void *)); +int aria_set_in_port __P((void *, int)); +int aria_get_in_port __P((void *)); +int aria_speaker_ctl __P((void *, int)); +int aria_commit_settings __P((void *)); + +int aria_start_output __P((void *, void *, int, void (*)(), void*)); +int aria_start_input __P((void *, void *, int, void (*)(), void*)); + +int aria_halt_input __P((void *)); +int aria_halt_output __P((void *)); +int aria_cont __P((void *)); + +u_int aria_get_silence __P((int)); + +int aria_sendcmd __P((u_short, u_short, int, int, int)); + +u_short aria_getdspmem __P((u_short, u_short)); +u_short aria_putdspmem __P((u_short, u_short, u_short)); + +int aria_intr __P((void *)); +short ariaversion __P((struct aria_softc *)); + +int aria_setfd __P((void *, int)); + +void aria_mix_write __P((struct aria_softc *, int, int)); +int aria_mix_read __P((struct aria_softc *, int)); + +int aria_mixer_set_port __P((void *, mixer_ctrl_t *)); +int aria_mixer_get_port __P((void *, mixer_ctrl_t *)); +int aria_mixer_query_devinfo __P((void *, mixer_devinfo_t *)); + +/* + * Mixer defines... + */ + +struct cfattach aria_ca = { + sizeof(struct aria_softc), ariaprobe, ariaattach +}; + +struct cfdriver aria_cd = { + NULL, "aria", DV_DULL +}; + +struct audio_device aria_device = { + "Aria 16(se)", + "x", + "aria" +}; + +/* + * Define our interface to the higher level audio driver. + */ + +struct audio_hw_if aria_hw_if = { + ariaopen, + ariaclose, + NULL, + aria_set_sr, + aria_get_sr, + aria_set_sr, + aria_get_sr, + aria_query_encoding, + aria_set_encoding, + aria_get_encoding, + aria_set_precision, + aria_get_precision, + aria_set_channels, + aria_get_channels, + aria_round_blocksize, + aria_set_out_port, + aria_get_out_port, + aria_set_in_port, + aria_get_in_port, + aria_commit_settings, + aria_get_silence, + mulaw_expand, + mulaw_compress, + aria_start_output, + aria_start_input, + aria_halt_input, + aria_halt_output, + aria_cont, + aria_cont, + aria_speaker_ctl, + aria_getdev, + aria_setfd, + aria_mixer_set_port, + aria_mixer_get_port, + aria_mixer_query_devinfo, + 1, /* full-duplex */ + 0 +}; + +/* + * Probe / attach routines. + */ + +/* + * Probe for the aria hardware. + */ +int +ariaprobe(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + register struct aria_softc *sc = (void *)self; + register struct isa_attach_args *ia = aux; + struct cfdata *cf = sc->sc_dev.dv_cfdata; + register u_short iobase = ia->ia_iobase; + static u_char irq_conf[11] = { + -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08 + }; + int i,j; + int flags = cf->cf_flags; + + if (!ARIA_BASE_VALID(ia->ia_iobase)) { + printf("aria: configured iobase %d invalid\n", ia->ia_iobase); + return 0; + } + sc->sc_iobase = iobase; + + if (!ARIA_IRQ_VALID(ia->ia_irq)) { + printf("aria: configured irq %d invalid\n", ia->ia_irq); + return 0; + } + + sc->sc_irq = ia->ia_irq; + + if (flags & ARIAR_PROMETHEUS_KLUDGE) + aria_prometheus_kludge(ia); + + if (aria_reset(sc) != 0) { + DPRINTF(("aria: aria probe failed\n")); + return 0; + } + + ia->ia_iosize = ARIADSP_NPORT; + return 1; +} + + + +/* + * I didn't call this a kludge for + * nothing. This is cribbed from + * ariainit, the author of that + * disassembled some code to discover + * how to set up the initial values of + * the card. Without this, the card + * is dead. (It will not respond to _any_ + * input at all.) + * + * ariainit can be found (ftp) at: + * ftp://ftp.wi.leidenuniv.nl/pub/audio/aria/programming/contrib/ariainit.zip + * currently. + */ + +void +aria_prometheus_kludge(ia) + register struct isa_attach_args *ia; +{ + int i, j; + u_short end; + u_short rba = ia->ia_iobase; + + DPRINTF(("aria_prometheus_kludge\n")); + +/* Begin Config Sequence */ + + outb(0x204, 0x4c); + outb(0x205, 0x42); + outb(0x206, 0x00); + outw(0x200, 0x0f); + outb(0x201, 0x00); + outw(0x200, 0x02); + outb(0x201, rba>>2); + +/* These next three lines set up the iobase, and the irq; and disable the drq. */ + + aria_do_kludge(0x111, ((ia->ia_iobase-0x280)>>2)+0xA0, 0xbf, 0xa0, rba); + aria_do_kludge(0x011, ia->ia_irq-6, 0xf8, 0x00, rba); + aria_do_kludge(0x011, 0x00, 0xef, 0x00, rba); + +/* The rest of these lines just disable everything else */ + + aria_do_kludge(0x113, 0x00, 0x88, 0x00, rba); + aria_do_kludge(0x013, 0x00, 0xf8, 0x00, rba); + aria_do_kludge(0x013, 0x00, 0xef, 0x00, rba); + aria_do_kludge(0x117, 0x00, 0x88, 0x00, rba); + aria_do_kludge(0x017, 0x00, 0xff, 0x00, rba); + +/* End Sequence */ + + outb(0x200, 0x0f); + end = inb(rba); + outw(0x200, 0x0f); + outb(0x201, end|0x80); + inb(0x200); +/* + * This delay is necessary for some reason, + * at least it would crash, and sometimes not + * probe properly if it did not exist. + */ + delay(1000000); +} + +void +aria_do_kludge(func, bits, and, or, rba) + u_short func; + u_short bits; + u_short and; + u_short or; + u_short rba; +{ + u_int i; + if (func & 0x100) { + func &= ~0x100; + if (bits) { + outw(0x200, func-1); + outb(0x201, bits); + } + } else + or |= bits; + + outb(0x200, func); + i = inb(rba); + outw(0x200, func); + outb(0x201, (i&and) | or); +} + +#ifdef NEWCONFIG +void +ariaforceintr(aux) + void *aux; +{ + struct isa_attach_args *ia = aux; + u_short iobase = ia->ia_iobase; + + (void)aria_sendcmd(iobase, ARIADSPC_FORCEINTR, -1, -1, -1); +} +#endif + +/* + * Attach hardware to driver, attach hardware driver to audio + * pseudo-device driver. + */ +void +ariaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + register struct aria_softc *sc = (struct aria_softc *)self; + struct isa_attach_args *ia = (struct isa_attach_args *)aux; + register u_short iobase = ia->ia_iobase; + register u_short i; + int err; + + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_AUDIO, aria_intr, sc, sc->sc_dev.dv_xname); + + i = aria_getdspmem(iobase, ARIAA_HARDWARE_A); + + sc->sc_hardware = 0; + sc->sc_hardware |= ((i>>13)&0x01==1)?ARIA_TELEPHONE:0; + sc->sc_hardware |= (((i>>5)&0x07)==0x04)?ARIA_MIXER:0; + sc->sc_hardware |= (aria_getdspmem(iobase, ARIAA_MODEL_A)==1)?ARIA_MODEL:0; + + sc->sc_open = 0; + sc->sc_play = 0; + sc->sc_record = 0; + sc->sc_rate = 7875; + sc->sc_chans = 1; + sc->sc_change = 1; + sc->sc_blocksize = 1024; + sc->sc_precision = 8; + sc->sc_rintr = 0; + sc->sc_rarg = 0; + sc->sc_pintr = 0; + sc->sc_parg = 0; + sc->gain[0] = 127; + sc->gain[1] = 127; + + for (i=0; i<6; i++) { + if (i == ARIAMIX_TEL_LVL) + sc->aria_mix[i].num_channels = 1; + else + sc->aria_mix[i].num_channels = 2; + sc->aria_mix[i].level[0] = 127; + sc->aria_mix[i].level[1] = 127; + } + + sc->ariamix_master.num_channels = 2; + sc->ariamix_master.level[0] = 222; + sc->ariamix_master.level[1] = 222; + sc->ariamix_master.bass[0] = 127; + sc->ariamix_master.bass[1] = 127; + sc->ariamix_master.treble[0] = 127; + sc->ariamix_master.treble[1] = 127; + sc->aria_mix_source = 0; + + sc->sc_change = 1; + aria_commit_settings(sc); /* so that my cdplayer is at the 'right' vol */ + + printf(": dsp %s", (ARIA_MODEL&sc->sc_hardware)?"SC18026":"SC18025"); + if (ARIA_TELEPHONE&sc->sc_hardware) + printf(", tel"); + if (ARIA_MIXER&sc->sc_hardware) + printf(", SC18075 mixer"); + printf("\n"); + + sprintf(aria_device.version, "%s", (ARIA_MODEL&sc->sc_hardware?"SC18026":"SC18025")); + + if ((err = audio_hardware_attach(&aria_hw_if, sc)) != 0) + printf("aria: could not attach to audio pseudo-device driver (%d)\n", err); +} + +/* + * Various routines to interface to higher level audio driver + */ + +int +ariaopen(dev, flags) + dev_t dev; + int flags; +{ + struct aria_softc *sc; + register u_short iobase = sc->sc_iobase; + int unit = AUDIOUNIT(dev); + short err; + + DPRINTF(("ariaopen() called\n")); + + if (unit >= aria_cd.cd_ndevs) + return ENODEV; + + sc = aria_cd.cd_devs[unit]; + + if (!sc || sc->sc_open != 0) + return ENXIO; + + sc->sc_open = 0; + if (flags&FREAD) + sc->sc_open |= ARIAR_OPEN_RECORD; + if (flags&FWRITE) + sc->sc_open |= ARIAR_OPEN_PLAY; + sc->sc_play = 0; + sc->sc_record= 0; + sc->sc_rintr = 0; + sc->sc_rarg = 0; + sc->sc_pintr = 0; + sc->sc_parg = 0; + sc->sc_change= 1; + + return 0; +} + +int +aria_getdev(addr, retp) + void *addr; + struct audio_device *retp; +{ + *retp = aria_device; + return 0; +} + +#ifdef AUDIO_DEBUG +void +aria_printsc(struct aria_softc *sc) +{ + printf("open %x dmachan %d irq %d iobase %x nintr %d\n", sc->sc_open, sc->sc_drq, + sc->sc_irq, sc->sc_iobase, sc->sc_interrupts); + printf("irate %d encoding %x chans %d\n", sc->sc_rate, sc->encoding, + sc->sc_chans); + printf("\n"); +} +#endif + + +/* + * Various routines to interface to higher level audio driver + */ + +int +aria_set_sr(addr, sr) + void *addr; + u_long sr; +{ + struct aria_softc *sc = addr; + + if (sr<=9000) + sr = 7875; + else if (sr<=15000) + sr = 11025; + else if (sr<=20000) + sr = 15750; + else if (sr<=25000) + sr = 22050; + else if (sr<=40000) + sr = 31500; + else + sr = 44100; + + sc->sc_rate = sr; + return 0; +} + +u_long +aria_get_sr(addr) + void *addr; +{ + struct aria_softc *sc = addr; + return sc->sc_rate; +} + +int +aria_query_encoding(addr, fp) + void *addr; + struct audio_encoding *fp; +{ + register struct aria_softc *sc = addr; + + switch (fp->index) { + case 0: + strcpy(fp->name, AudioEmulaw); + fp->format_id = AUDIO_ENCODING_ULAW; + break; + case 1: + strcpy(fp->name, AudioEpcm16); + fp->format_id = AUDIO_ENCODING_PCM16; + break; + default: + return(EINVAL); + /*NOTREACHED*/ + } + + return (0); +} + +int +aria_set_encoding(addr, enc) + void *addr; + u_int enc; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_set_encoding\n")); + + switch(enc){ + case AUDIO_ENCODING_ULAW: + sc->encoding = AUDIO_ENCODING_ULAW; + break; + case AUDIO_ENCODING_LINEAR: + sc->encoding = AUDIO_ENCODING_LINEAR; + break; + default: + return (EINVAL); + } + return (0); +} + +int +aria_get_encoding(addr) + void *addr; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_get_encoding\n")); + + return(sc->encoding); +} + +int +aria_set_precision(addr, prec) + void *addr; + u_int prec; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_set_precision\n")); + + if (prec!=8 && prec!=16) + return EINVAL; + + if (sc->encoding!=AUDIO_ENCODING_PCM16 && prec==16) + return EINVAL; + + sc->sc_precision = prec; + return(0); +} + +int +aria_get_precision(addr) + void *addr; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_get_precision\n")); + + return sc->sc_precision; +} + +int +aria_set_channels(addr, chans) + void *addr; + int chans; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_set_channels\n")); + + if (chans != 1 && chans != 2) + return EINVAL; + + sc->sc_chans = chans; + + return(0); +} + +int +aria_get_channels(addr) + void *addr; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_get_channels\n")); + + return sc->sc_chans; +} + +/* + * There is only one way to output on + * this card. + */ +int +aria_set_out_port(addr, port) + void *addr; + int port; +{ + DPRINTF(("aria_set_out_port\n")); + return(0); +} + +int +aria_get_out_port(addr) + void *addr; +{ + DPRINTF(("aria_get_out_port\n")); + return(ARIAMIX_OUT_LVL); +} + + +int +aria_set_in_port(addr, port) + void *addr; + int port; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_set_in_port\n")); + + if (port<0 || port>6) + return ENXIO; + + sc->aria_mix_source = port; + return(0); +} + +int +aria_get_in_port(addr) + void *addr; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_get_in_port\n")); + + return(sc->aria_mix_source); +} + +/* + * XXX -- to be done + * I should probably just add a mixer thing, and + * access it through here. + */ +int +aria_speaker_ctl(addr, newstate) + void *addr; + int newstate; +{ + return(0); +} + +/* + * Store blocksize in words (what the chipset + * understands), but report and take values + * in bytes. + */ + +int +aria_round_blocksize(addr, blk) + void *addr; + int blk; +{ + int i; + struct aria_softc *sc = addr; + for (i=64; i<1024; i*=2) + if (blk <= i) + break; + sc->sc_blocksize = i; + sc->sc_change = 1; + return(i); +} + +/* + * This is where all of the twiddling goes on. + */ + +int +aria_commit_settings(addr) + void *addr; +{ + struct aria_softc *sc = addr; + register u_short iobase = sc->sc_iobase; + u_char tones[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 }; + u_short format; + u_short left, right; + u_short samp; + u_char i; + + DPRINTF(("aria_commit_settings\n")); + + switch (sc->sc_rate) { + case 7875: format = 0x00; samp = 0x60; break; + case 11025: format = 0x00; samp = 0x40; break; + case 15750: format = 0x10; samp = 0x60; break; + case 22050: format = 0x10; samp = 0x40; break; + case 31500: format = 0x10; samp = 0x20; break; + case 44100: format = 0x20; samp = 0x00; break; + default: format = 0x00; samp = 0x40; break; + } + + format |= (sc->sc_chans==2)?1:0; + format |= (sc->sc_precision==16)?2:0; + + aria_sendcmd(iobase, ARIADSPC_FORMAT, format, -1, -1); + outw(iobase+ARIADSP_CONTROL, (inw(iobase+ARIADSP_STATUS)&~0x60)|samp); /* Addition parm for sample rate */ + + if (sc->sc_hardware&ARIA_MIXER) { + for (i=0; i<6; i++) { + u_char source; + switch(i) { + case ARIAMIX_MIC_LVL: source = 0x0001; break; + case ARIAMIX_CD_LVL: source = 0x0002; break; + case ARIAMIX_LINE_IN_LVL: source = 0x0008; break; + case ARIAMIX_TEL_LVL: source = 0x0020; break; + case ARIAMIX_AUX_LVL: source = 0x0010; break; + case ARIAMIX_DAC_LVL: source = 0x0004; break; + default: source = 0x0000; break; + } + + if (source != 0x0000 && source != 0x0004) { + if (sc->aria_mix[i].mute == 1) + aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, 3, -1); + else + aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, (sc->aria_mix[i].num_channels==2)?0:1, -1); + + aria_sendcmd(iobase, ARIADSPC_INPMONMODE, 0x8000|source, (sc->aria_mix[i].num_channels==2)?0:1, -1); + aria_sendcmd(iobase, ARIADSPC_MIXERVOL, source, sc->aria_mix[i].level[0] << 7, sc->aria_mix[i].level[1] << 7); + } + + if (sc->aria_mix_source == i) { + aria_sendcmd(iobase, ARIADSPC_ADCSOURCE, source, -1, -1); + + if (sc->sc_open & ARIAR_OPEN_RECORD) + aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 1, -1, -1); + else + aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 0, -1, -1); + } + } + + if (sc->sc_chans==2) { + aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, (sc->gain[0]+sc->gain[1])/2, -1, -1); + aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, (sc->gain[0]-sc->gain[1])/4+0x40, -1, -1); + } else { + aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, sc->gain[0], -1, -1); + aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, 0x40, -1, -1); + } + + /* aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1 | (1<<8), -1, -1); */ + aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1, -1, -1); + + aria_sendcmd(iobase, ARIADSPC_MIXERVOL, 0x0004, sc->ariamix_master.level[0] << 7, sc->ariamix_master.level[1] << 7); + + /* Convert treb/bass from byte to soundcard style */ + + left = tones[(sc->ariamix_master.bass[0]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[0]>>4)&0x0f]; + right = tones[(sc->ariamix_master.bass[1]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[1]>>4)&0x0f]; + + aria_sendcmd(iobase, ARIADSPC_TONE, left, right, -1); + } + + if (sc->sc_change != 0) + aria_sendcmd(iobase, ARIADSPC_BLOCKSIZE, sc->sc_blocksize/2, -1, -1); + +/* + * If we think that the card is recording or playing, start it up again here. + * Some of the previous commands turn the channels off. + */ + + if (sc->sc_record&(1<sc_play |= (1<sc_play&(1<sc_play |= (1<sc_change = 0; + + return(0); +} + +void +ariaclose(addr) + void *addr; +{ + struct aria_softc *sc = addr; + register u_int iobase = sc->sc_iobase; + + DPRINTF(("aria_close sc=0x%x\n", sc)); + + sc->spkr_state = SPKR_OFF; + sc->sc_rintr = 0; + sc->sc_pintr = 0; + sc->sc_rdiobuffer = 0; + sc->sc_pdiobuffer = 0; + + if (sc->sc_play&(1<sc_open & ARIAR_OPEN_PLAY) { + aria_sendcmd(iobase, ARIADSPC_STOP_PLAY, ARIAR_PLAY_CHAN, -1, -1); + sc->sc_play &= ~(1<sc_record&(1<sc_open & ARIAR_OPEN_RECORD) { + aria_sendcmd(iobase, ARIADSPC_STOP_REC, ARIAR_RECORD_CHAN, -1, -1); + sc->sc_record &= ~(1<sc_open = 0; + + if (aria_reset(sc) != 0) { + delay(500); + aria_reset(sc); + } +} + +/* + * Reset the hardware. + */ + +int +aria_reset(sc) + register struct aria_softc *sc; +{ + register u_short iobase = sc->sc_iobase; + int fail=0; + + outw(iobase + ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR); + aria_putdspmem(iobase, 0x6102, 0); + + fail |= aria_sendcmd(iobase, ARIADSPC_SYSINIT, 0x0000, 0x0000, 0x0000); + + while (aria_getdspmem(iobase, ARIAA_TASK_A) != 1) + ; + + outw(iobase+ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR|ARIAR_PCINTWR); + fail |= aria_sendcmd(iobase, ARIADSPC_MODE, ARIAV_MODE_NO_SYNTH,-1,-1); + + return (fail); +} + +/* + * Lower-level routines + */ + +u_short +aria_putdspmem(iobase, loc, val) + register u_short iobase; + register u_short loc; + register u_short val; +{ + outw(iobase + ARIADSP_DMAADDRESS, loc); + outw(iobase + ARIADSP_DMADATA, val); +} + +u_short +aria_getdspmem(iobase, loc) + register u_short iobase; + register u_short loc; +{ + outw(iobase+ARIADSP_DMAADDRESS, loc); + return inw(iobase+ARIADSP_DMADATA); +} + +/* + * aria_sendcmd() + * each full DSP command is unified into this + * function. + */ + +int +aria_sendcmd(iobase, command, arg1, arg2, arg3) + u_short iobase; + u_short command; + int arg1; + int arg2; + int arg3; +{ + int i, fail = 0; + + for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) + ; + + fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:1; + outw(iobase + ARIADSP_WRITE, (u_short) command); + + if (arg1 != -1) { + for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) + ; + + fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:2; + outw(iobase + ARIADSP_WRITE, (u_short) arg1); + } + + if (arg2 != -1) { + for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) + ; + + fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:4; + outw(iobase + ARIADSP_WRITE, (u_short) arg2); + } + + if (arg3 != -1) { + for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) + ; + + fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:8; + outw(iobase + ARIADSP_WRITE, (u_short) arg3); + } + + for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) + ; + + fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:16; + outw(iobase + ARIADSP_WRITE, (u_short) ARIADSPC_TERM); + +#ifdef AUDIO_DEBUG + if (fail) { + ++ariaerr.sendcmd; + DPRINTF(("aria_sendcmd: failure=(%d) cmd=(0x%x) fail=(0x%x)\n", ariaerr.sendcmd, command, fail)); + return -1; + } +#else + if (fail != 0) { + ++ariaerr.sendcmd; + return -1; + } +#endif + + return 0; +} + +int +aria_halt_input(addr) + void *addr; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_halt_input\n")); + + if (sc->sc_record&(1<<0)) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_REC, 0, -1, -1); + sc->sc_record &= ~(1<<0); + } + + return(0); +} + +int +aria_halt_output(addr) + void *addr; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_halt_output\n")); + + if (sc->sc_play & (1<<1)) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_PLAY, 1, -1, -1); + sc->sc_play &= ~(1<<1); + } + + return(0); +} + +/* + * This is not called in dev/audio.c? + */ +int +aria_cont(addr) + void *addr; +{ + register struct aria_softc *sc = addr; + + DPRINTF(("aria_cont\n")); + + if (!sc->sc_record&(1<<0) && (sc->sc_open&ARIAR_OPEN_RECORD)) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC, ARIAR_RECORD_CHAN, -1, -1); + sc->sc_record |= ~(1<sc_play&(1<sc_open&ARIAR_OPEN_PLAY)) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY, 1, -1, -1); + sc->sc_play |= ~(1<sc_blocksize) { + DPRINTF(("aria_start_input reqsize %d not sc_blocksize %d\n", + cc, sc->sc_blocksize)); + return EINVAL; + } + + sc->sc_rarg = arg; + sc->sc_rintr = intr; + sc->sc_rdiobuffer = p; + + if (!(sc->sc_record&(1<<0))) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC, 0, -1, -1); + sc->sc_record |= (1<<0); + } + + return 0; +} + +int +aria_start_output(addr, p, cc, intr, arg) + void *addr; + void *p; + int cc; + void (*intr)(); + void *arg; +{ + register struct aria_softc *sc = addr; + register int i; + + DPRINTF(("aria_start_output %d @ %x\n", cc, p)); + + if (cc != sc->sc_blocksize) { + DPRINTF(("aria_start_output reqsize %d not sc_blocksize %d\n", + cc, sc->sc_blocksize)); + return EINVAL; + } + + sc->sc_parg = arg; + sc->sc_pintr = intr; + sc->sc_pdiobuffer = p; + + if (!(sc->sc_play&(1<<1))) { + aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY, 1, -1, -1); + sc->sc_play |= (1<<1); + } + + return 0; +} + +/* + * Process an interrupt. This should be a + * request (from the card) to write or read + * samples. + */ +int +aria_intr(arg) + void *arg; +{ + register struct aria_softc *sc = arg; + register u_short iobase = sc->sc_iobase; + register u_short *pdata = sc->sc_pdiobuffer; + register u_short *rdata = sc->sc_rdiobuffer; + u_short address; + int i; + + if (inw(iobase) & 1 != 0x1) + return 0; /* not for us */ + + sc->sc_interrupts++; + + DPRINTF(("aria_intr\n")); + + if ((sc->sc_open & ARIAR_OPEN_PLAY) && (pdata!=NULL)) { + DPRINTF(("aria_intr play=(%x)\n", pdata)); + address = 0x8000 - 2*(sc->sc_blocksize); + address+= aria_getdspmem(iobase, ARIAA_PLAY_FIFO_A); + outw(iobase+ARIADSP_DMAADDRESS, address); + outsw(iobase + ARIADSP_DMADATA, pdata, sc->sc_blocksize/2); + if (sc->sc_pintr != NULL) + (*sc->sc_pintr)(sc->sc_parg); + } + + if ((sc->sc_open & ARIAR_OPEN_RECORD) && (rdata!=NULL)) { + DPRINTF(("aria_intr record=(%x)\n", rdata)); + address = 0x8000 - (sc->sc_blocksize); + address+= aria_getdspmem(iobase, ARIAA_REC_FIFO_A); + outw(iobase+ARIADSP_DMAADDRESS, address); + insw(iobase + ARIADSP_DMADATA, rdata, sc->sc_blocksize/2); + if (sc->sc_rintr != NULL) + (*sc->sc_rintr)(sc->sc_rarg); + } + + aria_sendcmd(iobase, ARIADSPC_TRANSCOMPLETE, -1, -1, -1); + + return 1; +} + +u_int +aria_get_silence(enc) + int enc; +{ +#define ULAW_SILENCE 0x7f +#define ALAW_SILENCE 0x55 +#define LINEAR_SILENCE 0x00 + u_int auzero; + + switch (enc) { + case AUDIO_ENCODING_ULAW: + auzero = ULAW_SILENCE; + break; + case AUDIO_ENCODING_ALAW: + auzero = ALAW_SILENCE; + break; + case AUDIO_ENCODING_PCM8: + case AUDIO_ENCODING_PCM16: + default: + auzero = LINEAR_SILENCE; + break; + } + + return(auzero); +} + +int +aria_setfd(addr, flag) + void *addr; + int flag; +{ +/* + * okay return yes. I'll assume that it will only + * ask when the file open read/write... Or before... + */ + return(0); +} + +int +aria_mixer_set_port(addr, cp) + void *addr; + mixer_ctrl_t *cp; +{ + register struct aria_softc *sc = addr; + int error = EINVAL; + + DPRINTF(("aria_mixer_set_port\n")); + + if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ + return ENXIO; + + if (cp->type == AUDIO_MIXER_VALUE) { + register mixer_level_t *mv = &cp->un.value; + switch (cp->dev) { + case ARIAMIX_MIC_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->aria_mix[ARIAMIX_MIC_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_MIC_LVL].level[0] = mv->level[0]; + sc->aria_mix[ARIAMIX_MIC_LVL].level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_LINE_IN_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0] = mv->level[0]; + sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_CD_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->aria_mix[ARIAMIX_CD_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_CD_LVL].level[0] = mv->level[0]; + sc->aria_mix[ARIAMIX_CD_LVL].level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_TEL_LVL: + if (mv->num_channels == 1) { + sc->aria_mix[ARIAMIX_TEL_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_TEL_LVL].level[0] = mv->level[0]; + error = 0; + } + break; + + case ARIAMIX_DAC_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->aria_mix[ARIAMIX_DAC_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_DAC_LVL].level[0] = mv->level[0]; + sc->aria_mix[ARIAMIX_DAC_LVL].level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_AUX_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->aria_mix[ARIAMIX_AUX_LVL].num_channels = mv->num_channels; + sc->aria_mix[ARIAMIX_AUX_LVL].level[0] = mv->level[0]; + sc->aria_mix[ARIAMIX_AUX_LVL].level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_MASTER_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->ariamix_master.num_channels = mv->num_channels; + sc->ariamix_master.level[0] = mv->level[0]; + sc->ariamix_master.level[1] = mv->level[1]; + error = 0; + } + break; + + case ARIAMIX_MASTER_TREBLE: + if (mv->num_channels == 2) { + sc->ariamix_master.treble[0] = (mv->level[0]==0)?1:mv->level[0]; + sc->ariamix_master.treble[1] = (mv->level[1]==0)?1:mv->level[1]; + error = 0; + } + break; + case ARIAMIX_MASTER_BASS: + if (mv->num_channels == 2) { + sc->ariamix_master.bass[0] = (mv->level[0]==0)?1:mv->level[0]; + sc->ariamix_master.bass[1] = (mv->level[1]==0)?1:mv->level[1]; + error = 0; + } + break; + case ARIAMIX_OUT_LVL: + if (mv->num_channels == 1 || mv->num_channels == 2) { + sc->gain[0] = mv->level[0]; + sc->gain[1] = mv->level[1]; + error = 0; + } + break; + default: + } + } + + if (cp->type == AUDIO_MIXER_ENUM) + switch(cp->dev) { + case ARIAMIX_RECORD_SOURCE: + if (cp->un.ord>=0 && cp->un.ord<=6) { + sc->aria_mix_source = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_MIC_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_MIC_LVL].mute = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_LINE_IN_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_CD_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_CD_LVL].mute = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_DAC_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_DAC_LVL].mute = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_AUX_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_AUX_LVL].mute = cp->un.ord; + error = 0; + } + break; + + case ARIAMIX_TEL_MUTE: + if (cp->un.ord == 0 || cp->un.ord == 1) { + sc->aria_mix[ARIAMIX_TEL_LVL].mute = cp->un.ord; + error = 0; + } + break; + + default: + return ENXIO; + /* NOTREACHED */ + } + + return(error); +} + +int +aria_mixer_get_port(addr, cp) + void *addr; + mixer_ctrl_t *cp; +{ + register struct aria_softc *sc = addr; + int error = EINVAL; + + DPRINTF(("aria_mixer_get_port\n")); + + if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ + return ENXIO; + + switch (cp->dev) { + case ARIAMIX_MIC_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_MIC_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_MIC_LVL].level[0]; + cp->un.value.level[1] = sc->aria_mix[ARIAMIX_MIC_LVL].level[1]; + error = 0; + } + break; + + case ARIAMIX_LINE_IN_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0]; + cp->un.value.level[1] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1]; + error = 0; + } + break; + + case ARIAMIX_CD_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_CD_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_CD_LVL].level[0]; + cp->un.value.level[1] = sc->aria_mix[ARIAMIX_CD_LVL].level[1]; + error = 0; + } + break; + + case ARIAMIX_TEL_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_TEL_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_TEL_LVL].level[0]; + error = 0; + } + break; + case ARIAMIX_DAC_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_DAC_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_DAC_LVL].level[0]; + cp->un.value.level[1] = sc->aria_mix[ARIAMIX_DAC_LVL].level[1]; + error = 0; + } + break; + + case ARIAMIX_AUX_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->aria_mix[ARIAMIX_AUX_LVL].num_channels; + cp->un.value.level[0] = sc->aria_mix[ARIAMIX_AUX_LVL].level[0]; + cp->un.value.level[1] = sc->aria_mix[ARIAMIX_AUX_LVL].level[1]; + error = 0; + } + break; + + case ARIAMIX_MIC_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_MIC_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_LINE_IN_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_CD_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_CD_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_DAC_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_DAC_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_AUX_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_AUX_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_TEL_MUTE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix[ARIAMIX_TEL_LVL].mute; + error = 0; + } + break; + + case ARIAMIX_MASTER_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->ariamix_master.num_channels; + cp->un.value.level[0] = sc->ariamix_master.level[0]; + cp->un.value.level[1] = sc->ariamix_master.level[1]; + error = 0; + } + break; + + case ARIAMIX_MASTER_TREBLE: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = 2; + cp->un.value.level[0] = sc->ariamix_master.treble[0]; + cp->un.value.level[1] = sc->ariamix_master.treble[1]; + error = 0; + } + break; + + case ARIAMIX_MASTER_BASS: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = 2; + cp->un.value.level[0] = sc->ariamix_master.bass[0]; + cp->un.value.level[1] = sc->ariamix_master.bass[1]; + error = 0; + } + break; + + case ARIAMIX_OUT_LVL: + if (cp->type == AUDIO_MIXER_VALUE) { + cp->un.value.num_channels = sc->sc_chans; + cp->un.value.level[0] = sc->gain[0]; + cp->un.value.level[1] = sc->gain[1]; + error = 0; + } + break; + case ARIAMIX_RECORD_SOURCE: + if (cp->type == AUDIO_MIXER_ENUM) { + cp->un.ord = sc->aria_mix_source; + error = 0; + } + break; + + default: + return ENXIO; + /* NOT REACHED */ + } + + return(error); +} + +int +aria_mixer_query_devinfo(addr, dip) + void *addr; + register mixer_devinfo_t *dip; +{ + + register struct aria_softc *sc = addr; + + DPRINTF(("aria_mixer_query_devinfo\n")); + + if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ + return ENXIO; + + dip->prev = dip->next = AUDIO_MIXER_LAST; + + switch(dip->index) { + case ARIAMIX_MIC_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_MIC_MUTE; + strcpy(dip->label.name, AudioNmicrophone); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_LINE_IN_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_LINE_IN_MUTE; + strcpy(dip->label.name, AudioNline); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_CD_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_CD_MUTE; + strcpy(dip->label.name, AudioNcd); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_TEL_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_TEL_MUTE; + strcpy(dip->label.name, "telephone"); + dip->un.v.num_channels = 1; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_DAC_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_DAC_MUTE; + strcpy(dip->label.name, AudioNdac); + dip->un.v.num_channels = 1; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_AUX_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->next = ARIAMIX_AUX_MUTE; + strcpy(dip->label.name, AudioNoutput); + dip->un.v.num_channels = 1; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_MIC_MUTE: + dip->prev = ARIAMIX_MIC_LVL; + goto mode; + + case ARIAMIX_LINE_IN_MUTE: + dip->prev = ARIAMIX_LINE_IN_LVL; + goto mode; + + case ARIAMIX_CD_MUTE: + dip->prev = ARIAMIX_CD_LVL; + goto mode; + + case ARIAMIX_DAC_MUTE: + dip->prev = ARIAMIX_DAC_LVL; + goto mode; + + case ARIAMIX_AUX_MUTE: + dip->prev = ARIAMIX_AUX_LVL; + goto mode; + + case ARIAMIX_TEL_MUTE: + dip->prev = ARIAMIX_TEL_LVL; + goto mode; + +mode: + dip->mixer_class = ARIAMIX_INPUT_CLASS; + dip->type = AUDIO_MIXER_ENUM; + strcpy(dip->label.name, AudioNmute); + dip->un.e.num_mem = 2; + strcpy(dip->un.e.member[0].label.name, AudioNoff); + dip->un.e.member[0].ord = 0; + strcpy(dip->un.e.member[1].label.name, AudioNon); + dip->un.e.member[1].ord = 1; + break; + + case ARIAMIX_MASTER_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_OUTPUT_CLASS; + dip->next = ARIAMIX_MASTER_TREBLE; + strcpy(dip->label.name, AudioNvolume); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_MASTER_TREBLE: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_OUTPUT_CLASS; + dip->prev = ARIAMIX_MASTER_LVL; + dip->next = ARIAMIX_MASTER_BASS; + strcpy(dip->label.name, AudioNmaster); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNtreble); + break; + + case ARIAMIX_MASTER_BASS: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_OUTPUT_CLASS; + dip->prev = ARIAMIX_MASTER_TREBLE; + strcpy(dip->label.name, AudioNmaster); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNbass); + break; + + case ARIAMIX_OUT_LVL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = ARIAMIX_OUTPUT_CLASS; + strcpy(dip->label.name, AudioNoutput); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + break; + + case ARIAMIX_RECORD_SOURCE: + dip->mixer_class = ARIAMIX_RECORD_CLASS; + dip->type = AUDIO_MIXER_ENUM; + strcpy(dip->label.name, AudioNsource); + dip->un.e.num_mem = 6; + strcpy(dip->un.e.member[0].label.name, AudioNoutput); + dip->un.e.member[0].ord = ARIAMIX_AUX_LVL; + strcpy(dip->un.e.member[1].label.name, AudioNmicrophone); + dip->un.e.member[1].ord = ARIAMIX_MIC_LVL; + strcpy(dip->un.e.member[2].label.name, AudioNdac); + dip->un.e.member[2].ord = ARIAMIX_DAC_LVL; + strcpy(dip->un.e.member[3].label.name, AudioNline); + dip->un.e.member[3].ord = ARIAMIX_LINE_IN_LVL; + strcpy(dip->un.e.member[3].label.name, AudioNcd); + dip->un.e.member[4].ord = ARIAMIX_CD_LVL; + strcpy(dip->un.e.member[3].label.name, "telephone"); + dip->un.e.member[5].ord = ARIAMIX_TEL_LVL; + break; + + case ARIAMIX_INPUT_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = ARIAMIX_INPUT_CLASS; + strcpy(dip->label.name, AudioCInputs); + break; + + case ARIAMIX_OUTPUT_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = ARIAMIX_OUTPUT_CLASS; + strcpy(dip->label.name, AudioCOutputs); + break; + + case ARIAMIX_RECORD_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = ARIAMIX_RECORD_CLASS; + strcpy(dip->label.name, AudioCRecord); + break; + + case ARIAMIX_EQ_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = ARIAMIX_EQ_CLASS; + strcpy(dip->label.name, AudioCEqualization); + break; + + default: + return ENXIO; + /*NOTREACHED*/ + } + return 0; +} + +#endif /* NARIA */ diff --git a/sys/dev/isa/ariareg.h b/sys/dev/isa/ariareg.h new file mode 100644 index 00000000000..14d1909b224 --- /dev/null +++ b/sys/dev/isa/ariareg.h @@ -0,0 +1,138 @@ +/* $OpenBSD: ariareg.h,v 1.1 1996/05/04 13:29:33 deraadt Exp $ */ + +/* + * Copyright (c) 1995, 1996 Roland C. Dowdeswell. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Roland C. Dowdeswell. + * 4. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * Macros to detect valid hardware configuration data. + */ +#define ARIA_IRQ_VALID(irq) ((irq) == 10 || (irq) == 11 || (irq) == 12) +#define ARIA_DRQ_VALID(chan) ((chan) == 5 || (chan) == 6) +#define ARIA_BASE_VALID(base) ((base) == 0x290 || (base) == 0x280 || (base) == 0x2a0 || (base) == 0x2b0) + +/* + * Aria DSP ports + * (abrieviated ARIADSP_) + */ + +#define ARIADSP_NPORT 8 + +#define ARIADSP_DSPDATA 0 +#define ARIADSP_WRITE 0 +#define ARIADSP_STATUS 2 +#define ARIADSP_CONTROL 2 +#define ARIADSP_DMAADDRESS 4 +#define ARIADSP_DMADATA 6 + +/* + * Aria DSP Addresses and the like... + * (abrieviated ARIAA_) + */ + +#define ARIAA_HARDWARE_A 0x6050 +#define ARIAA_MODEL_A 0x60c3 +#define ARIAA_PLAY_FIFO_A 0x6100 +#define ARIAA_REC_FIFO_A 0x6101 +#define ARIAA_TASK_A 0x6102 + +/* + * DSP random values + * (abrieviated ARIAR_) + */ + +#define ARIAR_PROMETHEUS_KLUDGE 0x0001 +#define ARIAR_NPOLL 30000 +#define ARIAR_OPEN_PLAY 0x0002 +#define ARIAR_OPEN_RECORD 0x0001 +#define ARIAR_PLAY_CHAN 1 +#define ARIAR_RECORD_CHAN 0 +#define ARIAR_BUSY 0x8000 +#define ARIAR_ARIA_SYNTH 0x0080 +#define ARIAR_SR22K 0x0040 +#define ARIAR_DSPINTWR 0x0008 +#define ARIAR_PCINTWR 0x0002 + +/* + * Aria DSP Commands + * (abrieviated ARIADSPC_) + */ + +#define ARIADSPC_SYSINIT 0x0000 /* Initialise system */ +#define ARIADSPC_FORMAT 0x0003 /* format (pcm8, pcm16, etc) */ +#define ARIADSPC_MASTERVOLUME 0x0004 +#define ARIADSPC_BLOCKSIZE 0x0005 +#define ARIADSPC_MODE 0x0006 +#define ARIADSPC_CDVOLUME 0x0007 +#define ARIADSPC_MICVOLUME 0x0008 +#define ARIADSPC_MIXERCONFIG 0x0009 +#define ARIADSPC_FORCEINTR 0x000a /* Force an Interupt */ +#define ARIADSPC_TRANSCOMPLETE 0x0010 /* Transfer Complete */ +#define ARIADSPC_START_PLAY 0x0011 +#define ARIADSPC_STOP_PLAY 0x0012 +#define ARIADSPC_CHAN_VOL 0x0013 +#define ARIADSPC_CHAN_PAN 0x0014 +#define ARIADSPC_START_REC 0x0015 +#define ARIADSPC_STOP_REC 0x0016 +#define ARIADSPC_DAPVOL 0x0017 /* Digital Audio Playback Vol */ +#define ARIADSPC_ADCSOURCE 0x0030 +#define ARIADSPC_ADCCONTROL 0x0031 /* Turn ADC off/on */ +#define ARIADSPC_INPMONMODE 0x0032 /* Input Monitor Mode */ +#define ARIADSPC_MASMONMODE 0x0033 /* Master Monitor Mode */ +#define ARIADSPC_MIXERVOL 0x0034 /* Mixer Volumes */ +#define ARIADSPC_TONE 0x0035 /* Tone controls */ +#define ARIADSPC_TERM 0xffff /* End of Command */ + +/* + * DSP values (for commands) + * (abrieviated ARIAV_) + */ + +#define ARIAV_MODE_NO_SYNTH 0x0000 /* No synthesizer mode */ + +#define ARIAMIX_MIC_LVL 0 +#define ARIAMIX_LINE_IN_LVL 1 +#define ARIAMIX_CD_LVL 2 +#define ARIAMIX_DAC_LVL 3 +#define ARIAMIX_TEL_LVL 4 +#define ARIAMIX_AUX_LVL 5 +#define ARIAMIX_MASTER_LVL 6 +#define ARIAMIX_MASTER_TREBLE 7 +#define ARIAMIX_MASTER_BASS 8 +#define ARIAMIX_RECORD_SOURCE 9 +#define ARIAMIX_MIC_MUTE 10 +#define ARIAMIX_LINE_IN_MUTE 11 +#define ARIAMIX_CD_MUTE 12 +#define ARIAMIX_DAC_MUTE 13 +#define ARIAMIX_TEL_MUTE 14 +#define ARIAMIX_AUX_MUTE 15 +#define ARIAMIX_OUT_LVL 16 +#define ARIAMIX_OUTPUT_CLASS 17 +#define ARIAMIX_INPUT_CLASS 18 +#define ARIAMIX_RECORD_CLASS 19 +#define ARIAMIX_EQ_CLASS 20 diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 4e0136ea6a7..2b001688b63 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.13 1996/05/02 13:38:09 deraadt Exp $ +# $OpenBSD: files.isa,v 1.14 1996/05/04 13:29:31 deraadt Exp $ # $NetBSD: files.isa,v 1.18 1996/04/25 02:15:42 thorpej Exp $ # # Config.new file and device description for machine-independent ISA code. @@ -210,6 +210,13 @@ device sb: audio, isadma, sbdsp, mulaw, opti attach sb at isa file dev/isa/sb.c sb needs-flag +# Soundcards based on Sierra's Aria chipset. +# Such as the Prometheus Aria 16 or the Diamond +# sonic sound. +device aria: audio, mulaw +attach aria at isa +file dev/isa/aria.c aria needs-flag + # ProAudio Spectrum device pas: audio, isadma, sbdsp, mulaw attach pas at isa -- 2.20.1