diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-02 00:02:57 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-02 00:02:57 +0000 |
commit | 16eef665101a8c1334032296ea7d1584ff9c7e57 (patch) | |
tree | 5cc9b881cb0bdd13a85c95e2cbd124b47ddc4645 /sys/dev/isa | |
parent | 890d46b55a21bec77e2f60dbf22d16199ccdbaa7 (diff) |
Midi & sequencer support from NetBSD, mostly by Lennart Augustsson
Diffstat (limited to 'sys/dev/isa')
-rw-r--r-- | sys/dev/isa/files.isa | 30 | ||||
-rw-r--r-- | sys/dev/isa/gus.c | 5 | ||||
-rw-r--r-- | sys/dev/isa/midi_pcppi.c | 165 | ||||
-rw-r--r-- | sys/dev/isa/mpu401.c | 226 | ||||
-rw-r--r-- | sys/dev/isa/mpu401var.h | 57 | ||||
-rw-r--r-- | sys/dev/isa/opl_isa.c | 105 | ||||
-rw-r--r-- | sys/dev/isa/opl_sb.c | 113 | ||||
-rw-r--r-- | sys/dev/isa/pas.c | 23 | ||||
-rw-r--r-- | sys/dev/isa/pcppi.c | 235 | ||||
-rw-r--r-- | sys/dev/isa/pcppireg.h | 11 | ||||
-rw-r--r-- | sys/dev/isa/pcppivar.h | 37 | ||||
-rw-r--r-- | sys/dev/isa/pss.c | 4 | ||||
-rw-r--r-- | sys/dev/isa/sb.c | 136 | ||||
-rw-r--r-- | sys/dev/isa/sb_isapnp.c | 23 | ||||
-rw-r--r-- | sys/dev/isa/sbdsp.c | 641 | ||||
-rw-r--r-- | sys/dev/isa/sbdspvar.h | 54 | ||||
-rw-r--r-- | sys/dev/isa/spkr.c | 502 | ||||
-rw-r--r-- | sys/dev/isa/spkrio.h | 19 | ||||
-rw-r--r-- | sys/dev/isa/wss.c | 4 | ||||
-rw-r--r-- | sys/dev/isa/ym.c | 4 |
20 files changed, 1993 insertions, 401 deletions
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 62da4a6e5a1..eb45fe2bf1e 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,7 +1,7 @@ -# $OpenBSD: files.isa,v 1.48 1998/12/27 09:41:56 deraadt Exp $ +# $OpenBSD: files.isa,v 1.49 1999/01/02 00:02:45 niklas Exp $ # $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $ # -# Config.new file and device description for machine-independent ISA code. +# Config file and device description for machine-independent ISA code. # Included by ports that need it. Requires that the SCSI files be # defined first. @@ -231,17 +231,24 @@ file dev/isa/if_sm_isa.c sm_isa # ISA Sound hardware # +# MPU401 MIDI UART compatibles +define mpu401 +file dev/isa/mpu401.c mpu401 & midi + # the SoundBlaster DSP, or close likenesses; used by other drivers -define sbdsp +define sbdsp { } file dev/isa/sbdsp.c sbdsp # SoundBlaster family -device sb: audio, isa_dma, sbdsp, mulaw, opti, auconv +device sb: audio, isa_dma, sbdsp, mulaw, opti, auconv, mpu401, midibus file dev/isa/sb.c sb needs-flag attach sb at isa with sb_isa file dev/isa/sb_isa.c sb & (sb_isa | sb_isapnp) needs-flag +attach opl at sbdsp with opl_sb +file dev/isa/opl_sb.c opl_sb + # Soundcards based on Sierra's Aria chipset. # Such as the Prometheus Aria 16 or the Diamond # sonic sound. @@ -286,6 +293,20 @@ device gus: audio, isa_dma, ics2101, ad1848, mulaw, auconv attach gus at isa file dev/isa/gus.c gus needs-flag +# Yamaha OPL2/OPL3 FM synth +attach opl at isa with opl_isa +file dev/isa/opl_isa.c opl_isa + +# PC PPI + TIMER 1 (speaker interface) +device pcppi {} +attach pcppi at isa +file dev/isa/pcppi.c pcppi needs-flag +device spkr +attach spkr at pcppi +file dev/isa/spkr.c spkr needs-flag +attach midi at pcppi with midi_pcppi: midisyn +file dev/isa/midi_pcppi.c midi_pcppi + # # PCMCIA PCIC (i82365SL and compatibles): # @@ -296,4 +317,3 @@ file dev/isa/gus.c gus needs-flag #file dev/isa/pcmcia_pcic.c pcic | pcicmaster #file dev/isa/pcmcia_isa.c pcmcia - diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c index 50a6de1db83..d7e244e246a 100644 --- a/sys/dev/isa/gus.c +++ b/sys/dev/isa/gus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gus.c,v 1.18 1998/11/03 21:14:59 downsj Exp $ */ +/* $OpenBSD: gus.c,v 1.19 1999/01/02 00:02:45 niklas Exp $ */ /* $NetBSD: gus.c,v 1.51 1998/01/25 23:48:06 mycroft Exp $ */ /*- @@ -1039,7 +1039,8 @@ gusattach(parent, self, aux) * Attach to the generic audio layer */ - audio_attach_mi(&gus_hw_if, 0, HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc, &sc->sc_dev); + audio_attach_mi(&gus_hw_if, + HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc, &sc->sc_dev); } int diff --git a/sys/dev/isa/midi_pcppi.c b/sys/dev/isa/midi_pcppi.c new file mode 100644 index 00000000000..c42ae87fe5d --- /dev/null +++ b/sys/dev/isa/midi_pcppi.c @@ -0,0 +1,165 @@ +/* $OpenBSD: midi_pcppi.c,v 1.1 1999/01/02 00:02:42 niklas Exp $ */ +/* $NetBSD: midi_pcppi.c,v 1.4 1998/11/25 22:17:06 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (augustss@netbsd.org). + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/select.h> +#include <sys/audioio.h> +#include <sys/midiio.h> + +#include <dev/isa/pcppivar.h> + +#include <dev/audio_if.h> +#include <dev/midi_if.h> +#include <dev/midivar.h> +#include <dev/midisynvar.h> + +#define MAX_DURATION 30 /* turn off sound automagically after 30 s */ + +struct midi_pcppi_softc { + struct midi_softc sc_mididev; + midisyn sc_midisyn; +}; + +#define __BROKEN_INDIRECT_CONFIG /* XXX */ +#ifdef __BROKEN_INDIRECT_CONFIG +int midi_pcppi_match __P((struct device *, void *, void *)); +#else +int midi_pcppi_match __P((struct device *, struct cfdata *, void *)); +#endif +void midi_pcppi_attach __P((struct device *, struct device *, void *)); + +void midi_pcppi_on __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); +void midi_pcppi_off __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); +void midi_pcppi_close __P((midisyn *)); + +struct cfattach midi_pcppi_ca = { + sizeof(struct midi_pcppi_softc), midi_pcppi_match, midi_pcppi_attach +}; + +struct midisyn_methods midi_pcppi_hw = { + 0, /* open */ + midi_pcppi_close, + 0, /* ioctl */ + 0, /* allocv */ + midi_pcppi_on, + midi_pcppi_off, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +int midi_pcppi_attached = 0; /* Not very nice */ + +int +midi_pcppi_match(parent, match, aux) + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + return (!midi_pcppi_attached); +} + +void +midi_pcppi_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct midi_pcppi_softc *sc = (struct midi_pcppi_softc *)self; + struct pcppi_attach_args *pa = (struct pcppi_attach_args *)aux; + midisyn *ms; + + ms = &sc->sc_midisyn; + ms->mets = &midi_pcppi_hw; + strcpy(ms->name, "PC speaker"); + ms->nvoice = 1; + ms->flags = MS_DOALLOC | MS_FREQXLATE; + ms->data = pa->pa_cookie; + + midi_pcppi_attached++; + + midisyn_attach(&sc->sc_mididev, ms); + midi_attach(&sc->sc_mididev, parent); +} + +void +midi_pcppi_on(ms, chan, note, vel) + midisyn *ms; + u_int32_t chan, note, vel; +{ + pcppi_tag_t t = ms->data; + + /*printf("ON %p %d\n", t, MIDISYN_FREQ_TO_HZ(note));*/ + pcppi_bell(t, MIDISYN_FREQ_TO_HZ(note), MAX_DURATION * hz, 0); +} + +void +midi_pcppi_off(ms, chan, note, vel) + midisyn *ms; + u_int32_t chan, note, vel; +{ + pcppi_tag_t t = ms->data; + + /*printf("OFF %p %d\n", t, note >> 16);*/ + pcppi_bell(t, 0, 0, 0); +} + +void +midi_pcppi_close(ms) + midisyn *ms; +{ + pcppi_tag_t t = ms->data; + + /* Make sure we are quiet. */ + pcppi_bell(t, 0, 0, 0); +} diff --git a/sys/dev/isa/mpu401.c b/sys/dev/isa/mpu401.c new file mode 100644 index 00000000000..6463690724a --- /dev/null +++ b/sys/dev/isa/mpu401.c @@ -0,0 +1,226 @@ +/* $OpenBSD: mpu401.c,v 1.1 1999/01/02 00:02:42 niklas Exp $ */ +/* $NetBSD: mpu401.c,v 1.3 1998/11/25 22:17:06 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (augustss@netbsd.org). + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#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/intr.h> +#include <machine/bus.h> + +#include <dev/midi_if.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> + +#include <dev/isa/mpu401var.h> + +#define splaudio() splbio() /* XXX found in audio_if.h normally */ + +#ifdef AUDIO_DEBUG +#define DPRINTF(x) if (mpu401debug) printf x +#define DPRINTFN(n,x) if (mpu401debug >= (n)) printf x +int mpu401debug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +#define MPU401_NPORT 2 +#define MPU_DATA 0 +#define MPU_COMMAND 1 +#define MPU_RESET 0xff +#define MPU_UART_MODE 0x3f +#define MPU_ACK 0xfe +#define MPU_STATUS 1 +#define MPU_OUTPUT_BUSY 0x40 +#define MPU_INPUT_EMPTY 0x80 + +#define MPU_MAXWAIT 10000 /* usec/10 to wait */ + +#define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS)) + +int mpu401_reset(struct mpu401_softc *); +static __inline int mpu401_waitready(struct mpu401_softc *); +void mpu401_readinput(struct mpu401_softc *); + +int +mpu401_find(sc) + struct mpu401_softc *sc; +{ + if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) { + DPRINTF(("mpu401_find: No status\n")); + goto bad; + } + sc->open = 0; + sc->intr = 0; + if (mpu401_reset(sc) == 0) + return 1; +bad: + return 0; +} + +static __inline int +mpu401_waitready(sc) + struct mpu401_softc *sc; +{ + int i; + + for(i = 0; i < MPU_MAXWAIT; i++) { + if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)) + return 0; + delay(10); + } + return 1; +} + +int +mpu401_reset(sc) + struct mpu401_softc *sc; +{ + bus_space_tag_t iot = sc->iot; + bus_space_handle_t ioh = sc->ioh; + int i; + int s; + + if (mpu401_waitready(sc)) { + DPRINTF(("mpu401_reset: not ready\n")); + return EIO; + } + s = splaudio(); /* Don't let the interrupt get our ACK. */ + bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET); + for(i = 0; i < 2*MPU_MAXWAIT; i++) { + if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) && + bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) { + splx(s); + return 0; + } + } + splx(s); + DPRINTF(("mpu401_reset: No ACK\n")); + return EIO; +} + +int +mpu401_open(sc, flags, iintr, ointr, arg) + struct mpu401_softc *sc; + int flags; + void (*iintr)__P((void *, int)); + void (*ointr)__P((void *)); + void *arg; +{ + DPRINTF(("mpu401_open: sc=%p\n", sc)); + + if (sc->open) + return EBUSY; + if (mpu401_reset(sc) != 0) + return EIO; + + bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE); + sc->open = 1; + sc->intr = iintr; + sc->arg = arg; + return 0; +} + +void +mpu401_close(sc) + struct mpu401_softc *sc; +{ + DPRINTF(("mpu401_close: sc=%p\n", sc)); + + sc->open = 0; + sc->intr = 0; + mpu401_reset(sc); /* exit UART mode */ +} + +void +mpu401_readinput(sc) + struct mpu401_softc *sc; +{ + bus_space_tag_t iot = sc->iot; + bus_space_handle_t ioh = sc->ioh; + int data; + + while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) { + data = bus_space_read_1(iot, ioh, MPU_DATA); + DPRINTFN(3, ("mpu401_rea: sc=%p 0x%02x\n", sc, data)); + if (sc->intr) + sc->intr(sc->arg, data); + } +} + +int +mpu401_output(sc, d) + struct mpu401_softc *sc; + int d; +{ + int s; + + DPRINTFN(3, ("mpu401_output: sc=%p 0x%02x\n", sc, d)); + if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) { + s = splaudio(); + mpu401_readinput(sc); + splx(s); + } + if (mpu401_waitready(sc)) { + DPRINTF(("mpu401_output: not ready\n")); + return EIO; + } + bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d); + return 0; +} + +void +mpu401_intr(sc) + struct mpu401_softc *sc; +{ + if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) { + DPRINTF(("mpu401_intr: no data\n")); + return; + } + mpu401_readinput(sc); +} diff --git a/sys/dev/isa/mpu401var.h b/sys/dev/isa/mpu401var.h new file mode 100644 index 00000000000..a197e4f6184 --- /dev/null +++ b/sys/dev/isa/mpu401var.h @@ -0,0 +1,57 @@ +/* $OpenBSD: mpu401var.h,v 1.1 1999/01/02 00:02:43 niklas Exp $ */ +/* $NetBSD: mpu401var.h,v 1.3 1998/11/25 22:17:06 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (augustss@netbsd.org). + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +struct mpu401_softc { + bus_space_tag_t iot; /* tag */ + bus_space_handle_t ioh; /* handle */ + int iobase; + int open; + void (*intr)__P((void*, int)); /* midi input intr handler */ + void *arg; /* arg for intr() */ +}; + +struct midi_hw_if mpu401_midi_hw_if; + +void mpu401_intr __P((struct mpu401_softc *)); +int mpu401_find __P((struct mpu401_softc *)); +int mpu401_open __P((struct mpu401_softc *, int, + void (*iintr)__P((void *, int)), + void (*ointr)__P((void *)), void *arg)); +void mpu401_close __P((struct mpu401_softc *)); +int mpu401_output __P((struct mpu401_softc *, int)); diff --git a/sys/dev/isa/opl_isa.c b/sys/dev/isa/opl_isa.c new file mode 100644 index 00000000000..ff326b6ede5 --- /dev/null +++ b/sys/dev/isa/opl_isa.c @@ -0,0 +1,105 @@ +/* $OpenBSD: opl_isa.c,v 1.1 1999/01/02 00:02:44 niklas Exp $ */ +/* $NetBSD: opl_isa.c,v 1.1 1998/08/26 13:33:59 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Author: Lennart Augustsson + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/select.h> +#include <sys/audioio.h> +#include <sys/midiio.h> + +#include <machine/bus.h> + +#include <dev/audio_if.h> +#include <dev/midi_if.h> + +#include <dev/ic/oplreg.h> +#include <dev/ic/oplvar.h> + +#include <dev/isa/isavar.h> + +#define OPL_SIZE 4 + +int opl_isa_match __P((struct device *, struct cfdata *, void *)); +void opl_isa_attach __P((struct device *, struct device *, void *)); + +struct cfattach opl_isa_ca = { + sizeof (struct opl_softc), opl_isa_match, opl_isa_attach +}; + +int +opl_isa_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct isa_attach_args *ia = aux; + struct opl_softc sc; + int r; + + memset(&sc, 0, sizeof sc); + sc.iot = ia->ia_iot; + if (bus_space_map(sc.iot, ia->ia_iobase, OPL_SIZE, 0, &sc.ioh)) + return (0); + r = opl_find(&sc); + bus_space_unmap(sc.iot, sc.ioh, OPL_SIZE); + return (r); +} + +void +opl_isa_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct opl_softc *sc = (struct opl_softc *)self; + struct isa_attach_args *ia = aux; + + if (bus_space_map(sc->iot, ia->ia_iobase, OPL_SIZE, 0, &sc->ioh)) { + printf("opl_isa_attach: bus_space_map failed\n"); + return; + } + sc->offs = 0; + + opl_attach(sc); +} diff --git a/sys/dev/isa/opl_sb.c b/sys/dev/isa/opl_sb.c new file mode 100644 index 00000000000..b2a41c3fe92 --- /dev/null +++ b/sys/dev/isa/opl_sb.c @@ -0,0 +1,113 @@ +/* $OpenBSD: opl_sb.c,v 1.1 1999/01/02 00:02:45 niklas Exp $ */ +/* $NetBSD: opl_sb.c,v 1.4 1998/12/08 14:26:57 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (augustss@netbsd.org). + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/select.h> +#include <sys/audioio.h> +#include <sys/midiio.h> + +#include <machine/bus.h> + +#include <dev/audio_if.h> +#include <dev/midi_if.h> +#include <dev/ic/oplreg.h> +#include <dev/ic/oplvar.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/sbdspvar.h> + +#define __BROKEN_INDIRECT_CONFIG /* XXX */ +#ifdef __BROKEN_INDIRECT_CONFIG +int opl_sb_match __P((struct device *, void *, void *)); +#else +int opl_sb_match __P((struct device *, struct cfdata *, void *)); +#endif +void opl_sb_attach __P((struct device *, struct device *, void *)); + +struct cfattach opl_sb_ca = { + sizeof (struct opl_softc), opl_sb_match, opl_sb_attach +}; + +int +opl_sb_match(parent, match, aux) + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + struct audio_attach_args *aa = (struct audio_attach_args *)aux; + struct sbdsp_softc *ssc = (struct sbdsp_softc *)parent; + struct opl_softc sc; + + if (aa->type != AUDIODEV_TYPE_OPL) + return (0); + memset(&sc, 0, sizeof sc); + sc.ioh = ssc->sc_ioh; + sc.iot = ssc->sc_iot; + return (opl_find(&sc)); +} + +void +opl_sb_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct sbdsp_softc *ssc = (struct sbdsp_softc *)parent; + struct opl_softc *sc = (struct opl_softc *)self; + + sc->ioh = ssc->sc_ioh; + sc->iot = ssc->sc_iot; + sc->offs = 0; + sc->spkrctl = sbdsp_speaker_ctl; + sc->spkrarg = ssc; + strcpy(sc->syn.name, "SB "); + + opl_attach(sc); +} diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c index 771bf81ad58..77a3108b062 100644 --- a/sys/dev/isa/pas.c +++ b/sys/dev/isa/pas.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pas.c,v 1.17 1998/11/03 21:15:00 downsj Exp $ */ +/* $OpenBSD: pas.c,v 1.18 1999/01/02 00:02:46 niklas Exp $ */ /* $NetBSD: pas.c,v 1.37 1998/01/12 09:43:43 thorpej Exp $ */ /* @@ -62,6 +62,7 @@ #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/midi_if.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -113,20 +114,20 @@ void pasconf __P((int, int, int, int)); struct audio_hw_if pas_hw_if = { sbdsp_open, sbdsp_close, - NULL, + 0, sbdsp_query_encoding, sbdsp_set_params, sbdsp_round_blocksize, - NULL, - sbdsp_dma_init_output, - sbdsp_dma_init_input, - sbdsp_dma_output, - sbdsp_dma_input, + 0, + 0, + 0, + 0, + 0, sbdsp_haltdma, sbdsp_haltdma, sbdsp_speaker_ctl, pas_getdev, - NULL, + 0, sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, @@ -135,8 +136,8 @@ struct audio_hw_if pas_hw_if = { sb_round, sb_mappage, sbdsp_get_props, - NULL, - NULL + sbdsp_trigger_output, + sbdsp_trigger_input }; /* The Address Translation code is used to convert I/O register addresses to @@ -459,7 +460,7 @@ pasattach(parent, self, aux) sprintf(pas_device.name, "pas,%s", pasnames[sc->model]); sprintf(pas_device.version, "%d", sc->rev); - audio_attach_mi(&pas_hw_if, 0, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev); + audio_attach_mi(&pas_hw_if, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev); } int diff --git a/sys/dev/isa/pcppi.c b/sys/dev/isa/pcppi.c new file mode 100644 index 00000000000..3fdba2b4dcb --- /dev/null +++ b/sys/dev/isa/pcppi.c @@ -0,0 +1,235 @@ +/* $OpenBSD: pcppi.c,v 1.1 1999/01/02 00:02:44 niklas Exp $ */ +/* $NetBSD: pcppi.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ + +/* + * Copyright (c) 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/errno.h> + +#include <machine/bus.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/isa/pcppireg.h> +#include <dev/isa/pcppivar.h> + +#include <dev/ic/i8253reg.h> + +struct pcppi_softc { + struct device sc_dv; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ppi_ioh, sc_pit1_ioh; + + int sc_bellactive, sc_bellpitch; + int sc_slp; +}; + +#define __BROKEN_INDIRECT_CONFIG /* XXX */ +#ifdef __BROKEN_INDIRECT_CONFIG +int pcppi_match __P((struct device *, void *, void *)); +#else +int pcppi_match __P((struct device *, struct cfdata *, void *)); +#endif +void pcppi_attach __P((struct device *, struct device *, void *)); + +struct cfattach pcppi_ca = { + sizeof(struct pcppi_softc), pcppi_match, pcppi_attach, +}; + +struct cfdriver pcppi_cd = { + NULL, "pcppi", DV_DULL +}; + +static void pcppi_bell_stop __P((void*)); + +#define PCPPIPRI (PZERO - 1) + +int +pcppi_match(parent, match, aux) + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + struct isa_attach_args *ia = aux; + bus_space_handle_t ppi_ioh, pit1_ioh; + int have_pit1, have_ppi, rv; + u_int8_t v, nv; + + /* If values are hardwired to something that they can't be, punt. */ + if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_PPI) || + ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || + ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) + return (0); + + rv = 0; + have_pit1 = have_ppi = 0; + + if (bus_space_map(ia->ia_iot, IO_TIMER1, 4, 0, &pit1_ioh)) + goto lose; + have_pit1 = 1; + if (bus_space_map(ia->ia_iot, IO_PPI, 1, 0, &ppi_ioh)) + goto lose; + have_ppi = 1; + + /* + * Check for existence of PPI. Realistically, this is either going to + * be here or nothing is going to be here. + * + * We don't want to have any chance of changing speaker output (which + * this test might, if it crashes in the middle, or something; + * normally it's be to quick to produce anthing audible), but + * many "combo chip" mock-PPI's don't seem to support the top bit + * of Port B as a settable bit. The bottom bit has to be settable, + * since the speaker driver hardware still uses it. + */ + v = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ + bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v ^ 0x01); /* XXX */ + nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ + if (((nv ^ v) & 0x01) == 0x01) + rv = 1; + bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v); /* XXX */ + nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */ + if (((nv ^ v) & 0x01) != 0x00) { + rv = 0; + goto lose; + } + + /* + * We assume that the programmable interval timer is there. + */ + +lose: + if (have_pit1) + bus_space_unmap(ia->ia_iot, pit1_ioh, 4); + if (have_ppi) + bus_space_unmap(ia->ia_iot, ppi_ioh, 1); + if (rv) { + ia->ia_iobase = IO_PPI; + ia->ia_iosize = 0x1; + ia->ia_msize = 0x0; + } + return (rv); +} + +void +pcppi_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pcppi_softc *sc = (struct pcppi_softc *)self; + struct isa_attach_args *ia = aux; + bus_space_tag_t iot; + struct pcppi_attach_args pa; + + sc->sc_iot = iot = ia->ia_iot; + + if (bus_space_map(iot, IO_TIMER1, 4, 0, &sc->sc_pit1_ioh) || + bus_space_map(iot, IO_PPI, 1, 0, &sc->sc_ppi_ioh)) + panic("pcppi_attach: couldn't map"); + + printf("\n"); + + sc->sc_bellactive = sc->sc_bellpitch = sc->sc_slp = 0; + + pa.pa_cookie = sc; + while (config_found(self, &pa, 0)); +} + +void +pcppi_bell(self, pitch, period, slp) + pcppi_tag_t self; + int pitch, period; + int slp; +{ + struct pcppi_softc *sc = self; + int s1, s2; + + s1 = spltty(); /* ??? */ + if (sc->sc_bellactive) { + untimeout(pcppi_bell_stop, sc); + if (sc->sc_slp) + wakeup(pcppi_bell_stop); + } + if (pitch == 0 || period == 0) { + pcppi_bell_stop(sc); + sc->sc_bellpitch = 0; + splx(s1); + return; + } + if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) { + s2 = splhigh(); + bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_MODE, + TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); + bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2, + TIMER_DIV(pitch) % 256); + bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2, + TIMER_DIV(pitch) / 256); + splx(s2); + /* enable speaker */ + bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0, + bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0) + | PIT_SPKR); + } + sc->sc_bellpitch = pitch; + + sc->sc_bellactive = 1; + timeout(pcppi_bell_stop, sc, period); + if (slp) { + sc->sc_slp = 1; + tsleep(pcppi_bell_stop, PCPPIPRI | PCATCH, "bell", 0); + sc->sc_slp = 0; + } + splx(s1); +} + +static void +pcppi_bell_stop(arg) + void *arg; +{ + struct pcppi_softc *sc = arg; + int s; + + s = spltty(); /* ??? */ + /* disable bell */ + bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0, + bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0) + & ~PIT_SPKR); + sc->sc_bellactive = 0; + if (sc->sc_slp) + wakeup(pcppi_bell_stop); + splx(s); +} diff --git a/sys/dev/isa/pcppireg.h b/sys/dev/isa/pcppireg.h new file mode 100644 index 00000000000..8667ab80e6d --- /dev/null +++ b/sys/dev/isa/pcppireg.h @@ -0,0 +1,11 @@ +/* $OpenBSD: pcppireg.h,v 1.1 1999/01/02 00:02:44 niklas Exp $ */ +/* $NetBSD: pcppireg.h,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ + +/* + * PPI speaker control values + */ + +#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */ +#define PIT_SPKRDATA 0x02 /* Direct to speaker */ + +#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA) diff --git a/sys/dev/isa/pcppivar.h b/sys/dev/isa/pcppivar.h new file mode 100644 index 00000000000..fb61b38e9fa --- /dev/null +++ b/sys/dev/isa/pcppivar.h @@ -0,0 +1,37 @@ +/* $OpenBSD: pcppivar.h,v 1.1 1999/01/02 00:02:45 niklas Exp $ */ +/* $NetBSD: pcppivar.h,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ + +/* + * Copyright (c) 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +typedef void *pcppi_tag_t; + +struct pcppi_attach_args { + pcppi_tag_t pa_cookie; +}; + +void pcppi_bell __P((pcppi_tag_t, int, int, int)); diff --git a/sys/dev/isa/pss.c b/sys/dev/isa/pss.c index 0013819440a..acbc6b2e1b1 100644 --- a/sys/dev/isa/pss.c +++ b/sys/dev/isa/pss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pss.c,v 1.16 1998/11/03 21:15:01 downsj Exp $ */ +/* $OpenBSD: pss.c,v 1.17 1999/01/02 00:02:46 niklas Exp $ */ /* $NetBSD: pss.c,v 1.38 1998/01/12 09:43:44 thorpej Exp $ */ /* @@ -1050,7 +1050,7 @@ pssattach(parent, self, aux) (void)pss_set_treble(sc, AUDIO_MAX_GAIN/2); (void)pss_set_bass(sc, AUDIO_MAX_GAIN/2); - audio_attach_mi(&pss_audio_if, 0, sc->ad1848_sc, &sc->ad1848_sc->sc_dev); + audio_attach_mi(&pss_audio_if, sc->ad1848_sc, &sc->ad1848_sc->sc_dev); } void diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c index 46ee9b33aaa..10306436c48 100644 --- a/sys/dev/isa/sb.c +++ b/sys/dev/isa/sb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sb.c,v 1.16 1998/11/03 21:15:01 downsj Exp $ */ +/* $OpenBSD: sb.c,v 1.17 1999/01/02 00:02:47 niklas Exp $ */ /* $NetBSD: sb.c,v 1.57 1998/01/12 09:43:46 thorpej Exp $ */ /* @@ -35,6 +35,8 @@ * */ +#include "midi.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> @@ -50,6 +52,7 @@ #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/midi_if.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -62,6 +65,31 @@ struct cfdriver sb_cd = { NULL, "sb", DV_DULL }; +#if NMIDI > 0 +int sb_mpu401_open __P((void *, int, + void (*iintr)__P((void *, int)), + void (*ointr)__P((void *)), void *arg)); +void sb_mpu401_close __P((void *)); +int sb_mpu401_output __P((void *, int)); +void sb_mpu401_getinfo __P((void *, struct midi_info *)); + +struct midi_hw_if sb_midi_hw_if = { + sbdsp_midi_open, + sbdsp_midi_close, + sbdsp_midi_output, + sbdsp_midi_getinfo, + 0, /* ioctl */ +}; + +struct midi_hw_if sb_mpu401_hw_if = { + sb_mpu401_open, + sb_mpu401_close, + sb_mpu401_output, + sb_mpu401_getinfo, + 0, /* ioctl */ +}; +#endif + struct audio_device sb_device = { "SoundBlaster", "x", @@ -77,20 +105,20 @@ int sb_getdev __P((void *, struct audio_device *)); struct audio_hw_if sb_hw_if = { sbdsp_open, sbdsp_close, - NULL, + 0, sbdsp_query_encoding, sbdsp_set_params, sbdsp_round_blocksize, - NULL, - sbdsp_dma_init_output, - sbdsp_dma_init_input, - sbdsp_dma_output, - sbdsp_dma_input, + 0, + 0, + 0, + 0, + 0, sbdsp_haltdma, sbdsp_haltdma, sbdsp_speaker_ctl, sb_getdev, - NULL, + 0, sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, @@ -99,8 +127,8 @@ struct audio_hw_if sb_hw_if = { sb_round, sb_mappage, sbdsp_get_props, - NULL, - NULL + sbdsp_trigger_output, + sbdsp_trigger_input }; #ifdef AUDIO_DEBUG @@ -249,41 +277,35 @@ void sbattach(sc) struct sbdsp_softc *sc; { + struct audio_attach_args arg; +#if NMIDI > 0 + struct midi_hw_if *mhw = &sb_midi_hw_if; +#endif + sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq, IST_EDGE, IPL_AUDIO, sbdsp_intr, sc, sc->sc_dev.dv_xname); sbdsp_attach(sc); - audio_attach_mi(&sb_hw_if, 0, sc, &sc->sc_dev); -} - -#ifdef NEWCONFIG -void -sbforceintr(aux) - void *aux; -{ - static char dmabuf; - struct sbdsp_softc *sc = aux; - - /* - * Set up a DMA read of one byte. - * XXX Note that at this point we haven't called - * at_setup_dmachan(). This is okay because it just - * allocates a buffer in case it needs to make a copy, - * and it won't need to make a copy for a 1 byte buffer. - * (I think that calling at_setup_dmachan() should be optional; - * if you don't call it, it will be called the first time - * it is needed (and you pay the latency). Also, you might - * never need the buffer anyway.) - */ - at_dma(DMAMODE_READ, &dmabuf, 1, sc->sc_drq8); - if (sbdsp_wdsp(sc, SB_DSP_RDMA) == 0) { - (void)sbdsp_wdsp(sc, 0); - (void)sbdsp_wdsp(sc, 0); +#if NMIDI > 0 + sc->sc_hasmpu = 0; + if (ISSB16CLASS(sc) && sc->sc_mpu_sc.iobase != 0) { + sc->sc_mpu_sc.iot = sc->sc_iot; + if (mpu401_find(&sc->sc_mpu_sc)) { + sc->sc_hasmpu = 1; + mhw = &sb_mpu401_hw_if; + } } -} + midi_attach_mi(mhw, sc, &sc->sc_dev); #endif + audio_attach_mi(&sb_hw_if, sc, &sc->sc_dev); + + arg.type = AUDIODEV_TYPE_OPL; + arg.hwif = 0; + arg.hdl = 0; + (void)config_found(&sc->sc_dev, &arg, audioprint); +} /* * Various routines to interface to higher level audio driver @@ -313,3 +335,43 @@ sb_getdev(addr, retp) return 0; } + +#if NMIDI > 0 + +#define SBMPU(a) (&((struct sbdsp_softc *)addr)->sc_mpu_sc) + +int +sb_mpu401_open(addr, flags, iintr, ointr, arg) + void *addr; + int flags; + void (*iintr)__P((void *, int)); + void (*ointr)__P((void *)); + void *arg; +{ + return mpu401_open(SBMPU(addr), flags, iintr, ointr, arg); +} + +int +sb_mpu401_output(addr, d) + void *addr; + int d; +{ + return mpu401_output(SBMPU(addr), d); +} + +void +sb_mpu401_close(addr) + void *addr; +{ + mpu401_close(SBMPU(addr)); +} + +void +sb_mpu401_getinfo(addr, mi) + void *addr; + struct midi_info *mi; +{ + mi->name = "SB MPU-401 UART"; + mi->props = 0; +} +#endif diff --git a/sys/dev/isa/sb_isapnp.c b/sys/dev/isa/sb_isapnp.c index 774052dd5f7..c3b70a3a0e4 100644 --- a/sys/dev/isa/sb_isapnp.c +++ b/sys/dev/isa/sb_isapnp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sb_isapnp.c,v 1.5 1998/05/13 20:07:47 deraadt Exp $ */ +/* $OpenBSD: sb_isapnp.c,v 1.6 1999/01/02 00:02:47 niklas Exp $ */ /* $NetBSD: sb_isa.c,v 1.3 1997/03/20 11:03:11 mycroft Exp $ */ /* @@ -45,6 +45,7 @@ #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/midi_if.h> #include <dev/mulaw.h> #include <dev/isa/isavar.h> @@ -107,14 +108,22 @@ sb_isapnp_attach(parent, self, aux) } else sc->sc_drq16 = DRQUNK; - /* - * isapnp is a child if isa, and we needs isa for the dma - * routines - */ - sc->sc_isa = parent->dv_parent; +#if NMIDI > 0 + if (ia->ipa_nio > 1) { + sc->sc_mpu_sc.iobase = ia->ipa_io[1].base; + sc->sc_mpu_sc.ioh = ia->ipa_io[1].h; + } else + sc->sc_mpu_sc.iobase = 0; +#endif - if (!sbmatch(sc)) + if (!sbmatch(sc)) { + printf("%s: sbmatch failed\n", sc->sc_dev.dv_xname); return; + } + + printf("%s: %s %s", sc->sc_dev.dv_xname, ia->ipa_devident, + ia->ipa_devclass); + sc->sc_isa = parent; sbattach(sc); } diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c index 89cda5647d9..e3c6de44cc4 100644 --- a/sys/dev/isa/sbdsp.c +++ b/sys/dev/isa/sbdsp.c @@ -1,5 +1,4 @@ -/* $OpenBSD: sbdsp.c,v 1.12 1998/04/26 21:02:59 provos Exp $ */ -/* $NetBSD: sbdsp.c,v 1.78 1998/01/30 11:55:36 bouyer Exp $ */ +/* $OpenBSD: sbdsp.c,v 1.13 1999/01/02 00:02:47 niklas Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -45,6 +44,8 @@ * Linux drivers. */ +#include "midi.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> @@ -61,6 +62,7 @@ #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/midi_if.h> #include <dev/mulaw.h> #include <dev/auconv.h> @@ -70,11 +72,14 @@ #include <dev/isa/sbreg.h> #include <dev/isa/sbdspvar.h> + #ifdef AUDIO_DEBUG #define DPRINTF(x) if (sbdspdebug) printf x +#define DPRINTFN(n,x) if (sbdspdebug >= (n)) printf x int sbdspdebug = 0; #else #define DPRINTF(x) +#define DPRINTFN(n,x) #endif #ifndef SBDSP_NPOLL @@ -180,12 +185,14 @@ int sbdsp_set_in_ports __P((struct sbdsp_softc *, int)); void sbdsp_set_ifilter __P((void *, int)); int sbdsp_get_ifilter __P((void *)); -static int sbdsp_dma_setup_input __P((struct sbdsp_softc *sc)); -static int sbdsp_dma_setup_output __P((struct sbdsp_softc *sc)); +int sbdsp_block_output __P((void *)); +int sbdsp_block_input __P((void *)); static int sbdsp_adjust __P((int, int)); +int sbdsp_midi_intr __P((void *)); + #ifdef AUDIO_DEBUG -void sb_printsc __P((struct sbdsp_softc *)); +void sb_printsc __P((struct sbdsp_softc *)); void sb_printsc(sc) @@ -524,13 +531,33 @@ sbdsp_set_params(addr, setmode, usemode, play, rec) struct audio_params *p; int mode; + if (sc->sc_open == SB_OPEN_MIDI) + return EBUSY; + model = sc->sc_model; if (model > SB_16) model = SB_16; /* later models work like SB16 */ + /* + * Prior to the SB16, we have only one clock, so make the sample + * rates match. + */ + if (!ISSB16CLASS(sc) && + play->sample_rate != rec->sample_rate && + usemode == (AUMODE_PLAY | AUMODE_RECORD)) { + if (setmode == AUMODE_PLAY) { + rec->sample_rate = play->sample_rate; + setmode |= AUMODE_RECORD; + } else if (setmode == AUMODE_RECORD) { + play->sample_rate = rec->sample_rate; + setmode |= AUMODE_PLAY; + } else + return (EINVAL); + } + /* Set first record info, then play info */ - for(mode = AUMODE_RECORD; mode != -1; - mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { + for (mode = AUMODE_RECORD; mode != -1; + mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { if ((setmode & mode) == 0) continue; @@ -664,6 +691,7 @@ sbdsp_set_params(addr, setmode, usemode, play, rec) p->encoding, tc, m->cmd, bmode, m->cmdchan, swcode, factor)); } + /* * XXX * Should wait for chip to be idle. @@ -672,9 +700,9 @@ sbdsp_set_params(addr, setmode, usemode, play, rec) sc->sc_o.run = SB_NOTRUNNING; if (sc->sc_fullduplex && - (usemode & (AUMODE_PLAY | AUMODE_RECORD)) == (AUMODE_PLAY | AUMODE_RECORD) && + usemode == (AUMODE_PLAY | AUMODE_RECORD) && sc->sc_i.dmachan == sc->sc_o.dmachan) { - DPRINTF(("sbdsp_commit: fd=%d, usemode=%d, idma=%d, odma=%d\n", sc->sc_fullduplex, usemode, sc->sc_i.dmachan, sc->sc_o.dmachan)); + DPRINTF(("sbdsp_set_params: fd=%d, usemode=%d, idma=%d, odma=%d\n", sc->sc_fullduplex, usemode, sc->sc_i.dmachan, sc->sc_o.dmachan)); if (sc->sc_o.dmachan == sc->sc_drq8) { /* Use 16 bit DMA for playing by expanding the samples. */ play->sw_code = linear8_to_linear16; @@ -685,7 +713,8 @@ sbdsp_set_params(addr, setmode, usemode, play, rec) return EINVAL; } } - DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n", sc->sc_i.dmachan, sc->sc_o.dmachan)); + DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n", + sc->sc_i.dmachan, sc->sc_o.dmachan)); return 0; } @@ -742,6 +771,9 @@ sbdsp_set_in_ports(sc, mask) int bitsl, bitsr; int sbport; + if (sc->sc_open == SB_OPEN_MIDI) + return EBUSY; + DPRINTF(("sbdsp_set_in_ports: model=%d, mask=%x\n", sc->sc_mixer_model, mask)); @@ -786,7 +818,6 @@ sbdsp_set_in_ports(sc, mask) sbdsp_mix_write(sc, SBP_RECORD_SOURCE_R, bitsr); break; } - sc->in_mask = mask; return 0; @@ -799,6 +830,9 @@ sbdsp_speaker_ctl(addr, newstate) { struct sbdsp_softc *sc = addr; + if (sc->sc_open == SB_OPEN_MIDI) + return EBUSY; + if ((newstate == SPKR_ON) && (sc->spkr_state == SPKR_OFF)) { sbdsp_spkron(sc); @@ -817,8 +851,7 @@ sbdsp_round_blocksize(addr, blk) void *addr; int blk; { - blk &= -4; /* round to biggest sample size */ - return blk; + return blk & -4; /* round to biggest sample size */ } int @@ -830,12 +863,14 @@ sbdsp_open(addr, flags) DPRINTF(("sbdsp_open: sc=%p\n", sc)); - if (sc->sc_open != 0 || sbdsp_reset(sc) != 0) - return ENXIO; + if (sc->sc_open != SB_CLOSED) + return EBUSY; + if (sbdsp_reset(sc) != 0) + return EIO; - sc->sc_open = 1; + sc->sc_open = SB_OPEN_AUDIO; sc->sc_openflags = flags; - sc->sc_mintr = 0; + sc->sc_intrm = 0; if (ISSBPRO(sc) && sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) { DPRINTF(("sbdsp_open: can't set mono mode\n")); @@ -861,12 +896,12 @@ sbdsp_close(addr) DPRINTF(("sbdsp_close: sc=%p\n", sc)); - sc->sc_open = 0; + sc->sc_open = SB_CLOSED; sbdsp_spkroff(sc); sc->spkr_state = SPKR_OFF; sc->sc_intr8 = 0; sc->sc_intr16 = 0; - sc->sc_mintr = 0; + sc->sc_intrm = 0; sbdsp_haltdma(sc); DPRINTF(("sbdsp_close: closed\n")); @@ -1079,7 +1114,7 @@ sbversion(sc) sc->sc_model = SB_64; else #endif - sc->sc_model = SB_16; + sc->sc_model = SB_16; break; } } @@ -1128,345 +1163,272 @@ sbdsp16_set_rate(sc, cmd, rate) } int -sbdsp_dma_init_input(addr, buf, cc) +sbdsp_trigger_input(addr, start, end, blksize, intr, arg, param) void *addr; - void *buf; - int cc; + void *start, *end; + int blksize; + void (*intr) __P((void *)); + void *arg; + struct audio_params *param; { struct sbdsp_softc *sc = addr; + int stereo = param->channels == 2; + int width = param->precision * param->factor; + int filter; - if (sc->sc_model == SB_1) - return 0; - sc->sc_i.run = SB_DMARUNNING; - DPRINTF(("sbdsp: dma start loop input addr=%p cc=%d chan=%d\n", - buf, cc, sc->sc_i.dmachan)); - isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, buf, - cc, NULL, DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT); - return 0; -} +#ifdef DIAGNOSTIC + if (stereo && (blksize & 1)) { + DPRINTF(("stereo record odd bytes (%d)\n", blksize)); + return (EIO); + } +#endif -static int -sbdsp_dma_setup_input(sc) - struct sbdsp_softc *sc; -{ - int stereo = sc->sc_i.modep->channels == 2; - int filter; + sc->sc_intrr = intr; + sc->sc_argr = arg; + + if (width == 8) { +#ifdef DIAGNOSTIC + if (sc->sc_i.dmachan != sc->sc_drq8) { + printf("sbdsp_trigger_input: width=%d bad chan %d\n", + width, sc->sc_i.dmachan); + return (EIO); + } +#endif + sc->sc_intr8 = sbdsp_block_input; + sc->sc_arg8 = addr; + } else { +#ifdef DIAGNOSTIC + if (sc->sc_i.dmachan != sc->sc_drq16) { + printf("sbdsp_trigger_input: width=%d bad chan %d\n", + width, sc->sc_i.dmachan); + return (EIO); + } +#endif + sc->sc_intr16 = sbdsp_block_input; + sc->sc_arg16 = addr; + } + + if ((sc->sc_model == SB_JAZZ) ? (sc->sc_i.dmachan > 3) : (width == 16)) + blksize >>= 1; + --blksize; + sc->sc_i.blksize = blksize; - /* Initialize the PCM */ if (ISSBPRO(sc)) { if (sbdsp_wdsp(sc, sc->sc_i.modep->cmdchan) < 0) - return 0; + return (EIO); filter = stereo ? SBP_FILTER_OFF : sc->in_filter; sbdsp_mix_write(sc, SBP_INFILTER, - (sbdsp_mix_read(sc, SBP_INFILTER) & - ~SBP_IFILTER_MASK) | filter); + (sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK) | + filter); } if (ISSB16CLASS(sc)) { - if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, - sc->sc_i.rate)) { - DPRINTF(("sbdsp_dma_setup_input: rate=%d set failed\n", + if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, sc->sc_i.rate)) { + DPRINTF(("sbdsp_trigger_input: rate=%d set failed\n", sc->sc_i.rate)); - return 0; + return (EIO); } } else { if (sbdsp_set_timeconst(sc, sc->sc_i.tc)) { - DPRINTF(("sbdsp_dma_setup_input: tc=%d set failed\n", + DPRINTF(("sbdsp_trigger_input: tc=%d set failed\n", sc->sc_i.rate)); - return 0; + return (EIO); } } - return 1; + + DPRINTF(("sbdsp: dma start loop input start=%p end=%p chan=%d\n", + start, end, sc->sc_i.dmachan)); + isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, start, end - start, + NULL, DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT); + + return sbdsp_block_input(addr); } int -sbdsp_dma_input(addr, p, cc, intr, arg) +sbdsp_block_input(addr) void *addr; - void *p; - int cc; - void (*intr) __P((void *)); - void *arg; { struct sbdsp_softc *sc = addr; + int cc = sc->sc_i.blksize; -#ifdef AUDIO_DEBUG - if (sbdspdebug > 1) - printf("sbdsp_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n", - addr, p, cc, intr, arg); -#endif -#ifdef DIAGNOSTIC - if (sc->sc_i.modep->channels == 2 && (cc & 1)) { - DPRINTF(("stereo record odd bytes (%d)\n", cc)); - return EIO; - } -#endif + DPRINTFN(2, ("sbdsp_block_input: sc=%p cc=%d\n", addr, cc)); - if (sc->sc_i.modep->precision == 8) { -#ifdef DIAGNOSTIC - if (sc->sc_i.dmachan != sc->sc_drq8) { - printf("sbdsp_dma_input: prec=%d bad chan %d\n", - sc->sc_i.modep->precision, sc->sc_i.dmachan); - return EIO; - } -#endif - sc->sc_intr8 = intr; - sc->sc_arg8 = arg; - } else { -#ifdef DIAGNOSTIC - if (sc->sc_i.dmachan != sc->sc_drq16) { - printf("sbdsp_dma_input: prec=%d bad chan %d\n", - sc->sc_i.modep->precision, sc->sc_i.dmachan); - return EIO; - } -#endif - sc->sc_intr16 = intr; - sc->sc_arg16 = arg; - } - - switch(sc->sc_i.run) { - case SB_NOTRUNNING: - /* Non-looping mode, not initialized */ - sc->sc_i.run = SB_RUNNING; - if (!sbdsp_dma_setup_input(sc)) - goto giveup; - /* fall into */ - case SB_RUNNING: + if (sc->sc_i.run != SB_NOTRUNNING) + sc->sc_intrr(sc->sc_argr); + + if (sc->sc_model == SB_1) { /* Non-looping mode, start DMA */ -#ifdef AUDIO_DEBUG - if (sbdspdebug > 2) - printf("sbdsp_dma_input: dmastart buf=%p cc=%d chan=%d\n", - p, cc, sc->sc_i.dmachan); -#endif - isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, p, - cc, NULL, DMAMODE_READ, BUS_DMA_NOWAIT); - - /* Start PCM in non-looping mode */ - if ((sc->sc_model == SB_JAZZ && sc->sc_i.dmachan > 3) || - (sc->sc_model != SB_JAZZ && sc->sc_i.modep->precision == 16)) - cc >>= 1; - --cc; if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_input: SB1 DMA start failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_input: SB1 DMA start failed\n")); + return (EIO); } - break; - case SB_DMARUNNING: - /* Looping mode, not initialized */ - sc->sc_i.run = SB_PCMRUNNING; - if (!sbdsp_dma_setup_input(sc)) - goto giveup; - if ((sc->sc_model == SB_JAZZ && sc->sc_i.dmachan > 3) || - (sc->sc_model != SB_JAZZ && sc->sc_i.modep->precision == 16)) - cc >>= 1; - --cc; + sc->sc_i.run = SB_RUNNING; + } else if (sc->sc_i.run == SB_NOTRUNNING) { /* Initialize looping PCM */ if (ISSB16CLASS(sc)) { -#ifdef AUDIO_DEBUG - if (sbdspdebug > 2) - printf("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n", - sc->sc_i.modep->cmd, sc->sc_i.bmode, cc); -#endif + DPRINTFN(3, ("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n", + sc->sc_i.modep->cmd, sc->sc_i.bmode, cc)); if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 || sbdsp_wdsp(sc, sc->sc_i.bmode) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_input: SB16 DMA start failed\n")); - DPRINTF(("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n", - sc->sc_i.modep->cmd, sc->sc_i.bmode, cc)); - goto giveup; + DPRINTF(("sbdsp_block_input: SB16 DMA start failed\n")); + return (EIO); } } else { - DPRINTF(("sbdsp_dma_input: set blocksize=%d\n", cc)); + DPRINTF(("sbdsp_block_input: set blocksize=%d\n", cc)); if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_input: SB2 DMA blocksize failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_input: SB2 DMA blocksize failed\n")); + return (EIO); } if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0) { - DPRINTF(("sbdsp_dma_input: SB2 DMA start failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_input: SB2 DMA start failed\n")); + return (EIO); } } - break; - case SB_PCMRUNNING: - /* Looping mode, nothing to do */ - break; + sc->sc_i.run = SB_LOOPING; } - return 0; -giveup: - sbdsp_reset(sc); - return EIO; + return (0); } int -sbdsp_dma_init_output(addr, buf, cc) +sbdsp_trigger_output(addr, start, end, blksize, intr, arg, param) void *addr; - void *buf; - int cc; + void *start, *end; + int blksize; + void (*intr) __P((void *)); + void *arg; + struct audio_params *param; { struct sbdsp_softc *sc = addr; + int stereo = param->channels == 2; + int width = param->precision * param->factor; + int cmd; - if (sc->sc_model == SB_1) - return 0; - sc->sc_o.run = SB_DMARUNNING; - DPRINTF(("sbdsp: dma start loop output buf=%p cc=%d chan=%d\n", - buf, cc, sc->sc_o.dmachan)); - isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, buf, - cc, NULL, DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT); - return 0; -} +#ifdef DIAGNOSTIC + if (stereo && (blksize & 1)) { + DPRINTF(("stereo playback odd bytes (%d)\n", blksize)); + return (EIO); + } +#endif -static int -sbdsp_dma_setup_output(sc) - struct sbdsp_softc *sc; -{ - int stereo = sc->sc_o.modep->channels == 2; - int cmd; + sc->sc_intrp = intr; + sc->sc_argp = arg; + + if (width == 8) { +#ifdef DIAGNOSTIC + if (sc->sc_o.dmachan != sc->sc_drq8) { + printf("sbdsp_trigger_output: width=%d bad chan %d\n", + width, sc->sc_o.dmachan); + return (EIO); + } +#endif + sc->sc_intr8 = sbdsp_block_output; + sc->sc_arg8 = addr; + } else { +#ifdef DIAGNOSTIC + if (sc->sc_o.dmachan != sc->sc_drq16) { + printf("sbdsp_trigger_output: width=%d bad chan %d\n", + width, sc->sc_o.dmachan); + return (EIO); + } +#endif + sc->sc_intr16 = sbdsp_block_output; + sc->sc_arg16 = addr; + } + + if ((sc->sc_model == SB_JAZZ) ? (sc->sc_o.dmachan > 3) : (width == 16)) + blksize >>= 1; + --blksize; + sc->sc_o.blksize = blksize; if (ISSBPRO(sc)) { /* make sure we re-set stereo mixer bit when we start output. */ sbdsp_mix_write(sc, SBP_STEREO, - (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) | - (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO)); + (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) | + (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO)); cmd = sc->sc_o.modep->cmdchan; if (cmd && sbdsp_wdsp(sc, cmd) < 0) - return 0; + return (EIO); } if (ISSB16CLASS(sc)) { - if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, - sc->sc_o.rate)) { - DPRINTF(("sbdsp_dma_setup_output: rate=%d set failed\n", + if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, sc->sc_o.rate)) { + DPRINTF(("sbdsp_trigger_output: rate=%d set failed\n", sc->sc_o.rate)); - return 0; + return (EIO); } } else { if (sbdsp_set_timeconst(sc, sc->sc_o.tc)) { - DPRINTF(("sbdsp_dma_setup_output: tc=%d set failed\n", + DPRINTF(("sbdsp_trigger_output: tc=%d set failed\n", sc->sc_o.rate)); - return 0; + return (EIO); } } - return 1; + + DPRINTF(("sbdsp: dma start loop output start=%p end=%p chan=%d\n", + start, end, sc->sc_o.dmachan)); + isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, start, end - start, + NULL, DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT); + + return sbdsp_block_output(addr); } int -sbdsp_dma_output(addr, p, cc, intr, arg) +sbdsp_block_output(addr) void *addr; - void *p; - int cc; - void (*intr) __P((void *)); - void *arg; { struct sbdsp_softc *sc = addr; + int cc = sc->sc_o.blksize; -#ifdef AUDIO_DEBUG - if (sbdspdebug > 1) - printf("sbdsp_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n", addr, p, cc, intr, arg); -#endif -#ifdef DIAGNOSTIC - if (sc->sc_o.modep->channels == 2 && (cc & 1)) { - DPRINTF(("stereo playback odd bytes (%d)\n", cc)); - return EIO; - } -#endif + DPRINTFN(2, ("sbdsp_block_output: sc=%p cc=%d\n", addr, cc)); - if (sc->sc_o.modep->precision == 8) { -#ifdef DIAGNOSTIC - if (sc->sc_o.dmachan != sc->sc_drq8) { - printf("sbdsp_dma_output: prec=%d bad chan %d\n", - sc->sc_o.modep->precision, sc->sc_o.dmachan); - return EIO; - } -#endif - sc->sc_intr8 = intr; - sc->sc_arg8 = arg; - } else { -#ifdef DIAGNOSTIC - if (sc->sc_o.dmachan != sc->sc_drq16) { - printf("sbdsp_dma_output: prec=%d bad chan %d\n", - sc->sc_o.modep->precision, sc->sc_o.dmachan); - return EIO; - } -#endif - sc->sc_intr16 = intr; - sc->sc_arg16 = arg; - } + if (sc->sc_o.run != SB_NOTRUNNING) + sc->sc_intrp(sc->sc_argp); - switch(sc->sc_o.run) { - case SB_NOTRUNNING: - /* Non-looping mode, not initialized */ - sc->sc_o.run = SB_RUNNING; - if (!sbdsp_dma_setup_output(sc)) - goto giveup; - /* fall into */ - case SB_RUNNING: + if (sc->sc_model == SB_1) { /* Non-looping mode, initialized. Start DMA and PCM */ -#ifdef AUDIO_DEBUG - if (sbdspdebug > 2) - printf("sbdsp: start dma out addr=%p, cc=%d, chan=%d\n", - p, cc, sc->sc_o.dmachan); -#endif - isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, p, - cc, NULL, DMAMODE_WRITE, BUS_DMA_NOWAIT); - if ((sc->sc_model == SB_JAZZ && sc->sc_o.dmachan > 3) || - (sc->sc_model != SB_JAZZ && sc->sc_o.modep->precision == 16)) - cc >>= 1; - --cc; if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_output: SB1 DMA start failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_output: SB1 DMA start failed\n")); + return (EIO); } - break; - case SB_DMARUNNING: - /* Looping mode, not initialized */ - sc->sc_o.run = SB_PCMRUNNING; - if (!sbdsp_dma_setup_output(sc)) - goto giveup; - if ((sc->sc_model == SB_JAZZ && sc->sc_o.dmachan > 3) || - (sc->sc_model != SB_JAZZ && sc->sc_o.modep->precision == 16)) - cc >>= 1; - --cc; + sc->sc_o.run = SB_RUNNING; + } else if (sc->sc_o.run == SB_NOTRUNNING) { /* Initialize looping PCM */ if (ISSB16CLASS(sc)) { - DPRINTF(("sbdsp_dma_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n", - sc->sc_o.modep->cmd,sc->sc_o.bmode, cc)); + DPRINTF(("sbdsp_block_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n", + sc->sc_o.modep->cmd,sc->sc_o.bmode, cc)); if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 || sbdsp_wdsp(sc, sc->sc_o.bmode) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_output: SB16 DMA start failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_output: SB16 DMA start failed\n")); + return (EIO); } } else { - DPRINTF(("sbdsp_dma_output: set blocksize=%d\n", cc)); + DPRINTF(("sbdsp_block_output: set blocksize=%d\n", cc)); if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_output: SB2 DMA blocksize failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_output: SB2 DMA blocksize failed\n")); + return (EIO); } if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0) { - DPRINTF(("sbdsp_dma_output: SB2 DMA start failed\n")); - goto giveup; + DPRINTF(("sbdsp_block_output: SB2 DMA start failed\n")); + return (EIO); } } - break; - case SB_PCMRUNNING: - /* Looping mode, nothing to do */ - break; + sc->sc_o.run = SB_LOOPING; } - return 0; -giveup: - sbdsp_reset(sc); - return EIO; + return (0); } /* @@ -1484,94 +1446,44 @@ sbdsp_intr(arg) void *arg; { struct sbdsp_softc *sc = arg; - int loop = sc->sc_model != SB_1; u_char irq; -#ifdef AUDIO_DEBUG - if (sbdspdebug > 1) - printf("sbdsp_intr: intr8=%p, intr16=%p\n", - sc->sc_intr8, sc->sc_intr16); -#endif + DPRINTFN(2, ("sbdsp_intr: intr8=%p, intr16=%p\n", + sc->sc_intr8, sc->sc_intr16)); if (ISSB16CLASS(sc)) { irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS); - if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16)) == 0) { + if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16 | SBP_IRQ_MPU401)) == 0) { DPRINTF(("sbdsp_intr: Spurious interrupt 0x%x\n", irq)); return 0; } } else { - if (!loop && !isa_dmafinished(sc->sc_isa, sc->sc_drq8)) - return 0; + /* XXXX CHECK FOR INTERRUPT */ irq = SBP_IRQ_DMA8; } + sc->sc_interrupts++; delay(10); /* XXX why? */ -#if 0 - if (sc->sc_mintr != 0) { - x = sbdsp_rdsp(sc); - (*sc->sc_mintr)(sc->sc_arg, x); - } else -#endif - if (sc->sc_intr8 == 0 && sc->sc_intr16 == 0) { - DPRINTF(("sbdsp_intr: Unexpected interrupt 0x%x\n", irq)); - /* XXX return 0;*/ /* Did not expect an interrupt */ - } /* clear interrupt */ if (irq & SBP_IRQ_DMA8) { bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK8); - if (!loop) - isa_dmadone(sc->sc_isa, sc->sc_drq8); if (sc->sc_intr8) - (*sc->sc_intr8)(sc->sc_arg8); + sc->sc_intr8(sc->sc_arg8); } if (irq & SBP_IRQ_DMA16) { bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK16); if (sc->sc_intr16) - (*sc->sc_intr16)(sc->sc_arg16); + sc->sc_intr16(sc->sc_arg16); } +#if NMIDI > 0 + if ((irq & SBP_IRQ_MPU401) && sc->sc_hasmpu) { + mpu401_intr(&sc->sc_mpu_sc); + } +#endif return 1; } -#if 0 -/* - * Enter midi uart mode and arrange for read interrupts - * to vector to `intr'. This puts the card in a mode - * which allows only midi I/O; the card must be reset - * to leave this mode. Unfortunately, the card does not - * use transmit interrupts, so bytes must be output - * using polling. To keep the polling overhead to a - * minimum, output should be driven off a timer. - * This is a little tricky since only 320us separate - * consecutive midi bytes. - */ -void -sbdsp_set_midi_mode(sc, intr, arg) - struct sbdsp_softc *sc; - void (*intr)(); - void *arg; -{ - - sbdsp_wdsp(sc, SB_MIDI_UART_INTR); - sc->sc_mintr = intr; - sc->sc_intr = 0; - sc->sc_arg = arg; -} - -/* - * Write a byte to the midi port, when in midi uart mode. - */ -void -sbdsp_midi_output(sc, v) - struct sbdsp_softc *sc; - int v; -{ - - if (sbdsp_wdsp(sc, v) < 0) - ++sberr.wmidi; -} -#endif - -/* Mask a value 0-255, but round it first */ +/* Like val & mask, but make sure the result is correctly rounded. */ #define MAXVAL 256 static int sbdsp_adjust(val, mask) @@ -1698,6 +1610,9 @@ sbdsp_mixer_set_port(addr, cp) int lmask, rmask, lbits, rbits; int mute, swap; + if (sc->sc_open == SB_OPEN_MIDI) + return EBUSY; + DPRINTF(("sbdsp_mixer_set_port: port=%d num_channels=%d\n", cp->dev, cp->un.value.num_channels)); @@ -1882,6 +1797,9 @@ sbdsp_mixer_get_port(addr, cp) { struct sbdsp_softc *sc = addr; + if (sc->sc_open == SB_OPEN_MIDI) + return EBUSY; + DPRINTF(("sbdsp_mixer_get_port: port=%d\n", cp->dev)); if (sc->sc_mixer_model == SBM_NONE) @@ -2175,7 +2093,7 @@ sbdsp_mixer_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_ENUM; dip->mixer_class = SB_INPUT_CLASS; dip->prev = dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, "AGC"); + strcpy(dip->label.name, "agc"); dip->un.e.num_mem = 2; strcpy(dip->un.e.member[0].label.name, AudioNoff); dip->un.e.member[0].ord = 0; @@ -2315,6 +2233,91 @@ sbdsp_get_props(addr) void *addr; { struct sbdsp_softc *sc = addr; - return AUDIO_PROP_MMAP | + return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | (sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0); } + +#if NMIDI > 0 +/* + * MIDI related routines. + */ + +int +sbdsp_midi_open(addr, flags, iintr, ointr, arg) + void *addr; + int flags; + void (*iintr)__P((void *, int)); + void (*ointr)__P((void *)); + void *arg; +{ + struct sbdsp_softc *sc = addr; + + DPRINTF(("sbdsp_midi_open: sc=%p\n", sc)); + + if (sc->sc_open != SB_CLOSED) + return EBUSY; + if (sbdsp_reset(sc) != 0) + return EIO; + + if (sc->sc_model >= SB_20) + if (sbdsp_wdsp(sc, SB_MIDI_UART_INTR)) /* enter UART mode */ + return EIO; + sc->sc_open = SB_OPEN_MIDI; + sc->sc_openflags = flags; + sc->sc_intr8 = sbdsp_midi_intr; + sc->sc_arg8 = addr; + sc->sc_intrm = iintr; + sc->sc_argm = arg; + return 0; +} + +void +sbdsp_midi_close(addr) + void *addr; +{ + struct sbdsp_softc *sc = addr; + + DPRINTF(("sbdsp_midi_close: sc=%p\n", sc)); + + if (sc->sc_model >= SB_20) + sbdsp_reset(sc); /* exit UART mode */ + sc->sc_open = SB_CLOSED; + sc->sc_intrm = 0; +} + +int +sbdsp_midi_output(addr, d) + void *addr; + int d; +{ + struct sbdsp_softc *sc = addr; + + if (sc->sc_model < SB_20 && sbdsp_wdsp(sc, SB_MIDI_WRITE)) + return EIO; + if (sbdsp_wdsp(sc, d)) + return EIO; + return 0; +} + +void +sbdsp_midi_getinfo(addr, mi) + void *addr; + struct midi_info *mi; +{ + struct sbdsp_softc *sc = addr; + + mi->name = sc->sc_model < SB_20 ? "SB MIDI cmd" : "SB MIDI UART"; + mi->props = MIDI_PROP_CAN_INPUT; +} + +int +sbdsp_midi_intr(addr) + void *addr; +{ + struct sbdsp_softc *sc = addr; + + sc->sc_intrm(sc->sc_argm, sbdsp_rdsp(sc)); + return (0); +} + +#endif diff --git a/sys/dev/isa/sbdspvar.h b/sys/dev/isa/sbdspvar.h index c70a012f447..3f8e5b5cb7e 100644 --- a/sys/dev/isa/sbdspvar.h +++ b/sys/dev/isa/sbdspvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: sbdspvar.h,v 1.8 1998/04/26 21:03:01 provos Exp $ */ -/* $NetBSD: sbdspvar.h,v 1.33 1997/10/19 07:42:44 augustss Exp $ */ +/* $OpenBSD: sbdspvar.h,v 1.9 1999/01/02 00:02:47 niklas Exp $ */ +/* $NetBSD: sbdspvar.h,v 1.37 1998/08/10 00:20:39 mycroft Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -35,6 +35,11 @@ * */ +#include "midi.h" +#if NMIDI > 0 +#include <dev/isa/mpu401var.h> +#endif + #define SB_MASTER_VOL 0 #define SB_MIDI_VOL 1 #define SB_CD_VOL 2 @@ -94,15 +99,18 @@ struct sbdsp_softc { bus_space_tag_t sc_iot; /* tag */ bus_space_handle_t sc_ioh; /* handle */ void *sc_ih; /* interrupt vectoring */ + struct device *sc_isa; int sc_iobase; /* I/O port base address */ int sc_irq; /* interrupt */ + int sc_ist; /* interrupt share type */ int sc_drq8; /* DMA (8-bit) */ int sc_drq16; /* DMA (16-bit) */ - struct device *sc_isa; /* pointer to ISA parent */ - - u_short sc_open; /* reference count of open calls */ + int sc_open; /* reference count of open calls */ +#define SB_CLOSED 0 +#define SB_OPEN_AUDIO 1 +#define SB_OPEN_MIDI 2 int sc_openflags; /* flags used on open */ u_char sc_fullduplex; /* can do full duplex */ @@ -123,19 +131,25 @@ struct sbdsp_softc { struct sbmode *modep; u_char bmode; int dmachan; /* DMA channel */ + int blksize; /* Block size, preadjusted */ u_char run; #define SB_NOTRUNNING 0 /* Not running, not initialized */ -#define SB_DMARUNNING 1 /* DMA has been initialized */ -#define SB_PCMRUNNING 2 /* DMA&PCM running (looping mode) */ #define SB_RUNNING 3 /* non-looping mode */ +#define SB_LOOPING 2 /* DMA&PCM running (looping mode) */ } sc_i, sc_o; /* Input and output state */ u_long sc_interrupts; /* number of interrupts taken */ - void (*sc_intr8)(void*); /* dma completion intr handler */ + + int (*sc_intr8)(void*); /* dma completion intr handler */ void *sc_arg8; /* arg for sc_intr8() */ - void (*sc_intr16)(void*); /* dma completion intr handler */ + int (*sc_intr16)(void*); /* dma completion intr handler */ void *sc_arg16; /* arg for sc_intr16() */ - void (*sc_mintr)(void*, int);/* midi input intr handler */ + void (*sc_intrp)(void*); /* PCM output intr handler */ + void *sc_argp; /* arg for sc_intrp() */ + void (*sc_intrr)(void*); /* PCM input intr handler */ + void *sc_argr; /* arg for sc_intrr() */ + void (*sc_intrm)(void*, int);/* midi input intr handler */ + void *sc_argm; /* arg for sc_intrm() */ u_int sc_mixer_model; #define SBM_NONE 0 @@ -161,6 +175,11 @@ struct sbdsp_softc { u_int sc_version; /* DSP version */ #define SBVER_MAJOR(v) (((v)>>8) & 0xff) #define SBVER_MINOR(v) ((v)&0xff) + +#if NMIDI > 0 + int sc_hasmpu; + struct mpu401_softc sc_mpu_sc; /* MPU401 Uart state */ +#endif }; #define ISSBPRO(sc) ((sc)->sc_model == SB_PRO || (sc)->sc_model == SB_JAZZ) @@ -190,10 +209,10 @@ int sbdsp_get_avail_out_ports __P((void *)); int sbdsp_speaker_ctl __P((void *, int)); int sbdsp_commit __P((void *)); -int sbdsp_dma_init_input __P((void *, void *, int)); -int sbdsp_dma_init_output __P((void *, void *, int)); -int sbdsp_dma_output __P((void *, void *, int, void (*)(void *), void*)); -int sbdsp_dma_input __P((void *, void *, int, void (*)(void *), void*)); +int sbdsp_trigger_output __P((void *, void *, void *, int, void (*)(void *), + void *, struct audio_params *)); +int sbdsp_trigger_input __P((void *, void *, void *, int, void (*)(void *), + void *, struct audio_params *)); int sbdsp_haltdma __P((void *)); @@ -225,4 +244,11 @@ int sb_mappage __P((void *, void *, int, int)); int sbdsp_get_props __P((void *)); + +int sbdsp_midi_open __P((void *, int, + void (*iintr)__P((void *, int)), + void (*ointr)__P((void *)), void *arg)); +void sbdsp_midi_close __P((void *)); +int sbdsp_midi_output __P((void *, int)); +void sbdsp_midi_getinfo __P((void *, struct midi_info *)); #endif diff --git a/sys/dev/isa/spkr.c b/sys/dev/isa/spkr.c new file mode 100644 index 00000000000..09b2181861e --- /dev/null +++ b/sys/dev/isa/spkr.c @@ -0,0 +1,502 @@ +/* $OpenBSD: spkr.c,v 1.1 1999/01/02 00:02:43 niklas Exp $ */ +/* $NetBSD: spkr.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ + +/* + * spkr.c -- device driver for console speaker on 80386 + * + * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 + * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> + * 386bsd only clean version, all SYSV stuff removed + * use hz value from param.c + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/conf.h> + +#include <dev/isa/pcppivar.h> + +#include <dev/isa/spkrio.h> + +cdev_decl(spkr); + +int spkrprobe __P((struct device *, struct cfdata *, void *)); +void spkrattach __P((struct device *, struct device *, void *)); + +struct spkr_softc { + struct device sc_dev; +}; + +struct cfattach spkr_ca = { + sizeof(struct spkr_softc), spkrprobe, spkrattach +}; + +static pcppi_tag_t ppicookie; + +#define SPKRPRI (PZERO - 1) + +static void tone __P((u_int, u_int)); +static void rest __P((int)); +static void playinit __P((void)); +static void playtone __P((int, int, int)); +static void playstring __P((char *, int)); + +static +void tone(hz, ticks) +/* emit tone of frequency hz for given number of ticks */ + u_int hz, ticks; +{ + pcppi_bell(ppicookie, hz, ticks, 1); +} + +static void +rest(ticks) +/* rest for given number of ticks */ + int ticks; +{ + /* + * Set timeout to endrest function, then give up the timeslice. + * This is so other processes can execute while the rest is being + * waited out. + */ +#ifdef SPKRDEBUG + printf("rest: %d\n", ticks); +#endif /* SPKRDEBUG */ + if (ticks > 0) + tsleep(rest, SPKRPRI | PCATCH, "rest", ticks); +} + +/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** + * + * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; + * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. + * Requires tone(), rest(), and endtone(). String play is not interruptible + * except possibly at physical block boundaries. + */ + +typedef int bool; +#define TRUE 1 +#define FALSE 0 + +#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) +#define isdigit(c) (((c) >= '0') && ((c) <= '9')) +#define dtoi(c) ((c) - '0') + +static int octave; /* currently selected octave */ +static int whole; /* whole-note time at current tempo, in ticks */ +static int value; /* whole divisor for note time, quarter note = 1 */ +static int fill; /* controls spacing of notes */ +static bool octtrack; /* octave-tracking on? */ +static bool octprefix; /* override current octave-tracking state? */ + +/* + * Magic number avoidance... + */ +#define SECS_PER_MIN 60 /* seconds per minute */ +#define WHOLE_NOTE 4 /* quarter notes per whole note */ +#define MIN_VALUE 64 /* the most we can divide a note by */ +#define DFLT_VALUE 4 /* default value (quarter-note) */ +#define FILLTIME 8 /* for articulation, break note in parts */ +#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ +#define NORMAL 7 /* 7/8ths of note interval is filled */ +#define LEGATO 8 /* all of note interval is filled */ +#define DFLT_OCTAVE 4 /* default octave */ +#define MIN_TEMPO 32 /* minimum tempo */ +#define DFLT_TEMPO 120 /* default tempo */ +#define MAX_TEMPO 255 /* max tempo */ +#define NUM_MULT 3 /* numerator of dot multiplier */ +#define DENOM_MULT 2 /* denominator of dot multiplier */ + +/* letter to half-tone: A B C D E F G */ +static int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; + +/* + * This is the American Standard A440 Equal-Tempered scale with frequencies + * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... + * our octave 0 is standard octave 2. + */ +#define OCTAVE_NOTES 12 /* semitones per octave */ +static int pitchtab[] = +{ +/* C C# D D# E F F# G G# A A# B*/ +/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, +/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, +/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, +/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, +/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, +/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, +/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, +}; +#define NOCTAVES (sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) + +static void +playinit() +{ + octave = DFLT_OCTAVE; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; + fill = NORMAL; + value = DFLT_VALUE; + octtrack = FALSE; + octprefix = TRUE; /* act as though there was an initial O(n) */ +} + +static void +playtone(pitch, value, sustain) +/* play tone of proper duration for current rhythm signature */ + int pitch, value, sustain; +{ + register int sound, silence, snum = 1, sdenom = 1; + + /* this weirdness avoids floating-point arithmetic */ + for (; sustain; sustain--) + { + snum *= NUM_MULT; + sdenom *= DENOM_MULT; + } + + if (pitch == -1) + rest(whole * snum / (value * sdenom)); + else + { + sound = (whole * snum) / (value * sdenom) + - (whole * (FILLTIME - fill)) / (value * FILLTIME); + silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); + +#ifdef SPKRDEBUG + printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", + pitch, sound, silence); +#endif /* SPKRDEBUG */ + + tone(pitchtab[pitch], sound); + if (fill != LEGATO) + rest(silence); + } +} + +static void +playstring(cp, slen) +/* interpret and play an item from a notation string */ + char *cp; + int slen; +{ + int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; + +#define GETNUM(cp, v) for(v=0; slen > 0 && isdigit(cp[1]); ) \ + {v = v * 10 + (*++cp - '0'); slen--;} + for (; slen--; cp++) + { + int sustain, timeval, tempo; + register char c = toupper(*cp); + +#ifdef SPKRDEBUG + printf("playstring: %c (%x)\n", c, c); +#endif /* SPKRDEBUG */ + + switch (c) + { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + + /* compute pitch */ + pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; + + /* this may be followed by an accidental sign */ + if (slen > 0 && (cp[1] == '#' || cp[1] == '+')) + { + ++pitch; + ++cp; + slen--; + } + else if (slen > 0 && cp[1] == '-') + { + --pitch; + ++cp; + slen--; + } + + /* + * If octave-tracking mode is on, and there has been no octave- + * setting prefix, find the version of the current letter note + * closest to the last regardless of octave. + */ + if (octtrack && !octprefix) + { + if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) + { + ++octave; + pitch += OCTAVE_NOTES; + } + + if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) + { + --octave; + pitch -= OCTAVE_NOTES; + } + } + octprefix = FALSE; + lastpitch = pitch; + + /* ...which may in turn be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + + /* ...and/or sustain dots */ + for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + + /* time to emit the actual tone */ + playtone(pitch, timeval, sustain); + break; + + case 'O': + if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) + { + octprefix = octtrack = FALSE; + ++cp; + slen--; + } + else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) + { + octtrack = TRUE; + ++cp; + slen--; + } + else + { + GETNUM(cp, octave); + if (octave >= NOCTAVES) + octave = DFLT_OCTAVE; + octprefix = TRUE; + } + break; + + case '>': + if (octave < NOCTAVES - 1) + octave++; + octprefix = TRUE; + break; + + case '<': + if (octave > 0) + octave--; + octprefix = TRUE; + break; + + case 'N': + GETNUM(cp, pitch); + for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(pitch - 1, value, sustain); + break; + + case 'L': + GETNUM(cp, value); + if (value <= 0 || value > MIN_VALUE) + value = DFLT_VALUE; + break; + + case 'P': + case '~': + /* this may be followed by an override time value */ + GETNUM(cp, timeval); + if (timeval <= 0 || timeval > MIN_VALUE) + timeval = value; + for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) + { + slen--; + sustain++; + } + playtone(-1, timeval, sustain); + break; + + case 'T': + GETNUM(cp, tempo); + if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) + tempo = DFLT_TEMPO; + whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; + break; + + case 'M': + if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) + { + fill = NORMAL; + ++cp; + slen--; + } + else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) + { + fill = LEGATO; + ++cp; + slen--; + } + else if (slen > 0 && (cp[1] == 'S' || cp[1] == 's')) + { + fill = STACCATO; + ++cp; + slen--; + } + break; + } + } +} + +/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** + * + * This section implements driver hooks to run playstring() and the tone(), + * endtone(), and rest() functions defined above. + */ + +static int spkr_active; /* exclusion flag */ +static void *spkr_inbuf; + +static int spkr_attached = 0; + +int +spkrprobe (parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + return (!spkr_attached); +} + +void +spkrattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + printf("\n"); + ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie; + spkr_attached = 1; +} + +int +spkropen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ +#ifdef SPKRDEBUG + printf("spkropen: entering with dev = %x\n", dev); +#endif /* SPKRDEBUG */ + + if (minor(dev) != 0 || !spkr_attached) + return(ENXIO); + else if (spkr_active) + return(EBUSY); + else + { + playinit(); + spkr_inbuf = malloc(DEV_BSIZE, M_DEVBUF, M_WAITOK); + spkr_active = 1; + } + return(0); +} + +int +spkrwrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register int n; + int error; +#ifdef SPKRDEBUG + printf("spkrwrite: entering with dev = %x, count = %d\n", + dev, uio->uio_resid); +#endif /* SPKRDEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + n = min(DEV_BSIZE, uio->uio_resid); + error = uiomove(spkr_inbuf, n, uio); + if (!error) + playstring((char *)spkr_inbuf, n); + return(error); + } +} + +int spkrclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ +#ifdef SPKRDEBUG + printf("spkrclose: entering with dev = %x\n", dev); +#endif /* SPKRDEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else + { + tone(0, 0); + free(spkr_inbuf, M_DEVBUF); + spkr_active = 0; + } + return(0); +} + +int spkrioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ +#ifdef SPKRDEBUG + printf("spkrioctl: entering with dev = %x, cmd = %lx\n", dev, cmd); +#endif /* SPKRDEBUG */ + + if (minor(dev) != 0) + return(ENXIO); + else if (cmd == SPKRTONE) + { + tone_t *tp = (tone_t *)data; + + if (tp->frequency == 0) + rest(tp->duration); + else + tone(tp->frequency, tp->duration); + } + else if (cmd == SPKRTUNE) + { + tone_t *tp = (tone_t *)(*(caddr_t *)data); + tone_t ttp; + int error; + + for (; ; tp++) { + error = copyin(tp, &ttp, sizeof(tone_t)); + if (error) + return(error); + if (ttp.duration == 0) + break; + if (ttp.frequency == 0) + rest(ttp.duration); + else + tone(ttp.frequency, ttp.duration); + } + } + else + return(EINVAL); + return(0); +} + +/* spkr.c ends here */ diff --git a/sys/dev/isa/spkrio.h b/sys/dev/isa/spkrio.h new file mode 100644 index 00000000000..a852cf0782f --- /dev/null +++ b/sys/dev/isa/spkrio.h @@ -0,0 +1,19 @@ +/* $OpenBSD: spkrio.h,v 1.1 1999/01/02 00:02:43 niklas Exp $ */ +/* $NetBSD: spkrio.h,v 1.1 1998/04/15 20:26:19 drochner Exp $ */ + +/* + * spkr.h -- interface definitions for speaker ioctl() + */ + +#ifndef _DEV_ISA_SPKR_H_ +#define _DEV_ISA_SPKR_H_ + +#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */ +#define SPKRTUNE _IO('S', 2) /* emit tone sequence */ + +typedef struct { + int frequency; /* in hertz */ + int duration; /* in 1/100ths of a second */ +} tone_t; + +#endif /* _DEV_ISA_SPKR_H_ */ diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c index 9476f45fb4e..c49eb337d44 100644 --- a/sys/dev/isa/wss.c +++ b/sys/dev/isa/wss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wss.c,v 1.17 1998/11/03 21:15:01 downsj Exp $ */ +/* $OpenBSD: wss.c,v 1.18 1999/01/02 00:02:48 niklas Exp $ */ /* $NetBSD: wss.c,v 1.42 1998/01/19 22:18:23 augustss Exp $ */ /* @@ -153,7 +153,7 @@ wssattach(sc) sc->sc_ad1848.parent = sc; - audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev); + audio_attach_mi(&wss_hw_if, &sc->sc_ad1848, &sc->sc_dev); } int diff --git a/sys/dev/isa/ym.c b/sys/dev/isa/ym.c index a4eb9551466..04611a1c815 100644 --- a/sys/dev/isa/ym.c +++ b/sys/dev/isa/ym.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ym.c,v 1.3 1998/12/29 09:10:30 deraadt Exp $ */ +/* $OpenBSD: ym.c,v 1.4 1999/01/02 00:02:48 niklas Exp $ */ /* @@ -134,7 +134,7 @@ ym_attach(sc) sc->mic_mute = 1; ym_mute(sc, SA3_MIC, sc->mic_mute); - audio_attach_mi(&ym_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev); + audio_attach_mi(&ym_hw_if, &sc->sc_ad1848, &sc->sc_dev); } static __inline int |