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/sbdsp.c | |
parent | 890d46b55a21bec77e2f60dbf22d16199ccdbaa7 (diff) |
Midi & sequencer support from NetBSD, mostly by Lennart Augustsson
Diffstat (limited to 'sys/dev/isa/sbdsp.c')
-rw-r--r-- | sys/dev/isa/sbdsp.c | 641 |
1 files changed, 322 insertions, 319 deletions
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 |