diff options
| author | augustss <augustss@NetBSD.org> | 1998-06-06 10:12:34 +0000 |
|---|---|---|
| committer | augustss <augustss@NetBSD.org> | 1998-06-06 10:12:34 +0000 |
| commit | 68e0540ee91639a7c2377a3b4fbe2f6adf780eea (patch) | |
| tree | 1b8bd732f4a4d86730b7aaf9d92c878d6b248866 /sys/dev | |
| parent | ad19e79da0debfc58f14c6a07cc3b577befe8069 (diff) | |
Add an Aria sound driver.
From "R. C. Dowdeswell" <elric@imrryr.org>.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/isa/aria.c | 1676 | ||||
| -rw-r--r-- | sys/dev/isa/ariareg.h | 136 | ||||
| -rw-r--r-- | sys/dev/isa/files.isa | 8 |
3 files changed, 1819 insertions, 1 deletions
diff --git a/sys/dev/isa/aria.c b/sys/dev/isa/aria.c new file mode 100644 index 00000000000..6b5c08bfa1e --- /dev/null +++ b/sys/dev/isa/aria.c @@ -0,0 +1,1676 @@ +/*- + * Copyright (c) 1995, 1996, 1998 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 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 We should nicely deal with the cards that can do mulaw + * and alaw output. + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <vm/vm.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/bus.h> + +#include <sys/audioio.h> +#include <dev/audio_if.h> +#include <dev/auconv.h> + +#include <dev/mulaw.h> +#include <dev/isa/isavar.h> +#include <i386/isa/icu.h> + +#include <dev/isa/ariareg.h> + +#define FREAD 1 +#define FWRITE 2 + +#ifdef AUDIO_DEBUG +#define DPRINTF(x) printf 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 device *sc_isa; /* pointer to ISA parent */ + void *sc_ih; /* interrupt vectoring */ + bus_space_tag_t sc_iot; /* Tag on 'da bus. */ + bus_space_handle_t sc_ioh; /* Handle of iospace */ + + 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 */ +/* XXX -- keep this? */ + u_short sc_gain[2]; /* left/right gain (play) */ + + u_long sc_rate; /* Sample rate for input and output */ + u_int sc_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; + + int sc_sendcmd_err; +}; + +#ifdef __BROKEN_INDIRECT_CONFIG +int ariaprobe __P((struct device *, void *, void *)); +#else +int ariaprobe __P((struct device *, struct cfdata *, void *)); +#endif +void ariaattach __P((struct device *, struct device *, void *)); +void ariaclose __P((void *)); +int ariaopen __P((void *, int)); +int ariareset __P((bus_space_tag_t, bus_space_handle_t)); +int aria_reset __P((struct aria_softc *)); +int aria_getdev __P((void *, struct audio_device *)); + +void aria_do_kludge __P((bus_space_tag_t, bus_space_handle_t, + bus_space_handle_t, + u_short, u_short, u_short, u_short)); +void aria_prometheus_kludge __P((struct isa_attach_args *, + bus_space_handle_t)); + +int aria_query_encoding __P((void *, struct audio_encoding *)); +int aria_round_blocksize __P((void *, int)); +int aria_speaker_ctl __P((void *, int)); +int aria_commit_settings __P((void *)); +int aria_set_params __P((void *, int, int, + struct audio_params *, struct audio_params *)); +int aria_get_props __P((void *)); + +int aria_start_output __P((void *, void *, int, + void (*) __P((void *)), void*)); +int aria_start_input __P((void *, void *, int, + void (*) __P((void *)), void*)); + +int aria_halt_input __P((void *)); +int aria_halt_output __P((void *)); + +int aria_sendcmd __P((struct aria_softc *, u_short, int, int, int)); + +u_short aria_getdspmem __P((struct aria_softc *, u_short)); +void aria_putdspmem __P((struct aria_softc *, u_short, u_short)); + +int aria_intr __P((void *)); +short ariaversion __P((struct aria_softc *)); + +void aria_set_mixer __P((struct aria_softc *, 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 *)); + +struct cfattach aria_ca = { + sizeof(struct aria_softc), ariaprobe, ariaattach +}; + +/* XXX temporary test for 1.3 */ +#ifndef AudioNaux +/* 1.3 */ +struct cfdriver aria_cd = { + NULL, "aria", DV_DULL +}; +#endif + +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_query_encoding, + aria_set_params, + aria_round_blocksize, + aria_commit_settings, + NULL, + NULL, + aria_start_output, + aria_start_input, + aria_halt_input, + aria_halt_output, + NULL, + aria_getdev, + NULL, + aria_mixer_set_port, + aria_mixer_get_port, + aria_mixer_query_devinfo, + NULL, + NULL, + NULL, + NULL, + aria_get_props, +}; + +/* + * Probe / attach routines. + */ + +/* + * Probe for the aria hardware. + */ +int +#ifdef __BROKEN_INDIRECT_CONFIG +ariaprobe(parent, match, aux) + struct device *parent; + void *match; +#else +ariaprobe(parent, cf, aux) + struct device *parent; + struct cfdata *cf; +#endif + void *aux; +{ + bus_space_handle_t ioh; + struct isa_attach_args *ia = aux; +#ifdef __BROKEN_INDIRECT_CONFIG + struct cfdata *cf = ((struct device *)match)->dv_cfdata; +#endif + + if (!ARIA_BASE_VALID(ia->ia_iobase)) { + printf("aria: configured iobase %d invalid\n", ia->ia_iobase); + return 0; + } + + if (!ARIA_IRQ_VALID(ia->ia_irq)) { + printf("aria: configured irq %d invalid\n", ia->ia_irq); + return 0; + } + + if (bus_space_map(ia->ia_iot, ia->ia_iobase, ARIADSP_NPORT, 0, &ioh)) { + DPRINTF(("aria: aria probe failed\n")); + return 0; + } + + if (cf->cf_flags & 1) + aria_prometheus_kludge(ia, ioh); + + if (ariareset(ia->ia_iot, ioh) != 0) { + DPRINTF(("aria: aria probe failed\n")); + bus_space_unmap(ia->ia_iot, ioh, ARIADSP_NPORT); + return 0; + } + + bus_space_unmap(ia->ia_iot, ioh, ARIADSP_NPORT); + + ia->ia_iosize = ARIADSP_NPORT; + DPRINTF(("aria: aria probe succeeded\n")); + 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, ioh1) + struct isa_attach_args *ia; + bus_space_handle_t ioh1; +{ + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_short end; + + DPRINTF(("aria: begin aria_prometheus_kludge\n")); + +/* Begin Config Sequence */ + + iot = ia->ia_iot; + bus_space_map(iot, 0x200, 8, 0, &ioh); + + bus_space_write_1(iot, ioh, 4, 0x4c); + bus_space_write_1(iot, ioh, 5, 0x42); + bus_space_write_1(iot, ioh, 6, 0x00); + bus_space_write_2(iot, ioh, 0, 0x0f); + bus_space_write_1(iot, ioh, 1, 0x00); + bus_space_write_2(iot, ioh, 0, 0x02); + bus_space_write_1(iot, ioh, 1, ia->ia_iobase>>2); + +/* + * These next three lines set up the iobase + * and the irq; and disable the drq. + */ + + aria_do_kludge(iot, ioh, ioh1, 0x111, ((ia->ia_iobase-0x280)>>2)+0xA0, + 0xbf, 0xa0); + aria_do_kludge(iot, ioh, ioh1, 0x011, ia->ia_irq-6, 0xf8, 0x00); + aria_do_kludge(iot, ioh, ioh1, 0x011, 0x00, 0xef, 0x00); + +/* The rest of these lines just disable everything else */ + + aria_do_kludge(iot, ioh, ioh1, 0x113, 0x00, 0x88, 0x00); + aria_do_kludge(iot, ioh, ioh1, 0x013, 0x00, 0xf8, 0x00); + aria_do_kludge(iot, ioh, ioh1, 0x013, 0x00, 0xef, 0x00); + aria_do_kludge(iot, ioh, ioh1, 0x117, 0x00, 0x88, 0x00); + aria_do_kludge(iot, ioh, ioh1, 0x017, 0x00, 0xff, 0x00); + +/* End Sequence */ + + bus_space_write_1(iot, ioh, 0, 0x0f); + end = bus_space_read_1(iot, ioh1, 0); + bus_space_write_2(iot, ioh, 0, 0x0f); + bus_space_write_1(iot, ioh, 1, end|0x80); + bus_space_read_1(iot, ioh, 0); + + bus_space_unmap(iot, ioh, 8); +/* + * 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(iot, ioh, ioh1, func, bits, and, or) + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_space_handle_t ioh1; + u_short func; + u_short bits; + u_short and; + u_short or; +{ + u_int i; + if (func & 0x100) { + func &= ~0x100; + if (bits) { + bus_space_write_2(iot, ioh, 0, func-1); + bus_space_write_1(iot, ioh, 1, bits); + } + } else + or |= bits; + + bus_space_write_1(iot, ioh, 0, func); + i = bus_space_read_1(iot, ioh1, 0); + bus_space_write_2(iot, ioh, 0, func); + bus_space_write_1(iot, ioh, 1, (i&and) | or); +} + +/* + * Attach hardware to driver, attach hardware driver to audio + * pseudo-device driver. + */ +void +ariaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + bus_space_handle_t ioh; + struct aria_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + u_short i; + + if (bus_space_map(ia->ia_iot, ia->ia_iobase, ARIADSP_NPORT, 0, &ioh)) + panic("%s: can map io port range", self->dv_xname); + + sc->sc_iot = ia->ia_iot; + sc->sc_ioh = ioh; + + sc->sc_isa = parent; + sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_AUDIO, aria_intr, sc); + + DPRINTF(("isa_intr_establish() returns (%x)\n", (unsigned) sc->sc_ih)); + + i = aria_getdspmem(sc, 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(sc, 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_blocksize = 1024; + sc->sc_precision = 8; + sc->sc_rintr = 0; + sc->sc_rarg = 0; + sc->sc_pintr = 0; + sc->sc_parg = 0; + sc->sc_gain[0] = 127; + sc->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; + + aria_commit_settings(sc); + + 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"); + + audio_attach_mi(&aria_hw_if, 0, (void *)sc, &sc->sc_dev); +} + +/* + * Various routines to interface to higher level audio driver + */ + +int +ariaopen(addr, flags) + void *addr; + int flags; +{ + struct aria_softc *sc = addr; + + DPRINTF(("ariaopen() called\n")); + + if (!sc) + return ENXIO; + if ((flags&FREAD) && (sc->sc_open & ARIAR_OPEN_RECORD)) + return ENXIO; + if ((flags&FWRITE) && (sc->sc_open & ARIAR_OPEN_PLAY)) + return ENXIO; + + 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; + + return 0; +} + +int +aria_getdev(addr, retp) + void *addr; + struct audio_device *retp; +{ + *retp = aria_device; + return 0; +} + +/* + * Various routines to interface to higher level audio driver + */ + +int +aria_query_encoding(addr, fp) + void *addr; + struct audio_encoding *fp; +{ + struct aria_softc *sc = addr; + + switch (fp->index) { + case 0: + strcpy(fp->name, AudioEmulaw); + fp->encoding = AUDIO_ENCODING_ULAW; + fp->precision = 8; + if ((ARIA_MODEL&sc->sc_hardware) == 0) + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 1: + strcpy(fp->name, AudioEalaw); + fp->encoding = AUDIO_ENCODING_ALAW; + fp->precision = 8; + if ((ARIA_MODEL&sc->sc_hardware) == 0) + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 2: + strcpy(fp->name, AudioEslinear); + fp->encoding = AUDIO_ENCODING_SLINEAR; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 3: + strcpy(fp->name, AudioEslinear_le); + fp->encoding = AUDIO_ENCODING_SLINEAR_LE; + fp->precision = 16; + fp->flags = 0; + break; + case 4: + strcpy(fp->name, AudioEslinear_be); + fp->encoding = AUDIO_ENCODING_SLINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 5: + strcpy(fp->name, AudioEulinear); + fp->encoding = AUDIO_ENCODING_ULINEAR; + fp->precision = 8; + fp->flags = 0; + break; + case 6: + strcpy(fp->name, AudioEulinear_le); + fp->encoding = AUDIO_ENCODING_ULINEAR_LE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 7: + strcpy(fp->name, AudioEulinear_be); + fp->encoding = AUDIO_ENCODING_ULINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + default: + return(EINVAL); + /*NOTREACHED*/ + } + + return (0); +} + +/* + * Store blocksize in bytes. + */ + +int +aria_round_blocksize(addr, blk) + void *addr; + int blk; +{ + int i; +#if 0 /* XXX -- this is being a tad bit of a problem... */ + for (i=64; i<1024; i*=2) + if (blk <= i) + break; +#else + i = 1024; +#endif + return(i); +} + +int +aria_get_props(addr) + void *addr; +{ + return AUDIO_PROP_FULLDUPLEX; +} + +int +aria_set_params(addr, setmode, usemode, p, r) + void *addr; + int setmode, usemode; + struct audio_params *p, *r; +{ + struct aria_softc *sc = addr; + + switch(p->encoding) { + case AUDIO_ENCODING_ULAW: + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_SLINEAR: + case AUDIO_ENCODING_SLINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_ULINEAR: + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_ULINEAR_BE: + break; + default: + return (EINVAL); + } + + if (p->sample_rate <= 9450) + p->sample_rate = 7875; + else if (p->sample_rate <= 13387) + p->sample_rate = 11025; + else if (p->sample_rate <= 18900) + p->sample_rate = 15750; + else if (p->sample_rate <= 26775) + p->sample_rate = 22050; + else if (p->sample_rate <= 37800) + p->sample_rate = 31500; + else + p->sample_rate = 44100; + + sc->sc_encoding = p->encoding; + sc->sc_precision = p->precision; + sc->sc_chans = p->channels; + sc->sc_rate = p->sample_rate; + + switch(p->encoding) { + case AUDIO_ENCODING_ULAW: + if ((ARIA_MODEL&sc->sc_hardware) == 0) { + p->sw_code = mulaw_to_ulinear8; + r->sw_code = ulinear8_to_mulaw; + } + break; + case AUDIO_ENCODING_ALAW: + if ((ARIA_MODEL&sc->sc_hardware) == 0) { + p->sw_code = alaw_to_ulinear8; + r->sw_code = ulinear8_to_alaw; + } + break; + case AUDIO_ENCODING_SLINEAR: + p->sw_code = r->sw_code = change_sign8; + break; + case AUDIO_ENCODING_ULINEAR_LE: + p->sw_code = r->sw_code = change_sign16; + break; + case AUDIO_ENCODING_SLINEAR_BE: + p->sw_code = r->sw_code = swap_bytes; + break; + case AUDIO_ENCODING_ULINEAR_BE: + p->sw_code = r->sw_code = swap_bytes_change_sign16; + break; + } + + return 0; +} + +/* + * This is where all of the twiddling goes on. + */ + +int +aria_commit_settings(addr) + void *addr; +{ + struct aria_softc *sc = addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + static 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;/* XXX can we get here? */ + } + + if ((ARIA_MODEL&sc->sc_hardware) != 0) { + format |= (sc->sc_encoding==AUDIO_ENCODING_ULAW)?0x06:0x00; + format |= (sc->sc_encoding==AUDIO_ENCODING_ALAW)?0x08:0x00; + } + + format |= (sc->sc_precision==16)?0x02:0x00; + format |= (sc->sc_chans==2)?1:0; + samp |= bus_space_read_2(iot, ioh, ARIADSP_STATUS) & ~0x60; + + aria_sendcmd(sc, ARIADSPC_FORMAT, format, -1, -1); + bus_space_write_2(iot, ioh, ARIADSP_CONTROL, samp); + + if (sc->sc_hardware&ARIA_MIXER) { + for (i = 0; i < 6; i++) + aria_set_mixer(sc, i); + + if (sc->sc_chans==2) { + aria_sendcmd(sc, ARIADSPC_CHAN_VOL, ARIAR_PLAY_CHAN, + ((sc->sc_gain[0]+sc->sc_gain[1])/2)<<7, + -1); + aria_sendcmd(sc, ARIADSPC_CHAN_PAN, ARIAR_PLAY_CHAN, + (sc->sc_gain[0]-sc->sc_gain[1])/4+0x40, + -1); + } else { + aria_sendcmd(sc, ARIADSPC_CHAN_VOL, ARIAR_PLAY_CHAN, + sc->sc_gain[0]<<7, -1); + aria_sendcmd(sc, ARIADSPC_CHAN_PAN, ARIAR_PLAY_CHAN, + 0x40, -1); + } + + aria_sendcmd(sc, ARIADSPC_MASMONMODE, + sc->ariamix_master.num_channels != 2, -1, -1); + + aria_sendcmd(sc, ARIADSPC_MIXERVOL, 0x0004, + sc->ariamix_master.level[0] << 7, + sc->ariamix_master.level[1] << 7); + + /* Convert treble/bass from byte to soundcard style */ + + left = (tones[(sc->ariamix_master.treble[0]>>4)&0x0f]<<8) | + tones[(sc->ariamix_master.bass[0]>>4)&0x0f]; + right = (tones[(sc->ariamix_master.treble[1]>>4)&0x0f]<<8) | + tones[(sc->ariamix_master.bass[1]>>4)&0x0f]; + + aria_sendcmd(sc, ARIADSPC_TONE, left, right, -1); + } + + aria_sendcmd(sc, 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<<ARIAR_RECORD_CHAN)) + aria_sendcmd(sc, ARIADSPC_START_REC, ARIAR_RECORD_CHAN, -1,-1); + + if (sc->sc_play&(1<<ARIAR_PLAY_CHAN)) + aria_sendcmd(sc, ARIADSPC_START_PLAY, ARIAR_PLAY_CHAN, -1, -1); + + return(0); +} + +void +aria_set_mixer(sc, i) + struct aria_softc *sc; + int 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(sc, ARIADSPC_INPMONMODE, source, 3, -1); + else + aria_sendcmd(sc, ARIADSPC_INPMONMODE, source, + sc->aria_mix[i].num_channels != 2, -1); + + aria_sendcmd(sc, ARIADSPC_INPMONMODE, 0x8000|source, + sc->aria_mix[i].num_channels != 2, -1); + aria_sendcmd(sc, 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(sc, ARIADSPC_ADCSOURCE, source, -1, -1); + + if (sc->sc_open & ARIAR_OPEN_RECORD) + aria_sendcmd(sc, ARIADSPC_ADCCONTROL, 1, -1, -1); + else + aria_sendcmd(sc, ARIADSPC_ADCCONTROL, 0, -1, -1); + } +} + +void +ariaclose(addr) + void *addr; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_close sc=0x%x\n", (unsigned) sc)); + + sc->sc_rintr = 0; + sc->sc_pintr = 0; + sc->sc_rdiobuffer = 0; + sc->sc_pdiobuffer = 0; + + if (sc->sc_play&(1<<ARIAR_PLAY_CHAN) && + sc->sc_open & ARIAR_OPEN_PLAY) { + aria_sendcmd(sc, ARIADSPC_STOP_PLAY, ARIAR_PLAY_CHAN, -1, -1); + sc->sc_play &= ~(1<<ARIAR_PLAY_CHAN); + } + + if (sc->sc_record&(1<<ARIAR_RECORD_CHAN) && + sc->sc_open & ARIAR_OPEN_RECORD) { + aria_sendcmd(sc, ARIADSPC_STOP_REC, ARIAR_RECORD_CHAN, -1, -1); + sc->sc_record &= ~(1<<ARIAR_RECORD_CHAN); + } + + sc->sc_open = 0; + + if (aria_reset(sc) != 0) { + delay(500); + aria_reset(sc); + } +} + +/* + * Reset the hardware. + */ + +int ariareset(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + struct aria_softc tmp, *sc = &tmp; + + sc->sc_iot = iot; + sc->sc_ioh = ioh; + return aria_reset(sc); +} + +int +aria_reset(sc) + struct aria_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int fail=0; + int i; + + bus_space_write_2(iot, ioh, ARIADSP_CONTROL, + ARIAR_ARIA_SYNTH | ARIAR_SR22K|ARIAR_DSPINTWR); + aria_putdspmem(sc, 0x6102, 0); + + fail |= aria_sendcmd(sc, ARIADSPC_SYSINIT, 0x0000, 0x0000, 0x0000); + + for (i=0; i < ARIAR_NPOLL; i++) + if (aria_getdspmem(sc, ARIAA_TASK_A) == 1) + break; + + bus_space_write_2(iot, ioh, ARIADSP_CONTROL, + ARIAR_ARIA_SYNTH|ARIAR_SR22K | ARIAR_DSPINTWR | + ARIAR_PCINTWR); + fail |= aria_sendcmd(sc, ARIADSPC_MODE, ARIAV_MODE_NO_SYNTH,-1,-1); + + return (fail); +} + +/* + * Lower-level routines + */ + +void +aria_putdspmem(sc, loc, val) + struct aria_softc *sc; + u_short loc; + u_short val; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + bus_space_write_2(iot, ioh, ARIADSP_DMAADDRESS, loc); + bus_space_write_2(iot, ioh, ARIADSP_DMADATA, val); +} + +u_short +aria_getdspmem(sc, loc) + struct aria_softc *sc; + u_short loc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + bus_space_write_2(iot, ioh, ARIADSP_DMAADDRESS, loc); + return bus_space_read_2(iot, ioh, ARIADSP_DMADATA); +} + +/* + * aria_sendcmd() + * each full DSP command is unified into this + * function. + */ + +#define ARIASEND(data, flag) \ + for (i = ARIAR_NPOLL; \ + (bus_space_read_2(iot, ioh, ARIADSP_STATUS) & ARIAR_BUSY) && i>0; \ + i--) \ + ; \ + if (bus_space_read_2(iot, ioh, ARIADSP_STATUS) & ARIAR_BUSY) \ + fail |= flag; \ + bus_space_write_2(iot, ioh, ARIADSP_WRITE, (u_short)data) + +int +aria_sendcmd(sc, command, arg1, arg2, arg3) + struct aria_softc *sc; + u_short command; + int arg1; + int arg2; + int arg3; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int i, fail = 0; + + ARIASEND(command, 1); + if (arg1 != -1) { + ARIASEND(arg1, 2); + } + if (arg2 != -1) { + ARIASEND(arg2, 4); + } + if (arg3 != -1) { + ARIASEND(arg3, 8); + } + ARIASEND(ARIADSPC_TERM, 16); + + if (fail) { + sc->sc_sendcmd_err++; +#ifdef AUDIO_DEBUG + DPRINTF(("aria_sendcmd: failure=(%d) cmd=(0x%x) fail=(0x%x)\n", + sc->sc_sendcmd_err, command, fail)); +#endif + return -1; + } + + return 0; +} +#undef ARIASEND + +int +aria_halt_input(addr) + void *addr; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_halt_input\n")); + + if (sc->sc_record & (1<<0)) { + aria_sendcmd(sc, ARIADSPC_STOP_REC, 0, -1, -1); + sc->sc_record &= ~(1<<0); + } + + return(0); +} + +int +aria_halt_output(addr) + void *addr; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_halt_output\n")); + + if (sc->sc_play & (1<<1)) { + aria_sendcmd(sc, ARIADSPC_STOP_PLAY, 1, -1, -1); + sc->sc_play &= ~(1<<1); + } + + return(0); +} + +/* + * Here we just set up the buffers. If we receive + * an interrupt without these set, it is ignored. + */ + +int +aria_start_input(addr, p, cc, intr, arg) + void *addr; + void *p; + int cc; + void (*intr) __P((void *)); + void *arg; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_start_input %d @ %x\n", cc, (unsigned) p)); + + if (cc != sc->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<<ARIAR_RECORD_CHAN))) { + aria_sendcmd(sc, ARIADSPC_START_REC, ARIAR_RECORD_CHAN, -1,-1); + sc->sc_record |= (1<<ARIAR_RECORD_CHAN); + } + + return 0; +} + +int +aria_start_output(addr, p, cc, intr, arg) + void *addr; + void *p; + int cc; + void (*intr) __P((void *)); + void *arg; +{ + struct aria_softc *sc = addr; + + DPRINTF(("aria_start_output %d @ %x\n", cc, (unsigned) 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<<ARIAR_PLAY_CHAN))) { + aria_sendcmd(sc, ARIADSPC_START_PLAY, ARIAR_PLAY_CHAN, -1, -1); + sc->sc_play |= (1<<ARIAR_PLAY_CHAN); + } + + return 0; +} + +/* + * Process an interrupt. This should be a + * request (from the card) to write or read + * samples. + */ +int +aria_intr(arg) + void *arg; +{ + struct aria_softc *sc = arg; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_short *pdata = sc->sc_pdiobuffer; + u_short *rdata = sc->sc_rdiobuffer; + u_short address; + +#if 0 /* XXX -- BAD BAD BAD (That this is #define'd out */ + DPRINTF(("Checking to see if this is our intr\n")); + + if ((inw(iobase) & 1) != 0x1) + return 0; /* not for us */ +#endif + + sc->sc_interrupts++; + + DPRINTF(("aria_intr\n")); + + if ((sc->sc_open & ARIAR_OPEN_PLAY) && (pdata!=NULL)) { + DPRINTF(("aria_intr play=(%x)\n", (unsigned) pdata)); + address = 0x8000 - 2*(sc->sc_blocksize); + address+= aria_getdspmem(sc, ARIAA_PLAY_FIFO_A); + bus_space_write_2(iot, ioh, ARIADSP_DMAADDRESS, address); + bus_space_write_multi_2(iot, ioh, 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", (unsigned) rdata)); + address = 0x8000 - (sc->sc_blocksize); + address+= aria_getdspmem(sc, ARIAA_REC_FIFO_A); + bus_space_write_2(iot, ioh, ARIADSP_DMAADDRESS, address); + bus_space_read_multi_2(iot, ioh, ARIADSP_DMADATA, rdata, + sc->sc_blocksize / 2); + if (sc->sc_rintr != NULL) + (*sc->sc_rintr)(sc->sc_rarg); + } + + aria_sendcmd(sc, ARIADSPC_TRANSCOMPLETE, -1, -1, -1); + + return 1; +} + +int +aria_mixer_set_port(addr, cp) + void *addr; + mixer_ctrl_t *cp; +{ + struct aria_softc *sc = addr; + int error = EINVAL; + + DPRINTF(("aria_mixer_set_port\n")); + + /* This could be done better, no mixer still has some controls. */ + if (!(ARIA_MIXER & sc->sc_hardware)) + return ENXIO; + + if (cp->type == AUDIO_MIXER_VALUE) { + 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->sc_gain[0] = mv->level[0]; + sc->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: + /* NOTREACHED */ + return ENXIO; + } + + return(error); +} + +int +aria_mixer_get_port(addr, cp) + void *addr; + mixer_ctrl_t *cp; +{ + struct aria_softc *sc = addr; + int error = EINVAL; + + DPRINTF(("aria_mixer_get_port\n")); + + /* This could be done better, no mixer still has some controls. */ + if (!(ARIA_MIXER&sc->sc_hardware)) + 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->sc_gain[0]; + cp->un.value.level[1] = sc->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; + mixer_devinfo_t *dip; +{ + + struct aria_softc *sc = addr; + + DPRINTF(("aria_mixer_query_devinfo\n")); + + /* This could be done better, no mixer still has some controls. */ + if (!(ARIA_MIXER & sc->sc_hardware)) + 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 mute; + + case ARIAMIX_LINE_IN_MUTE: + dip->prev = ARIAMIX_LINE_IN_LVL; + goto mute; + + case ARIAMIX_CD_MUTE: + dip->prev = ARIAMIX_CD_LVL; + goto mute; + + case ARIAMIX_DAC_MUTE: + dip->prev = ARIAMIX_DAC_LVL; + goto mute; + + case ARIAMIX_AUX_MUTE: + dip->prev = ARIAMIX_AUX_LVL; + goto mute; + + case ARIAMIX_TEL_MUTE: + dip->prev = ARIAMIX_TEL_LVL; + goto mute; + +mute: + 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 = AUDIO_MIXER_LAST; + 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_EQ_CLASS; + strcpy(dip->label.name, AudioNtreble); + 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_EQ_CLASS; + strcpy(dip->label.name, AudioNbass); + 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[4].label.name, AudioNcd); + dip->un.e.member[4].ord = ARIAMIX_CD_LVL; + strcpy(dip->un.e.member[5].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..d1949090fbc --- /dev/null +++ b/sys/dev/isa/ariareg.h @@ -0,0 +1,136 @@ +/* + * 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 31fb3475336..f5c131aff2e 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $NetBSD: files.isa,v 1.60 1998/05/28 16:51:50 drochner Exp $ +# $NetBSD: files.isa,v 1.61 1998/06/06 10:12:35 augustss Exp $ # # Config file and device description for machine-independent ISA code. # Included by ports that need it. Requires that the SCSI files be @@ -289,6 +289,12 @@ device gus: audio, isadma, ics2101, ad1848, mulaw, auconv attach gus at isa file dev/isa/gus.c gus needs-flag +# Sierra's Aria chipset. +# (e.g. Prometheus Aria 16) +device aria: audio, mulaw, auconv +attach aria at isa +file dev/isa/aria.c aria needs-flag + # # PlanetConnect satellite receiver driver. # |
