diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1998-04-26 21:03:19 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1998-04-26 21:03:19 +0000 |
commit | 74d8ccd39b9fa27c65fe29abc88e61deea50b102 (patch) | |
tree | ad8b9504a859efe3f96a8cc68f4c3e76f16886a0 /sys/dev/isa/wss.c | |
parent | db97ee572f05c64c35bd40855c1b415a3b4f08ab (diff) |
update audio from NetBSD, mostly by Lennart Augustsson <augustss@cs.chalmers.se>
Diffstat (limited to 'sys/dev/isa/wss.c')
-rw-r--r-- | sys/dev/isa/wss.c | 441 |
1 files changed, 181 insertions, 260 deletions
diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c index 930516b0ec1..e14338bdd44 100644 --- a/sys/dev/isa/wss.c +++ b/sys/dev/isa/wss.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wss.c,v 1.14 1997/07/10 23:06:40 provos Exp $ */ -/* $NetBSD: wss.c,v 1.13 1996/05/12 23:54:16 mycroft Exp $ */ +/* $OpenBSD: wss.c,v 1.15 1998/04/26 21:03:03 provos Exp $ */ +/* $NetBSD: wss.c,v 1.42 1998/01/19 22:18:23 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -47,6 +47,7 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> @@ -58,26 +59,8 @@ #include <dev/ic/ad1848reg.h> #include <dev/isa/ad1848var.h> #include <dev/isa/wssreg.h> -#include <dev/isa/opti.h> - -/* - * Mixer devices - */ -#define WSS_MIC_IN_LVL 0 -#define WSS_LINE_IN_LVL 1 -#define WSS_DAC_LVL 2 -#define WSS_REC_LVL 3 -#define WSS_MON_LVL 4 -#define WSS_MIC_IN_MUTE 5 -#define WSS_LINE_IN_MUTE 6 -#define WSS_DAC_MUTE 7 - -#define WSS_RECORD_SOURCE 8 - -/* Classes */ -#define WSS_INPUT_CLASS 9 -#define WSS_RECORD_CLASS 10 -#define WSS_MONITOR_CLASS 11 +#include <dev/isa/wssvar.h> +#include <dev/isa/madreg.h> #ifdef AUDIO_DEBUG #define DPRINTF(x) if (wssdebug) printf x @@ -86,191 +69,92 @@ int wssdebug = 0; #define DPRINTF(x) #endif -struct wss_softc { - struct device sc_dev; /* base device */ - struct isadev sc_id; /* ISA device */ - void *sc_ih; /* interrupt vectoring */ - - struct ad1848_softc sc_ad1848; -#define wss_irq sc_ad1848.sc_irq -#define wss_drq sc_ad1848.sc_drq - - int mic_mute, cd_mute, dac_mute; -}; - struct audio_device wss_device = { "wss,ad1848", "", "WSS" }; -int wssopen __P((dev_t, int)); int wss_getdev __P((void *, struct audio_device *)); -int wss_setfd __P((void *, int)); -int wss_set_out_port __P((void *, int)); -int wss_get_out_port __P((void *)); -int wss_set_in_port __P((void *, int)); -int wss_get_in_port __P((void *)); int wss_mixer_set_port __P((void *, mixer_ctrl_t *)); int wss_mixer_get_port __P((void *, mixer_ctrl_t *)); int wss_query_devinfo __P((void *, mixer_devinfo_t *)); static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); + /* * Define our interface to the higher level audio driver. */ struct audio_hw_if wss_hw_if = { - wssopen, + ad1848_open, ad1848_close, NULL, - ad1848_set_in_sr, - ad1848_get_in_sr, - ad1848_set_out_sr, - ad1848_get_out_sr, ad1848_query_encoding, - ad1848_set_format, - ad1848_get_encoding, - ad1848_get_precision, - ad1848_set_channels, - ad1848_get_channels, + ad1848_set_params, ad1848_round_blocksize, - wss_set_out_port, - wss_get_out_port, - wss_set_in_port, - wss_get_in_port, ad1848_commit_settings, - NULL, - NULL, + ad1848_dma_init_output, + ad1848_dma_init_input, ad1848_dma_output, ad1848_dma_input, ad1848_halt_out_dma, ad1848_halt_in_dma, - ad1848_cont_out_dma, - ad1848_cont_in_dma, NULL, wss_getdev, - wss_setfd, + NULL, wss_mixer_set_port, wss_mixer_get_port, wss_query_devinfo, - 0, /* not full-duplex */ - 0 + ad1848_malloc, + ad1848_free, + ad1848_round, + ad1848_mappage, + ad1848_get_props, }; -int wssprobe __P((struct device *, void *, void *)); -void wssattach __P((struct device *, struct device *, void *)); - -struct cfattach wss_ca = { - sizeof(struct wss_softc), wssprobe, wssattach -}; - -struct cfdriver wss_cd = { - NULL, "wss", DV_DULL -}; - -/* - * Probe for the Microsoft Sound System hardware. - */ -int -wssprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - register struct wss_softc *sc = match; - register struct isa_attach_args *ia = aux; - register int iobase = ia->ia_iobase; - static u_char interrupt_bits[12] = { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - static u_char dma_bits[4] = {1, 2, 0, 3}; - - if (!WSS_BASE_VALID(ia->ia_iobase)) { - DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); - return 0; - } - - if( !opti_snd_setup( OPTI_WSS, iobase, ia->ia_irq, ia->ia_drq ) ) - DPRINTF(("ad_detect_A: could not setup OPTi chipset.\n")); - - sc->sc_ad1848.sc_iobase = iobase + WSS_CODEC; - - /* Is there an ad1848 chip at the WSS iobase ? */ - if (ad1848_probe(&sc->sc_ad1848) == 0) { -#if 0 - DPRINTF(("ad_detect_A: no ad1848 found.\n")); -#endif - return 0; - } - - ia->ia_iosize = WSS_NPORT; - - /* Setup WSS interrupt and DMA */ - if (!WSS_DRQ_VALID(ia->ia_drq)) { - DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq)); - return 0; - } - sc->wss_drq = ia->ia_drq; - -#ifdef NEWCONFIG - /* - * If the IRQ wasn't compiled in, auto-detect it. - */ - if (ia->ia_irq == IRQUNK) { - ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848); - if (!WSS_IRQ_VALID(ia->ia_irq)) { - printf("wss: couldn't auto-detect interrupt\n"); - return 0; - } - } - else -#endif - if (!WSS_IRQ_VALID(ia->ia_irq)) { - DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq)); - return 0; - } - - sc->wss_irq = ia->ia_irq; - - outb(iobase+WSS_CONFIG, - (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq])); - - return 1; -} - /* * Attach hardware to driver, attach hardware driver to audio * pseudo-device driver . */ void -wssattach(parent, self, aux) - struct device *parent, *self; - void *aux; +wssattach(sc) + struct wss_softc *sc; { - register struct wss_softc *sc = (struct wss_softc *)self; - struct isa_attach_args *ia = (struct isa_attach_args *)aux; - register int iobase = ia->ia_iobase; - int err; + int version; - sc->sc_ad1848.sc_recdrq = ia->ia_drq; + madattach(sc); -#ifdef NEWCONFIG - isa_establish(&sc->sc_id, &sc->sc_dev); -#endif - sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, + sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->wss_irq, IST_EDGE, IPL_AUDIO, ad1848_intr, &sc->sc_ad1848, sc->sc_dev.dv_xname); ad1848_attach(&sc->sc_ad1848); - printf(" (vers %d)", inb(iobase+WSS_STATUS) & WSS_VERSMASK); + version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK; + printf(" (vers %d)", version); + switch(sc->mad_chip_type) { + case MAD_82C928: + printf(", 82C928"); + break; + case MAD_OTI601D: + printf(", OTI-601D"); + break; + case MAD_82C929: + printf(", 82C929"); + break; + case MAD_82C931: + printf(", 82C931"); + break; + default: + break; + } printf("\n"); sc->sc_ad1848.parent = sc; - if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0) - printf("wss: could not attach to audio pseudo-device driver (%d)\n", err); + audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev); } static int @@ -308,24 +192,6 @@ wss_from_vol(cp, vol) } int -wssopen(dev, flags) - dev_t dev; - int flags; -{ - struct wss_softc *sc; - int unit = AUDIOUNIT(dev); - - if (unit >= wss_cd.cd_ndevs) - return ENODEV; - - sc = wss_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - - return ad1848_open(&sc->sc_ad1848, dev, flags); -} - -int wss_getdev(addr, retp) void *addr; struct audio_device *retp; @@ -335,90 +201,12 @@ wss_getdev(addr, retp) } int -wss_setfd(addr, flag) - void *addr; - int flag; -{ - /* Can't do full-duplex */ - return(ENOTTY); -} - - -int -wss_set_out_port(addr, port) - void *addr; - int port; -{ - DPRINTF(("wss_set_out_port:\n")); - return(EINVAL); -} - -int -wss_get_out_port(addr) - void *addr; -{ - DPRINTF(("wss_get_out_port:\n")); - return(WSS_DAC_LVL); -} - -int -wss_set_in_port(addr, port) - void *addr; - int port; -{ - register struct ad1848_softc *ac = addr; - - DPRINTF(("wss_set_in_port: %d\n", port)); - - switch(port) { - case WSS_MIC_IN_LVL: - port = MIC_IN_PORT; - break; - case WSS_LINE_IN_LVL: - port = LINE_IN_PORT; - break; - case WSS_DAC_LVL: - port = DAC_IN_PORT; - break; - default: - return(EINVAL); - /*NOTREACHED*/ - } - - return(ad1848_set_rec_port(ac, port)); -} - -int -wss_get_in_port(addr) - void *addr; -{ - register struct ad1848_softc *ac = addr; - int port = WSS_MIC_IN_LVL; - - switch(ad1848_get_rec_port(ac)) { - case MIC_IN_PORT: - port = WSS_MIC_IN_LVL; - break; - case LINE_IN_PORT: - port = WSS_LINE_IN_LVL; - break; - case DAC_IN_PORT: - port = WSS_DAC_LVL; - break; - } - - DPRINTF(("wss_get_in_port: %d\n", port)); - - return(port); -} - -int wss_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct wss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct wss_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -503,8 +291,8 @@ wss_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct wss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct wss_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -590,7 +378,7 @@ wss_mixer_get_port(addr, cp) int wss_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { DPRINTF(("wss_query_devinfo: index=%d\n", dip->index)); @@ -648,21 +436,21 @@ wss_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_INPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + strcpy(dip->label.name, AudioCinputs); break; case WSS_MONITOR_CLASS: /* monitor class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_MONITOR_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNmonitor); + strcpy(dip->label.name, AudioCmonitor); break; case WSS_RECORD_CLASS: /* record source class */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_RECORD_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNrecord); + strcpy(dip->label.name, AudioCrecord); break; case WSS_MIC_IN_MUTE: @@ -716,3 +504,136 @@ wss_query_devinfo(addr, dip) return 0; } + + +/* + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * Initialization code for OPTi MAD16 compatible audio chips. Including + * + * OPTi 82C928 MAD16 (replaced by C929) + * OAK OTI-601D Mozart + * OPTi 82C929 MAD16 Pro + * + */ + +u_int +mad_read(sc, port) + struct wss_softc *sc; + int port; +{ + u_int tmp; + int pwd; + int s; + + switch (sc->mad_chip_type) { /* Output password */ + case MAD_82C928: + case MAD_OTI601D: + pwd = M_PASSWD_928; + break; + case MAD_82C929: + pwd = M_PASSWD_929; + break; + case MAD_82C931: + pwd = M_PASSWD_931; + break; + default: + panic("mad_read: Bad chip type=%d\n", sc->mad_chip_type); + } + s = splaudio(); /* don't want an interrupt between outb&inb */ + bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); + tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port); + splx(s); + return tmp; +} + +void +mad_write(sc, port, value) + struct wss_softc *sc; + int port; + int value; +{ + int pwd; + int s; + + switch (sc->mad_chip_type) { /* Output password */ + case MAD_82C928: + case MAD_OTI601D: + pwd = M_PASSWD_928; + break; + case MAD_82C929: + pwd = M_PASSWD_929; + break; + case MAD_82C931: + pwd = M_PASSWD_931; + break; + default: + panic("mad_write: Bad chip type=%d\n", sc->mad_chip_type); + } + s = splaudio(); + bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); + bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff); + splx(s); +} + +void +madattach(sc) + struct wss_softc *sc; +{ + unsigned char cs4231_mode; + int joy; + + if (sc->mad_chip_type == MAD_NONE) + return; + + /* Do we want the joystick disabled? */ + joy = sc->sc_dev.dv_cfdata->cf_flags & 2 ? MC1_JOYDISABLE : 0; + + /* enable WSS emulation at the I/O port */ + mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(sc->mad_ioindex) | joy); + mad_write(sc, MC2_PORT, 0x03); /* ? */ + mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */ + + cs4231_mode = + strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 || + strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0; + + if (sc->mad_chip_type == MAD_82C929) { + mad_write(sc, MC4_PORT, 0x92); + mad_write(sc, MC5_PORT, 0xA5 | cs4231_mode); + mad_write(sc, MC6_PORT, 0x03); /* Disable MPU401 */ + } else { + mad_write(sc, MC4_PORT, 0x02); + mad_write(sc, MC5_PORT, 0x30 | cs4231_mode); + } + +#ifdef AUDIO_DEBUG + if (wssdebug) { + int i; + for (i = MC1_PORT; i <= MC7_PORT; i++) + DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, i))); + } +#endif +} |