diff options
author | 1998-04-26 21:02:37 +0000 | |
---|---|---|
committer | 1998-04-26 21:02:37 +0000 | |
commit | e99cab2be4365da63b86b0d86d6cce79f3103c64 (patch) | |
tree | 33a2d4aa3f5856eca15ef5c699b9965fbacbe977 /sys/dev/isa | |
parent | handle ENOSPC as an end-of-tape marker; gibbs@narnia.plutotech.com (diff) | |
download | wireguard-openbsd-e99cab2be4365da63b86b0d86d6cce79f3103c64.tar.xz wireguard-openbsd-e99cab2be4365da63b86b0d86d6cce79f3103c64.zip |
update audio from NetBSD, mostly by Lennart Augustsson <augustss@cs.chalmers.se>
Diffstat (limited to 'sys/dev/isa')
-rw-r--r-- | sys/dev/isa/ad1848.c | 759 | ||||
-rw-r--r-- | sys/dev/isa/ad1848var.h | 50 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 18 | ||||
-rw-r--r-- | sys/dev/isa/gus.c | 1956 | ||||
-rw-r--r-- | sys/dev/isa/gusreg.h | 45 | ||||
-rw-r--r-- | sys/dev/isa/ics2101.c | 17 | ||||
-rw-r--r-- | sys/dev/isa/ics2101var.h | 11 | ||||
-rw-r--r-- | sys/dev/isa/isa.c | 19 | ||||
-rw-r--r-- | sys/dev/isa/isavar.h | 4 | ||||
-rw-r--r-- | sys/dev/isa/madreg.h | 102 | ||||
-rw-r--r-- | sys/dev/isa/mcd.c | 204 | ||||
-rw-r--r-- | sys/dev/isa/mcdreg.h | 5 | ||||
-rw-r--r-- | sys/dev/isa/pas.c | 116 | ||||
-rw-r--r-- | sys/dev/isa/pnpdevs | 3 | ||||
-rw-r--r-- | sys/dev/isa/pnpdevs.h | 1 | ||||
-rw-r--r-- | sys/dev/isa/pss.c | 209 | ||||
-rw-r--r-- | sys/dev/isa/sb.c | 119 | ||||
-rw-r--r-- | sys/dev/isa/sb_isa.c | 82 | ||||
-rw-r--r-- | sys/dev/isa/sb_isapnp.c | 21 | ||||
-rw-r--r-- | sys/dev/isa/sbdsp.c | 2439 | ||||
-rw-r--r-- | sys/dev/isa/sbdspvar.h | 183 | ||||
-rw-r--r-- | sys/dev/isa/sbreg.h | 95 | ||||
-rw-r--r-- | sys/dev/isa/wss.c | 441 | ||||
-rw-r--r-- | sys/dev/isa/wss_isa.c | 376 | ||||
-rw-r--r-- | sys/dev/isa/wssvar.h | 83 |
25 files changed, 4219 insertions, 3139 deletions
diff --git a/sys/dev/isa/ad1848.c b/sys/dev/isa/ad1848.c index 9a7ed0fc629..2e3e495d4cf 100644 --- a/sys/dev/isa/ad1848.c +++ b/sys/dev/isa/ad1848.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ad1848.c,v 1.9 1998/01/18 18:58:36 niklas Exp $ */ -/* $NetBSD: ad1848.c,v 1.10 1996/04/29 20:02:32 christos Exp $ */ +/* $OpenBSD: ad1848.c,v 1.10 1998/04/26 21:02:38 provos Exp $ */ +/* $NetBSD: ad1848.c,v 1.45 1998/01/30 02:02:38 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -67,11 +67,6 @@ * Portions also supplied from the SoundBlaster driver for NetBSD. */ -/* - * Todo: - * - Need datasheet for CS4231 (for use with GUS MAX) - * - Use fast audio_dma - */ #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> @@ -82,10 +77,14 @@ #include <sys/buf.h> #include <machine/cpu.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> +#include <vm/vm.h> + #include <dev/audio_if.h> +#include <dev/auconv.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -96,8 +95,7 @@ #include <dev/isa/cs4231var.h> #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (ad1848debug) Dprintf x +#define DPRINTF(x) if (ad1848debug) printf x int ad1848debug = 0; #else #define DPRINTF(x) @@ -144,12 +142,13 @@ static int ad1848_init_values[] = { MONO_INPUT_MUTE|ATTEN_6, /* mute mic by default */ 0, /* unused */ 0, /* record format */ + 0, /* Crystal Clock Select */ 0, /* upper record count */ 0 /* lower record count */ }; void ad1848_reset __P((struct ad1848_softc *)); -int ad1848_set_speed __P((struct ad1848_softc *, u_long)); +int ad1848_set_speed __P((struct ad1848_softc *, u_long *)); void ad1848_mute_monitor __P((void *, int)); static int ad_read __P((struct ad1848_softc *, int)); @@ -157,6 +156,8 @@ static __inline void ad_write __P((struct ad1848_softc *, int, int)); static void ad_set_MCE __P((struct ad1848_softc *, int)); static void wait_for_calibration __P((struct ad1848_softc *)); +#define ADREAD(sc, addr) bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_iooffs+(addr)) +#define ADWRITE(sc, addr, data) bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_iooffs+(addr), (data)) static int ad_read(sc, reg) @@ -165,8 +166,8 @@ ad_read(sc, reg) { int x; - outb(sc->sc_iobase+AD1848_IADDR, (u_char) (reg & 0xff) | sc->MCE_bit); - x = inb(sc->sc_iobase+AD1848_IDATA); + ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); + x = ADREAD(sc, AD1848_IDATA); /* printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */ return x; @@ -178,8 +179,8 @@ ad_write(sc, reg, data) int reg; int data; { - outb(sc->sc_iobase+AD1848_IADDR, (u_char) (reg & 0xff) | sc->MCE_bit); - outb(sc->sc_iobase+AD1848_IDATA, (u_char) (data & 0xff)); + ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); + ADWRITE(sc, AD1848_IDATA, data & 0xff); /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */ } @@ -193,14 +194,14 @@ ad_set_MCE(sc, state) else sc->MCE_bit = 0; - outb(sc->sc_iobase+AD1848_IADDR, sc->MCE_bit); + ADWRITE(sc, AD1848_IADDR, sc->MCE_bit); } static void wait_for_calibration(sc) struct ad1848_softc *sc; { - int timeout = 100000; + int timeout; DPRINTF(("ad1848: Auto calibration started.\n")); /* @@ -209,18 +210,19 @@ wait_for_calibration(sc) * 1) Wait until the chip becomes ready (reads don't return 0x80). * 2) Wait until the ACI bit of I11 gets on and then off. */ - while (timeout > 0 && inb(sc->sc_iobase+AD1848_IADDR) == SP_IN_INIT) + timeout = 100000; + while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) timeout--; - if (inb(sc->sc_iobase+AD1848_IADDR) == SP_IN_INIT) + if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) DPRINTF(("ad1848: Auto calibration timed out(1).\n")); - outb(sc->sc_iobase+AD1848_IADDR, SP_TEST_AND_INIT); + ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT); timeout = 100000; - while (timeout > 0 && inb(sc->sc_iobase+AD1848_IADDR) != SP_TEST_AND_INIT) + while (timeout > 0 && ADREAD(sc, AD1848_IADDR) != SP_TEST_AND_INIT) timeout--; - if (inb(sc->sc_iobase+AD1848_IADDR) == SP_TEST_AND_INIT) + if (ADREAD(sc, AD1848_IADDR) == SP_TEST_AND_INIT) DPRINTF(("ad1848: Auto calibration timed out(1.5).\n")); if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) { @@ -249,7 +251,7 @@ ad1848_dump_regs(sc) int i; u_char r; - printf("ad1848 status=%02x", inb(sc->sc_iobase+AD1848_STATUS)); + printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS)); printf(" regs: "); for (i = 0; i < 16; i++) { r = ad_read(sc, i); @@ -260,8 +262,8 @@ ad1848_dump_regs(sc) r = ad_read(sc, i); printf("%02x ", r); } - printf("\n"); } + printf("\n"); } #endif @@ -283,7 +285,8 @@ ad1848_forceintr(sc) * it is needed (and you pay the latency). Also, you might * never need the buffer anyway.) */ - isadma_start(&dmabuf, 1, sc->sc_drq, DMAMODE_READ); + isa_dmastart(sc->sc_isa, sc->sc_drq, &dmabuf, 1, NULL, + DMAMODE_READ, BUS_DMA_NOWAIT); ad_write(sc, SP_LOWER_BASE_COUNT, 0); ad_write(sc, SP_UPPER_BASE_COUNT, 0); @@ -292,16 +295,13 @@ ad1848_forceintr(sc) #endif /* - * Probe for the ad1848 chip + * Map and probe for the ad1848 chip */ int -ad1848_probe(sc) +ad1848_mapprobe(sc, iobase) struct ad1848_softc *sc; + int iobase; { - register int iobase = sc->sc_iobase; - u_char tmp, tmp1 = 0xff, tmp2 = 0xff; - int i; - if (!AD1848_BASE_VALID(iobase)) { #ifdef AUDIO_DEBUG printf("ad1848: configured iobase %04x invalid\n", iobase); @@ -309,8 +309,28 @@ ad1848_probe(sc) return 0; } - sc->sc_iobase = iobase; + sc->sc_iooffs = 0; + /* Map the AD1848 ports */ + if (bus_space_map(sc->sc_iot, iobase, AD1848_NPORT, 0, &sc->sc_ioh)) + return 0; + + if (!ad1848_probe(sc)) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, AD1848_NPORT); + return 0; + } else + return 1; +} +/* + * Probe for the ad1848 chip + */ +int +ad1848_probe(sc) + struct ad1848_softc *sc; +{ + u_char tmp, tmp1 = 0xff, tmp2 = 0xff; + int i; + /* Is there an ad1848 chip ? */ sc->MCE_bit = MODE_CHANGE_ENABLE; sc->mode = 1; /* MODE 1 = original ad1848/ad1846/cs4248 */ @@ -324,11 +344,12 @@ ad1848_probe(sc) * * If the I/O address is unused, inb() typically returns 0xff. */ - if (((tmp = inb(iobase+AD1848_IADDR)) & SP_IN_INIT) != 0x00) { /* Not a AD1848 */ + tmp = ADREAD(sc, AD1848_IADDR); + if (tmp & SP_IN_INIT) { /* Not a AD1848 */ #if 0 DPRINTF(("ad_detect_A %x\n", tmp)); #endif - return 0; + goto bad; } /* @@ -342,7 +363,7 @@ ad1848_probe(sc) if ((tmp1 = ad_read(sc, 0)) != 0xaa || (tmp2 = ad_read(sc, 1)) != 0x45) { DPRINTF(("ad_detect_B (%x/%x)\n", tmp1, tmp2)); - return 0; + goto bad; } ad_write(sc, 0, 0x45); @@ -351,7 +372,7 @@ ad1848_probe(sc) if ((tmp1 = ad_read(sc, 0)) != 0x45 || (tmp2 = ad_read(sc, 1)) != 0xaa) { DPRINTF(("ad_detect_C (%x/%x)\n", tmp1, tmp2)); - return 0; + goto bad; } /* @@ -363,7 +384,7 @@ ad1848_probe(sc) if ((tmp & 0x0f) != ((tmp1 = ad_read(sc, SP_MISC_INFO)) & 0x0f)) { DPRINTF(("ad_detect_D (%x)\n", tmp1)); - return 0; + goto bad; } /* @@ -412,7 +433,7 @@ ad1848_probe(sc) for (i = 0; i < 16; i++) if ((tmp1 = ad_read(sc, i)) != (tmp2 = ad_read(sc, i + 16))) { DPRINTF(("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2)); - return 0; + goto bad; } /* @@ -435,7 +456,7 @@ ad1848_probe(sc) ad_write(sc, 2, 0xaa); if ((tmp2 = ad_read(sc, 18)) == 0xaa) { /* Rotten bits? */ DPRINTF(("ad_detect_H(%x)\n", tmp2)); - return 0; + goto bad; } /* @@ -462,13 +483,25 @@ ad1848_probe(sc) } /* Wait for 1848 to init */ - while(inb(sc->sc_iobase+AD1848_IADDR) & SP_IN_INIT); + while(ADREAD(sc, AD1848_IADDR) & SP_IN_INIT) + ; /* Wait for 1848 to autocal */ - outb(sc->sc_iobase+AD1848_IADDR, SP_TEST_AND_INIT); - while(inb(sc->sc_iobase+AD1848_IDATA) & AUTO_CAL_IN_PROG); + ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT); + while(ADREAD(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG) + ; return 1; +bad: + return 0; +} + +/* Unmap the I/O ports */ +void +ad1848_unmap(sc) + struct ad1848_softc *sc; +{ + bus_space_unmap(sc->sc_iot, sc->sc_ioh, AD1848_NPORT); } /* @@ -480,28 +513,56 @@ ad1848_attach(sc) struct ad1848_softc *sc; { int i; - struct ad1848_volume vol_mid = {150, 150}; + struct ad1848_volume vol_mid = {220, 220}; struct ad1848_volume vol_0 = {0, 0}; + struct audio_params pparams, rparams; + int timeout; sc->sc_locked = 0; + sc->sc_playrun = NOTRUNNING; + sc->sc_recrun = NOTRUNNING; + + if (sc->sc_drq != -1) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_drq, MAX_ISADMA, + BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("ad1848_attach: can't create map for drq %d\n", + sc->sc_drq); + return; + } + } + if (sc->sc_recdrq != -1 && sc->sc_recdrq != sc->sc_drq) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_recdrq, MAX_ISADMA, + BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("ad1848_attach: can't creape map for drq %d\n", + sc->sc_recdrq); + return; + } + } /* Initialize the ad1848... */ - for (i = 0; i < 16; i++) + for (i = 0; i < 0x10; i++) { ad_write(sc, i, ad1848_init_values[i]); + timeout = 100000; + while (timeout > 0 && ad_read(sc, AD1848_IADDR) & SP_IN_INIT) + timeout--; + } /* ...and additional CS4231 stuff too */ if (sc->mode == 2) { ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */ - for (i = 0x10; i <= 0x1f; i++) - if (ad1848_init_values[i] != 0) + for (i = 0x10; i < 0x20; i++) + if (ad1848_init_values[i] != 0) { ad_write(sc, i, ad1848_init_values[i]); + timeout = 100000; + while (timeout > 0 && + ad_read(sc, AD1848_IADDR) & SP_IN_INIT) + timeout--; + } } ad1848_reset(sc); - /* Set default parameters (mono, 8KHz, ULAW) */ - (void) ad1848_set_channels(sc, 1); - (void) ad1848_set_speed(sc, 8000); - (void) ad1848_set_format(sc, AUDIO_ENCODING_ULAW, 8); - (void) ad1848_commit_settings(sc); + pparams = audio_default; + rparams = audio_default; + (void) ad1848_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams); /* Set default gains */ (void) ad1848_set_rec_gain(sc, &vol_mid); @@ -520,6 +581,7 @@ ad1848_attach(sc) (void) ad1848_set_rec_port(sc, MIC_IN_PORT); printf(": %s", sc->chip_name); +#undef WAITREADY } /* @@ -527,10 +589,10 @@ ad1848_attach(sc) */ int ad1848_set_rec_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { - register u_char reg, gain; + u_char reg, gain; DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right)); @@ -551,7 +613,7 @@ ad1848_set_rec_gain(sc, gp) int ad1848_get_rec_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->rec_gain; @@ -560,7 +622,7 @@ ad1848_get_rec_gain(sc, gp) int ad1848_set_out_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg; @@ -585,7 +647,7 @@ ad1848_set_out_gain(sc, gp) int ad1848_get_out_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->out_gain; @@ -594,7 +656,7 @@ ad1848_get_out_gain(sc, gp) int ad1848_set_mon_gain(sc, gp) /* monitor gain */ - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg; @@ -613,7 +675,7 @@ ad1848_set_mon_gain(sc, gp) /* monitor gain */ int ad1848_get_mon_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->mon_gain; @@ -622,7 +684,7 @@ ad1848_get_mon_gain(sc, gp) int cs4231_set_mono_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg, oreg; @@ -642,7 +704,7 @@ cs4231_set_mono_gain(sc, gp) int cs4231_get_mono_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->mono_gain; @@ -651,7 +713,7 @@ cs4231_get_mono_gain(sc, gp) int ad1848_set_mic_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg; @@ -673,7 +735,7 @@ ad1848_set_mic_gain(sc, gp) int ad1848_get_mic_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { if (sc->mic_gain_on) @@ -688,7 +750,7 @@ ad1848_mute_monitor(addr, mute) void *addr; int mute; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; DPRINTF(("ad1848_mute_monitor: %smuting\n", mute ? "" : "un")); if (sc->mode == 2) { @@ -703,7 +765,7 @@ ad1848_mute_monitor(addr, mute) void cs4231_mute_monitor(sc, mute) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int mute; { u_char reg; @@ -724,7 +786,7 @@ cs4231_mute_monitor(sc, mute) void cs4231_mute_mono(sc, mute) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int mute; { u_char reg; @@ -741,7 +803,7 @@ cs4231_mute_mono(sc, mute) void cs4231_mute_line(sc, mute) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int mute; { u_char reg; @@ -762,7 +824,7 @@ cs4231_mute_line(sc, mute) void ad1848_mute_aux1(sc, mute) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int mute; { u_char reg; @@ -783,7 +845,7 @@ ad1848_mute_aux1(sc, mute) void ad1848_mute_aux2(sc, mute) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int mute; { u_char reg; @@ -804,7 +866,7 @@ ad1848_mute_aux2(sc, mute) int ad1848_set_aux1_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg; @@ -829,7 +891,7 @@ ad1848_set_aux1_gain(sc, gp) int ad1848_get_aux1_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->aux1_gain; @@ -838,7 +900,7 @@ ad1848_get_aux1_gain(sc, gp) int cs4231_set_linein_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg, oregl, oregr; @@ -864,7 +926,7 @@ cs4231_set_linein_gain(sc, gp) int cs4231_get_linein_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->line_gain; @@ -873,7 +935,7 @@ cs4231_get_linein_gain(sc, gp) int ad1848_set_aux2_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { u_char reg; @@ -898,7 +960,7 @@ ad1848_set_aux2_gain(sc, gp) int ad1848_get_aux2_gain(sc, gp) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; struct ad1848_volume *gp; { *gp = sc->aux2_gain; @@ -906,161 +968,177 @@ ad1848_get_aux2_gain(sc, gp) } int -ad1848_set_in_sr(addr, sr) - void *addr; - u_long sr; -{ - register struct ad1848_softc *sc = addr; - - DPRINTF(("ad1848_set_in_sr: %d\n", sr)); - - return (ad1848_set_speed(sc, sr)); -} - -u_long -ad1848_get_in_sr(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; - - return (sc->speed); -} - -int -ad1848_set_out_sr(addr, sr) - void *addr; - u_long sr; -{ - register struct ad1848_softc *sc = addr; - - DPRINTF(("ad1848_set_out_sr: %d\n", sr)); - - return (ad1848_set_speed(sc, sr)); -} - -u_long -ad1848_get_out_sr(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; - - return (sc->speed); -} - -int ad1848_query_encoding(addr, fp) void *addr; struct audio_encoding *fp; { + struct ad1848_softc *sc = addr; + switch (fp->index) { case 0: strcpy(fp->name, AudioEmulaw); - fp->format_id = AUDIO_ENCODING_ULAW; + fp->encoding = AUDIO_ENCODING_ULAW; + fp->precision = 8; + fp->flags = 0; break; case 1: strcpy(fp->name, AudioEalaw); - fp->format_id = AUDIO_ENCODING_ALAW; + fp->encoding = AUDIO_ENCODING_ALAW; + fp->precision = 8; + fp->flags = 0; break; case 2: - strcpy(fp->name, AudioEpcm16); - fp->format_id = AUDIO_ENCODING_PCM16; + strcpy(fp->name, AudioEslinear_le); + fp->encoding = AUDIO_ENCODING_SLINEAR_LE; + fp->precision = 16; + fp->flags = 0; break; case 3: - strcpy(fp->name, AudioEpcm8); - fp->format_id = AUDIO_ENCODING_PCM8; + strcpy(fp->name, AudioEulinear); + fp->encoding = AUDIO_ENCODING_ULINEAR; + fp->precision = 8; + fp->flags = 0; + break; + + case 4: /* only on CS4231 */ + strcpy(fp->name, AudioEslinear_be); + fp->encoding = AUDIO_ENCODING_SLINEAR_BE; + fp->precision = 16; + fp->flags = sc->mode == 1 ? AUDIO_ENCODINGFLAG_EMULATED : 0; + break; + + /* emulate some modes */ + case 5: + strcpy(fp->name, AudioEslinear); + fp->encoding = AUDIO_ENCODING_SLINEAR; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 6: + strcpy(fp->name, AudioEulinear_le); + fp->encoding = AUDIO_ENCODING_ULINEAR_LE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 7: + strcpy(fp->name, AudioEulinear_le); + fp->encoding = AUDIO_ENCODING_ULINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + + case 8: /* only on CS4231 */ + if (sc->mode == 1) + return EINVAL; + strcpy(fp->name, AudioEadpcm); + fp->encoding = AUDIO_ENCODING_ADPCM; + fp->precision = 8; + fp->flags = 0; break; default: - return(EINVAL); + return EINVAL; /*NOTREACHED*/ } return (0); } int -ad1848_set_format(addr, encoding, precision) +ad1848_set_params(addr, setmode, usemode, p, r) void *addr; - u_int encoding, precision; + int setmode, usemode; + struct audio_params *p, *r; { - register struct ad1848_softc *sc = addr; - static u_char format2bits[] = { - /* AUDIO_ENCODING_NONE */ 0, - /* AUDIO_ENCODING_ULAW */ FMT_ULAW >> 5, - /* AUDIO_ENCODING_ALAW */ FMT_ALAW >> 5, - /* AUDIO_ENCODING_PCM16 */ FMT_TWOS_COMP >> 5, - /* AUDIO_ENCODING_PCM8 */ FMT_PCM8 >> 5, - /* AUDIO_ENCODING_ADPCM */ 0, - }; - - DPRINTF(("ad1848_set_format: encoding=%d precision=%d\n", encoding, precision)); - - switch (encoding) { + struct ad1848_softc *sc = addr; + int error, bits, enc; + void (*pswcode) __P((void *, u_char *buf, int cnt)); + void (*rswcode) __P((void *, u_char *buf, int cnt)); + + DPRINTF(("ad1848_set_params: %d %d %d %ld\n", + p->encoding, p->precision, p->channels, p->sample_rate)); + + enc = p->encoding; + pswcode = rswcode = 0; + switch (enc) { + case AUDIO_ENCODING_SLINEAR_LE: + if (p->precision == 8) { + enc = AUDIO_ENCODING_ULINEAR_LE; + pswcode = rswcode = change_sign8; + } + break; + case AUDIO_ENCODING_SLINEAR_BE: + if (p->precision == 16 && sc->mode == 1) { + enc = AUDIO_ENCODING_SLINEAR_LE; + pswcode = rswcode = swap_bytes; + } + break; + case AUDIO_ENCODING_ULINEAR_LE: + if (p->precision == 16) { + enc = AUDIO_ENCODING_SLINEAR_LE; + pswcode = rswcode = change_sign16; + } + break; + case AUDIO_ENCODING_ULINEAR_BE: + if (p->precision == 16) { + enc = AUDIO_ENCODING_SLINEAR_LE; + pswcode = swap_bytes_change_sign16; + rswcode = change_sign16_swap_bytes; + } + break; + } + switch (enc) { case AUDIO_ENCODING_ULAW: + bits = FMT_ULAW >> 5; + break; case AUDIO_ENCODING_ALAW: - case AUDIO_ENCODING_PCM16: - case AUDIO_ENCODING_PCM8: + bits = FMT_ALAW >> 5; + break; + case AUDIO_ENCODING_ADPCM: + bits = FMT_ADPCM >> 5; + break; + case AUDIO_ENCODING_SLINEAR_LE: + if (p->precision == 16) + bits = FMT_TWOS_COMP >> 5; + else + return EINVAL; + break; + case AUDIO_ENCODING_SLINEAR_BE: + if (p->precision == 16) + bits = FMT_TWOS_COMP_BE >> 5; + else + return EINVAL; + break; + case AUDIO_ENCODING_ULINEAR_LE: + if (p->precision == 8) + bits = FMT_PCM8 >> 5; + else + return EINVAL; break; default: - return (EINVAL); + return EINVAL; } - sc->encoding = encoding; - sc->precision = precision; - sc->format_bits = format2bits[encoding]; - sc->need_commit = 1; - - DPRINTF(("ad1848_set_format: bits=%x\n", sc->format_bits)); - - return (0); -} - -int -ad1848_get_encoding(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; - - return (sc->encoding); -} - -int -ad1848_get_precision(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; + if (p->channels < 1 || p->channels > 2) + return EINVAL; - return (sc->precision); -} - -int -ad1848_set_channels(addr, channels) - void *addr; - int channels; -{ - register struct ad1848_softc *sc = addr; - - DPRINTF(("ad1848_set_channels: %d\n", channels)); + error = ad1848_set_speed(sc, &p->sample_rate); + if (error) + return error; - if (channels != 1 && channels != 2) - return (EINVAL); + p->sw_code = pswcode; + r->sw_code = rswcode; - sc->channels = channels; + sc->format_bits = bits; + sc->channels = p->channels; + sc->precision = p->precision; sc->need_commit = 1; + DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits)); return (0); } int -ad1848_get_channels(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; - - return (sc->channels); -} - -int ad1848_set_rec_port(sc, port) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; int port; { u_char inp, reg; @@ -1097,7 +1175,7 @@ ad1848_set_rec_port(sc, port) int ad1848_get_rec_port(sc) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; { return(sc->rec_port); } @@ -1107,27 +1185,24 @@ ad1848_round_blocksize(addr, blk) void *addr; int blk; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; sc->sc_lastcc = -1; - /* Don't try to DMA too much at once. */ - if (blk > NBPG) - blk = NBPG; - - /* Round to a multiple of the sample size. */ - blk &= -(sc->channels * sc->precision / 8); + /* Round to a multiple of the biggest sample size. */ + blk &= -4; return (blk); } int -ad1848_open(sc, dev, flags) - struct ad1848_softc *sc; - dev_t dev; +ad1848_open(addr, flags) + void *addr; int flags; { - DPRINTF(("ad1848_open: sc=0x%x\n", sc)); + struct ad1848_softc *sc = addr; + + DPRINTF(("ad1848_open: sc=%p\n", sc)); sc->sc_intr = 0; sc->sc_lastcc = -1; @@ -1153,17 +1228,26 @@ ad1848_close(addr) void *addr; { struct ad1848_softc *sc = addr; - register u_char r; + u_char r; sc->sc_intr = 0; DPRINTF(("ad1848_close: stop DMA\n")); + if (sc->sc_playrun != NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_drq); + sc->sc_playrun = NOTRUNNING; + } + if (sc->sc_recrun != NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_recdrq); + sc->sc_recrun = NOTRUNNING; + } ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)0); ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)0); /* Disable interrupts */ DPRINTF(("ad1848_close: disable intrs\n")); - ad_write(sc, SP_PIN_CONTROL, ad_read(sc, SP_PIN_CONTROL) & ~(INTERRUPT_ENABLE)); + ad_write(sc, SP_PIN_CONTROL, + ad_read(sc, SP_PIN_CONTROL) & ~INTERRUPT_ENABLE); DPRINTF(("ad1848_close: disable capture and playback\n")); r = ad_read(sc, SP_INTERFACE_CONFIG); @@ -1211,31 +1295,31 @@ ad1848_commit_settings(addr) /* Gravis Ultrasound MAX SDK sources says something about errata * sheets, with the implication that these inb()s are necessary. */ - (void) inb(sc->sc_iobase+AD1848_IDATA); - (void) inb(sc->sc_iobase+AD1848_IDATA); + (void)ADREAD(sc, AD1848_IDATA); + (void)ADREAD(sc, AD1848_IDATA); /* * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 100000; - while (timeout > 0 && inb(sc->sc_iobase+AD1848_IADDR) == SP_IN_INIT) + while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) timeout--; ad_write(sc, CS_REC_FORMAT, fs); /* Gravis Ultrasound MAX SDK sources says something about errata * sheets, with the implication that these inb()s are necessary. */ - (void) inb(sc->sc_iobase+AD1848_IDATA); - (void) inb(sc->sc_iobase+AD1848_IDATA); + (void)ADREAD(sc, AD1848_IDATA); + (void)ADREAD(sc, AD1848_IDATA); /* Now wait for resync for capture side of the house */ } /* * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 100000; - while (timeout > 0 && inb(sc->sc_iobase+AD1848_IADDR) == SP_IN_INIT) + while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) timeout--; - if (inb(sc->sc_iobase+AD1848_IADDR) == SP_IN_INIT) + if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) printf("ad1848_commit: Auto calibration timed out\n"); /* @@ -1257,7 +1341,7 @@ ad1848_commit_settings(addr) void ad1848_reset(sc) - register struct ad1848_softc *sc; + struct ad1848_softc *sc; { u_char r; @@ -1269,11 +1353,11 @@ ad1848_reset(sc) ad_write(sc, SP_INTERFACE_CONFIG, r); if (sc->mode == 2) { - outb(sc->sc_iobase+AD1848_IADDR, CS_IRQ_STATUS); - outb(sc->sc_iobase+AD1848_IDATA, 0); + ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS); + ADWRITE(sc, AD1848_IDATA, 0); } /* Clear interrupt status */ - outb(sc->sc_iobase+AD1848_STATUS, 0); + ADWRITE(sc, AD1848_STATUS, 0); #ifdef AUDIO_DEBUG if (ad1848debug) ad1848_dump_regs(sc); @@ -1281,9 +1365,9 @@ ad1848_reset(sc) } int -ad1848_set_speed(sc, arg) - register struct ad1848_softc *sc; - u_long arg; +ad1848_set_speed(sc, argp) + struct ad1848_softc *sc; + u_long *argp; { /* * The sampling speed is encoded in the least significant nible of I8. The @@ -1297,6 +1381,7 @@ ad1848_set_speed(sc, arg) int speed; u_char bits; } speed_struct; + u_long arg = *argp; static speed_struct speed_table[] = { {5510, (0 << 1) | 1}, @@ -1345,9 +1430,9 @@ ad1848_set_speed(sc, arg) selected = 3; } - sc->speed = speed_table[selected].speed; sc->speed_bits = speed_table[selected].bits; sc->need_commit = 1; + *argp = speed_table[selected].speed; return (0); } @@ -1359,7 +1444,7 @@ int ad1848_halt_out_dma(addr) void *addr; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; u_char reg; DPRINTF(("ad1848: ad1848_halt_out_dma\n")); @@ -1375,7 +1460,7 @@ int ad1848_halt_in_dma(addr) void *addr; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; u_char reg; DPRINTF(("ad1848: ad1848_halt_in_dma\n")); @@ -1388,33 +1473,21 @@ ad1848_halt_in_dma(addr) } int -ad1848_cont_out_dma(addr) - void *addr; -{ - register struct ad1848_softc *sc = addr; - u_char reg; - - DPRINTF(("ad1848: ad1848_cont_out_dma %s\n", sc->sc_locked?"(locked)":"")); - - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (reg | PLAYBACK_ENABLE)); - - return(0); -} - -int -ad1848_cont_in_dma(addr) +ad1848_dma_init_input(addr, buf, cc) void *addr; + void *buf; + int cc; { - register struct ad1848_softc *sc = addr; - u_char reg; - - DPRINTF(("ad1848: ad1848_cont_in_dma %s\n", sc->sc_locked?"(locked)":"")); - - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (reg | CAPTURE_ENABLE)); + struct ad1848_softc *sc = addr; - return(0); + sc->sc_recrun = DMARUNNING; + sc->sc_dma_flags = DMAMODE_READ | DMAMODE_LOOP; + sc->sc_dma_bp = buf; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_recdrq, buf, cc, NULL, + sc->sc_dma_flags, BUS_DMA_NOWAIT); + DPRINTF(("ad1848_dma_init_input: %p %d\n", buf, cc)); + return 0; } /* @@ -1428,8 +1501,8 @@ ad1848_dma_input(addr, p, cc, intr, arg) void (*intr) __P((void *)); void *arg; { - register struct ad1848_softc *sc = addr; - register u_char reg; + struct ad1848_softc *sc = addr; + u_char reg; if (sc->sc_locked) { DPRINTF(("ad1848_dma_input: locked\n")); @@ -1438,43 +1511,74 @@ ad1848_dma_input(addr, p, cc, intr, arg) #ifdef AUDIO_DEBUG if (ad1848debug > 1) - Dprintf("ad1848_dma_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("ad1848_dma_input: cc=%d %p (%p)\n", cc, intr, arg); #endif sc->sc_locked = 1; sc->sc_intr = intr; sc->sc_arg = arg; - sc->sc_dma_flags = DMAMODE_READ; - sc->sc_dma_bp = p; - sc->sc_dma_cnt = cc; - isadma_start(p, cc, sc->sc_recdrq, DMAMODE_READ); - if (sc->precision == 16) - cc >>= 1; - - if (sc->channels == 2) - cc >>= 1; - cc--; + switch (sc->sc_recrun) { + case NOTRUNNING: + sc->sc_dma_flags = DMAMODE_READ; + sc->sc_dma_bp = p; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_recdrq, p, cc, NULL, + DMAMODE_READ, BUS_DMA_NOWAIT); + goto startpcm; + case DMARUNNING: + sc->sc_recrun = PCMRUNNING; + startpcm: + if (sc->precision == 16) + cc >>= 1; + if (sc->channels == 2) + cc >>= 1; + cc--; - if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_RECORD) { - ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); - ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); + if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_RECORD) { + ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); + ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); - if (sc->mode == 2) { - ad_write(sc, CS_LOWER_REC_CNT, (u_char)(cc & 0xff)); - ad_write(sc, CS_UPPER_REC_CNT, (u_char)((cc >> 8) & 0xff)); - } + if (sc->mode == 2) { + ad_write(sc, CS_LOWER_REC_CNT, (u_char)(cc & 0xff)); + ad_write(sc, CS_UPPER_REC_CNT, (u_char)((cc >> 8) & 0xff)); + } - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (CAPTURE_ENABLE|reg)); + reg = ad_read(sc, SP_INTERFACE_CONFIG); + ad_write(sc, SP_INTERFACE_CONFIG, (CAPTURE_ENABLE|reg)); - sc->sc_lastcc = cc; - sc->sc_mode = AUMODE_RECORD; + sc->sc_lastcc = cc; + sc->sc_mode = AUMODE_RECORD; +#ifdef AUDIO_DEBUG + if (ad1848debug > 1) + printf("ad1848_dma_input: started capture\n"); +#endif + } + case PCMRUNNING: + break; } return 0; } int +ad1848_dma_init_output(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct ad1848_softc *sc = addr; + + sc->sc_playrun = DMARUNNING; + sc->sc_dma_flags = DMAMODE_WRITE | DMAMODE_LOOP; + sc->sc_dma_bp = buf; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_drq, buf, cc, NULL, + sc->sc_dma_flags, BUS_DMA_NOWAIT); + DPRINTF(("ad1848_dma_init_output: %p %d\n", buf, cc)); + return 0; +} + +int ad1848_dma_output(addr, p, cc, intr, arg) void *addr; void *p; @@ -1482,8 +1586,8 @@ ad1848_dma_output(addr, p, cc, intr, arg) void (*intr) __P((void *)); void *arg; { - register struct ad1848_softc *sc = addr; - register u_char reg; + struct ad1848_softc *sc = addr; + u_char reg; if (sc->sc_locked) { DPRINTF(("ad1848_dma_output: locked\n")); @@ -1491,31 +1595,43 @@ ad1848_dma_output(addr, p, cc, intr, arg) } #ifdef AUDIO_DEBUG - if (ad1848debug > 1) - Dprintf("ad1848_dma_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + if (ad1848debug > 0) + printf("ad1848_dma_output: cc=%d at %p 0x%p (0x%p)\n", cc, p, intr, arg); #endif sc->sc_locked = 1; sc->sc_intr = intr; sc->sc_arg = arg; - sc->sc_dma_flags = DMAMODE_WRITE; - sc->sc_dma_bp = p; - sc->sc_dma_cnt = cc; - isadma_start(p, cc, sc->sc_drq, DMAMODE_WRITE); - - if (sc->precision == 16) - cc >>= 1; - - if (sc->channels == 2) - cc >>= 1; - cc--; - - if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_PLAY) { - ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); - ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (PLAYBACK_ENABLE|reg)); - sc->sc_lastcc = cc; - sc->sc_mode = AUMODE_PLAY; + + switch (sc->sc_playrun) { + case NOTRUNNING: + sc->sc_dma_flags = DMAMODE_WRITE; + sc->sc_dma_bp = p; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_drq, p, cc, NULL, + DMAMODE_WRITE, BUS_DMA_NOWAIT); + goto startpcm; + case DMARUNNING: + sc->sc_playrun = PCMRUNNING; + startpcm: + if (sc->precision == 16) + cc >>= 1; + if (sc->channels == 2) + cc >>= 1; + cc--; + + if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_PLAY) { + ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); + ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); + + reg = ad_read(sc, SP_INTERFACE_CONFIG); + ad_write(sc, SP_INTERFACE_CONFIG, (PLAYBACK_ENABLE|reg)); + + sc->sc_lastcc = cc; + sc->sc_mode = AUMODE_PLAY; + } + break; + case PCMRUNNING: + break; } return 0; @@ -1525,16 +1641,16 @@ int ad1848_intr(arg) void *arg; { - register struct ad1848_softc *sc = arg; + struct ad1848_softc *sc = arg; int retval = 0; u_char status; /* Get intr status */ - status = inb(sc->sc_iobase+AD1848_STATUS); + status = ADREAD(sc, AD1848_STATUS); #ifdef AUDIO_DEBUG if (ad1848debug > 1) - Dprintf("ad1848_intr: intr=0x%x status=%x\n", sc->sc_intr, status); + printf("ad1848_intr: intr=%p status=%x\n", sc->sc_intr, status); #endif sc->sc_locked = 0; sc->sc_interrupts++; @@ -1543,15 +1659,66 @@ ad1848_intr(arg) if (sc->sc_intr && (status & INTERRUPT_STATUS)) { /* ACK DMA read because it may be in a bounce buffer */ /* XXX Do write to mask DMA ? */ - if (sc->sc_dma_flags & DMAMODE_READ) - isadma_done(sc->sc_recdrq); + if ((sc->sc_dma_flags & DMAMODE_READ) && sc->sc_recrun == NOTRUNNING) + isa_dmadone(sc->sc_isa, sc->sc_recdrq); (*sc->sc_intr)(sc->sc_arg); retval = 1; } /* clear interrupt */ if (status & INTERRUPT_STATUS) - outb(sc->sc_iobase+AD1848_STATUS, 0); + ADWRITE(sc, AD1848_STATUS, 0); return(retval); } + +void * +ad1848_malloc(addr, size, pool, flags) + void *addr; + unsigned long size; + int pool; + int flags; +{ + struct ad1848_softc *sc = addr; + + return isa_malloc(sc->sc_isa, 4, size, pool, flags); +} + +void +ad1848_free(addr, ptr, pool) + void *addr; + void *ptr; + int pool; +{ + isa_free(ptr, pool); +} + +unsigned long +ad1848_round(addr, size) + void *addr; + unsigned long size; +{ + if (size > MAX_ISADMA) + size = MAX_ISADMA; + return size; +} + +int +ad1848_mappage(addr, mem, off, prot) + void *addr; + void *mem; + int off; + int prot; +{ + return isa_mappage(mem, off, prot); +} + +int +ad1848_get_props(addr) + void *addr; +{ + struct ad1848_softc *sc = addr; + + return AUDIO_PROP_MMAP | + (sc->sc_drq != sc->sc_recdrq ? AUDIO_PROP_FULLDUPLEX : 0); +} diff --git a/sys/dev/isa/ad1848var.h b/sys/dev/isa/ad1848var.h index 8d6e3729cbe..b5fdaf67365 100644 --- a/sys/dev/isa/ad1848var.h +++ b/sys/dev/isa/ad1848var.h @@ -1,5 +1,5 @@ -/* $OpenBSD: ad1848var.h,v 1.5 1997/11/07 08:06:42 niklas Exp $ */ -/* $NetBSD: ad1848var.h,v 1.8 1996/04/29 20:02:37 christos Exp $ */ +/* $OpenBSD: ad1848var.h,v 1.6 1998/04/26 21:02:39 provos Exp $ */ +/* $NetBSD: ad1848var.h,v 1.22 1998/01/19 22:18:26 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -36,7 +36,7 @@ * */ -#define AD1848_NPORT 8 +#define AD1848_NPORT 4 struct ad1848_volume { u_char left; @@ -47,9 +47,13 @@ struct ad1848_softc { struct device sc_dev; /* base device */ struct isadev sc_id; /* ISA device */ void *sc_ih; /* interrupt vectoring */ + bus_space_tag_t sc_iot; /* tag */ + bus_space_handle_t sc_ioh; /* handle */ + int sc_iooffs; /* offset from handle */ void *parent; - + struct device *sc_isa; /* ISA bus's device */ + u_short sc_locked; /* true when doing HS DMA */ u_int sc_lastcc; /* size of last DMA xfer */ int sc_mode; /* half-duplex record/play */ @@ -60,7 +64,12 @@ struct ad1848_softc { u_int sc_dma_cnt; #endif - int sc_iobase; /* I/O port base address */ + char sc_playrun; /* running in continuous mode */ + char sc_recrun; /* running in continuous mode */ +#define NOTRUNNING 0 +#define DMARUNNING 1 +#define PCMRUNNING 2 + int sc_irq; /* interrupt */ int sc_drq; /* DMA */ int sc_recdrq; /* record/capture DMA */ @@ -77,8 +86,6 @@ struct ad1848_softc { char *chip_name; int mode; - u_long speed; - u_int encoding; /* ulaw/linear -- keep track */ u_int precision; /* 8/16 bits */ int channels; @@ -89,6 +96,9 @@ struct ad1848_softc { u_long sc_interrupts; /* number of interrupts taken */ void (*sc_intr)(void *); /* dma completion intr handler */ void *sc_arg; /* arg for sc_intr() */ + + /* Only used by pss XXX */ + int sc_iobase; }; /* @@ -100,27 +110,23 @@ struct ad1848_softc { #define DAC_IN_PORT 3 #ifdef _KERNEL +int ad1848_mapprobe __P((struct ad1848_softc *, int)); int ad1848_probe __P((struct ad1848_softc *)); +void ad1848_unmap __P((struct ad1848_softc *)); void ad1848_attach __P((struct ad1848_softc *)); -int ad1848_open __P((struct ad1848_softc *, dev_t, int)); +int ad1848_open __P((void *, int)); void ad1848_close __P((void *)); void ad1848_forceintr __P((struct ad1848_softc *)); -int ad1848_set_in_sr __P((void *, u_long)); -u_long ad1848_get_in_sr __P((void *)); -int ad1848_set_out_sr __P((void *, u_long)); -u_long ad1848_get_out_sr __P((void *)); int ad1848_query_encoding __P((void *, struct audio_encoding *)); -int ad1848_set_format __P((void *, u_int, u_int)); -int ad1848_get_encoding __P((void *)); -int ad1848_get_precision __P((void *)); -int ad1848_set_channels __P((void *, int)); -int ad1848_get_channels __P((void *)); +int ad1848_set_params __P((void *, int, int, struct audio_params *, struct audio_params *)); int ad1848_round_blocksize __P((void *, int)); +int ad1848_dma_init_output __P((void *, void *, int)); +int ad1848_dma_init_input __P((void *, void *, int)); int ad1848_dma_output __P((void *, void *, int, void (*)(void *), void*)); int ad1848_dma_input __P((void *, void *, int, void (*)(void *), void*)); @@ -128,8 +134,6 @@ int ad1848_commit_settings __P((void *)); int ad1848_halt_in_dma __P((void *)); int ad1848_halt_out_dma __P((void *)); -int ad1848_cont_in_dma __P((void *)); -int ad1848_cont_out_dma __P((void *)); int ad1848_intr __P((void *)); @@ -151,4 +155,12 @@ int ad1848_set_mic_gain __P((struct ad1848_softc *, struct ad1848_volume *)); int ad1848_get_mic_gain __P((struct ad1848_softc *, struct ad1848_volume *)); void ad1848_mute_aux1 __P((struct ad1848_softc *, int /* onoff */)); void ad1848_mute_aux2 __P((struct ad1848_softc *, int /* onoff */)); + +void *ad1848_malloc __P((void *, unsigned long, int, int)); +void ad1848_free __P((void *, void *, int)); +unsigned long ad1848_round __P((void *, unsigned long)); +int ad1848_mappage __P((void *, void *, int, int)); + +int ad1848_get_props __P((void *)); + #endif diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 98e00a8d7c2..ba476852ccd 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.39 1998/03/31 23:02:11 niklas Exp $ +# $OpenBSD: files.isa,v 1.40 1998/04/26 21:02:40 provos 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. @@ -12,7 +12,7 @@ device isa {[port = -1], [size = 0], [iomem = -1], [iosiz = 0], [irq = -1], [drq = -1], - [pnpid = -1]} + [drq2 = -1]} attach isa at isabus file dev/isa/isa.c isa needs-flag @@ -217,7 +217,7 @@ define sbdsp file dev/isa/sbdsp.c sbdsp # SoundBlaster family -device sb: audio, isa_dma, sbdsp, mulaw, opti +device sb: audio, isa_dma, sbdsp, mulaw, opti, auconv file dev/isa/sb.c sb needs-flag attach sb at isa with sb_isa @@ -231,7 +231,7 @@ attach aria at isa file dev/isa/aria.c aria needs-flag # ProAudio Spectrum -device pas: audio, isa_dma, sbdsp, mulaw +device pas: audio, isa_dma, sbdsp, mulaw, auconv attach pas at isa file dev/isa/pas.c pas needs-flag @@ -249,19 +249,21 @@ device pss {[port = -1], [size = 0], [iomem = -1], [iosiz = 0], [irq = -1], [drq = -1]} attach pss at isa -device sp: audio, isa_dma, ad1848 +device sp: audio, isa_dma, ad1848, auconv attach sp at pss file dev/isa/pss.c pss needs-flag # Microsoft Windows Sound System -device wss: audio, isa_dma, ad1848, opti -attach wss at isa +device wss: audio, isa_dma, ad1848, auconv file dev/isa/wss.c wss needs-flag +attach wss at isa with wss_isa +file dev/isa/wss_isa.c wss_isa needs-flag + # Gravis UltraSound & UltraSound MAX. # Use the "flags" keyword in a config file to specify an extra DMA # channel for full-duplex operation. -device gus: audio, isa_dma, ics2101, ad1848, mulaw +device gus: audio, isa_dma, ics2101, ad1848, mulaw, auconv attach gus at isa file dev/isa/gus.c gus needs-flag diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c index 8922f8889f7..eb01c44a1a8 100644 --- a/sys/dev/isa/gus.c +++ b/sys/dev/isa/gus.c @@ -1,5 +1,5 @@ -/* $OpenBSD: gus.c,v 1.13 1998/01/18 18:58:37 niklas Exp $ */ -/* $NetBSD: gus.c,v 1.16 1996/05/12 23:52:08 mycroft Exp $ */ +/* $OpenBSD: gus.c,v 1.14 1998/04/26 21:02:41 provos Exp $ */ +/* $NetBSD: gus.c,v 1.51 1998/01/25 23:48:06 mycroft Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -27,8 +27,8 @@ * 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 REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * 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 @@ -112,11 +112,13 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <machine/cpufunc.h> #include <sys/audioio.h> #include <dev/audio_if.h> #include <dev/mulaw.h> +#include <dev/auconv.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -177,8 +179,13 @@ struct gus_voice { struct gus_softc { struct device sc_dev; /* base device */ - struct isadev sc_id; /* ISA device */ + struct device *sc_isa; /* pointer to ISA parent */ void *sc_ih; /* interrupt vector */ + bus_space_tag_t sc_iot; /* tag */ + bus_space_handle_t sc_ioh1; /* handle */ + bus_space_handle_t sc_ioh2; /* handle */ + bus_space_handle_t sc_ioh3; /* ICS2101 handle */ + bus_space_handle_t sc_ioh4; /* MIDI handle */ int sc_iobase; /* I/O base address */ int sc_irq; /* IRQ used */ @@ -290,37 +297,35 @@ struct ics2101_volume { /* * Mixer & MUX devices for CS4231 */ -#define GUSMAX_MIX_IN 0 /* input to MUX from mixer output */ -#define GUSMAX_MONO_LVL 1 /* mic input to MUX; +#define GUSMAX_MONO_LVL 0 /* mic input to MUX; also mono mixer input */ -#define GUSMAX_DAC_LVL 2 /* input to MUX; also mixer input */ -#define GUSMAX_LINE_IN_LVL 3 /* input to MUX; also mixer input */ -#define GUSMAX_CD_LVL 4 /* mixer input only */ -#define GUSMAX_MONITOR_LVL 5 /* digital mix (?) */ -#define GUSMAX_OUT_LVL 6 /* output level. (?) */ -#define GUSMAX_SPEAKER_LVL 7 /* pseudo-device for mute */ -#define GUSMAX_LINE_IN_MUTE 8 /* pre-mixer */ -#define GUSMAX_DAC_MUTE 9 /* pre-mixer */ -#define GUSMAX_CD_MUTE 10 /* pre-mixer */ -#define GUSMAX_MONO_MUTE 11 /* pre-mixer--microphone/mono */ -#define GUSMAX_MONITOR_MUTE 12 /* post-mixer level/mute */ -#define GUSMAX_SPEAKER_MUTE 13 /* speaker mute */ - -#define GUSMAX_REC_LVL 14 /* post-MUX gain */ - -#define GUSMAX_RECORD_SOURCE 15 +#define GUSMAX_DAC_LVL 1 /* input to MUX; also mixer input */ +#define GUSMAX_LINE_IN_LVL 2 /* input to MUX; also mixer input */ +#define GUSMAX_CD_LVL 3 /* mixer input only */ +#define GUSMAX_MONITOR_LVL 4 /* digital mix (?) */ +#define GUSMAX_OUT_LVL 5 /* output level. (?) */ +#define GUSMAX_SPEAKER_LVL 6 /* pseudo-device for mute */ +#define GUSMAX_LINE_IN_MUTE 7 /* pre-mixer */ +#define GUSMAX_DAC_MUTE 8 /* pre-mixer */ +#define GUSMAX_CD_MUTE 9 /* pre-mixer */ +#define GUSMAX_MONO_MUTE 10 /* pre-mixer--microphone/mono */ +#define GUSMAX_MONITOR_MUTE 11 /* post-mixer level/mute */ +#define GUSMAX_SPEAKER_MUTE 12 /* speaker mute */ + +#define GUSMAX_REC_LVL 13 /* post-MUX gain */ + +#define GUSMAX_RECORD_SOURCE 14 /* Classes */ -#define GUSMAX_INPUT_CLASS 16 -#define GUSMAX_RECORD_CLASS 17 -#define GUSMAX_MONITOR_CLASS 18 -#define GUSMAX_OUTPUT_CLASS 19 +#define GUSMAX_INPUT_CLASS 15 +#define GUSMAX_RECORD_CLASS 16 +#define GUSMAX_MONITOR_CLASS 17 +#define GUSMAX_OUTPUT_CLASS 18 #ifdef AUDIO_DEBUG #define GUSPLAYDEBUG /*XXX*/ -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (gusdebug) Dprintf x -#define DMAPRINTF(x) if (gusdmadebug) Dprintf x +#define DPRINTF(x) if (gusdebug) printf x +#define DMAPRINTF(x) if (gusdmadebug) printf x int gusdebug = 0; int gusdmadebug = 0; #else @@ -348,7 +353,7 @@ int dmarecord_index = 0; * local routines */ -int gusopen __P((dev_t, int)); +int gusopen __P((void *, int)); void gusclose __P((void *)); void gusmax_close __P((void *)); int gusintr __P((void *)); @@ -356,62 +361,33 @@ int gus_set_in_gain __P((caddr_t, u_int, u_char)); int gus_get_in_gain __P((caddr_t)); int gus_set_out_gain __P((caddr_t, u_int, u_char)); int gus_get_out_gain __P((caddr_t)); -int gus_set_in_sr __P((void *, u_long)); -u_long gus_get_in_sr __P((void *)); -int gusmax_set_in_sr __P((void *, u_long)); -u_long gusmax_get_in_sr __P((void *)); -int gus_set_out_sr __P((void *, u_long)); -u_long gus_get_out_sr __P((void *)); -int gusmax_set_out_sr __P((void *, u_long)); -u_long gusmax_get_out_sr __P((void *)); -int gus_set_format __P((void *, u_int, u_int)); -int gus_get_encoding __P((void *)); -int gus_get_precision __P((void *)); -int gusmax_set_format __P((void *, u_int, u_int)); -int gusmax_get_encoding __P((void *)); -int gusmax_get_precision __P((void *)); -int gus_set_channels __P((void *, int)); -int gus_get_channels __P((void *)); -int gusmax_set_channels __P((void *, int)); -int gusmax_get_channels __P((void *)); +int gus_set_params __P((void *, int, int, struct audio_params *, struct audio_params *)); +int gusmax_set_params __P((void *, int, int, struct audio_params *, struct audio_params *)); int gus_round_blocksize __P((void *, int)); -int gus_set_out_port __P((void *, int)); -int gus_get_out_port __P((void *)); -int gus_set_in_port __P((void *, int)); -int gus_get_in_port __P((void *)); int gus_commit_settings __P((void *)); int gus_dma_output __P((void *, void *, int, void (*)(void *), void *)); int gus_dma_input __P((void *, void *, int, void (*)(void *), void *)); int gus_halt_out_dma __P((void *)); int gus_halt_in_dma __P((void *)); -int gus_cont_out_dma __P((void *)); -int gus_cont_in_dma __P((void *)); int gus_speaker_ctl __P((void *, int)); +int gusmaxopen __P((void *, int)); int gusmax_round_blocksize __P((void *, int)); int gusmax_commit_settings __P((void *)); int gusmax_dma_output __P((void *, void *, int, void (*)(void *), void *)); int gusmax_dma_input __P((void *, void *, int, void (*)(void *), void *)); int gusmax_halt_out_dma __P((void *)); int gusmax_halt_in_dma __P((void *)); -int gusmax_cont_out_dma __P((void *)); -int gusmax_cont_in_dma __P((void *)); int gusmax_speaker_ctl __P((void *, int)); -int gusmax_set_out_port __P((void *, int)); -int gusmax_get_out_port __P((void *)); -int gusmax_set_in_port __P((void *, int)); -int gusmax_get_in_port __P((void *)); int gus_getdev __P((void *, struct audio_device *)); STATIC void gus_deinterleave __P((struct gus_softc *, void *, int)); -STATIC void gus_expand __P((void *, int, u_char *, int)); -STATIC void gusmax_expand __P((void *, int, u_char *, int)); STATIC int gus_mic_ctl __P((void *, int)); STATIC int gus_linein_ctl __P((void *, int)); -STATIC int gus_test_iobase __P((int)); -STATIC void guspoke __P((int, long, u_char)); +STATIC int gus_test_iobase __P((bus_space_tag_t, int)); +STATIC void guspoke __P((bus_space_tag_t, bus_space_handle_t, long, u_char)); STATIC void gusdmaout __P((struct gus_softc *, int, u_long, caddr_t, int)); -STATIC void gus_init_cs4231 __P((struct gus_softc *)); +STATIC int gus_init_cs4231 __P((struct gus_softc *)); STATIC void gus_init_ics2101 __P((struct gus_softc *)); STATIC void gus_set_chan_addrs __P((struct gus_softc *)); @@ -434,9 +410,8 @@ STATIC int gus_dmain_intr __P((struct gus_softc *)); STATIC int gus_voice_intr __P((struct gus_softc *)); STATIC void gus_start_playing __P((struct gus_softc *, int)); STATIC int gus_continue_playing __P((struct gus_softc *, int)); -STATIC u_char guspeek __P((int, u_long)); +STATIC u_char guspeek __P((bus_space_tag_t, bus_space_handle_t, u_long)); STATIC u_long convert_to_16bit __P((u_long)); -STATIC int gus_setfd __P((void *, int)); STATIC int gus_mixer_set_port __P((void *, mixer_ctrl_t *)); STATIC int gus_mixer_get_port __P((void *, mixer_ctrl_t *)); STATIC int gusmax_mixer_set_port __P((void *, mixer_ctrl_t *)); @@ -444,6 +419,8 @@ STATIC int gusmax_mixer_get_port __P((void *, mixer_ctrl_t *)); STATIC int gus_mixer_query_devinfo __P((void *, mixer_devinfo_t *)); STATIC int gusmax_mixer_query_devinfo __P((void *, mixer_devinfo_t *)); STATIC int gus_query_encoding __P((void *, struct audio_encoding *)); +STATIC int gus_get_props __P((void *)); +STATIC int gusmax_get_props __P((void *)); STATIC void gusics_master_mute __P((struct ics2101_softc *, int)); STATIC void gusics_dac_mute __P((struct ics2101_softc *, int)); @@ -460,7 +437,12 @@ void stereo_dmaintr __P((void *)); * ISA bus driver routines */ +#define __BROKEN_INDIRECT_CONFIG +#ifdef __BROKEN_INDIRECT_CONFIG int gusprobe __P((struct device *, void *, void *)); +#else +int gusprobe __P((struct device *, struct cfdata *, void *)); +#endif void gusattach __P((struct device *, struct device *, void *)); struct cfattach gus_ca = { @@ -586,8 +568,7 @@ static unsigned short gus_log_volumes[512] = { 0x0ff0, 0x0ff1, 0x0ff2, 0x0ff3, 0x0ff4, 0x0ff5, 0x0ff6, 0x0ff7, 0x0ff8, 0x0ff9, 0x0ffa, 0x0ffb, 0x0ffc, 0x0ffd, 0x0ffe, 0x0fff}; -#define SELECT_GUS_REG(port,x) outb(port+GUS_REG_SELECT,x) -#define WHICH_GUS_REG(port) inb(port+GUS_REG_SELECT) +#define SELECT_GUS_REG(iot,ioh1,x) bus_space_write_1(iot,ioh1,GUS_REG_SELECT,x) #define ADDR_HIGH(x) (unsigned int) ((x >> 7L) & 0x1fffL) #define ADDR_LOW(x) (unsigned int) ((x & 0x7fL) << 9L) @@ -614,49 +595,70 @@ struct audio_hw_if gus_hw_if = { gusopen, gusclose, NULL, /* drain */ - gus_set_in_sr, - gus_get_in_sr, - gus_set_out_sr, - gus_get_out_sr, gus_query_encoding, - gus_set_format, - gus_get_encoding, - gus_get_precision, - gus_set_channels, - gus_get_channels, + gus_set_params, gus_round_blocksize, - gus_set_out_port, - gus_get_out_port, - gus_set_in_port, - gus_get_in_port, - gus_commit_settings, - gus_expand, - mulaw_compress, + NULL, + NULL, gus_dma_output, gus_dma_input, gus_halt_out_dma, gus_halt_in_dma, - gus_cont_out_dma, - gus_cont_in_dma, - gus_speaker_ctl, gus_getdev, - gus_setfd, + NULL, gus_mixer_set_port, gus_mixer_get_port, gus_mixer_query_devinfo, - 1, /* full-duplex */ - 0, + NULL, + NULL, + NULL, + NULL, + gus_get_props, }; +static struct audio_hw_if gusmax_hw_if = { + gusmaxopen, + gusmax_close, + NULL, /* drain */ + + gus_query_encoding, /* query encoding */ + + gusmax_set_params, + + gusmax_round_blocksize, + + gusmax_commit_settings, + + NULL, + NULL, + + gusmax_dma_output, + gusmax_dma_input, + gusmax_halt_out_dma, + gusmax_halt_in_dma, + + gusmax_speaker_ctl, + + gus_getdev, + NULL, + gusmax_mixer_set_port, + gusmax_mixer_get_port, + gusmax_mixer_query_devinfo, + NULL, + NULL, + NULL, + NULL, + gusmax_get_props, +}; /* * Some info about the current audio device @@ -674,33 +676,37 @@ struct audio_device gus_device = { int gusprobe(parent, match, aux) struct device *parent; - void *match, *aux; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; { - register struct gus_softc *sc = match; - register struct isa_attach_args *ia = aux; - struct cfdata *cf = sc->sc_dev.dv_cfdata; - register int iobase = ia->ia_iobase; - int recdrq = cf->cf_flags; + struct isa_attach_args *ia = aux; + int iobase = ia->ia_iobase; + int recdrq = ia->ia_drq2; /* * Before we do anything else, make sure requested IRQ and DRQ are * valid for this card. */ - if (gus_irq_map[ia->ia_irq] == IRQUNK) { + /* XXX range check before indexing!! */ + if (ia->ia_irq == IRQUNK || gus_irq_map[ia->ia_irq] == IRQUNK) { printf("gus: invalid irq %d, card not probed\n", ia->ia_irq); - return(0); + return 0; } - if (gus_drq_map[ia->ia_drq] == DRQUNK) { + if (ia->ia_drq == DRQUNK || gus_drq_map[ia->ia_drq] == DRQUNK) { printf("gus: invalid drq %d, card not probed\n", ia->ia_drq); - return(0); + return 0; } - if (recdrq != 0x00) { + if (recdrq != DRQUNK) { if (recdrq > 7 || gus_drq_map[recdrq] == DRQUNK) { - printf("gus: invalid flag given for second DMA channel (0x%x), card not probed\n", recdrq); - return(0); + printf("gus: invalid second DMA channel (%d), card not probed\n", recdrq); + return 0; } } else recdrq = ia->ia_drq; @@ -708,23 +714,22 @@ gusprobe(parent, match, aux) if (iobase == IOBASEUNK) { int i; for(i = 0; i < gus_addrs; i++) - if (gus_test_iobase(gus_base_addrs[i])) { + if (gus_test_iobase(ia->ia_iot, gus_base_addrs[i])) { iobase = gus_base_addrs[i]; goto done; } return 0; - } else if (! gus_test_iobase(iobase)) + } else if (!gus_test_iobase(ia->ia_iot, iobase)) return 0; done: - sc->sc_iobase = iobase; - sc->sc_irq = ia->ia_irq; - sc->sc_drq = ia->ia_drq; - sc->sc_recdrq = recdrq; + if ((ia->ia_drq != -1 && !isa_drq_isfree(parent, ia->ia_drq)) || + (recdrq != -1 && !isa_drq_isfree(parent, recdrq))) + return 0; - ia->ia_iobase = sc->sc_iobase; - ia->ia_iosize = 16; /* XXX */ - return(1); + ia->ia_iobase = iobase; + ia->ia_iosize = GUS_NPORT1; + return 1; } /* @@ -733,47 +738,74 @@ done: */ STATIC int -gus_test_iobase (int iobase) +gus_test_iobase (iot, iobase) + bus_space_tag_t iot; + int iobase; { - int i = splgus(); + bus_space_handle_t ioh1, ioh2, ioh3, ioh4; u_char s1, s2; + int s, rv = 0; + + /* Map i/o space */ + if (bus_space_map(iot, iobase, GUS_NPORT1, 0, &ioh1)) + return 0; + if (bus_space_map(iot, iobase+GUS_IOH2_OFFSET, GUS_NPORT2, 0, &ioh2)) + goto bad1; + + /* XXX Maybe we shouldn't fail on mapping this, but just assume + * the card is of revision 0? */ + if (bus_space_map(iot, iobase+GUS_IOH3_OFFSET, GUS_NPORT3, 0, &ioh3)) + goto bad2; + + if (bus_space_map(iot, iobase+GUS_IOH4_OFFSET, GUS_NPORT4, 0, &ioh4)) + goto bad3; /* * Reset GUS to an initial state before we do anything. */ + s = splgus(); delay(500); - SELECT_GUS_REG(iobase, GUSREG_RESET); - outb(iobase+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); delay(500); - SELECT_GUS_REG(iobase, GUSREG_RESET); - outb(iobase+GUS_DATA_HIGH, GUSMASK_MASTER_RESET); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET); delay(500); - splx(i); + splx(s); /* * See if we can write to the board's memory */ - s1 = guspeek(iobase, 0L); - s2 = guspeek(iobase, 1L); + s1 = guspeek(iot, ioh2, 0L); + s2 = guspeek(iot, ioh2, 1L); - guspoke(iobase, 0L, 0xaa); - guspoke(iobase, 1L, 0x55); + guspoke(iot, ioh2, 0L, 0xaa); + guspoke(iot, ioh2, 1L, 0x55); - if ((i=(int)guspeek(iobase, 0L)) != 0xaa) { - return(0); - } + if (guspeek(iot, ioh2, 0L) != 0xaa) + goto bad; - guspoke(iobase, 0L, s1); - guspoke(iobase, 1L, s2); + guspoke(iot, ioh2, 0L, s1); + guspoke(iot, ioh2, 1L, s2); - return 1; + rv = 1; + +bad: + bus_space_unmap(iot, ioh4, GUS_NPORT4); +bad3: + bus_space_unmap(iot, ioh3, GUS_NPORT3); +bad2: + bus_space_unmap(iot, ioh2, GUS_NPORT2); +bad1: + bus_space_unmap(iot, ioh1, GUS_NPORT1); + return rv; } /* @@ -785,28 +817,57 @@ gusattach(parent, self, aux) struct device *parent, *self; void *aux; { - register struct gus_softc *sc = (void *) self; - register struct isa_attach_args *ia = aux; - register int port = ia->ia_iobase; - int i; - register unsigned char c,d,m; + struct gus_softc *sc = (void *) self; + struct isa_attach_args *ia = aux; + bus_space_tag_t iot; + bus_space_handle_t ioh1, ioh2, ioh3, ioh4; + int iobase, i; + unsigned char c,d,m; + + sc->sc_iot = iot = ia->ia_iot; + iobase = ia->ia_iobase; + + /* Map i/o space */ + if (bus_space_map(iot, iobase, GUS_NPORT1, 0, &ioh1)) + panic("%s: can't map io port range 1", self->dv_xname); + sc->sc_ioh1 = ioh1; + if (bus_space_map(iot, iobase+GUS_IOH2_OFFSET, GUS_NPORT2, 0, &ioh2)) + panic("%s: can't map io port range 2", self->dv_xname); + sc->sc_ioh2 = ioh2; + + /* XXX Maybe we shouldn't fail on mapping this, but just assume + * the card is of revision 0? */ + if (bus_space_map(iot, iobase+GUS_IOH3_OFFSET, GUS_NPORT3, 0, &ioh3)) + panic("%s: can't map io port range 3", self->dv_xname); + sc->sc_ioh3 = ioh3; + + if (bus_space_map(iot, iobase+GUS_IOH4_OFFSET, GUS_NPORT4, 0, &ioh4)) + panic("%s: can't map io port range 4", self->dv_xname); + sc->sc_ioh4 = ioh4; + + sc->sc_iobase = iobase; + sc->sc_irq = ia->ia_irq; + sc->sc_drq = ia->ia_drq; + sc->sc_recdrq = ia->ia_drq2; /* * Figure out our board rev, and see if we need to initialize the * mixer */ + sc->sc_isa = parent; + delay(500); - c = inb(port+GUS_BOARD_REV); + c = bus_space_read_1(iot, ioh3, GUS_BOARD_REV); if (c != 0xff) sc->sc_revision = c; else sc->sc_revision = 0; - SELECT_GUS_REG(port, GUSREG_RESET); - outb(port+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); gusreset(sc, GUS_MAX_VOICES); /* initialize all voices */ gusreset(sc, GUS_MIN_VOICES); /* then set to just the ones we use */ @@ -837,54 +898,72 @@ gusattach(parent, self, aux) * The order of these operations is very magical. */ - disable_intr(); + disable_intr(); /* XXX needed? */ - outb(port+GUS_REG_CONTROL, GUS_REG_IRQCTL); - outb(port+GUS_MIX_CONTROL, m); - outb(port+GUS_IRQCTL_CONTROL, 0x00); - outb(port+0x0f, 0x00); + bus_space_write_1(iot, ioh1, GUS_REG_CONTROL, GUS_REG_IRQCTL); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m); + bus_space_write_1(iot, ioh1, GUS_IRQCTL_CONTROL, 0x00); + bus_space_write_1(iot, ioh1, 0x0f, 0x00); - outb(port+GUS_MIX_CONTROL, m); - outb(port+GUS_DMA_CONTROL, d | 0x80); /* magic reset? */ + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m); + bus_space_write_1(iot, ioh1, GUS_DMA_CONTROL, d | 0x80); /* magic reset? */ - outb(port+GUS_MIX_CONTROL, m | GUSMASK_CONTROL_SEL); - outb(port+GUS_IRQ_CONTROL, c); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m | GUSMASK_CONTROL_SEL); + bus_space_write_1(iot, ioh1, GUS_IRQ_CONTROL, c); - outb(port+GUS_MIX_CONTROL, m); - outb(port+GUS_DMA_CONTROL, d); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m); + bus_space_write_1(iot, ioh1, GUS_DMA_CONTROL, d); - outb(port+GUS_MIX_CONTROL, m | GUSMASK_CONTROL_SEL); - outb(port+GUS_IRQ_CONTROL, c); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m | GUSMASK_CONTROL_SEL); + bus_space_write_1(iot, ioh1, GUS_IRQ_CONTROL, c); - outb(port+GUS_VOICE_SELECT, 0x00); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, 0x00); /* enable line in, line out. leave mic disabled. */ - outb(port+GUS_MIX_CONTROL, + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN)); - outb(port+GUS_VOICE_SELECT, 0x00); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, 0x00); enable_intr(); sc->sc_mixcontrol = (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN); + /* XXX WILL THIS ALWAYS WORK THE WAY THEY'RE OVERLAYED?! */ + sc->sc_codec.sc_isa = sc->sc_dev.dv_parent; if (sc->sc_revision >= 5 && sc->sc_revision <= 9) { sc->sc_flags |= GUS_MIXER_INSTALLED; gus_init_ics2101(sc); } - if (sc->sc_revision >= 0xa) { - gus_init_cs4231(sc); + if (sc->sc_revision < 0xa || !gus_init_cs4231(sc)) { + /* Not using the CS4231, so create our DMA maps. */ + if (sc->sc_drq != -1) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_drq, + MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("%s: can't create map for drq %d\n", + sc->sc_dev.dv_xname, sc->sc_drq); + return; + } + } + if (sc->sc_recdrq != -1 && sc->sc_recdrq != sc->sc_drq) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_recdrq, + MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("%s: can't create map for drq %d\n", + sc->sc_dev.dv_xname, sc->sc_recdrq); + return; + } + } } - SELECT_GUS_REG(port, GUSREG_RESET); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); /* * Check to see how much memory we have on this card; see if any * "mirroring" occurs. We're assuming at least 256K already exists * on the card; otherwise the initial probe would have failed */ - guspoke(port, 0L, 0x00); + guspoke(iot, ioh2, 0L, 0x00); for(i = 1; i < 1024; i++) { u_long loc; @@ -892,13 +971,13 @@ gusattach(parent, self, aux) * See if we've run into mirroring yet */ - if (guspeek(port, 0L) != 0) + if (guspeek(iot, ioh2, 0L) != 0) break; loc = i << 10; - guspoke(port, loc, 0xaa); - if (guspeek(port, loc) != 0xaa) + guspoke(iot, ioh2, loc, 0xaa); + if (guspeek(iot, ioh2, loc) != 0xaa) break; } @@ -913,10 +992,8 @@ gusattach(parent, self, aux) printf("%s codec/mixer, ", sc->sc_codec.chip_name); if (sc->sc_recdrq == sc->sc_drq) { printf("half-duplex"); - gus_hw_if.full_duplex = 0; } else { printf("full-duplex, record drq %d", sc->sc_recdrq); - gus_hw_if.full_duplex = 1; } printf(">\n"); @@ -933,10 +1010,11 @@ gusattach(parent, self, aux) /* * Set some default values + * XXX others start with 8kHz mono mulaw */ sc->sc_irate = sc->sc_orate = 44100; - sc->sc_encoding = AUDIO_ENCODING_LINEAR; + sc->sc_encoding = AUDIO_ENCODING_SLINEAR_LE; sc->sc_precision = 16; sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_DATA_SIZE16; sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16; @@ -949,38 +1027,30 @@ gusattach(parent, self, aux) * full right. * For mono playback, we set up both voices playing the same buffer. */ - outb(sc->sc_iobase+GUS_VOICE_SELECT, (unsigned char) GUS_VOICE_LEFT); - SELECT_GUS_REG(sc->sc_iobase, GUSREG_PAN_POS); - outb(sc->sc_iobase+GUS_DATA_HIGH, GUS_PAN_FULL_LEFT); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) GUS_VOICE_LEFT); + SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_LEFT); - outb(sc->sc_iobase+GUS_VOICE_SELECT, (unsigned char) GUS_VOICE_RIGHT); - SELECT_GUS_REG(sc->sc_iobase, GUSREG_PAN_POS); - outb(sc->sc_iobase+GUS_DATA_HIGH, GUS_PAN_FULL_RIGHT); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) GUS_VOICE_RIGHT); + SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_RIGHT); /* * Attach to the generic audio layer */ - if (audio_hardware_attach(&gus_hw_if, HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc) != 0) - printf("gus: could not attach to audio pseudo-device driver\n"); + audio_attach_mi(&gus_hw_if, 0, HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc, &sc->sc_dev); } int -gusopen(dev, flags) - dev_t dev; +gusopen(addr, flags) + void *addr; int flags; { - int unit = AUDIOUNIT(dev); - struct gus_softc *sc; + struct gus_softc *sc = addr; DPRINTF(("gusopen() called\n")); - if (unit >= gus_cd.cd_ndevs) - return ENXIO; - sc = gus_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - if (sc->sc_flags & GUS_OPEN) return EBUSY; @@ -996,7 +1066,7 @@ gusopen(dev, flags) sc->sc_voc[GUS_VOICE_LEFT].current_addr = GUS_MEM_OFFSET; if (HAS_CODEC(sc)) { - ad1848_open(&sc->sc_codec, dev, flags); + ad1848_open(&sc->sc_codec, flags); sc->sc_codec.aux1_mute = 0; ad1848_mute_aux1(&sc->sc_codec, 0); /* turn on DAC output */ if (flags & FREAD) { @@ -1015,51 +1085,38 @@ gusopen(dev, flags) return 0; } -STATIC void -gusmax_expand(hdl, encoding, buf, count) - void *hdl; - int encoding; - u_char *buf; - int count; -{ - register struct ad1848_softc *ac = hdl; - - gus_expand(ac->parent, encoding, buf, count); -} - -STATIC void -gus_expand(hdl, encoding, buf, count) - void *hdl; - int encoding; - u_char *buf; - int count; +int +gusmaxopen(addr, flags) + void *addr; + int flags; { - struct gus_softc *sc = hdl; - - mulaw_expand(NULL, encoding, buf, count); - /* - * If we need stereo deinterleaving, do it now. - */ - if (sc->sc_channels == 2) - gus_deinterleave(sc, (void *)buf, count); + struct ad1848_softc *ac = addr; + return gusopen(ac->parent, flags); } STATIC void gus_deinterleave(sc, buf, size) - register struct gus_softc *sc; + struct gus_softc *sc; void *buf; int size; { /* deinterleave the stereo data. We can use sc->sc_deintr_buf for scratch space. */ - register int i; + int i; + + if (size > sc->sc_blocksize) { + printf("gus: deinterleave %d > %d\n", size, sc->sc_blocksize); + return; + } else if (size < sc->sc_blocksize) { + DPRINTF(("gus: deinterleave %d < %d\n", size, sc->sc_blocksize)); + } /* * size is in bytes. */ if (sc->sc_precision == 16) { - register u_short *dei = sc->sc_deintr_buf; - register u_short *sbuf = buf; + u_short *dei = sc->sc_deintr_buf; + u_short *sbuf = buf; size >>= 1; /* bytecnt to shortcnt */ /* copy 2nd of each pair of samples to the staging area, while compacting the 1st of each pair into the original area. */ @@ -1079,8 +1136,8 @@ gus_deinterleave(sc, buf, size) */ bcopy(dei, &sbuf[size/2], i * sizeof(short)); } else { - register u_char *dei = sc->sc_deintr_buf; - register u_char *sbuf = buf; + u_char *dei = sc->sc_deintr_buf; + u_char *sbuf = buf; for (i = 0; i < size/2-1; i++) { dei[i] = sbuf[i*2+1]; sbuf[i+1] = sbuf[i*2+2]; @@ -1101,7 +1158,7 @@ gusmax_dma_output(addr, buf, size, intr, arg) void (*intr) __P((void *)); void *arg; { - register struct ad1848_softc *ac = addr; + struct ad1848_softc *ac = addr; return gus_dma_output(ac->parent, buf, size, intr, arg); } @@ -1164,7 +1221,7 @@ gus_dma_output(addr, buf, size, intr, arg) u_long boarddma; int flags; - DMAPRINTF(("gus_dma_output %d @ %x\n", size, buf)); + DMAPRINTF(("gus_dma_output %d @ %p\n", size, buf)); if (size != sc->sc_blocksize) { DPRINTF(("gus_dma_output reqsize %d not sc_blocksize %d\n", @@ -1175,9 +1232,10 @@ gus_dma_output(addr, buf, size, intr, arg) flags = GUSMASK_DMA_WRITE; if (sc->sc_precision == 16) flags |= GUSMASK_DMA_DATA_SIZE; - /* pcm16 is signed, mulaw & pcm8 are unsigned */ if (sc->sc_encoding == AUDIO_ENCODING_ULAW || - sc->sc_encoding == AUDIO_ENCODING_PCM8) + sc->sc_encoding == AUDIO_ENCODING_ALAW || + sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE || + sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE) flags |= GUSMASK_DMA_INVBIT; if (sc->sc_channels == 2) { @@ -1192,9 +1250,12 @@ gus_dma_output(addr, buf, size, intr, arg) } if (size == 0) return 0; + + gus_deinterleave(sc, (void *)buffer, size); + size >>= 1; - boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET; + boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET; sc->sc_stereo.intr = intr; sc->sc_stereo.arg = arg; @@ -1235,8 +1296,8 @@ void gusmax_close(addr) void *addr; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; #if 0 ac->aux1_mute = 1; ad1848_mute_aux1(ac, 1); /* turn off DAC output */ @@ -1254,7 +1315,7 @@ gusclose(addr) { struct gus_softc *sc = addr; - DPRINTF(("gus_close: sc=0x%x\n", sc)); + DPRINTF(("gus_close: sc=%p\n", sc)); /* if (sc->sc_flags & GUS_DMAOUT_ACTIVE) */ { @@ -1291,9 +1352,12 @@ int gusintr(arg) void *arg; { - register struct gus_softc *sc = arg; + struct gus_softc *sc = arg; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; + bus_space_handle_t ioh2 = sc->sc_ioh2; unsigned char intr; - register int port = sc->sc_iobase; + int retval = 0; DPRINTF(("gusintr\n")); @@ -1302,15 +1366,15 @@ gusintr(arg) #endif if (HAS_CODEC(sc)) retval = ad1848_intr(&sc->sc_codec); - if ((intr = inb(port+GUS_IRQ_STATUS)) & GUSMASK_IRQ_DMATC) { + if ((intr = bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS)) & GUSMASK_IRQ_DMATC) { DMAPRINTF(("gusintr dma flags=%x\n", sc->sc_flags)); #ifdef DIAGNOSTIC gusdmaintrcnt++; #endif retval += gus_dmaout_intr(sc); if (sc->sc_flags & GUS_DMAIN_ACTIVE) { - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - intr = inb(port+GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); if (intr & GUSMASK_SAMPLE_DMATC) { retval += gus_dmain_intr(sc); } @@ -1350,27 +1414,29 @@ int playcntr; STATIC void gus_dmaout_timeout(arg) - void *arg; + void *arg; { - register struct gus_softc *sc = arg; - register int port = sc->sc_iobase; - int s; - - printf("%s: dmaout timeout\n", sc->sc_dev.dv_xname); - /* - * Stop any DMA. - */ + struct gus_softc *sc = arg; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; + int s; - s = splgus(); - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - outb(sc->sc_iobase+GUS_DATA_HIGH, 0); + printf("%s: dmaout timeout\n", sc->sc_dev.dv_xname); + /* + * Stop any DMA. + */ + s = splgus(); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0); + #if 0 - isadma_abort(sc->sc_drq); /* XXX we will dmadone below? */ + /* XXX we will dmadone below? */ + isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq); #endif - - gus_dmaout_dointr(sc); - splx(s); + + gus_dmaout_dointr(sc); + splx(s); } @@ -1383,15 +1449,16 @@ STATIC int gus_dmaout_intr(sc) struct gus_softc *sc; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; /* * If we got a DMA transfer complete from the GUS DRAM, then deal * with it. */ - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - if (inb(port+GUS_DATA_HIGH) & GUSMASK_DMA_IRQPEND) { + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + if (bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & GUSMASK_DMA_IRQPEND) { untimeout(gus_dmaout_timeout, sc); gus_dmaout_dointr(sc); return 1; @@ -1403,12 +1470,13 @@ STATIC void gus_dmaout_dointr(sc) struct gus_softc *sc; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; /* sc->sc_dmaoutcnt - 1 because DMA controller counts from zero?. */ - isadma_done(sc->sc_drq); + isa_dmadone(sc->sc_dev.dv_parent, sc->sc_drq); sc->sc_flags &= ~GUS_DMAOUT_ACTIVE; /* pending DMA is done */ - DMAPRINTF(("gus_dmaout_dointr %d @ %x\n", sc->sc_dmaoutcnt, + DMAPRINTF(("gus_dmaout_dointr %d @ %p\n", sc->sc_dmaoutcnt, sc->sc_dmaoutaddr)); /* @@ -1419,21 +1487,31 @@ gus_dmaout_dointr(sc) * byte rather than the one we have in memory. */ if (sc->sc_dmabuf == sc->sc_nbufs - 1) { - register int i; + int i; switch (sc->sc_encoding) { - case AUDIO_ENCODING_PCM16: + case AUDIO_ENCODING_SLINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + if (sc->sc_precision == 8) + goto byte; /* we have the native format */ for (i = 1; i <= 2; i++) - guspoke(port, sc->sc_gusaddr - + guspoke(iot, ioh2, sc->sc_gusaddr - (sc->sc_nbufs - 1) * sc->sc_chanblocksize - i, sc->sc_dmaoutaddr[sc->sc_dmaoutcnt-i]); break; - case AUDIO_ENCODING_PCM8: + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_ULINEAR_BE: + guspoke(iot, ioh2, sc->sc_gusaddr - + (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 2, + guspeek(iot, ioh2, + sc->sc_gusaddr + sc->sc_chanblocksize - 2)); + case AUDIO_ENCODING_ALAW: case AUDIO_ENCODING_ULAW: + byte: /* we need to fetch the translated byte, then stuff it. */ - guspoke(port, sc->sc_gusaddr - + guspoke(iot, ioh2, sc->sc_gusaddr - (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 1, - guspeek(port, + guspeek(iot, ioh2, sc->sc_gusaddr + sc->sc_chanblocksize - 1)); break; } @@ -1509,11 +1587,11 @@ gus_dmaout_dointr(sc) playcntr = ++playcntr % NDMARECS; } #endif - outb(port+GUS_VOICE_SELECT, GUS_VOICE_LEFT); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl); } } gus_bufcnt[sc->sc_bufcnt-1]++; @@ -1546,7 +1624,8 @@ STATIC int gus_voice_intr(sc) struct gus_softc *sc; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; int ignore = 0, voice, rval = 0; unsigned char intr, status; @@ -1557,8 +1636,8 @@ gus_voice_intr(sc) */ while(1) { - SELECT_GUS_REG(port, GUSREG_IRQ_STATUS); - intr = inb(port+GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS); + intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); if ((intr & (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE)) == (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE)) @@ -1587,8 +1666,8 @@ gus_voice_intr(sc) * (this stops it from continuously generating IRQs) */ - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL+0x80); - status = inb(port+GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL+0x80); + status = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); if (status & GUSMASK_VOICE_STOPPED) { if (voice != GUS_VOICE_LEFT) { DMAPRINTF(("%s: spurious voice %d stop?\n", @@ -1692,177 +1771,179 @@ gus_voice_intr(sc) STATIC void gus_start_playing(sc, bufno) -struct gus_softc *sc; -int bufno; + struct gus_softc *sc; + int bufno; { - register int port = sc->sc_iobase; - /* - * Start the voices playing, with buffer BUFNO. - */ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; + /* + * Start the voices playing, with buffer BUFNO. + */ - /* - * Loop or roll if we have buffers ready. - */ + /* + * Loop or roll if we have buffers ready. + */ - if (sc->sc_bufcnt == 1) { - sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~(GUSMASK_LOOP_ENABLE); - sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL); - } else { - if (bufno == sc->sc_nbufs - 1) { - sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE; - sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL); + if (sc->sc_bufcnt == 1) { + sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~(GUSMASK_LOOP_ENABLE); + sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL); } else { - sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE; - sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL; + if (bufno == sc->sc_nbufs - 1) { + sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE; + sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL); + } else { + sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE; + sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL; + } } - } - outb(port+GUS_VOICE_SELECT, GUS_VOICE_LEFT); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl); - sc->sc_voc[GUS_VOICE_LEFT].current_addr = - GUS_MEM_OFFSET + sc->sc_chanblocksize * bufno; - sc->sc_voc[GUS_VOICE_LEFT].end_addr = - sc->sc_voc[GUS_VOICE_LEFT].current_addr + sc->sc_chanblocksize - 1; - sc->sc_voc[GUS_VOICE_RIGHT].current_addr = - sc->sc_voc[GUS_VOICE_LEFT].current_addr + - (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0); - /* - * set up right channel to just loop forever, no interrupts, - * starting at the buffer we just filled. We'll feed it data - * at the same time as left channel. - */ - sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_LOOP_ENABLE; - sc->sc_voc[GUS_VOICE_RIGHT].volcntl &= ~(GUSMASK_VOICE_ROLL); + sc->sc_voc[GUS_VOICE_LEFT].current_addr = + GUS_MEM_OFFSET + sc->sc_chanblocksize * bufno; + sc->sc_voc[GUS_VOICE_LEFT].end_addr = + sc->sc_voc[GUS_VOICE_LEFT].current_addr + sc->sc_chanblocksize - 1; + sc->sc_voc[GUS_VOICE_RIGHT].current_addr = + sc->sc_voc[GUS_VOICE_LEFT].current_addr + + (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0); + /* + * set up right channel to just loop forever, no interrupts, + * starting at the buffer we just filled. We'll feed it data + * at the same time as left channel. + */ + sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_LOOP_ENABLE; + sc->sc_voc[GUS_VOICE_RIGHT].volcntl &= ~(GUSMASK_VOICE_ROLL); #ifdef GUSPLAYDEBUG - if (gusstats) { - microtime(&playstats[playcntr].tv); - playstats[playcntr].curaddr = sc->sc_voc[GUS_VOICE_LEFT].current_addr; - - playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl; - playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl; - playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr; - playstats[playcntr].playbuf = bufno; - playstats[playcntr].dmabuf = sc->sc_dmabuf; - playstats[playcntr].bufcnt = sc->sc_bufcnt; - playstats[playcntr].vaction = 5; - playcntr = ++playcntr % NDMARECS; - } + if (gusstats) { + microtime(&playstats[playcntr].tv); + playstats[playcntr].curaddr = sc->sc_voc[GUS_VOICE_LEFT].current_addr; + + playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl; + playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl; + playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr; + playstats[playcntr].playbuf = bufno; + playstats[playcntr].dmabuf = sc->sc_dmabuf; + playstats[playcntr].bufcnt = sc->sc_bufcnt; + playstats[playcntr].vaction = 5; + playcntr = ++playcntr % NDMARECS; + } #endif - outb(port+GUS_VOICE_SELECT, GUS_VOICE_RIGHT); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].volcntl); - - gus_start_voice(sc, GUS_VOICE_RIGHT, 0); - gus_start_voice(sc, GUS_VOICE_LEFT, 1); - if (sc->sc_playbuf == -1) - /* mark start of playing */ - sc->sc_playbuf = bufno; + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_RIGHT); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].volcntl); + + gus_start_voice(sc, GUS_VOICE_RIGHT, 0); + gus_start_voice(sc, GUS_VOICE_LEFT, 1); + if (sc->sc_playbuf == -1) + /* mark start of playing */ + sc->sc_playbuf = bufno; } STATIC int gus_continue_playing(sc, voice) -register struct gus_softc *sc; -int voice; + struct gus_softc *sc; + int voice; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; - /* - * stop this voice from interrupting while we work. - */ + /* + * stop this voice from interrupting while we work. + */ - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl & ~(GUSMASK_VOICE_IRQ)); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl & ~(GUSMASK_VOICE_IRQ)); - /* - * update playbuf to point to the buffer the hardware just started - * playing - */ - sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs; + /* + * update playbuf to point to the buffer the hardware just started + * playing + */ + sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs; - /* - * account for buffer just finished - */ - if (--sc->sc_bufcnt == 0) { - DPRINTF(("gus: bufcnt 0 on continuing voice?\n")); - } - if (sc->sc_playbuf == sc->sc_dmabuf && (sc->sc_flags & GUS_LOCKED)) { - printf("%s: continue into active dmabuf?\n", sc->sc_dev.dv_xname); - return 1; - } - - /* - * Select the end of the buffer based on the currently active - * buffer, [plus extra contiguous buffers (if ready)]. - */ - - /* - * set endpoint at end of buffer we just started playing. - * - * The total gets -1 because end addrs are one less than you might - * think (the end_addr is the address of the last sample to play) - */ - gus_set_endaddr(sc, voice, GUS_MEM_OFFSET + - sc->sc_chanblocksize * (sc->sc_playbuf + 1) - 1); - - if (sc->sc_bufcnt < 2) { /* - * Clear out the loop and roll flags, and rotate the currently - * playing buffer. That way, if we don't manage to get more - * data before this buffer finishes, we'll just stop. + * account for buffer just finished */ - sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE; - sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL; - playstats[playcntr].vaction = 0; - } else { + if (--sc->sc_bufcnt == 0) { + DPRINTF(("gus: bufcnt 0 on continuing voice?\n")); + } + if (sc->sc_playbuf == sc->sc_dmabuf && (sc->sc_flags & GUS_LOCKED)) { + printf("%s: continue into active dmabuf?\n", sc->sc_dev.dv_xname); + return 1; + } + /* - * We have some buffers to play. set LOOP if we're on the - * last buffer in the ring, otherwise set ROLL. + * Select the end of the buffer based on the currently active + * buffer, [plus extra contiguous buffers (if ready)]. + */ + + /* + * set endpoint at end of buffer we just started playing. + * + * The total gets -1 because end addrs are one less than you might + * think (the end_addr is the address of the last sample to play) */ - if (sc->sc_playbuf == sc->sc_nbufs - 1) { - sc->sc_voc[voice].voccntl |= GUSMASK_LOOP_ENABLE; - sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL; - playstats[playcntr].vaction = 1; + gus_set_endaddr(sc, voice, GUS_MEM_OFFSET + + sc->sc_chanblocksize * (sc->sc_playbuf + 1) - 1); + + if (sc->sc_bufcnt < 2) { + /* + * Clear out the loop and roll flags, and rotate the currently + * playing buffer. That way, if we don't manage to get more + * data before this buffer finishes, we'll just stop. + */ + sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE; + sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL; + playstats[playcntr].vaction = 0; } else { - sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE; - sc->sc_voc[voice].volcntl |= GUSMASK_VOICE_ROLL; - playstats[playcntr].vaction = 2; + /* + * We have some buffers to play. set LOOP if we're on the + * last buffer in the ring, otherwise set ROLL. + */ + if (sc->sc_playbuf == sc->sc_nbufs - 1) { + sc->sc_voc[voice].voccntl |= GUSMASK_LOOP_ENABLE; + sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL; + playstats[playcntr].vaction = 1; + } else { + sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE; + sc->sc_voc[voice].volcntl |= GUSMASK_VOICE_ROLL; + playstats[playcntr].vaction = 2; + } } - } #ifdef GUSPLAYDEBUG - if (gusstats) { - microtime(&playstats[playcntr].tv); - playstats[playcntr].curaddr = gus_get_curaddr(sc, voice); - - playstats[playcntr].voccntl = sc->sc_voc[voice].voccntl; - playstats[playcntr].volcntl = sc->sc_voc[voice].volcntl; - playstats[playcntr].endaddr = sc->sc_voc[voice].end_addr; - playstats[playcntr].playbuf = sc->sc_playbuf; - playstats[playcntr].dmabuf = sc->sc_dmabuf; - playstats[playcntr].bufcnt = sc->sc_bufcnt; - playcntr = ++playcntr % NDMARECS; - } + if (gusstats) { + microtime(&playstats[playcntr].tv); + playstats[playcntr].curaddr = gus_get_curaddr(sc, voice); + + playstats[playcntr].voccntl = sc->sc_voc[voice].voccntl; + playstats[playcntr].volcntl = sc->sc_voc[voice].volcntl; + playstats[playcntr].endaddr = sc->sc_voc[voice].end_addr; + playstats[playcntr].playbuf = sc->sc_playbuf; + playstats[playcntr].dmabuf = sc->sc_dmabuf; + playstats[playcntr].bufcnt = sc->sc_bufcnt; + playcntr = ++playcntr % NDMARECS; + } #endif - /* - * (re-)set voice parameters. This will reenable interrupts from this - * voice. - */ + /* + * (re-)set voice parameters. This will reenable interrupts from this + * voice. + */ - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].volcntl); - return 0; + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].volcntl); + return 0; } /* @@ -1876,8 +1957,9 @@ gusdmaout(sc, flags, gusaddr, buffaddr, length) u_long gusaddr; caddr_t buffaddr; { - register unsigned char c = (unsigned char) flags; - register int port = sc->sc_iobase; + unsigned char c = (unsigned char) flags; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; DMAPRINTF(("gusdmaout flags=%x scflags=%x\n", flags, sc->sc_flags)); @@ -1903,8 +1985,8 @@ gusdmaout(sc, flags, gusaddr, buffaddr, length) * Make sure the GUS _isn't_ setup for DMA */ - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - outb(port+GUS_DATA_HIGH, 0); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0); /* * Tell the PC DMA controller to start doing DMA @@ -1912,7 +1994,8 @@ gusdmaout(sc, flags, gusaddr, buffaddr, length) sc->sc_dmaoutaddr = (u_char *) buffaddr; sc->sc_dmaoutcnt = length; - isadma_start(buffaddr, length, sc->sc_drq, DMAMODE_WRITE); + isa_dmastart(sc->sc_dev.dv_parent, sc->sc_drq, buffaddr, length, + NULL, DMAMODE_WRITE, BUS_DMA_NOWAIT); /* * Set up DMA address - use the upper 16 bits ONLY @@ -1920,15 +2003,15 @@ gusdmaout(sc, flags, gusaddr, buffaddr, length) sc->sc_flags |= GUS_DMAOUT_ACTIVE; - SELECT_GUS_REG(port, GUSREG_DMA_START); - outw(port+GUS_DATA_LOW, (int) (gusaddr >> 4)); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_START); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (int) (gusaddr >> 4)); /* * Tell the GUS to start doing DMA */ - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - outb(port+GUS_DATA_HIGH, c); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, c); /* * XXX If we don't finish in one second, give up... @@ -1948,7 +2031,8 @@ gus_start_voice(sc, voice, intrs) int voice; int intrs; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; u_long start; u_long current; u_long end; @@ -1978,22 +2062,22 @@ gus_start_voice(sc, voice, intrs) * Select the voice we want to use, and program the data addresses */ - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_START_ADDR_HIGH); - outw(port+GUS_DATA_LOW, ADDR_HIGH(start)); - SELECT_GUS_REG(port, GUSREG_START_ADDR_LOW); - outw(port+GUS_DATA_LOW, ADDR_LOW(start)); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(start)); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(start)); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_HIGH); - outw(port+GUS_DATA_LOW, ADDR_HIGH(current)); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_LOW); - outw(port+GUS_DATA_LOW, ADDR_LOW(current)); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(current)); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(current)); - SELECT_GUS_REG(port, GUSREG_END_ADDR_HIGH); - outw(port+GUS_DATA_LOW, ADDR_HIGH(end)); - SELECT_GUS_REG(port, GUSREG_END_ADDR_LOW); - outw(port+GUS_DATA_LOW, ADDR_LOW(end)); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(end)); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(end)); /* * (maybe) enable interrupts, disable voice stopping @@ -2013,24 +2097,24 @@ gus_start_voice(sc, voice, intrs) * from 0 up to the set volume to help reduce clicks. */ - SELECT_GUS_REG(port, GUSREG_START_VOLUME); - outb(port+GUS_DATA_HIGH, 0x00); - SELECT_GUS_REG(port, GUSREG_END_VOLUME); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].current_volume >> 4); - SELECT_GUS_REG(port, GUSREG_CUR_VOLUME); - outw(port+GUS_DATA_LOW, 0x00); - SELECT_GUS_REG(port, GUSREG_VOLUME_RATE); - outb(port+GUS_DATA_HIGH, 63); - - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].current_volume >> 4); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 63); + + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); delay(50); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); } @@ -2044,7 +2128,8 @@ gus_stop_voice(sc, voice, intrs_too) int voice; int intrs_too; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_STOPPED | GUSMASK_STOP_VOICE; @@ -2055,24 +2140,24 @@ gus_stop_voice(sc, voice, intrs_too) } DMAPRINTF(("gusintr voice notplaying=%x\n", sc->sc_flags)); - guspoke(port, 0L, 0); + guspoke(iot, ioh2, 0L, 0); - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_CUR_VOLUME); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); delay(100); - SELECT_GUS_REG(port, GUSREG_CUR_VOLUME); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_HIGH); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_LOW); - outw(port+GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); } @@ -2085,59 +2170,66 @@ gus_set_volume(sc, voice, volume) struct gus_softc *sc; int voice, volume; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; unsigned int gusvol; gusvol = gus_log_volumes[volume < 512 ? volume : 511]; sc->sc_voc[voice].current_volume = gusvol; - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_START_VOLUME); - outb(port+GUS_DATA_HIGH, (unsigned char) (gusvol >> 4)); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4)); - SELECT_GUS_REG(port, GUSREG_END_VOLUME); - outb(port+GUS_DATA_HIGH, (unsigned char) (gusvol >> 4)); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4)); - SELECT_GUS_REG(port, GUSREG_CUR_VOLUME); - outw(port+GUS_DATA_LOW, gusvol << 4); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4); delay(500); - outw(port+GUS_DATA_LOW, gusvol << 4); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4); } /* - * Interface to the audio layer - set the data encoding type + * Interface to the audio layer. */ int -gusmax_set_format(addr, encoding, precision) - void * addr; - u_int encoding, precision; +gusmax_set_params(addr, setmode, usemode, p, r) + void *addr; + int setmode, usemode; + struct audio_params *p, *r; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; int error; - error = ad1848_set_format(ac, encoding, precision); - return (error ? error : gus_set_format(sc, encoding, precision)); + error = ad1848_set_params(ac, setmode, usemode, p, r); + if (error) + return error; + error = gus_set_params(sc, setmode, usemode, p, r); + return error; } int -gus_set_format(addr, encoding, precision) - void * addr; - u_int encoding, precision; +gus_set_params(addr, setmode, usemode, p, r) + void *addr; + int setmode, usemode; + struct audio_params *p, *r; { - register struct gus_softc *sc = addr; + struct gus_softc *sc = addr; int s; - DPRINTF(("gus_set_format called\n")); - - switch (encoding) { + switch (p->encoding) { case AUDIO_ENCODING_ULAW: - case AUDIO_ENCODING_PCM16: - case AUDIO_ENCODING_PCM8: + case AUDIO_ENCODING_ALAW: + case AUDIO_ENCODING_SLINEAR_LE: + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_ULINEAR_BE: break; default: return (EINVAL); @@ -2145,7 +2237,7 @@ gus_set_format(addr, encoding, precision) s = splaudio(); - if (precision == 8) { + if (p->precision == 8) { sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_DATA_SIZE16; sc->sc_voc[GUS_VOICE_RIGHT].voccntl &= ~GUSMASK_DATA_SIZE16; } else { @@ -2153,40 +2245,33 @@ gus_set_format(addr, encoding, precision) sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16; } - sc->sc_encoding = encoding; - sc->sc_precision = precision; + sc->sc_encoding = p->encoding; + sc->sc_precision = p->precision; + sc->sc_channels = p->channels; splx(s); - return 0; -} - -int -gusmax_set_channels(addr, channels) - void * addr; - int channels; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - int error; - - error = ad1848_set_channels(ac, channels); - return (error ? error : gus_set_channels(sc, channels)); -} - -int -gus_set_channels(addr, channels) - void * addr; - int channels; -{ - register struct gus_softc *sc = addr; + if (p->sample_rate > gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES]) + p->sample_rate = gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES]; + if (setmode & AUMODE_RECORD) + sc->sc_irate = p->sample_rate; + if (setmode & AUMODE_PLAY) + sc->sc_orate = p->sample_rate; - DPRINTF(("gus_set_channels called\n")); - - if (channels != 1 && channels != 2) - return EINVAL; - - sc->sc_channels = channels; + switch (p->encoding) { + case AUDIO_ENCODING_ULAW: + p->sw_code = mulaw_to_ulinear8; + r->sw_code = ulinear8_to_mulaw; + break; + case AUDIO_ENCODING_ALAW: + p->sw_code = alaw_to_ulinear8; + r->sw_code = ulinear8_to_alaw; + break; + case AUDIO_ENCODING_ULINEAR_BE: + case AUDIO_ENCODING_SLINEAR_BE: + r->sw_code = p->sw_code = swap_bytes; + break; + } return 0; } @@ -2201,8 +2286,8 @@ gusmax_round_blocksize(addr, blocksize) void * addr; int blocksize; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; /* blocksize = ad1848_round_blocksize(ac, blocksize);*/ return gus_round_blocksize(sc, blocksize); @@ -2213,11 +2298,12 @@ gus_round_blocksize(addr, blocksize) void * addr; int blocksize; { - register struct gus_softc *sc = addr; + struct gus_softc *sc = addr; DPRINTF(("gus_round_blocksize called\n")); - if (sc->sc_encoding == AUDIO_ENCODING_ULAW && blocksize > 32768) + if ((sc->sc_encoding == AUDIO_ENCODING_ULAW || + sc->sc_encoding == AUDIO_ENCODING_ALAW) && blocksize > 32768) blocksize = 32768; else if (blocksize > 65536) blocksize = 65536; @@ -2243,164 +2329,28 @@ gus_round_blocksize(addr, blocksize) return blocksize; } -/* - * Interfaces to the audio layer - return values from the software config - * struct - */ - -int -gusmax_get_encoding(addr) - void * addr; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - return gus_get_encoding(sc); -} - -int -gus_get_encoding(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_get_encoding called\n")); - - /* XXX TODO: codec stuff */ - return sc->sc_encoding; -} - -int -gusmax_get_channels(addr) - void * addr; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - return gus_get_channels(sc); -} - -int -gus_get_channels(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_get_channels called\n")); - - return sc->sc_channels; -} - -u_long -gus_get_in_sr(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_get_in_sr called\n")); - return sc->sc_irate; -} - -u_long -gusmax_get_in_sr(addr) - void * addr; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - return gus_get_in_sr(sc); -} - -u_long -gusmax_get_out_sr(addr) - void * addr; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - return gus_get_out_sr(sc); -} - -u_long -gus_get_out_sr(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_get_out_sr called\n")); - return sc->sc_orate; -} - -int -gusmax_get_precision(addr) - void * addr; -{ - register struct ad1848_softc *sc = addr; - return gus_get_precision(sc->parent); -} - -int -gus_get_precision(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_get_precision called\n")); - - return sc->sc_precision; -} - int gus_get_out_gain(addr) caddr_t addr; { - register struct gus_softc *sc = (struct gus_softc *) addr; + struct gus_softc *sc = (struct gus_softc *) addr; DPRINTF(("gus_get_out_gain called\n")); return sc->sc_ogain / 2; } -/* - * Interface to the audio layer - set the sample rate of the output voices - */ - -int -gusmax_set_out_sr(addr, rate) - void * addr; - u_long rate; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - int error; - - error = ad1848_set_out_sr(ac, rate); - return (error ? error : gus_set_out_sr(sc, rate)); -} - -int -gus_set_out_sr(addr, rate) - void * addr; - u_long rate; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_set_out_sr called\n")); - - if (rate > gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES]) - rate = gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES]; - - sc->sc_orate = rate; - - return 0; -} - STATIC inline void gus_set_voices(sc, voices) struct gus_softc *sc; int voices; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; /* * Select the active number of voices */ - SELECT_GUS_REG(port, GUSREG_ACTIVE_VOICES); - outb(port+GUS_DATA_HIGH, (voices-1) | 0xc0); + SELECT_GUS_REG(iot, ioh2, GUSREG_ACTIVE_VOICES); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (voices-1) | 0xc0); sc->sc_voices = voices; } @@ -2413,10 +2363,13 @@ int gusmax_commit_settings(addr) void * addr; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; + int error; - (void) ad1848_commit_settings(ac); + error = ad1848_commit_settings(ac); + if (error) + return error; return gus_commit_settings(sc); } @@ -2427,7 +2380,7 @@ int gus_commit_settings(addr) void * addr; { - register struct gus_softc *sc = addr; + struct gus_softc *sc = addr; int s; DPRINTF(("gus_commit_settings called (gain = %d)\n",sc->sc_ogain)); @@ -2489,7 +2442,8 @@ gus_set_samprate(sc, voice, freq) struct gus_softc *sc; int voice, freq; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; unsigned int fc; u_long temp, f = (u_long) freq; @@ -2509,46 +2463,15 @@ gus_set_samprate(sc, voice, freq) * Program the voice frequency, and set it in the voice data record */ - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_FREQ_CONTROL); - outw(port+GUS_DATA_LOW, fc); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); + SELECT_GUS_REG(iot, ioh2, GUSREG_FREQ_CONTROL); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, fc); sc->sc_voc[voice].rate = freq; } /* - * Interface to the audio layer - set the recording sampling rate - */ - -int -gusmax_set_in_sr(addr, rate) - void * addr; - u_long rate; -{ - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; - int error; - - error = ad1848_set_in_sr(ac, rate); - return (error ? error : gus_set_in_sr(sc, rate)); -} - - -int -gus_set_in_sr(addr, rate) - void *addr; - u_long rate; -{ - register struct gus_softc *sc = addr; - - DPRINTF(("gus_set_in_sr called\n")); - - sc->sc_irate = rate; - - return 0; -} -/* * Set the sample rate of the recording frequency. Formula is from the GUS * SDK. Called at splgus(). */ @@ -2558,7 +2481,8 @@ gus_set_recrate(sc, rate) struct gus_softc *sc; u_long rate; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; u_char realrate; DPRINTF(("gus_set_recrate %lu\n", rate)); @@ -2567,8 +2491,8 @@ gus_set_recrate(sc, rate) #endif realrate = (9878400 >> 4)/rate - 2; /* formula from code, sigh. */ - SELECT_GUS_REG(port, GUSREG_SAMPLE_FREQ); - outb(port+GUS_DATA_HIGH, realrate); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_FREQ); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, realrate); } /* @@ -2581,7 +2505,7 @@ gusmax_speaker_ctl(addr, newstate) void * addr; int newstate; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; return gus_speaker_ctl(sc->parent, newstate); } @@ -2590,18 +2514,20 @@ gus_speaker_ctl(addr, newstate) void * addr; int newstate; { - register struct gus_softc *sc = (struct gus_softc *) addr; + struct gus_softc *sc = (struct gus_softc *) addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; /* Line out bit is flipped: 0 enables, 1 disables */ if ((newstate == SPKR_ON) && (sc->sc_mixcontrol & GUSMASK_LINE_OUT)) { sc->sc_mixcontrol &= ~GUSMASK_LINE_OUT; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } if ((newstate == SPKR_OFF) && (sc->sc_mixcontrol & GUSMASK_LINE_OUT) == 0) { sc->sc_mixcontrol |= GUSMASK_LINE_OUT; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } return 0; @@ -2612,18 +2538,20 @@ gus_linein_ctl(addr, newstate) void * addr; int newstate; { - register struct gus_softc *sc = (struct gus_softc *) addr; + struct gus_softc *sc = (struct gus_softc *) addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; /* Line in bit is flipped: 0 enables, 1 disables */ if ((newstate == SPKR_ON) && (sc->sc_mixcontrol & GUSMASK_LINE_IN)) { sc->sc_mixcontrol &= ~GUSMASK_LINE_IN; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } if ((newstate == SPKR_OFF) && (sc->sc_mixcontrol & GUSMASK_LINE_IN) == 0) { sc->sc_mixcontrol |= GUSMASK_LINE_IN; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } return 0; @@ -2634,18 +2562,20 @@ gus_mic_ctl(addr, newstate) void * addr; int newstate; { - register struct gus_softc *sc = (struct gus_softc *) addr; + struct gus_softc *sc = (struct gus_softc *) addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; /* Mic bit is normal: 1 enables, 0 disables */ if ((newstate == SPKR_ON) && (sc->sc_mixcontrol & GUSMASK_MIC_IN) == 0) { sc->sc_mixcontrol |= GUSMASK_MIC_IN; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } if ((newstate == SPKR_OFF) && (sc->sc_mixcontrol & GUSMASK_MIC_IN)) { sc->sc_mixcontrol &= ~GUSMASK_MIC_IN; - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); } return 0; @@ -2661,17 +2591,18 @@ gus_set_endaddr(sc, voice, addr) int voice; u_long addr; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; sc->sc_voc[voice].end_addr = addr; if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) addr = convert_to_16bit(addr); - SELECT_GUS_REG(port, GUSREG_END_ADDR_HIGH); - outw(port+GUS_DATA_LOW, ADDR_HIGH(addr)); - SELECT_GUS_REG(port, GUSREG_END_ADDR_LOW); - outw(port+GUS_DATA_LOW, ADDR_LOW(addr)); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr)); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr)); } @@ -2685,19 +2616,20 @@ gus_set_curaddr(sc, voice, addr) int voice; u_long addr; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; sc->sc_voc[voice].current_addr = addr; if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) addr = convert_to_16bit(addr); - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_HIGH); - outw(port+GUS_DATA_LOW, ADDR_HIGH(addr)); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_LOW); - outw(port+GUS_DATA_LOW, ADDR_LOW(addr)); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr)); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr)); } @@ -2709,18 +2641,19 @@ gus_get_curaddr(sc, voice) struct gus_softc *sc; int voice; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; u_long addr; - outb(port+GUS_VOICE_SELECT, (unsigned char) voice); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_HIGH|GUSREG_READ); - addr = (inw(port+GUS_DATA_LOW) & 0x1fff) << 7; - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_LOW|GUSREG_READ); - addr |= (inw(port+GUS_DATA_LOW) >> 9L) & 0x7f; + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH|GUSREG_READ); + addr = (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) & 0x1fff) << 7; + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW|GUSREG_READ); + addr |= (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) >> 9L) & 0x7f; if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) addr = (addr & 0xc0000) | ((addr & 0x1ffff) << 1); /* undo 16-bit change */ - DPRINTF(("gus voice %d curaddr %d end_addr %d\n", + DPRINTF(("gus voice %d curaddr %ld end_addr %ld\n", voice, addr, sc->sc_voc[voice].end_addr)); /* XXX sanity check the address? */ @@ -2752,8 +2685,9 @@ convert_to_16bit(address) */ STATIC void -guspoke(port, address, value) - int port; +guspoke(iot, ioh2, address, value) + bus_space_tag_t iot; + bus_space_handle_t ioh2; long address; unsigned char value; { @@ -2762,16 +2696,16 @@ guspoke(port, address, value) * Select the DRAM address */ - SELECT_GUS_REG(port, GUSREG_DRAM_ADDR_LOW); - outw(port+GUS_DATA_LOW, (unsigned int) (address & 0xffff)); - SELECT_GUS_REG(port, GUSREG_DRAM_ADDR_HIGH); - outb(port+GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff)); + SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff)); + SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff)); /* * Actually write the data */ - outb(port+GUS_DRAM_DATA, value); + bus_space_write_1(iot, ioh2, GUS_DRAM_DATA, value); } /* @@ -2779,8 +2713,9 @@ guspoke(port, address, value) */ STATIC unsigned char -guspeek(port, address) - int port; +guspeek(iot, ioh2, address) + bus_space_tag_t iot; + bus_space_handle_t ioh2; u_long address; { @@ -2788,16 +2723,16 @@ guspeek(port, address) * Select the DRAM address */ - SELECT_GUS_REG(port, GUSREG_DRAM_ADDR_LOW); - outw(port+GUS_DATA_LOW, (unsigned int) (address & 0xffff)); - SELECT_GUS_REG(port, GUSREG_DRAM_ADDR_HIGH); - outb(port+GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff)); + SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff)); + SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff)); /* * Read in the data from the board */ - return (unsigned char) inb(port+GUS_DRAM_DATA); + return (unsigned char) bus_space_read_1(iot, ioh2, GUS_DRAM_DATA); } /* @@ -2809,7 +2744,10 @@ gusreset(sc, voices) struct gus_softc *sc; int voices; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; + bus_space_handle_t ioh2 = sc->sc_ioh2; + bus_space_handle_t ioh4 = sc->sc_ioh4; int i,s; s = splgus(); @@ -2818,8 +2756,8 @@ gusreset(sc, voices) * Reset the GF1 chip */ - SELECT_GUS_REG(port, GUSREG_RESET); - outb(port+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); delay(500); @@ -2827,8 +2765,8 @@ gusreset(sc, voices) * Release reset */ - SELECT_GUS_REG(port, GUSREG_RESET); - outb(port+GUS_DATA_HIGH, GUSMASK_MASTER_RESET); + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET); delay(500); @@ -2836,106 +2774,108 @@ gusreset(sc, voices) * Reset MIDI port as well */ - outb(GUS_MIDI_CONTROL,MIDI_RESET); + bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, MIDI_RESET); delay(500); - outb(GUS_MIDI_CONTROL,0x00); + bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, 0x00); /* * Clear interrupts */ - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - outb(port+GUS_DATA_HIGH, 0x00); - SELECT_GUS_REG(port, GUSREG_TIMER_CONTROL); - outb(port+GUS_DATA_HIGH, 0x00); - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - outb(port+GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_TIMER_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00); gus_set_voices(sc, voices); - inb(port+GUS_IRQ_STATUS); - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - inb(port+GUS_DATA_HIGH); - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - inb(port+GUS_DATA_HIGH); - SELECT_GUS_REG(port, GUSREG_IRQ_STATUS); - inb(port+GUS_DATA_HIGH); + bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); /* * Reset voice specific information */ for(i = 0; i < voices; i++) { - outb(port+GUS_VOICE_SELECT, (unsigned char) i); + bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) i); - SELECT_GUS_REG(port, GUSREG_VOICE_CNTL); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL); sc->sc_voc[i].voccntl = GUSMASK_VOICE_STOPPED | GUSMASK_STOP_VOICE; - outb(port+GUS_DATA_HIGH, sc->sc_voc[i].voccntl); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].voccntl); sc->sc_voc[i].volcntl = GUSMASK_VOLUME_STOPPED | GUSMASK_STOP_VOLUME; - SELECT_GUS_REG(port, GUSREG_VOLUME_CONTROL); - outb(port+GUS_DATA_HIGH, sc->sc_voc[i].volcntl); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].volcntl); delay(100); gus_set_samprate(sc, i, 8000); - SELECT_GUS_REG(port, GUSREG_START_ADDR_HIGH); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_START_ADDR_LOW); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_END_ADDR_HIGH); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_END_ADDR_LOW); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_VOLUME_RATE); - outb(port+GUS_DATA_HIGH, 0x01); - SELECT_GUS_REG(port, GUSREG_START_VOLUME); - outb(port+GUS_DATA_HIGH, 0x10); - SELECT_GUS_REG(port, GUSREG_END_VOLUME); - outb(port+GUS_DATA_HIGH, 0xe0); - SELECT_GUS_REG(port, GUSREG_CUR_VOLUME); - outw(port+GUS_DATA_LOW, 0x0000); - - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_HIGH); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_CUR_ADDR_LOW); - outw(port+GUS_DATA_LOW, 0x0000); - SELECT_GUS_REG(port, GUSREG_PAN_POS); - outb(port+GUS_DATA_HIGH, 0x07); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x01); + SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x10); + SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0xe0); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW); + bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000); + SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x07); } /* * Clear out any pending IRQs */ - inb(port+GUS_IRQ_STATUS); - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - inb(port+GUS_DATA_HIGH); - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - inb(port+GUS_DATA_HIGH); - SELECT_GUS_REG(port, GUSREG_IRQ_STATUS); - inb(port+GUS_DATA_HIGH); + bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); + SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS); + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH); - SELECT_GUS_REG(port, GUSREG_RESET); - outb(port+GUS_DATA_HIGH, GUSMASK_MASTER_RESET | GUSMASK_DAC_ENABLE | + SELECT_GUS_REG(iot, ioh2, GUSREG_RESET); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET | GUSMASK_DAC_ENABLE | GUSMASK_IRQ_ENABLE); splx(s); } -STATIC void +STATIC int gus_init_cs4231(sc) struct gus_softc *sc; { - register int port = sc->sc_iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh1 = sc->sc_ioh1; + int port = sc->sc_iobase; u_char ctrl; ctrl = (port & 0xf0) >> 4; /* set port address middle nibble */ @@ -2948,60 +2888,16 @@ gus_init_cs4231(sc) if (sc->sc_recdrq >= 4) ctrl |= GUS_MAX_PLAYCHAN16; - outb(port+GUS_MAX_CTRL, ctrl); + bus_space_write_1(iot, ioh1, GUS_MAX_CTRL, ctrl); + sc->sc_codec.sc_iot = sc->sc_iot; sc->sc_codec.sc_iobase = port+GUS_MAX_CODEC_BASE; if (ad1848_probe(&sc->sc_codec) == 0) { sc->sc_flags &= ~GUS_CODEC_INSTALLED; + return (0); } else { struct ad1848_volume vol = {AUDIO_MAX_GAIN, AUDIO_MAX_GAIN}; - struct audio_hw_if gusmax_hw_if = { - gusopen, - gusmax_close, - NULL, /* drain */ - gusmax_set_in_sr, - gusmax_get_in_sr, - gusmax_set_out_sr, - gusmax_get_out_sr, - - ad1848_query_encoding, /* query encoding */ - gusmax_set_format, - gusmax_get_encoding, - gusmax_get_precision, - - gusmax_set_channels, - gusmax_get_channels, - - gusmax_round_blocksize, - - gusmax_set_out_port, - gusmax_get_out_port, - gusmax_set_in_port, - gusmax_get_in_port, - - gusmax_commit_settings, - - gusmax_expand, /* XXX use codec */ - mulaw_compress, - - gusmax_dma_output, - gusmax_dma_input, - gusmax_halt_out_dma, - gusmax_halt_in_dma, - gusmax_cont_out_dma, - gusmax_cont_in_dma, - - gusmax_speaker_ctl, - - gus_getdev, - gus_setfd, - gusmax_mixer_set_port, - gusmax_mixer_get_port, - gusmax_mixer_query_devinfo, - 1, /* full-duplex */ - 0, - }; sc->sc_flags |= GUS_CODEC_INSTALLED; sc->sc_codec.parent = sc; sc->sc_codec.sc_drq = sc->sc_recdrq; @@ -3011,11 +2907,13 @@ gus_init_cs4231(sc) will do the real mixing for them. */ sc->sc_mixcontrol &= ~GUSMASK_LINE_IN; /* 0 enables. */ sc->sc_mixcontrol |= GUSMASK_MIC_IN; /* 1 enables. */ - outb(sc->sc_iobase+GUS_MIX_CONTROL, sc->sc_mixcontrol); + bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol); ad1848_attach(&sc->sc_codec); /* turn on pre-MUX microphone gain. */ ad1848_set_mic_gain(&sc->sc_codec, &vol); + + return (1); } } @@ -3056,128 +2954,6 @@ gus_get_in_gain(addr) } int -gusmax_set_out_port(addr, port) - void * addr; - int port; -{ - register struct ad1848_softc *sc = addr; - return gus_set_out_port(sc->parent, port); -} - -int -gus_set_out_port(addr, port) - void * addr; - int port; -{ - register struct gus_softc *sc = addr; - DPRINTF(("gus_set_out_port called\n")); - sc->sc_out_port = port; - - return 0; -} - -int -gusmax_get_out_port(addr) - void * addr; -{ - register struct ad1848_softc *sc = addr; - return gus_get_out_port(sc->parent); -} - -int -gus_get_out_port(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - DPRINTF(("gus_get_out_port() called\n")); - return sc->sc_out_port; -} - -int -gusmax_set_in_port(addr, port) - void * addr; - int port; -{ - register struct ad1848_softc *sc = addr; - DPRINTF(("gusmax_set_in_port: %d\n", port)); - - switch(port) { - case GUSMAX_MONO_LVL: - port = MIC_IN_PORT; - break; - case GUSMAX_LINE_IN_LVL: - port = LINE_IN_PORT; - break; - case GUSMAX_DAC_LVL: - port = AUX1_IN_PORT; - break; - case GUSMAX_MIX_IN: - port = DAC_IN_PORT; - break; - default: - return(EINVAL); - /*NOTREACHED*/ - } - return(ad1848_set_rec_port(sc, port)); -} - -int -gusmax_get_in_port(addr) - void * addr; -{ - register struct ad1848_softc *sc = addr; - int port = GUSMAX_MONO_LVL; - - switch(ad1848_get_rec_port(sc)) { - case MIC_IN_PORT: - port = GUSMAX_MONO_LVL; - break; - case LINE_IN_PORT: - port = GUSMAX_LINE_IN_LVL; - break; - case DAC_IN_PORT: - port = GUSMAX_MIX_IN; - break; - case AUX1_IN_PORT: - port = GUSMAX_DAC_LVL; - break; - } - - DPRINTF(("gusmax_get_in_port: %d\n", port)); - - return(port); -} - -int -gus_set_in_port(addr, port) - void * addr; - int port; -{ - register struct gus_softc *sc = addr; - DPRINTF(("gus_set_in_port called\n")); - /* - * On the GUS with ICS mixer, the ADC input is after the mixer stage, - * so we can't set the input port. - * - * On the GUS with CS4231 codec/mixer, see gusmax_set_in_port(). - */ - sc->sc_in_port = port; - - return 0; -} - - -int -gus_get_in_port(addr) - void * addr; -{ - register struct gus_softc *sc = addr; - DPRINTF(("gus_get_in_port called\n")); - return sc->sc_in_port; -} - - -int gusmax_dma_input(addr, buf, size, callback, arg) void * addr; void *buf; @@ -3185,7 +2961,7 @@ gusmax_dma_input(addr, buf, size, callback, arg) void (*callback) __P((void *)); void *arg; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; return gus_dma_input(sc->parent, buf, size, callback, arg); } @@ -3201,9 +2977,10 @@ gus_dma_input(addr, buf, size, callback, arg) void (*callback) __P((void *)); void *arg; { - register struct gus_softc *sc = addr; - register int port = sc->sc_iobase; - register u_char dmac; + struct gus_softc *sc = addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; + u_char dmac; DMAPRINTF(("gus_dma_input called\n")); /* @@ -3218,11 +2995,14 @@ gus_dma_input(addr, buf, size, callback, arg) if (sc->sc_recdrq >= 4) dmac |= GUSMASK_SAMPLE_DATA16; if (sc->sc_encoding == AUDIO_ENCODING_ULAW || - sc->sc_encoding == AUDIO_ENCODING_PCM8) + sc->sc_encoding == AUDIO_ENCODING_ALAW || + sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE || + sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE) dmac |= GUSMASK_SAMPLE_INVBIT; if (sc->sc_channels == 2) dmac |= GUSMASK_SAMPLE_STEREO; - isadma_start((caddr_t)buf, size, sc->sc_recdrq, DMAMODE_READ); + isa_dmastart(sc->sc_dev.dv_parent, sc->sc_recdrq, buf, size, + NULL, DMAMODE_READ, BUS_DMA_NOWAIT); DMAPRINTF(("gus_dma_input isadma_started\n")); sc->sc_flags |= GUS_DMAIN_ACTIVE; @@ -3231,8 +3011,8 @@ gus_dma_input(addr, buf, size, callback, arg) sc->sc_dmaincnt = size; sc->sc_dmainaddr = buf; - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - outb(port+GUS_DATA_HIGH, dmac); /* Go! */ + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, dmac); /* Go! */ DMAPRINTF(("gus_dma_input returning\n")); @@ -3249,7 +3029,7 @@ gus_dmain_intr(sc) DMAPRINTF(("gus_dmain_intr called\n")); if (sc->sc_dmainintr) { - isadma_done(sc->sc_recdrq); + isa_dmadone(sc->sc_dev.dv_parent, sc->sc_recdrq); callback = sc->sc_dmainintr; arg = sc->sc_inarg; @@ -3259,7 +3039,7 @@ gus_dmain_intr(sc) sc->sc_inarg = 0; sc->sc_flags &= ~GUS_DMAIN_ACTIVE; - DMAPRINTF(("calling dmain_intr callback %x(%x)\n", callback, arg)); + DMAPRINTF(("calling dmain_intr callback %p(%p)\n", callback, arg)); (*callback)(arg); return 1; } else { @@ -3272,7 +3052,7 @@ int gusmax_halt_out_dma(addr) void * addr; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; return gus_halt_out_dma(sc->parent); } @@ -3281,26 +3061,10 @@ int gusmax_halt_in_dma(addr) void * addr; { - register struct ad1848_softc *sc = addr; + struct ad1848_softc *sc = addr; return gus_halt_in_dma(sc->parent); } -int -gusmax_cont_out_dma(addr) - void * addr; -{ - register struct ad1848_softc *sc = addr; - return gus_cont_out_dma(sc->parent); -} - -int -gusmax_cont_in_dma(addr) - void * addr; -{ - register struct ad1848_softc *sc = addr; - return gus_cont_in_dma(sc->parent); -} - /* * Stop any DMA output. Called at splgus(). */ @@ -3308,19 +3072,20 @@ int gus_halt_out_dma(addr) void * addr; { - register struct gus_softc *sc = addr; - register int port = sc->sc_iobase; + struct gus_softc *sc = addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; DMAPRINTF(("gus_halt_out_dma called\n")); /* * Make sure the GUS _isn't_ setup for DMA */ - SELECT_GUS_REG(port, GUSREG_DMA_CONTROL); - outb(sc->sc_iobase+GUS_DATA_HIGH, 0); + SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0); untimeout(gus_dmaout_timeout, sc); - isadma_abort(sc->sc_drq); + isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq); sc->sc_flags &= ~(GUS_DMAOUT_ACTIVE|GUS_LOCKED); sc->sc_dmaoutintr = 0; sc->sc_outarg = 0; @@ -3343,20 +3108,20 @@ int gus_halt_in_dma(addr) void * addr; { - register struct gus_softc *sc = addr; - register int port = sc->sc_iobase; + struct gus_softc *sc = addr; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh2 = sc->sc_ioh2; DMAPRINTF(("gus_halt_in_dma called\n")); /* * Make sure the GUS _isn't_ setup for DMA */ - SELECT_GUS_REG(port, GUSREG_SAMPLE_CONTROL); - outb(port+GUS_DATA_HIGH, - inb(port+GUS_DATA_HIGH) & - ~(GUSMASK_SAMPLE_START|GUSMASK_SAMPLE_IRQ)); - - isadma_abort(sc->sc_recdrq); + SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL); + bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, + bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & ~(GUSMASK_SAMPLE_START|GUSMASK_SAMPLE_IRQ)); + + isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_recdrq); sc->sc_flags &= ~GUS_DMAIN_ACTIVE; sc->sc_dmainintr = 0; sc->sc_inarg = 0; @@ -3366,34 +3131,6 @@ gus_halt_in_dma(addr) return 0; } -int -gus_cont_out_dma(addr) - void * addr; -{ - DPRINTF(("gus_cont_out_dma called\n")); - return EOPNOTSUPP; -} - -int -gus_cont_in_dma(addr) - void * addr; -{ - DPRINTF(("gus_cont_in_dma called\n")); - return EOPNOTSUPP; -} - - -STATIC int -gus_setfd(addr, flag) - void *addr; - int flag; -{ - if (gus_hw_if.full_duplex == 0) - return ENOTTY; - - return(0); /* nothing fancy to do. */ -} - STATIC __inline int gus_to_vol(cp, vol) mixer_ctrl_t *cp; @@ -3433,8 +3170,8 @@ gusmax_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -3584,8 +3321,8 @@ gus_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct gus_softc *sc = addr; - register struct ics2101_softc *ic = &sc->sc_mixer; + struct gus_softc *sc = addr; + struct ics2101_softc *ic = &sc->sc_mixer; struct ad1848_volume vol; int error = EINVAL; @@ -3754,8 +3491,8 @@ gusmax_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct gus_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct gus_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -3907,8 +3644,8 @@ gus_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct gus_softc *sc = addr; - register struct ics2101_softc *ic = &sc->sc_mixer; + struct gus_softc *sc = addr; + struct ics2101_softc *ic = &sc->sc_mixer; struct ad1848_volume vol; int error = EINVAL; @@ -4063,21 +3800,29 @@ gus_mixer_set_port(addr, cp) } STATIC int +gus_get_props(addr) + void *addr; +{ + struct gus_softc *sc = addr; + return sc->sc_recdrq == sc->sc_drq ? 0 : AUDIO_PROP_FULLDUPLEX; +} + +STATIC int +gusmax_get_props(addr) + void *addr; +{ + struct ad1848_softc *ac = addr; + return gus_get_props(ac->parent); +} + +STATIC int gusmax_mixer_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index)); switch(dip->index) { - case GUSMAX_MIX_IN: /* mixed MUX input */ - dip->type = AUDIO_MIXER_ENUM; - dip->mixer_class = GUSMAX_INPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNmixerout); - dip->un.e.num_mem = 0; /* XXX */ - break; - #if 0 case GUSMAX_MIC_IN_LVL: /* Microphone */ dip->type = AUDIO_MIXER_VALUE; @@ -4155,7 +3900,7 @@ gusmax_mixer_query_devinfo(addr, dip) dip->mixer_class = GUSMAX_MONITOR_CLASS; dip->prev = AUDIO_MIXER_LAST; dip->next = GUSMAX_SPEAKER_MUTE; - strcpy(dip->label.name, AudioNspeaker); + strcpy(dip->label.name, AudioNmaster); dip->un.v.num_channels = 2; strcpy(dip->un.v.units.name, AudioNvolume); break; @@ -4227,41 +3972,41 @@ gusmax_mixer_query_devinfo(addr, dip) strcpy(dip->label.name, AudioNsource); dip->un.e.num_mem = 4; strcpy(dip->un.e.member[0].label.name, AudioNoutput); - dip->un.e.member[0].ord = GUSMAX_MIX_IN; + dip->un.e.member[0].ord = DAC_IN_PORT; strcpy(dip->un.e.member[1].label.name, AudioNmicrophone); - dip->un.e.member[1].ord = GUSMAX_MONO_LVL; + dip->un.e.member[1].ord = MIC_IN_PORT; strcpy(dip->un.e.member[2].label.name, AudioNdac); - dip->un.e.member[2].ord = GUSMAX_DAC_LVL; + dip->un.e.member[2].ord = AUX1_IN_PORT; strcpy(dip->un.e.member[3].label.name, AudioNline); - dip->un.e.member[3].ord = GUSMAX_LINE_IN_LVL; + dip->un.e.member[3].ord = LINE_IN_PORT; break; case GUSMAX_INPUT_CLASS: /* input class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSMAX_INPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + strcpy(dip->label.name, AudioCinputs); break; case GUSMAX_OUTPUT_CLASS: /* output class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSMAX_OUTPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCOutputs); + strcpy(dip->label.name, AudioCoutputs); break; case GUSMAX_MONITOR_CLASS: /* monitor class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSMAX_MONITOR_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCMonitor); + strcpy(dip->label.name, AudioCmonitor); break; case GUSMAX_RECORD_CLASS: /* record source class */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSMAX_RECORD_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCRecord); + strcpy(dip->label.name, AudioCrecord); break; default: @@ -4275,9 +4020,9 @@ gusmax_mixer_query_devinfo(addr, dip) STATIC int gus_mixer_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { - register struct gus_softc *sc = addr; + struct gus_softc *sc = addr; DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index)); @@ -4331,7 +4076,7 @@ gus_mixer_query_devinfo(addr, dip) dip->mixer_class = GUSICS_OUTPUT_CLASS; dip->prev = AUDIO_MIXER_LAST; dip->next = GUSICS_MASTER_MUTE; - strcpy(dip->label.name, AudioNvolume); + strcpy(dip->label.name, AudioNmaster); dip->un.v.num_channels = 2; strcpy(dip->un.v.units.name, AudioNvolume); break; @@ -4393,21 +4138,21 @@ mute: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSICS_INPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + strcpy(dip->label.name, AudioCinputs); break; case GUSICS_OUTPUT_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSICS_OUTPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCOutputs); + strcpy(dip->label.name, AudioCoutputs); break; case GUSICS_RECORD_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = GUSICS_RECORD_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCRecord); + strcpy(dip->label.name, AudioCrecord); break; default: @@ -4426,16 +4171,53 @@ gus_query_encoding(addr, fp) switch (fp->index) { case 0: strcpy(fp->name, AudioEmulaw); - fp->format_id = AUDIO_ENCODING_ULAW; + fp->encoding = AUDIO_ENCODING_ULAW; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; break; case 1: - strcpy(fp->name, AudioEpcm16); - fp->format_id = AUDIO_ENCODING_PCM16; + strcpy(fp->name, AudioEslinear); + fp->encoding = AUDIO_ENCODING_SLINEAR; + fp->precision = 8; + fp->flags = 0; break; case 2: - strcpy(fp->name, AudioEpcm8); - fp->format_id = AUDIO_ENCODING_PCM8; + strcpy(fp->name, AudioEslinear_le); + fp->encoding = AUDIO_ENCODING_SLINEAR_LE; + fp->precision = 16; + fp->flags = 0; break; + case 3: + strcpy(fp->name, AudioEulinear); + fp->encoding = AUDIO_ENCODING_ULINEAR; + fp->precision = 8; + fp->flags = 0; + break; + case 4: + strcpy(fp->name, AudioEulinear_le); + fp->encoding = AUDIO_ENCODING_ULINEAR_LE; + fp->precision = 16; + fp->flags = 0; + break; + case 5: + strcpy(fp->name, AudioEslinear_be); + fp->encoding = AUDIO_ENCODING_SLINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 6: + strcpy(fp->name, AudioEulinear_be); + fp->encoding = AUDIO_ENCODING_ULINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + case 7: + strcpy(fp->name, AudioEalaw); + fp->encoding = AUDIO_ENCODING_ALAW; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + break; + default: return(EINVAL); /*NOTREACHED*/ @@ -4452,10 +4234,12 @@ STATIC void gus_init_ics2101(sc) struct gus_softc *sc; { - register int port = sc->sc_iobase; - register struct ics2101_softc *ic = &sc->sc_mixer; - sc->sc_mixer.sc_selio = port+GUS_MIXER_SELECT; - sc->sc_mixer.sc_dataio = port+GUS_MIXER_DATA; + struct ics2101_softc *ic = &sc->sc_mixer; + sc->sc_mixer.sc_iot = sc->sc_iot; + sc->sc_mixer.sc_selio = GUS_MIXER_SELECT; + sc->sc_mixer.sc_selio_ioh = sc->sc_ioh3; + sc->sc_mixer.sc_dataio = GUS_MIXER_DATA; + sc->sc_mixer.sc_dataio_ioh = sc->sc_ioh2; sc->sc_mixer.sc_flags = (sc->sc_revision == 5) ? ICS_FLIP : 0; ics2101_mix_attenuate(ic, diff --git a/sys/dev/isa/gusreg.h b/sys/dev/isa/gusreg.h index 88f55d1cf81..b1b86a42e87 100644 --- a/sys/dev/isa/gusreg.h +++ b/sys/dev/isa/gusreg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: gusreg.h,v 1.3 1997/07/10 23:06:35 provos Exp $ */ -/* $NetBSD: gusreg.h,v 1.3 1996/02/05 02:22:10 jtc Exp $ */ +/* $OpenBSD: gusreg.h,v 1.4 1998/04/26 21:02:43 provos Exp $ */ +/* $NetBSD: gusreg.h,v 1.6 1997/10/09 07:57:22 jtc Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -27,8 +27,8 @@ * 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 REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * 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 @@ -47,10 +47,13 @@ * address. */ -#define GUS_MIDI_CONTROL 0x100 -#define GUS_MIDI_STATUS 0x100 -#define GUS_MIDI_READ 0x101 -#define GUS_MIDI_WRITE 0x101 +#define GUS_IOH4_OFFSET 0x100 +#define GUS_NPORT4 2 + +#define GUS_MIDI_CONTROL (0x100-GUS_IOH4_OFFSET) +#define GUS_MIDI_STATUS (0x100-GUS_IOH4_OFFSET) +#define GUS_MIDI_READ (0x101-GUS_IOH4_OFFSET) +#define GUS_MIDI_WRITE (0x101-GUS_IOH4_OFFSET) /* * Joystick interface - note this is an absolute address, NOT an offset from @@ -79,11 +82,18 @@ #define GUS_DMA_CONTROL 0x00b #define GUS_IRQCTL_CONTROL 0x00b #define GUS_JUMPER_CONTROL 0x00b -#define GUS_VOICE_SELECT 0x102 -#define GUS_REG_SELECT 0x103 -#define GUS_DATA_LOW 0x104 -#define GUS_DATA_HIGH 0x105 -#define GUS_DRAM_DATA 0x107 + +#define GUS_NPORT1 16 + +#define GUS_IOH2_OFFSET 0x102 +#define GUS_VOICE_SELECT (0x102-GUS_IOH2_OFFSET) +#define GUS_REG_SELECT (0x103-GUS_IOH2_OFFSET) +#define GUS_DATA_LOW (0x104-GUS_IOH2_OFFSET) +#define GUS_DATA_HIGH (0x105-GUS_IOH2_OFFSET) +/* GUS_MIXER_SELECT 106 */ +#define GUS_DRAM_DATA (0x107-GUS_IOH2_OFFSET) + +#define GUS_NPORT2 6 /* * GUS on-board global registers @@ -229,9 +239,12 @@ * ICS Mixer registers */ -#define GUS_MIXER_SELECT 0x506 /* read=board rev, wr=mixer */ -#define GUS_BOARD_REV 0x506 -#define GUS_MIXER_DATA 0x106 /* data for mixer control */ +#define GUS_IOH3_OFFSET 0x506 +#define GUS_NPORT3 1 + +#define GUS_MIXER_SELECT (0x506-GUS_IOH3_OFFSET) /* read=board rev, wr=mixer */ +#define GUS_BOARD_REV (0x506-GUS_IOH3_OFFSET) +#define GUS_MIXER_DATA (0x106-GUS_IOH2_OFFSET) /* data for mixer control */ #define GUSMIX_CHAN_MIC ICSMIX_CHAN_0 #define GUSMIX_CHAN_LINE ICSMIX_CHAN_1 diff --git a/sys/dev/isa/ics2101.c b/sys/dev/isa/ics2101.c index 458d1424ffd..88049e3e56d 100644 --- a/sys/dev/isa/ics2101.c +++ b/sys/dev/isa/ics2101.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ics2101.c,v 1.3 1996/05/07 07:36:42 deraadt Exp $ */ -/* $NetBSD: ics2101.c,v 1.4 1996/04/29 20:03:10 christos Exp $ */ +/* $OpenBSD: ics2101.c,v 1.4 1998/04/26 21:02:44 provos Exp $ */ +/* $NetBSD: ics2101.c,v 1.6 1997/10/09 07:57:23 jtc Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -27,8 +27,8 @@ * 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 REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * 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 @@ -80,6 +80,7 @@ ics2101_mix_doit(sc, chan, side, value, flags) struct ics2101_softc *sc; u_int chan, side, value, flags; { + bus_space_tag_t iot = sc->sc_iot; unsigned char flip_left[6] = {0x01, 0x01, 0x01, 0x02, 0x01, 0x02}; unsigned char flip_right[6] = {0x02, 0x02, 0x02, 0x01, 0x02, 0x01}; register unsigned char ctrl_addr; @@ -128,11 +129,11 @@ ics2101_mix_doit(sc, chan, side, value, flags) s = splaudio(); - outb(sc->sc_selio, ctrl_addr); - outb(sc->sc_dataio, normal); + bus_space_write_1(iot, sc->sc_selio_ioh, sc->sc_selio, ctrl_addr); + bus_space_write_1(iot, sc->sc_dataio_ioh, sc->sc_dataio, normal); - outb(sc->sc_selio, attn_addr); - outb(sc->sc_dataio, (unsigned char) value); + bus_space_write_1(iot, sc->sc_selio_ioh, sc->sc_selio, attn_addr); + bus_space_write_1(iot, sc->sc_dataio_ioh, sc->sc_dataio, (unsigned char) value); splx(s); } diff --git a/sys/dev/isa/ics2101var.h b/sys/dev/isa/ics2101var.h index b9a61a63758..26d88f71717 100644 --- a/sys/dev/isa/ics2101var.h +++ b/sys/dev/isa/ics2101var.h @@ -1,5 +1,5 @@ -/* $OpenBSD: ics2101var.h,v 1.2 1996/03/08 16:42:58 niklas Exp $ */ -/* $NetBSD: ics2101var.h,v 1.3 1996/02/05 02:22:12 jtc Exp $ */ +/* $OpenBSD: ics2101var.h,v 1.3 1998/04/26 21:02:45 provos Exp $ */ +/* $NetBSD: ics2101var.h,v 1.5 1997/10/09 07:57:24 jtc Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -27,8 +27,8 @@ * 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 REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * 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 @@ -41,6 +41,9 @@ #define ICSMIX_RIGHT 1 /* Value for right channel */ struct ics2101_softc { + bus_space_tag_t sc_iot; /* tag */ + bus_space_handle_t sc_selio_ioh; + bus_space_handle_t sc_dataio_ioh; u_short sc_selio; /* select I/O address */ u_short sc_dataio; /* data I/O address */ int sc_flags; /* Various flags */ diff --git a/sys/dev/isa/isa.c b/sys/dev/isa/isa.c index 3010e861fdd..39366021b0e 100644 --- a/sys/dev/isa/isa.c +++ b/sys/dev/isa/isa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: isa.c,v 1.31 1998/01/20 21:42:25 niklas Exp $ */ +/* $OpenBSD: isa.c,v 1.32 1998/04/26 21:02:47 provos Exp $ */ /* $NetBSD: isa.c,v 1.85 1996/05/14 00:31:04 thorpej Exp $ */ /* @@ -173,6 +173,8 @@ isaprint(aux, isa) printf(" irq %d", ia->ia_irq); if (ia->ia_drq != DRQUNK) printf(" drq %d", ia->ia_drq); + if (ia->ia_drq2 != DRQUNK) + printf(" drq2 %d", ia->ia_drq2); return (UNCONF); } @@ -192,12 +194,13 @@ isascan(parent, match) ia.ia_dmat = sc->sc_dmat; #endif /* NISADMA > 0 */ ia.ia_ic = sc->sc_ic; - ia.ia_iobase = cf->cf_loc[0]; + ia.ia_iobase = cf->cf_iobase; ia.ia_iosize = 0x666; - ia.ia_maddr = cf->cf_loc[2]; - ia.ia_msize = cf->cf_loc[3]; - ia.ia_irq = cf->cf_loc[4] == 2 ? 9 : cf->cf_loc[4]; - ia.ia_drq = cf->cf_loc[5]; + ia.ia_maddr = cf->cf_maddr; + ia.ia_msize = cf->cf_msize; + ia.ia_irq = cf->cf_irq == 2 ? 9 : cf->cf_irq; + ia.ia_drq = cf->cf_drq; + ia.ia_drq2 = cf->cf_drq2; ia.ia_delaybah = sc->sc_delaybah; if (cf->cf_fstate == FSTATE_STAR) { @@ -223,6 +226,8 @@ isascan(parent, match) #if NISADMA > 0 if (ia.ia_drq != DRQUNK) ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq); + if (ia.ia_drq2 != DRQUNK) + ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq2); #endif /* NISAMDA > 0 */ } if (autoconf_verbose) @@ -244,6 +249,8 @@ isascan(parent, match) #if NISADMA > 0 if (ia.ia_drq != DRQUNK) ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq); + if (ia.ia_drq2 != DRQUNK) + ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq2); #endif /* NISAMDA > 0 */ } else { if (autoconf_verbose) diff --git a/sys/dev/isa/isavar.h b/sys/dev/isa/isavar.h index a6ef11c2547..3cbfd104aa4 100644 --- a/sys/dev/isa/isavar.h +++ b/sys/dev/isa/isavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: isavar.h,v 1.27 1998/01/20 18:40:33 niklas Exp $ */ +/* $OpenBSD: isavar.h,v 1.28 1998/04/26 21:02:48 provos Exp $ */ /* $NetBSD: isavar.h,v 1.26 1997/06/06 23:43:57 thorpej Exp $ */ /*- @@ -289,6 +289,7 @@ struct isa_attach_args { #define ia_iosize ipa_io[0].length #define ia_irq ipa_irq[0].num #define ia_drq ipa_drq[0].num +#define ia_drq2 ipa_drq[1].num #define ia_maddr ipa_mem[0].base #define ia_msize ipa_mem[0].length #define ia_ioh ipa_io[0].h @@ -372,6 +373,7 @@ struct isa_softc { #define cf_msize cf_loc[3] #define cf_irq cf_loc[4] #define cf_drq cf_loc[5] +#define cf_drq2 cf_loc[6] /* * ISA interrupt handler manipulation. diff --git a/sys/dev/isa/madreg.h b/sys/dev/isa/madreg.h new file mode 100644 index 00000000000..5e6e114aaec --- /dev/null +++ b/sys/dev/isa/madreg.h @@ -0,0 +1,102 @@ +/* $OpenBSD: madreg.h,v 1.1 1998/04/26 21:02:37 provos Exp $ */ +/* $NetBSD: madreg.h,v 1.4 1998/01/19 22:18:27 augustss Exp $ */ +/* + * Copyright (c) 1996 Lennart Augustsson + * Copyright (c) 1995 Hannu Savolainen + * Copyright (c) 1991-1993 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* + * Variations of the suppored chips. + */ + +#define MAD_NONE 0 +#define MAD_82C928 1 /* OPTi 82C928 MAD16 */ +#define MAD_OTI601D 2 /* OAK OTI-601D Mozart */ +#define MAD_82C929 3 /* OPTi 82C929 MAD16 Pro */ +#define MAD_82C931 4 /* OPTi 82C831 */ + +/* + * Registers + * + * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). + * All ports are inactive by default. They can be activated by + * writing 0xE2 or 0xE3 to the password register. The password is valid + * only until the next I/O read or write. + */ + +#define MAD_BASE 0xf8d +#define MAD_NPORT 7 + +#define MC1_PORT 0 /* SB address, CDROM interface type, joystick */ +#define MC2_PORT 1 /* CDROM address, IRQ, DMA, plus OPL4 bit */ +#define MC3_PORT 2 +#define MC_PASSWD_REG MC3_PORT +#define MC4_PORT 3 +#define MC5_PORT 4 +#define MC6_PORT 5 +#define MC7_PORT 6 + +#define MC1_NOCD 0x00 +#define MC1_JOYDISABLE 0x01 +#define MC1_SONY 0x02 +#define MC1_MITSUMI 0x04 +#define MC1_PANASONIC 0x06 +#define MC1_SECIDE 0x08 +#define MC1_PRIMIDE 0x0a + +#define MC2_CDDISABLE 0x03 +#define MC2_OPL4 0x20 + +/* Possible WSS emulation ports */ +#define M_WSS_PORT0 0x530 +#define M_WSS_PORT1 0xe80 +#define M_WSS_PORT2 0xf40 +#define M_WSS_PORT3 0x604 +#define M_WSS_NPORTS 4 + +/* Port 1 */ +#define M_WSS_PORT_SELECT(i) (0x80 | ((i) << 4)) + +#define M_PASSWD_928 0xe2 +#define M_PASSWD_929 0xe3 +#define M_PASSWD_931 0xe4 + +/* Regions of I/O space that the MAD occupies besides + WSS emulation and MAD_BASE. Talk about waste. */ +#define MAD_REG1 0x220 +#define MAD_LEN1 16 +#define MAD_REG2 0x380 +#define MAD_LEN2 2 +#define MAD_REG3 0x388 +#define MAD_LEN3 4 diff --git a/sys/dev/isa/mcd.c b/sys/dev/isa/mcd.c index 107599f8965..602aee9a684 100644 --- a/sys/dev/isa/mcd.c +++ b/sys/dev/isa/mcd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: mcd.c,v 1.23 1997/11/30 22:33:21 mickey Exp $ */ -/* $NetBSD: mcd.c,v 1.49 1996/05/12 23:53:11 mycroft Exp $ */ +/* $OpenBSD: mcd.c,v 1.24 1998/04/26 21:02:49 provos Exp $ */ +/* $NetBSD: mcd.c,v 1.60 1998/01/14 12:14:41 drochner Exp $ */ /* * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. @@ -75,7 +75,7 @@ #include <machine/cpu.h> #include <machine/intr.h> -#include <machine/pio.h> +#include <machine/bus.h> #include <dev/isa/isavar.h> #include <dev/isa/mcdreg.h> @@ -118,12 +118,12 @@ struct mcd_softc { struct disk sc_dk; void *sc_ih; - int iobase; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + int irq, drq; char *type; - u_char readcmd; - u_char attached; int flags; #define MCDF_LOCKED 0x01 #define MCDF_WANTED 0x02 @@ -143,8 +143,10 @@ struct mcd_softc { #define MCD_MD_UNKNOWN -1 int lastupc; #define MCD_UPC_UNKNOWN -1 - int debug; struct buf buf_queue; + u_char readcmd; + u_char debug; + u_char probe; }; /* prototypes */ @@ -181,7 +183,13 @@ int mcd_read_toc __P((struct mcd_softc *)); int mcd_getqchan __P((struct mcd_softc *, union mcd_qchninfo *, int)); int mcd_setlock __P((struct mcd_softc *, int)); +int mcd_find __P((bus_space_tag_t, bus_space_handle_t, struct mcd_softc *)); +#define __BROKEN_INDIRECT_CONFIG +#ifdef __BROKEN_INDIRECT_CONFIG int mcdprobe __P((struct device *, void *, void *)); +#else +int mcdprobe __P((struct device *, struct cfdata *, void *)); +#endif void mcdattach __P((struct device *, struct device *, void *)); struct cfattach mcd_ca = { @@ -192,6 +200,7 @@ struct cfdriver mcd_cd = { NULL, "mcd", DV_DISK }; +void mcdgetdefaultlabel __P((dev_t, struct mcd_softc *, struct disklabel *)); void mcdgetdisklabel __P((dev_t, struct mcd_softc *)); int mcd_get_parms __P((struct mcd_softc *)); void mcdstrategy __P((struct buf *)); @@ -219,8 +228,27 @@ mcdattach(parent, self, aux) { struct mcd_softc *sc = (void *)self; struct isa_attach_args *ia = aux; + bus_space_tag_t iot = ia->ia_iot; + bus_space_handle_t ioh; struct mcd_mbox mbx; + /* Map i/o space */ + if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh)) { + printf(": can't map i/o space\n"); + return; + } + + sc->sc_iot = iot; + sc->sc_ioh = ioh; + + sc->probe = 0; + sc->debug = 0; + + if (!mcd_find(iot, ioh, sc)) { + printf(": mcd_find failed\n"); + return; + } + /* * Initialize and attach the disk structure. */ @@ -611,6 +639,10 @@ mcdioctl(dev, cmd, addr, flag, p) case DIOCWLABEL: return EBADF; +/* case DIOCGDEFLABEL: + mcdgetdefaultlabel(dev, sc, (struct disklabel *)addr); + return 0; +*/ case CDIOCPLAYTRACKS: return mcd_playtracks(sc, (struct ioc_play_track *)addr); case CDIOCPLAYMSF: @@ -673,20 +705,15 @@ mcdioctl(dev, cmd, addr, flag, p) #endif } -/* - * This could have been taken from scsi/cd.c, but it is not clear - * whether the scsi cd driver is linked in. - */ void -mcdgetdisklabel(dev, sc) +mcdgetdefaultlabel(dev, sc, lp) dev_t dev; struct mcd_softc *sc; + struct disklabel *lp; { - struct disklabel *lp = sc->sc_dk.dk_label; char *errstring; bzero(lp, sizeof(struct disklabel)); - bzero(sc->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel)); lp->d_secsize = sc->blksize; lp->d_ntracks = 1; @@ -711,7 +738,7 @@ mcdgetdisklabel(dev, sc) lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; lp->d_npartitions = RAW_PART + 1; - + lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_checksum = dkcksum(lp); @@ -727,6 +754,22 @@ mcdgetdisklabel(dev, sc) } } +/* + * This could have been taken from scsi/cd.c, but it is not clear + * whether the scsi cd driver is linked in. + */ +void +mcdgetdisklabel(dev, sc) + dev_t dev; + struct mcd_softc *sc; +{ + struct disklabel *lp = sc->sc_dk.dk_label; + + bzero(sc->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel)); + + mcdgetdefaultlabel(dev, sc, lp); +} + int mcd_get_parms(sc) struct mcd_softc *sc; @@ -775,28 +818,27 @@ mcddump(dev, blkno, va, size) return ENXIO; } +/* + * Find the board and fill in the softc. + */ int -mcdprobe(parent, match, aux) - struct device *parent; - void *match, *aux; +mcd_find(iot, ioh, sc) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct mcd_softc *sc; { - struct mcd_softc *sc = match; - struct isa_attach_args *ia = aux; - int iobase = ia->ia_iobase; int i; struct mcd_mbox mbx; - sc->iobase = iobase; - - if( !opti_cd_setup( OPTI_MITSUMI, iobase, ia->ia_irq, ia->ia_drq ) ) - /* printf("mcdprobe: could not setup OPTi chipset.\n") */; + sc->sc_iot = iot; + sc->sc_ioh = ioh; /* Send a reset. */ - outb(iobase + MCD_RESET, 0); + bus_space_write_1(iot, ioh, MCD_RESET, 0); delay(1000000); /* Get any pending status and throw away. */ for (i = 10; i; i--) - inb(iobase + MCD_STATUS); + bus_space_read_1(iot, ioh, MCD_STATUS); delay(1000); /* Send get status command. */ @@ -849,22 +891,64 @@ mcdprobe(parent, match, aux) break; } - sc->attached = 1; - ia->ia_iosize = 4; - ia->ia_msize = 0; return 1; + +} + +int +mcdprobe(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; + struct mcd_softc sc; + bus_space_tag_t iot = ia->ia_iot; + bus_space_handle_t ioh; + int rv; + + /* Disallow wildcarded i/o address. */ + if (ia->ia_iobase == -1 /*ISACF_PORT_DEFAULT*/) + return (0); + + /* Map i/o space */ + if (bus_space_map(iot, ia->ia_iobase, MCD_NPORT, 0, &ioh)) + return 0; + + if (!opti_cd_setup(OPTI_MITSUMI, ia->ia_iobase, ia->ia_irq, ia->ia_drq)) + /* printf("mcdprobe: could not setup OPTi chipset.\n") */; + + sc.debug = 0; + sc.probe = 1; + + rv = mcd_find(iot, ioh, &sc); + + bus_space_unmap(iot, ioh, MCD_NPORT); + + if (rv) { + ia->ia_iosize = MCD_NPORT; + ia->ia_msize = 0; + } + + return (rv); } int mcd_getreply(sc) struct mcd_softc *sc; { - int iobase = sc->iobase; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; int i; /* Wait until xfer port senses data ready. */ for (i = DELAY_GETREPLY; i; i--) { - if ((inb(iobase + MCD_XFER) & MCD_XF_STATUSUNAVAIL) == 0) + if ((bus_space_read_1(iot, ioh, MCD_XFER) & + MCD_XF_STATUSUNAVAIL) == 0) break; delay(DELAY_GRANULARITY); } @@ -872,7 +956,7 @@ mcd_getreply(sc) return -1; /* Get the data. */ - return inb(iobase + MCD_STATUS); + return bus_space_read_1(iot, ioh, MCD_STATUS); } int @@ -901,7 +985,7 @@ mcd_getresult(sc, res) if ((x = mcd_getreply(sc)) < 0) { if (sc->debug) printf(" timeout\n"); - else if (sc->attached) + else if (sc->probe) printf("%s: timeout in getresult\n", sc->sc_dev.dv_xname); return EIO; } @@ -931,8 +1015,9 @@ mcd_getresult(sc, res) #ifdef MCDDEBUG delay(10); - while ((inb(sc->iobase + MCD_XFER) & MCD_XF_STATUSUNAVAIL) == 0) { - x = inb(sc->iobase + MCD_STATUS); + while ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_XFER) & + MCD_XF_STATUSUNAVAIL) == 0) { + x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_STATUS); printf("%s: got extra byte %02x during getstatus\n", sc->sc_dev.dv_xname, (u_int)x); delay(10); @@ -973,8 +1058,9 @@ mcd_send(sc, mbx, diskin) struct mcd_mbox *mbx; int diskin; { - int iobase = sc->iobase; int retry, i, error; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; if (sc->debug) { printf("%s: mcd_send: %d %02x", sc->sc_dev.dv_xname, @@ -985,9 +1071,9 @@ mcd_send(sc, mbx, diskin) } for (retry = MCD_RETRIES; retry; retry--) { - outb(iobase + MCD_COMMAND, mbx->cmd.opcode); + bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.opcode); for (i = 0; i < mbx->cmd.length; i++) - outb(iobase + MCD_COMMAND, mbx->cmd.data.raw.data[i]); + bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->cmd.data.raw.data[i]); if ((error = mcd_getresult(sc, &mbx->res)) == 0) break; if (error == EINVAL) @@ -1054,8 +1140,9 @@ mcdintr(arg) { struct mcd_softc *sc = arg; struct mcd_mbx *mbx = &sc->mbx; - int iobase = sc->iobase; struct buf *bp = mbx->bp; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; int i; u_char x; @@ -1071,8 +1158,8 @@ mcdintr(arg) goto firstblock; sc->lastmode = MCD_MD_UNKNOWN; - outb(iobase + MCD_COMMAND, MCD_CMDSETMODE); - outb(iobase + MCD_COMMAND, mbx->mode); + bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE); + bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode); mbx->count = RDELAY_WAITMODE; mbx->state = MCD_S_WAITMODE; @@ -1080,14 +1167,14 @@ mcdintr(arg) case MCD_S_WAITMODE: untimeout(mcd_pseudointr, sc); for (i = 20; i; i--) { - x = inb(iobase + MCD_XFER); + x = bus_space_read_1(iot, ioh, MCD_XFER); if ((x & MCD_XF_STATUSUNAVAIL) == 0) break; delay(50); } if (i == 0) goto hold; - sc->status = inb(iobase + MCD_STATUS); + sc->status = bus_space_read_1(iot, ioh, MCD_STATUS); mcd_setflags(sc); if ((sc->flags & MCDF_LOADED) == 0) goto changed; @@ -1104,13 +1191,13 @@ mcdintr(arg) hsg2msf(mbx->blkno, msf); /* Send the read command. */ - outb(iobase + MCD_COMMAND, sc->readcmd); - outb(iobase + MCD_COMMAND, msf[0]); - outb(iobase + MCD_COMMAND, msf[1]); - outb(iobase + MCD_COMMAND, msf[2]); - outb(iobase + MCD_COMMAND, 0); - outb(iobase + MCD_COMMAND, 0); - outb(iobase + MCD_COMMAND, mbx->nblk); + bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd); + bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]); + bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]); + bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]); + bus_space_write_1(iot, ioh, MCD_COMMAND, 0); + bus_space_write_1(iot, ioh, MCD_COMMAND, 0); + bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk); mbx->count = RDELAY_WAITREAD; mbx->state = MCD_S_WAITREAD; @@ -1120,7 +1207,7 @@ mcdintr(arg) nextblock: loop: for (i = 20; i; i--) { - x = inb(iobase + MCD_XFER); + x = bus_space_read_1(iot, ioh, MCD_XFER); if ((x & MCD_XF_DATAUNAVAIL) == 0) goto gotblock; if ((x & MCD_XF_STATUSUNAVAIL) == 0) @@ -1129,7 +1216,7 @@ mcdintr(arg) } if (i == 0) goto hold; - sc->status = inb(iobase + MCD_STATUS); + sc->status = bus_space_read_1(iot, ioh, MCD_STATUS); mcd_setflags(sc); if ((sc->flags & MCDF_LOADED) == 0) goto changed; @@ -1144,9 +1231,10 @@ mcdintr(arg) RDELAY_WAITREAD - mbx->count, 0, 0, 0); /* Data is ready. */ - outb(iobase + MCD_CTL2, 0x04); /* XXX */ - insb(iobase + MCD_RDATA, bp->b_data + mbx->skip, mbx->sz); - outb(iobase + MCD_CTL2, 0x0c); /* XXX */ + bus_space_write_1(iot, ioh, MCD_CTL2, 0x04); /* XXX */ + bus_space_read_multi_1(iot, ioh, MCD_RDATA, + bp->b_data + mbx->skip, mbx->sz); + bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c); /* XXX */ mbx->blkno += 1; mbx->skip += mbx->sz; if (--mbx->nblk > 0) @@ -1196,7 +1284,7 @@ changed: #ifdef notyet printf("%s: unit timeout; resetting\n", sc->sc_dev.dv_xname); - outb(mbx->iobase + MCD_RESET, MCD_CMDRESET); + bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET); delay(300000); (void) mcd_getstat(sc, 1); (void) mcd_getstat(sc, 1); @@ -1215,7 +1303,7 @@ mcd_soft_reset(sc) sc->lastmode = MCD_MD_UNKNOWN; sc->lastupc = MCD_UPC_UNKNOWN; sc->audio_status = CD_AS_AUDIO_INVALID; - outb(sc->iobase + MCD_CTL2, 0x0c); /* XXX */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, MCD_CTL2, 0x0c); /* XXX */ } int diff --git a/sys/dev/isa/mcdreg.h b/sys/dev/isa/mcdreg.h index 92677c4f307..198a6c22a53 100644 --- a/sys/dev/isa/mcdreg.h +++ b/sys/dev/isa/mcdreg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: mcdreg.h,v 1.2 1997/11/07 08:07:05 niklas Exp $ */ -/* $NetBSD: mcdreg.h,v 1.7 1995/07/10 01:27:27 cgd Exp $ */ +/* $OpenBSD: mcdreg.h,v 1.3 1998/04/26 21:02:50 provos Exp $ */ +/* $NetBSD: mcdreg.h,v 1.8 1997/04/04 18:59:37 christos Exp $ */ /* * Copyright 1993 by Holger Veit (data part) @@ -60,6 +60,7 @@ typedef unsigned char bcd_t; #define MCD_XFER 1 #define MCD_CTL2 2 /* XXX Is this right? */ #define MCD_CONFIG 3 +#define MCD_NPORT 4 #define MCD_MASK_DMA 0x07 /* bits 2-0 = DMA channel */ #define MCD_MASK_IRQ 0x70 /* bits 6-4 = INT number */ diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c index 41236ebe549..772bcf8d431 100644 --- a/sys/dev/isa/pas.c +++ b/sys/dev/isa/pas.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pas.c,v 1.14 1997/07/10 23:06:36 provos Exp $ */ -/* $NetBSD: pas.c,v 1.17 1996/05/12 23:53:18 mycroft Exp $ */ +/* $OpenBSD: pas.c,v 1.15 1998/04/26 21:02:51 provos Exp $ */ +/* $NetBSD: pas.c,v 1.37 1998/01/12 09:43:43 thorpej Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -35,6 +35,13 @@ * */ /* + * jfw 7/13/97 - The soundblaster code requires the generic bus-space + * structures to be set up properly. Rather than go to the effort of making + * code for a dead line fully generic, properly set up the SB structures and + * leave the rest x86/ISA/default-configuration specific. If you have a + * REAL computer, go buy a REAL sound card. + */ +/* * Todo: * - look at other PAS drivers (for PAS native suport) * - use common sb.c once emulation is setup @@ -50,11 +57,11 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> #include <dev/audio_if.h> -#include <dev/mulaw.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -95,7 +102,6 @@ struct pas_softc { }; -int pasopen __P((dev_t, int)); int pas_getdev __P((void *, struct audio_device *)); void pasconf __P((int, int, int, int)); @@ -105,41 +111,30 @@ void pasconf __P((int, int, int, int)); */ struct audio_hw_if pas_hw_if = { - pasopen, + sbdsp_open, sbdsp_close, - NULL, - sbdsp_set_in_sr, - sbdsp_get_in_sr, - sbdsp_set_out_sr, - sbdsp_get_out_sr, + 0, sbdsp_query_encoding, - sbdsp_set_format, - sbdsp_get_encoding, - sbdsp_get_precision, - sbdsp_set_channels, - sbdsp_get_channels, + sbdsp_set_params, sbdsp_round_blocksize, - sbdsp_set_out_port, - sbdsp_get_out_port, - sbdsp_set_in_port, - sbdsp_get_in_port, - sbdsp_commit_settings, - mulaw_expand, - mulaw_compress, + 0, + sbdsp_dma_init_output, + sbdsp_dma_init_input, sbdsp_dma_output, sbdsp_dma_input, sbdsp_haltdma, sbdsp_haltdma, - sbdsp_contdma, - sbdsp_contdma, sbdsp_speaker_ctl, pas_getdev, - sbdsp_setfd, + 0, sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, - 0, /* not full-duplex */ - 0 + sb_malloc, + sb_free, + sb_round, + sb_mappage, + sbdsp_get_props, }; /* The Address Translation code is used to convert I/O register addresses to @@ -266,11 +261,17 @@ pasprobe(parent, match, aux) struct device *parent; void *match, *aux; { - register struct pas_softc *sc = match; - register struct isa_attach_args *ia = aux; - register int iobase; + struct pas_softc *sc = match; + struct isa_attach_args *ia = aux; + int iobase; u_char id, t; + /* ensure we can set this up as a sound blaster */ + if (!SB_BASE_VALID(ia->ia_iobase)) { + printf("pas: configured SB iobase 0x%x invalid\n", ia->ia_iobase); + return 0; + } + /* * WARNING: Setting an option like W:1 or so that disables * warm boot reset of the card will screw up this detect code @@ -342,11 +343,24 @@ pasprobe(parent, match, aux) return (0); } - /* Now a SoundBlaster */ + /* Now a SoundBlaster, so set up proper bus-space hooks + * appropriately + */ + sc->sc_sbdsp.sc_iobase = ia->ia_iobase; + sc->sc_sbdsp.sc_iot = ia->ia_iot; + + /* Map i/o space [we map 24 ports which is the max of the sb and pro */ + if (bus_space_map(sc->sc_sbdsp.sc_iot, ia->ia_iobase, SBP_NPORT, 0, + &sc->sc_sbdsp.sc_ioh)) { + printf("pas: can't map i/o space 0x%x/%d in probe\n", + ia->ia_iobase, SBP_NPORT); + return 0; + } + if (sbdsp_reset(&sc->sc_sbdsp) < 0) { DPRINTF(("pas: couldn't reset card\n")); - return 0; + goto unmap; } /* @@ -354,7 +368,7 @@ pasprobe(parent, match, aux) */ if (!SB_DRQ_VALID(ia->ia_drq)) { printf("pas: configured dma chan %d invalid\n", ia->ia_drq); - return 0; + goto unmap; } #ifdef NEWCONFIG /* @@ -365,13 +379,13 @@ pasprobe(parent, match, aux) sbdsp_reset(&sc->sc_sbdsp); if (!SB_IRQ_VALID(ia->ia_irq)) { printf("pas: couldn't auto-detect interrupt"); - return 0; + goto unmap; } } else #endif if (!SB_IRQ_VALID(ia->ia_irq)) { printf("pas: configured irq chan %d invalid\n", ia->ia_irq); - return 0; + goto unmap; } sc->sc_sbdsp.sc_irq = ia->ia_irq; @@ -380,11 +394,15 @@ pasprobe(parent, match, aux) if (sbdsp_probe(&sc->sc_sbdsp) == 0) { DPRINTF(("pas: sbdsp probe failed\n")); - return 0; + goto unmap; } ia->ia_iosize = SB_NPORT; return 1; + + unmap: + bus_space_unmap(sc->sc_sbdsp.sc_iot, sc->sc_sbdsp.sc_ioh, SBP_NPORT); + return 0; } #ifdef NEWCONFIG @@ -424,10 +442,9 @@ pasattach(parent, self, aux) struct device *parent, *self; void *aux; { - register struct pas_softc *sc = (struct pas_softc *)self; + struct pas_softc *sc = (struct pas_softc *)self; struct isa_attach_args *ia = (struct isa_attach_args *)aux; - register int iobase = ia->ia_iobase; - int err; + int iobase = ia->ia_iobase; sc->sc_sbdsp.sc_iobase = iobase; sc->sc_sbdsp.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, @@ -440,26 +457,7 @@ pasattach(parent, self, aux) sprintf(pas_device.name, "pas,%s", pasnames[sc->model]); sprintf(pas_device.version, "%d", sc->rev); - if ((err = audio_hardware_attach(&pas_hw_if, &sc->sc_sbdsp)) != 0) - printf("pas: could not attach to audio pseudo-device driver (%d)\n", err); -} - -int -pasopen(dev, flags) - dev_t dev; - int flags; -{ - struct pas_softc *sc; - int unit = AUDIOUNIT(dev); - - if (unit >= pas_cd.cd_ndevs) - return ENODEV; - - sc = pas_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - - return sbdsp_open(&sc->sc_sbdsp, dev, flags); + audio_attach_mi(&pas_hw_if, 0, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev); } int diff --git a/sys/dev/isa/pnpdevs b/sys/dev/isa/pnpdevs index be03594869d..f3e003a5cb2 100644 --- a/sys/dev/isa/pnpdevs +++ b/sys/dev/isa/pnpdevs @@ -1,4 +1,4 @@ -# $OpenBSD: pnpdevs,v 1.10 1998/03/16 05:21:55 dgregor Exp $ +# $OpenBSD: pnpdevs,v 1.11 1998/04/26 21:02:53 provos Exp $ # # NOTE: All `com' devices also need pccom identifiers. @@ -368,4 +368,5 @@ sb CTL0041 #SB16 PnP (CT4131) sb CTL0042 #SB AWE64 Value sb CTL0044 #SB AWE64 Gold sb CTL0045 #SB AWE64 Value +sb YMH0021 # sb ESS1868 # diff --git a/sys/dev/isa/pnpdevs.h b/sys/dev/isa/pnpdevs.h index 68a5edaf949..75bb1ffe38d 100644 --- a/sys/dev/isa/pnpdevs.h +++ b/sys/dev/isa/pnpdevs.h @@ -58,6 +58,7 @@ struct isapnp_knowndev isapnp_knowndevs[] = { { "CTL0042", "sb" }, { "CTL0044", "sb" }, { "CTL0045", "sb" }, + { "YMH0021", "sb" }, { "ESS1868", "sb" }, { NULL, NULL, } }; diff --git a/sys/dev/isa/pss.c b/sys/dev/isa/pss.c index 636b208cc18..c2bf800b640 100644 --- a/sys/dev/isa/pss.c +++ b/sys/dev/isa/pss.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pss.c,v 1.12 1997/07/12 01:42:08 millert Exp $ */ -/* $NetBSD: pss.c,v 1.15 1996/05/12 23:53:23 mycroft Exp $ */ +/* $OpenBSD: pss.c,v 1.13 1998/04/26 21:02:55 provos Exp $ */ +/* $NetBSD: pss.c,v 1.38 1998/01/12 09:43:44 thorpej Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -62,6 +62,7 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> @@ -155,8 +156,7 @@ struct pcd_softc { #endif #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (pssdebug) Dprintf x +#define DPRINTF(x) if (pssdebug) printf x int pssdebug = 0; #else #define DPRINTF(x) @@ -176,8 +176,6 @@ int pcdprobe __P((struct device *, void *, void *)); void pcdattach __P((struct device *, struct device *, void *)); #endif -int spopen __P((dev_t, int)); - int pssintr __P((void *)); #ifdef notyet int mpuintr __P((void *)); @@ -186,12 +184,7 @@ int mpuintr __P((void *)); int pss_speaker_ctl __P((void *, int)); int pss_getdev __P((void *, struct audio_device *)); -int pss_setfd __P((void *, int)); -int pss_set_out_port __P((void *, int)); -int pss_get_out_port __P((void *)); -int pss_set_in_port __P((void *, int)); -int pss_get_in_port __P((void *)); int pss_mixer_set_port __P((void *, mixer_ctrl_t *)); int pss_mixer_get_port __P((void *, mixer_ctrl_t *)); int pss_query_devinfo __P((void *, mixer_devinfo_t *)); @@ -232,41 +225,30 @@ void wss_dump_regs __P((struct ad1848_softc *)); */ struct audio_hw_if pss_audio_if = { - spopen, + ad1848_open, ad1848_close, NULL, - ad1848_set_in_sr, - ad1848_get_in_sr, - ad1848_set_out_sr, - ad1848_get_out_sr, ad1848_query_encoding, - ad1848_set_format, - ad1848_get_encoding, - ad1848_get_precision, - ad1848_set_channels, - ad1848_get_channels, + ad1848_set_params, ad1848_round_blocksize, - pss_set_out_port, - pss_get_out_port, - pss_set_in_port, - pss_get_in_port, ad1848_commit_settings, - NULL, - NULL, + ad1848_dma_init_output, + ad1848_dma_init_input, ad1848_dma_output, ad1848_dma_input, ad1848_halt_out_dma, ad1848_halt_in_dma, - ad1848_cont_out_dma, - ad1848_cont_in_dma, pss_speaker_ctl, pss_getdev, - pss_setfd, + NULL, pss_mixer_set_port, pss_mixer_get_port, pss_query_devinfo, - 0, /* not full-duplex */ - 0 + ad1848_malloc, + ad1848_free, + ad1848_round, + ad1848_mappage, + ad1848_get_props, }; @@ -845,9 +827,11 @@ spprobe(parent, match, aux) struct ad1848_softc *sc = match; struct pss_softc *pc = (void *) parent; struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata; + struct isa_attach_args *ia = aux; u_char bits; int i; + sc->sc_iot = ia->ia_iot; sc->sc_iobase = cf->cf_iobase + WSS_CODEC; /* Set WSS io address */ @@ -1043,7 +1027,6 @@ pssattach(parent, self, aux) int iobase = ia->ia_iobase; u_char vers; struct ad1848_volume vol = {150, 150}; - int err; sc->sc_iobase = iobase; sc->sc_drq = ia->ia_drq; @@ -1068,8 +1051,7 @@ pssattach(parent, self, aux) (void)pss_set_treble(sc, AUDIO_MAX_GAIN/2); (void)pss_set_bass(sc, AUDIO_MAX_GAIN/2); - if ((err = audio_hardware_attach(&pss_audio_if, sc->ad1848_sc)) != 0) - printf("pss: could not attach to audio pseudo-device driver (%d)\n", err); + audio_attach_mi(&pss_audio_if, 0, sc->ad1848_sc, &sc->ad1848_sc->sc_dev); } void @@ -1092,10 +1074,7 @@ spattach(parent, self, aux) sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO, ad1848_intr, sc, sc->sc_dev.dv_xname); - /* XXX might use pssprint func ?? */ - printf(" port 0x%x-0x%x irq %d drq %d", - sc->sc_iobase, sc->sc_iobase+AD1848_NPORT, - cf->cf_irq, cf->cf_drq); + sc->sc_isa = parent->dv_parent; ad1848_attach(sc); @@ -1190,26 +1169,8 @@ pss_from_vol(cp, vol) } int -spopen(dev, flags) - dev_t dev; - int flags; -{ - struct ad1848_softc *sc; - int unit = AUDIOUNIT(dev); - - if (unit >= sp_cd.cd_ndevs) - return ENODEV; - - sc = sp_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - - return ad1848_open(sc, dev, flags); -} - -int pss_set_master_gain(sc, gp) - register struct pss_softc *sc; + struct pss_softc *sc; struct ad1848_volume *gp; { DPRINTF(("pss_set_master_gain: %d:%d\n", gp->left, gp->right)); @@ -1236,7 +1197,7 @@ pss_set_master_gain(sc, gp) int pss_set_master_mode(sc, mode) - register struct pss_softc *sc; + struct pss_softc *sc; int mode; { short phillips_mode; @@ -1266,7 +1227,7 @@ pss_set_master_mode(sc, mode) int pss_set_treble(sc, treb) - register struct pss_softc *sc; + struct pss_softc *sc; u_int treb; { DPRINTF(("pss_set_treble: %d\n", treb)); @@ -1287,7 +1248,7 @@ pss_set_treble(sc, treb) int pss_set_bass(sc, bass) - register struct pss_softc *sc; + struct pss_softc *sc; u_int bass; { DPRINTF(("pss_set_bass: %d\n", bass)); @@ -1308,7 +1269,7 @@ pss_set_bass(sc, bass) int pss_get_master_gain(sc, gp) - register struct pss_softc *sc; + struct pss_softc *sc; struct ad1848_volume *gp; { *gp = sc->master_volume; @@ -1317,7 +1278,7 @@ pss_get_master_gain(sc, gp) int pss_get_master_mode(sc, mode) - register struct pss_softc *sc; + struct pss_softc *sc; u_int *mode; { *mode = sc->master_mode; @@ -1326,7 +1287,7 @@ pss_get_master_mode(sc, mode) int pss_get_treble(sc, tp) - register struct pss_softc *sc; + struct pss_softc *sc; u_char *tp; { *tp = sc->monitor_treble; @@ -1335,7 +1296,7 @@ pss_get_treble(sc, tp) int pss_get_bass(sc, bp) - register struct pss_softc *sc; + struct pss_softc *sc; u_char *bp; { *bp = sc->monitor_bass; @@ -1354,12 +1315,12 @@ int pssintr(arg) void *arg; { - register struct pss_softc *sc = arg; + struct pss_softc *sc = arg; u_short sr; sr = inw(sc->sc_iobase+PSS_STATUS); - DPRINTF(("pssintr: sc=%x st=%x\n", sc, sr)); + DPRINTF(("pssintr: sc=%p st=%x\n", sc, sr)); /* Acknowledge intr */ outw(sc->sc_iobase+PSS_IRQ_ACK, 0); @@ -1378,7 +1339,7 @@ int mpuintr(arg) void *arg; { - register struct mpu_softc *sc = arg; + struct mpu_softc *sc = arg; u_char sr; sr = inb(sc->sc_iobase+MIDI_STATUS_REG); @@ -1395,109 +1356,19 @@ pss_getdev(addr, retp) void *addr; struct audio_device *retp; { - DPRINTF(("pss_getdev: retp=0x%x\n", retp)); + DPRINTF(("pss_getdev: retp=%p\n", retp)); *retp = pss_device; return 0; } int -pss_setfd(addr, flag) - void *addr; - int flag; -{ - /* Can't do full-duplex */ - return(ENOTTY); -} - -int -pss_set_out_port(addr, port) - void *addr; - int port; -{ - register struct ad1848_softc *ac = addr; - register struct pss_softc *sc = ac->parent; - - DPRINTF(("pss_set_out_port: %d\n", port)); - - if (port != PSS_MASTER_VOL) - return(EINVAL); - - sc->out_port = port; - - return(0); -} - -int -pss_get_out_port(addr) - void *addr; -{ - register struct ad1848_softc *ac = addr; - register struct pss_softc *sc = ac->parent; - - DPRINTF(("pss_get_out_port: %d\n", sc->out_port)); - - return(sc->out_port); -} - -int -pss_set_in_port(addr, port) - void *addr; - int port; -{ - register struct ad1848_softc *ac = addr; - - DPRINTF(("pss_set_in_port: %d\n", port)); - - switch(port) { - case PSS_MIC_IN_LVL: - port = MIC_IN_PORT; - break; - case PSS_LINE_IN_LVL: - port = LINE_IN_PORT; - break; - case PSS_DAC_LVL: - port = DAC_IN_PORT; - break; - default: - return(EINVAL); - /*NOTREACHED*/ - } - - return(ad1848_set_rec_port(ac, port)); -} - -int -pss_get_in_port(addr) - void *addr; -{ - register struct ad1848_softc *ac = addr; - int port = PSS_MIC_IN_LVL; - - switch(ad1848_get_rec_port(ac)) { - case MIC_IN_PORT: - port = PSS_MIC_IN_LVL; - break; - case LINE_IN_PORT: - port = PSS_LINE_IN_LVL; - break; - case DAC_IN_PORT: - port = PSS_DAC_LVL; - break; - } - - DPRINTF(("pss_get_in_port: %d\n", port)); - - return(port); -} - -int pss_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct pss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct pss_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -1606,8 +1477,8 @@ pss_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct pss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct pss_softc *sc = ac->parent; struct ad1848_volume vol; u_char eq; int error = EINVAL; @@ -1723,7 +1594,7 @@ pss_mixer_get_port(addr, cp) int pss_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { DPRINTF(("pss_query_devinfo: index=%d\n", dip->index)); @@ -1782,7 +1653,7 @@ pss_query_devinfo(addr, dip) dip->mixer_class = PSS_OUTPUT_CLASS; dip->prev = AUDIO_MIXER_LAST; dip->next = PSS_OUTPUT_MODE; - strcpy(dip->label.name, AudioNvolume); + strcpy(dip->label.name, AudioNmaster); dip->un.v.num_channels = 2; strcpy(dip->un.v.units.name, AudioNvolume); break; @@ -1809,28 +1680,28 @@ pss_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = PSS_OUTPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNspeaker); + strcpy(dip->label.name, AudioCoutputs); break; case PSS_INPUT_CLASS: /* input class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = PSS_INPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + strcpy(dip->label.name, AudioCinputs); break; case PSS_MONITOR_CLASS: /* monitor class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = PSS_MONITOR_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNmonitor); + strcpy(dip->label.name, AudioCmonitor); break; case PSS_RECORD_CLASS: /* record source class */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = PSS_RECORD_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNrecord); + strcpy(dip->label.name, AudioCrecord); break; case PSS_MIC_IN_MUTE: diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c index 5bcc4010db0..06274862b28 100644 --- a/sys/dev/isa/sb.c +++ b/sys/dev/isa/sb.c @@ -1,5 +1,5 @@ -/* $OpenBSD: sb.c,v 1.13 1997/08/07 05:27:32 deraadt Exp $ */ -/* $NetBSD: sb.c,v 1.36 1996/05/12 23:53:33 mycroft Exp $ */ +/* $OpenBSD: sb.c,v 1.14 1998/04/26 21:02:56 provos Exp $ */ +/* $NetBSD: sb.c,v 1.57 1998/01/12 09:43:46 thorpej Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -45,11 +45,11 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> #include <dev/audio_if.h> -#include <dev/mulaw.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> @@ -58,14 +58,6 @@ #include <dev/isa/sbvar.h> #include <dev/isa/sbdspvar.h> -struct sb_softc { - struct device sc_dev; /* base device */ - struct isadev sc_id; /* ISA device */ - void *sc_ih; /* interrupt vectoring */ - - struct sbdsp_softc sc_sbdsp; -}; - struct cfdriver sb_cd = { NULL, "sb", DV_DULL }; @@ -76,7 +68,6 @@ struct audio_device sb_device = { "sb" }; -int sbopen __P((dev_t, int)); int sb_getdev __P((void *, struct audio_device *)); /* @@ -84,41 +75,30 @@ int sb_getdev __P((void *, struct audio_device *)); */ struct audio_hw_if sb_hw_if = { - sbopen, + sbdsp_open, sbdsp_close, - NULL, - sbdsp_set_in_sr, - sbdsp_get_in_sr, - sbdsp_set_out_sr, - sbdsp_get_out_sr, + 0, sbdsp_query_encoding, - sbdsp_set_format, - sbdsp_get_encoding, - sbdsp_get_precision, - sbdsp_set_channels, - sbdsp_get_channels, + sbdsp_set_params, sbdsp_round_blocksize, - sbdsp_set_out_port, - sbdsp_get_out_port, - sbdsp_set_in_port, - sbdsp_get_in_port, - sbdsp_commit_settings, - mulaw_expand, - mulaw_compress, + 0, + sbdsp_dma_init_output, + sbdsp_dma_init_input, sbdsp_dma_output, sbdsp_dma_input, sbdsp_haltdma, sbdsp_haltdma, - sbdsp_contdma, - sbdsp_contdma, sbdsp_speaker_ctl, sb_getdev, - sbdsp_setfd, + 0, sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, - 0, /* not full-duplex */ - 0 + sb_malloc, + sb_free, + sb_round, + sb_mappage, + sbdsp_get_props, }; /* @@ -157,7 +137,15 @@ sbmatch(sc) return 0; } } - + + if (0 <= sc->sc_drq16 && sc->sc_drq16 <= 3) + /* + * XXX Some ViBRA16 cards seem to have two 8 bit DMA + * channels. I've no clue how to use them, so ignore + * one of them for now. -- augustss@netbsd.org + */ + sc->sc_drq16 = -1; + if (ISSB16CLASS(sc)) { if (sc->sc_drq16 == -1) sc->sc_drq16 = sc->sc_drq8; @@ -207,14 +195,21 @@ sbmatch(sc) } if (ISSB16CLASS(sc)) { + int w, r; #if 0 printf("%s: old drq conf %02x\n", sc->sc_dev.dv_xname, sbdsp_mix_read(sc, SBP_SET_DRQ)); printf("%s: try drq conf %02x\n", sc->sc_dev.dv_xname, drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]); #endif - sbdsp_mix_write(sc, SBP_SET_DRQ, - drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]); + w = drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]; + sbdsp_mix_write(sc, SBP_SET_DRQ, w); + r = sbdsp_mix_read(sc, SBP_SET_DRQ) & 0xeb; + if (r != w) { + printf("%s: setting drq mask %02x failed, got %02x\n", + sc->sc_dev.dv_xname, w, r); + return 0; + } #if 0 printf("%s: new drq conf %02x\n", sc->sc_dev.dv_xname, sbdsp_mix_read(sc, SBP_SET_DRQ)); @@ -226,8 +221,14 @@ sbmatch(sc) printf("%s: try irq conf %02x\n", sc->sc_dev.dv_xname, irq_conf[sc->sc_irq]); #endif - sbdsp_mix_write(sc, SBP_SET_IRQ, - irq_conf[sc->sc_irq]); + w = irq_conf[sc->sc_irq]; + sbdsp_mix_write(sc, SBP_SET_IRQ, w); + r = sbdsp_mix_read(sc, SBP_SET_IRQ) & 0x0f; + if (r != w) { + printf("%s: setting irq mask %02x failed, got %02x\n", + sc->sc_dev.dv_xname, w, r); + return 0; + } #if 0 printf("%s: new irq conf %02x\n", sc->sc_dev.dv_xname, sbdsp_mix_read(sc, SBP_SET_IRQ)); @@ -242,16 +243,12 @@ void sbattach(sc) struct sbdsp_softc *sc; { - int error; - 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); - if ((error = audio_hardware_attach(&sb_hw_if, sc)) != 0) - printf("%s: could not attach to audio device driver (%d)\n", - sc->sc_dev.dv_xname, error); + audio_attach_mi(&sb_hw_if, 0, sc, &sc->sc_dev); } #ifdef NEWCONFIG @@ -287,38 +284,26 @@ sbforceintr(aux) */ int -sbopen(dev, flags) - dev_t dev; - int flags; -{ - struct sbdsp_softc *sc; - int unit = AUDIOUNIT(dev); - - if (unit >= sb_cd.cd_ndevs) - return ENODEV; - - sc = sb_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - - return sbdsp_open(sc, dev, flags); -} - -int sb_getdev(addr, retp) void *addr; struct audio_device *retp; { struct sbdsp_softc *sc = addr; + static char *names[] = SB_NAMES; + char *config; - if (sc->sc_model & MODEL_JAZZ16) + if (sc->sc_model == SB_JAZZ) strncpy(retp->name, "MV Jazz16", sizeof(retp->name)); else strncpy(retp->name, "SoundBlaster", sizeof(retp->name)); sprintf(retp->version, "%d.%02d", - SBVER_MAJOR(sc->sc_model), - SBVER_MINOR(sc->sc_model)); - strncpy(retp->config, "sb", sizeof(retp->config)); + SBVER_MAJOR(sc->sc_version), + SBVER_MINOR(sc->sc_version)); + if (0 <= sc->sc_model && sc->sc_model < sizeof names / sizeof names[0]) + config = names[sc->sc_model]; + else + config = "??"; + strncpy(retp->config, config, sizeof(retp->config)); return 0; } diff --git a/sys/dev/isa/sb_isa.c b/sys/dev/isa/sb_isa.c index da747efd05f..9cba8d91df8 100644 --- a/sys/dev/isa/sb_isa.c +++ b/sys/dev/isa/sb_isa.c @@ -1,5 +1,5 @@ -/* $OpenBSD: sb_isa.c,v 1.1 1997/07/10 23:06:37 provos Exp $ */ -/* $NetBSD: sb_isa.c,v 1.3 1997/03/20 11:03:11 mycroft Exp $ */ +/* $OpenBSD: sb_isa.c,v 1.2 1998/04/26 21:02:57 provos Exp $ */ +/* $NetBSD: sb_isa.c,v 1.15 1997/11/30 15:32:25 drochner Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -43,6 +43,8 @@ #include <sys/device.h> #include <sys/proc.h> +#include <machine/bus.h> + #include <sys/audioio.h> #include <dev/audio_if.h> #include <dev/mulaw.h> @@ -55,7 +57,14 @@ #include <dev/isa/sbdspvar.h> +static int sbfind __P((struct device *, struct sbdsp_softc *, struct isa_attach_args *)); + +#define __BROKEN_INDIRECT_CONFIG /* XXX */ +#ifdef __BROKEN_INDIRECT_CONFIG int sb_isa_match __P((struct device *, void *, void *)); +#else +int sb_isa_match __P((struct device *, struct cfdata *, void *)); +#endif void sb_isa_attach __P((struct device *, struct device *, void *)); struct cfattach sb_isa_ca = { @@ -72,13 +81,32 @@ struct cfattach sb_isa_ca = { int sb_isa_match(parent, match, aux) struct device *parent; - void *match, *aux; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + struct sbdsp_softc probesc, *sc = &probesc; + + bzero(sc, sizeof *sc); +#ifdef __BROKEN_INDIRECT_CONFIG + sc->sc_dev.dv_cfdata = ((struct device *)match)->dv_cfdata; +#else + sc->sc_dev.dv_cfdata = match; +#endif + strcpy(sc->sc_dev.dv_xname, "sb"); + return sbfind(parent, sc, aux); +} + +static int +sbfind(parent, sc, ia) + struct device *parent; + struct sbdsp_softc *sc; + struct isa_attach_args *ia; { - /* - * Indirect brokedness! - */ - register struct sbdsp_softc *sc = match; - register struct isa_attach_args *ia = aux; + int rc = 0; if (!SB_BASE_VALID(ia->ia_iobase)) { printf("sb: configured iobase 0x%x invalid\n", ia->ia_iobase); @@ -87,7 +115,7 @@ sb_isa_match(parent, match, aux) sc->sc_iot = ia->ia_iot; - /* Map i/o space [we map 24 ports which is the max of the sb and pro */ + /* Map i/o space [we map 24 ports which is the max of the sb and pro */ if (bus_space_map(sc->sc_iot, ia->ia_iobase, SBP_NPORT, 0, &sc->sc_ioh)) { printf("sb: can't map i/o space 0x%x/%d in probe\n", @@ -95,28 +123,34 @@ sb_isa_match(parent, match, aux) return 0; } - /* - * Indirect brokedness! - */ sc->sc_iobase = ia->ia_iobase; sc->sc_irq = ia->ia_irq; sc->sc_drq8 = ia->ia_drq; - sc->sc_drq16 = -1; /* XXX */ + sc->sc_drq16 = ia->ia_drq2; sc->sc_ic = ia->ia_ic; - if (!sbmatch(sc)) { - bus_space_unmap(sc->sc_iot, sc->sc_ioh, SBP_NPORT); - return 0; - } + if (!sbmatch(sc)) + goto bad; + + if ((sc->sc_drq8 != -1 && !isa_drq_isfree(parent, sc->sc_drq8)) || + (sc->sc_drq16 != -1 && !isa_drq_isfree(parent, sc->sc_drq16))) + goto bad; if (ISSBPROCLASS(sc)) ia->ia_iosize = SBP_NPORT; else ia->ia_iosize = SB_NPORT; + if (!ISSB16CLASS(sc) && sc->sc_model != SB_JAZZ) + ia->ia_drq2 = -1; + ia->ia_irq = sc->sc_irq; - return 1; + rc = 1; + +bad: + bus_space_unmap(sc->sc_iot, sc->sc_ioh, SBP_NPORT); + return rc; } @@ -129,5 +163,15 @@ sb_isa_attach(parent, self, aux) struct device *parent, *self; void *aux; { - sbattach((struct sbdsp_softc *) self); + struct sbdsp_softc *sc = (struct sbdsp_softc *)self; + struct isa_attach_args *ia = aux; + + if (!sbfind(parent, sc, ia) || + bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, + 0, &sc->sc_ioh)) { + printf("%s: sbfind failed\n", sc->sc_dev.dv_xname); + return; + } + sc->sc_isa = parent; + sbattach(sc); } diff --git a/sys/dev/isa/sb_isapnp.c b/sys/dev/isa/sb_isapnp.c index 13f3038c9af..47115e98e3d 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.2 1997/12/26 09:35:38 deraadt Exp $ */ +/* $OpenBSD: sb_isapnp.c,v 1.3 1998/04/26 21:02:58 provos Exp $ */ /* $NetBSD: sb_isa.c,v 1.3 1997/03/20 11:03:11 mycroft Exp $ */ /* @@ -93,9 +93,24 @@ sb_isapnp_attach(parent, self, aux) sc->sc_ioh = ia->ipa_io[0].h; sc->sc_iobase = ia->ipa_io[0].base; sc->sc_irq = ia->ipa_irq[0].num; - sc->sc_drq8 = ia->ipa_drq[0].num; - sc->sc_drq16 = ia->ipa_drq[1].num; sc->sc_ic = ia->ia_ic; + sc->sc_drq8 = ia->ipa_drq[0].num; + + if (ia->ipa_ndrq > 1 && ia->ipa_drq[0].num != ia->ipa_drq[1].num) { + /* Some cards have the 16 bit drq first */ + if (sc->sc_drq8 >= 4) { + sc->sc_drq16 = sc->sc_drq8; + sc->sc_drq8 = ia->ipa_drq[1].num; + } else + sc->sc_drq16 = ia->ipa_drq[1].num; + } 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 (!sbmatch(sc)) { printf("%s: sbmatch failed\n", sc->sc_dev.dv_xname); diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c index ca7ebb359d2..89cda5647d9 100644 --- a/sys/dev/isa/sbdsp.c +++ b/sys/dev/isa/sbdsp.c @@ -1,5 +1,5 @@ -/* $OpenBSD: sbdsp.c,v 1.11 1998/01/18 18:58:39 niklas Exp $ */ -/* $NetBSD: sbdsp.c,v 1.30 1996/10/25 07:25:48 fvdl Exp $ */ +/* $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 $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -40,6 +40,9 @@ * information he gleaned from Steve Haehnichen <steve@vigra.com>'s * SBlast driver for 386BSD and DOS driver code from Daniel Sachs * <sachs@meibm15.cen.uiuc.edu>. + * Lots of rewrites by Lennart Augustsson <augustss@cs.chalmers.se> + * with information from SB "Hardware Programming Guide" and the + * Linux drivers. */ #include <sys/param.h> @@ -54,21 +57,21 @@ #include <machine/cpu.h> #include <machine/intr.h> -#include <machine/pio.h> +#include <machine/bus.h> #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/mulaw.h> +#include <dev/auconv.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> -#include <i386/isa/icu.h> /* XXX BROKEN; WHY? */ #include <dev/isa/sbreg.h> #include <dev/isa/sbdspvar.h> #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (sbdspdebug) Dprintf x +#define DPRINTF(x) if (sbdspdebug) printf x int sbdspdebug = 0; #else #define DPRINTF(x) @@ -84,10 +87,6 @@ struct { int wmidi; } sberr; -int sbdsp_srtotc __P((struct sbdsp_softc *sc, int sr, int isdac, - int *tcp, int *modep)); -u_int sbdsp_jazz16_probe __P((struct sbdsp_softc *)); - /* * Time constant routines follow. See SBK, section 12. * Although they don't come out and say it (in the docs), @@ -113,48 +112,106 @@ u_int sbdsp_jazz16_probe __P((struct sbdsp_softc *)); * output ls max 23 KHz 23 KHz * output hs max 44.1 KHz 44.1 KHz */ -#define SB_LS_MIN 0x06 /* 4000 Hz */ -#define SB_8K 0x83 /* 8000 Hz */ -#define SBPRO_ADC_LS_MAX 0xd4 /* 22727 Hz */ -#define SBPRO_ADC_HS_MAX 0xea /* 45454 Hz */ -#define SBCLA_ADC_LS_MAX 0xb3 /* 12987 Hz */ -#define SBCLA_ADC_HS_MAX 0xbd /* 14925 Hz */ -#define SB_DAC_LS_MAX 0xd4 /* 22727 Hz */ -#define SB_DAC_HS_MAX 0xea /* 45454 Hz */ - -int sbdsp16_wait __P((struct sbdsp_softc *)); +/* XXX Should we round the tc? +#define SB_RATE_TO_TC(x) (((65536 - 256 * 1000000 / (x)) + 128) >> 8) +*/ +#define SB_RATE_TO_TC(x) (256 - 1000000 / (x)) +#define SB_TC_TO_RATE(tc) (1000000 / (256 - (tc))) + +struct sbmode { + short model; + u_char channels; + u_char precision; + u_short lowrate, highrate; + u_char cmd; + u_char cmdchan; +}; +static struct sbmode sbpmodes[] = { + { SB_1, 1, 8, 4000, 22727, SB_DSP_WDMA }, + { SB_20, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP }, + { SB_2x, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP }, + { SB_2x, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT }, + { SB_PRO, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP }, + { SB_PRO, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT }, + { SB_PRO, 2, 8, 11025, 22727, SB_DSP_HS_OUTPUT }, + /* Yes, we write the record mode to set 16-bit playback mode. weird, huh? */ + { SB_JAZZ, 1, 8, 4000, 22727, SB_DSP_WDMA_LOOP, SB_DSP_RECORD_MONO }, + { SB_JAZZ, 1, 8, 22727, 45454, SB_DSP_HS_OUTPUT, SB_DSP_RECORD_MONO }, + { SB_JAZZ, 2, 8, 11025, 22727, SB_DSP_HS_OUTPUT, SB_DSP_RECORD_STEREO }, + { SB_JAZZ, 1, 16, 4000, 22727, SB_DSP_WDMA_LOOP, JAZZ16_RECORD_MONO }, + { SB_JAZZ, 1, 16, 22727, 45454, SB_DSP_HS_OUTPUT, JAZZ16_RECORD_MONO }, + { SB_JAZZ, 2, 16, 11025, 22727, SB_DSP_HS_OUTPUT, JAZZ16_RECORD_STEREO }, + { SB_16, 1, 8, 5000, 45000, SB_DSP16_WDMA_8 }, + { SB_16, 2, 8, 5000, 45000, SB_DSP16_WDMA_8 }, +#define PLAY16 15 /* must be the index of the next entry in the table */ + { SB_16, 1, 16, 5000, 45000, SB_DSP16_WDMA_16 }, + { SB_16, 2, 16, 5000, 45000, SB_DSP16_WDMA_16 }, + { -1 } +}; +static struct sbmode sbrmodes[] = { + { SB_1, 1, 8, 4000, 12987, SB_DSP_RDMA }, + { SB_20, 1, 8, 4000, 12987, SB_DSP_RDMA_LOOP }, + { SB_2x, 1, 8, 4000, 12987, SB_DSP_RDMA_LOOP }, + { SB_2x, 1, 8, 12987, 14925, SB_DSP_HS_INPUT }, + { SB_PRO, 1, 8, 4000, 22727, SB_DSP_RDMA_LOOP, SB_DSP_RECORD_MONO }, + { SB_PRO, 1, 8, 22727, 45454, SB_DSP_HS_INPUT, SB_DSP_RECORD_MONO }, + { SB_PRO, 2, 8, 11025, 22727, SB_DSP_HS_INPUT, SB_DSP_RECORD_STEREO }, + { SB_JAZZ, 1, 8, 4000, 22727, SB_DSP_RDMA_LOOP, SB_DSP_RECORD_MONO }, + { SB_JAZZ, 1, 8, 22727, 45454, SB_DSP_HS_INPUT, SB_DSP_RECORD_MONO }, + { SB_JAZZ, 2, 8, 11025, 22727, SB_DSP_HS_INPUT, SB_DSP_RECORD_STEREO }, + { SB_JAZZ, 1, 16, 4000, 22727, SB_DSP_RDMA_LOOP, JAZZ16_RECORD_MONO }, + { SB_JAZZ, 1, 16, 22727, 45454, SB_DSP_HS_INPUT, JAZZ16_RECORD_MONO }, + { SB_JAZZ, 2, 16, 11025, 22727, SB_DSP_HS_INPUT, JAZZ16_RECORD_STEREO }, + { SB_16, 1, 8, 5000, 45000, SB_DSP16_RDMA_8 }, + { SB_16, 2, 8, 5000, 45000, SB_DSP16_RDMA_8 }, + { SB_16, 1, 16, 5000, 45000, SB_DSP16_RDMA_16 }, + { SB_16, 2, 16, 5000, 45000, SB_DSP16_RDMA_16 }, + { -1 } +}; + +void sbversion __P((struct sbdsp_softc *)); +void sbdsp_jazz16_probe __P((struct sbdsp_softc *)); +void sbdsp_set_mixer_gain __P((struct sbdsp_softc *sc, int port)); void sbdsp_to __P((void *)); void sbdsp_pause __P((struct sbdsp_softc *)); -int sbdsp16_setrate __P((struct sbdsp_softc *, int, int, int *)); -int sbdsp_tctosr __P((struct sbdsp_softc *, int)); int sbdsp_set_timeconst __P((struct sbdsp_softc *, int)); +int sbdsp16_set_rate __P((struct sbdsp_softc *, int, int)); +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)); +static int sbdsp_adjust __P((int, int)); #ifdef AUDIO_DEBUG void sb_printsc __P((struct sbdsp_softc *)); -#endif -#ifdef AUDIO_DEBUG void sb_printsc(sc) struct sbdsp_softc *sc; { int i; - printf("open %d dmachan %d/%d/%d iobase %x\n", - sc->sc_open, sc->dmachan, sc->sc_drq8, sc->sc_drq16, sc->sc_iobase); - printf("irate %d itc %d imode %d orate %d otc %d omode %d encoding %x\n", - sc->sc_irate, sc->sc_itc, sc->sc_imode, - sc->sc_orate, sc->sc_otc, sc->sc_omode, sc->sc_encoding); - printf("outport %d inport %d spkron %d nintr %lu\n", - sc->out_port, sc->in_port, sc->spkr_state, sc->sc_interrupts); - printf("precision %d channels %d intr %p arg %p\n", - sc->sc_precision, sc->sc_channels, sc->sc_intr, sc->sc_arg); - printf("gain: "); + printf("open %d dmachan %d/%d %d/%d iobase 0x%x irq %d\n", + (int)sc->sc_open, sc->sc_i.run, sc->sc_o.run, + sc->sc_drq8, sc->sc_drq16, + sc->sc_iobase, sc->sc_irq); + printf("irate %d itc %x orate %d otc %x\n", + sc->sc_i.rate, sc->sc_i.tc, + sc->sc_o.rate, sc->sc_o.tc); + printf("spkron %u nintr %lu\n", + sc->spkr_state, sc->sc_interrupts); + printf("intr8 %p arg8 %p\n", + sc->sc_intr8, sc->sc_arg16); + printf("intr16 %p arg16 %p\n", + sc->sc_intr8, sc->sc_arg16); + printf("gain:"); for (i = 0; i < SB_NDEVS; i++) - printf("%d ", sc->gain[i]); + printf(" %u,%u", sc->gain[i][SB_LEFT], sc->gain[i][SB_RIGHT]); printf("\n"); } -#endif +#endif /* AUDIO_DEBUG */ /* * Probe / attach routines. @@ -173,19 +230,22 @@ sbdsp_probe(sc) return 0; } /* if flags set, go and probe the jazz16 stuff */ - if (sc->sc_dev.dv_cfdata->cf_flags != 0) { - sc->sc_model = sbdsp_jazz16_probe(sc); - } else { - sc->sc_model = sbversion(sc); + if (sc->sc_dev.dv_cfdata->cf_flags & 1) + sbdsp_jazz16_probe(sc); + else + sbversion(sc); + if (sc->sc_model == SB_UNK) { + /* Unknown SB model found. */ + DPRINTF(("sbdsp: unknown SB model found\n")); + return 0; } - return 1; } /* * Try add-on stuff for Jazz16. */ -u_int +void sbdsp_jazz16_probe(sc) struct sbdsp_softc *sc; { @@ -198,15 +258,16 @@ sbdsp_jazz16_probe(sc) -1, 0x01, -1, 0x02, -1, 0x03, -1, 0x04}; - u_int rval = sbversion(sc); bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh; + sbversion(sc); + DPRINTF(("jazz16 probe\n")); if (bus_space_map(iot, JAZZ16_CONFIG_PORT, 1, 0, &ioh)) { DPRINTF(("bus map failed\n")); - return rval; + return; } if (jazz16_drq_conf[sc->sc_drq8] == (u_char)-1 || @@ -244,12 +305,12 @@ sbdsp_jazz16_probe(sc) DPRINTF(("sbdsp: can't write jazz16 probe stuff\n")); } else { DPRINTF(("jazz16 detected!\n")); - rval |= MODEL_JAZZ16; + sc->sc_model = SB_JAZZ; + sc->sc_mixer_model = SBM_CT1345; /* XXX really? */ } done: bus_space_unmap(iot, ioh, 1); - return rval; } /* @@ -260,49 +321,81 @@ void sbdsp_attach(sc) struct sbdsp_softc *sc; { + struct audio_params pparams, rparams; + int i; + u_int v; - /* Set defaults */ - if (ISSB16CLASS(sc)) - sc->sc_irate = sc->sc_orate = 8000; - else if (ISSBPROCLASS(sc)) - sc->sc_itc = sc->sc_otc = SB_8K; - else - sc->sc_itc = sc->sc_otc = SB_8K; - sc->sc_encoding = AUDIO_ENCODING_ULAW; - sc->sc_precision = 8; - sc->sc_channels = 1; - - (void) sbdsp_set_in_port(sc, SB_MIC_PORT); - (void) sbdsp_set_out_port(sc, SB_SPEAKER); - - if (ISSBPROCLASS(sc)) { - int i; - - /* set mixer to default levels, by sending a mixer - reset command. */ + /* + * Create our DMA maps. + */ + if (sc->sc_drq8 != -1) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_drq8, + MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("%s: can't create map for drq %d\n", + sc->sc_dev.dv_xname, sc->sc_drq8); + return; + } + } + if (sc->sc_drq16 != -1 && sc->sc_drq16 != sc->sc_drq8) { + if (isa_dmamap_create(sc->sc_isa, sc->sc_drq16, + MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { + printf("%s: can't create map for drq %d\n", + sc->sc_dev.dv_xname, sc->sc_drq16); + return; + } + } + + pparams = audio_default; + rparams = audio_default; + sbdsp_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams); + + sbdsp_set_in_ports(sc, 1 << SB_MIC_VOL); + + if (sc->sc_mixer_model != SBM_NONE) { + /* Reset the mixer.*/ sbdsp_mix_write(sc, SBP_MIX_RESET, SBP_MIX_RESET); - /* then some adjustments :) */ - sbdsp_mix_write(sc, SBP_CD_VOL, - sbdsp_stereo_vol(SBP_MAXVOL, SBP_MAXVOL)); - sbdsp_mix_write(sc, SBP_DAC_VOL, - sbdsp_stereo_vol(SBP_MAXVOL, SBP_MAXVOL)); - sbdsp_mix_write(sc, SBP_MASTER_VOL, - sbdsp_stereo_vol(SBP_MAXVOL/2, SBP_MAXVOL/2)); - sbdsp_mix_write(sc, SBP_LINE_VOL, - sbdsp_stereo_vol(SBP_MAXVOL, SBP_MAXVOL)); - for (i = 0; i < SB_NDEVS; i++) - sc->gain[i] = sbdsp_stereo_vol(SBP_MAXVOL, SBP_MAXVOL); + /* And set our own default values */ + for (i = 0; i < SB_NDEVS; i++) { + switch(i) { + case SB_MIC_VOL: + case SB_LINE_IN_VOL: + v = 0; + break; + case SB_BASS: + case SB_TREBLE: + v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN/2); + break; + case SB_CD_IN_MUTE: + case SB_MIC_IN_MUTE: + case SB_LINE_IN_MUTE: + case SB_MIDI_IN_MUTE: + case SB_CD_SWAP: + case SB_MIC_SWAP: + case SB_LINE_SWAP: + case SB_MIDI_SWAP: + case SB_CD_OUT_MUTE: + case SB_MIC_OUT_MUTE: + case SB_LINE_OUT_MUTE: + v = 0; + break; + default: + v = SB_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); + break; + } + sc->gain[i][SB_LEFT] = sc->gain[i][SB_RIGHT] = v; + sbdsp_set_mixer_gain(sc, i); + } sc->in_filter = 0; /* no filters turned on, please */ } printf(": dsp v%d.%02d%s\n", - SBVER_MAJOR(sc->sc_model), SBVER_MINOR(sc->sc_model), - ISJAZZ16(sc) ? ": <Jazz16>" : ""); -} + SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version), + sc->sc_model == SB_JAZZ ? ": <Jazz16>" : ""); -/* - * Various routines to interface to higher level audio driver - */ + sc->sc_fullduplex = ISSB16CLASS(sc) && + sc->sc_drq8 != -1 && sc->sc_drq16 != -1 && + sc->sc_drq8 != sc->sc_drq16; +} void sbdsp_mix_write(sc, mixerport, val) @@ -312,11 +405,14 @@ sbdsp_mix_write(sc, mixerport, val) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + int s; + s = splaudio(); bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport); - delay(10); + delay(20); bus_space_write_1(iot, ioh, SBP_MIXER_DATA, val); delay(30); + splx(s); } int @@ -326,305 +422,382 @@ sbdsp_mix_read(sc, mixerport) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; + int val; + int s; + s = splaudio(); bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport); - delay(10); - return bus_space_read_1(iot, ioh, SBP_MIXER_DATA); -} - -int -sbdsp_set_in_sr(addr, sr) - void *addr; - u_long sr; -{ - register struct sbdsp_softc *sc = addr; - - if (ISSB16CLASS(sc)) - return (sbdsp16_setrate(sc, sr, SB_INPUT_RATE, &sc->sc_irate)); - else - return (sbdsp_srtotc(sc, sr, SB_INPUT_RATE, &sc->sc_itc, &sc->sc_imode)); -} - -u_long -sbdsp_get_in_sr(addr) - void *addr; -{ - register struct sbdsp_softc *sc = addr; - - if (ISSB16CLASS(sc)) - return (sc->sc_irate); - else - return (sbdsp_tctosr(sc, sc->sc_itc)); -} - -int -sbdsp_set_out_sr(addr, sr) - void *addr; - u_long sr; -{ - register struct sbdsp_softc *sc = addr; - - if (ISSB16CLASS(sc)) - return (sbdsp16_setrate(sc, sr, SB_OUTPUT_RATE, &sc->sc_orate)); - else - return (sbdsp_srtotc(sc, sr, SB_OUTPUT_RATE, &sc->sc_otc, &sc->sc_omode)); + delay(20); + val = bus_space_read_1(iot, ioh, SBP_MIXER_DATA); + delay(30); + splx(s); + return val; } -u_long -sbdsp_get_out_sr(addr) - void *addr; -{ - register struct sbdsp_softc *sc = addr; - - if (ISSB16CLASS(sc)) - return (sc->sc_orate); - else - return (sbdsp_tctosr(sc, sc->sc_otc)); -} +/* + * Various routines to interface to higher level audio driver + */ int sbdsp_query_encoding(addr, fp) void *addr; struct audio_encoding *fp; { + struct sbdsp_softc *sc = addr; + int emul; + + emul = ISSB16CLASS(sc) ? 0 : AUDIO_ENCODINGFLAG_EMULATED; + switch (fp->index) { case 0: - strcpy(fp->name, AudioEmulaw); - fp->format_id = AUDIO_ENCODING_ULAW; - break; + strcpy(fp->name, AudioEulinear); + fp->encoding = AUDIO_ENCODING_ULINEAR; + fp->precision = 8; + fp->flags = 0; + return 0; case 1: - strcpy(fp->name, AudioEpcm16); - fp->format_id = AUDIO_ENCODING_PCM16; - break; - default: - return (EINVAL); - } - return (0); -} + strcpy(fp->name, AudioEmulaw); + fp->encoding = AUDIO_ENCODING_ULAW; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + return 0; + case 2: + strcpy(fp->name, AudioEalaw); + fp->encoding = AUDIO_ENCODING_ALAW; + fp->precision = 8; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + return 0; + case 3: + strcpy(fp->name, AudioEslinear); + fp->encoding = AUDIO_ENCODING_SLINEAR; + fp->precision = 8; + fp->flags = emul; + return 0; + } + if (!ISSB16CLASS(sc) && sc->sc_model != SB_JAZZ) + return EINVAL; -int -sbdsp_set_format(addr, encoding, precision) - void *addr; - u_int encoding, precision; -{ - register struct sbdsp_softc *sc = addr; - - switch (encoding) { - case AUDIO_ENCODING_ULAW: - case AUDIO_ENCODING_PCM16: - case AUDIO_ENCODING_PCM8: - break; + switch(fp->index) { + case 4: + strcpy(fp->name, AudioEslinear_le); + fp->encoding = AUDIO_ENCODING_SLINEAR_LE; + fp->precision = 16; + fp->flags = 0; + return 0; + case 5: + strcpy(fp->name, AudioEulinear_le); + fp->encoding = AUDIO_ENCODING_ULINEAR_LE; + fp->precision = 16; + fp->flags = emul; + return 0; + case 6: + strcpy(fp->name, AudioEslinear_be); + fp->encoding = AUDIO_ENCODING_SLINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + return 0; + case 7: + strcpy(fp->name, AudioEulinear_be); + fp->encoding = AUDIO_ENCODING_ULINEAR_BE; + fp->precision = 16; + fp->flags = AUDIO_ENCODINGFLAG_EMULATED; + return 0; default: - return (EINVAL); + return EINVAL; } - - if (precision == 16) - if (!ISSB16CLASS(sc) && !ISJAZZ16(sc)) - return (EINVAL); - - sc->sc_encoding = encoding; - sc->sc_precision = precision; - - return (0); + return 0; } int -sbdsp_get_encoding(addr) +sbdsp_set_params(addr, setmode, usemode, play, rec) void *addr; + int setmode, usemode; + struct audio_params *play, *rec; { - register struct sbdsp_softc *sc = addr; - - return (sc->sc_encoding); -} + struct sbdsp_softc *sc = addr; + struct sbmode *m; + u_int rate, tc, bmode; + void (*swcode) __P((void *, u_char *buf, int cnt)); + int factor; + int model; + int chan; + struct audio_params *p; + int mode; + + model = sc->sc_model; + if (model > SB_16) + model = SB_16; /* later models work like SB16 */ + + /* Set first record info, then play info */ + for(mode = AUMODE_RECORD; mode != -1; + mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { + if ((setmode & mode) == 0) + continue; -int -sbdsp_get_precision(addr) - void *addr; -{ - register struct sbdsp_softc *sc = addr; + p = mode == AUMODE_PLAY ? play : rec; + /* Locate proper commands */ + for(m = mode == AUMODE_PLAY ? sbpmodes : sbrmodes; + m->model != -1; m++) { + if (model == m->model && + p->channels == m->channels && + p->precision == m->precision && + p->sample_rate >= m->lowrate && + p->sample_rate < m->highrate) + break; + } + if (m->model == -1) + return EINVAL; + rate = p->sample_rate; + swcode = 0; + factor = 1; + tc = 1; + bmode = -1; + if (model == SB_16) { + switch (p->encoding) { + case AUDIO_ENCODING_SLINEAR_BE: + if (p->precision == 16) + swcode = swap_bytes; + /* fall into */ + case AUDIO_ENCODING_SLINEAR_LE: + bmode = SB_BMODE_SIGNED; + break; + case AUDIO_ENCODING_ULINEAR_BE: + if (p->precision == 16) + swcode = swap_bytes; + /* fall into */ + case AUDIO_ENCODING_ULINEAR_LE: + bmode = SB_BMODE_UNSIGNED; + break; + case AUDIO_ENCODING_ULAW: + if (mode == AUMODE_PLAY) { + swcode = mulaw_to_ulinear16; + factor = 2; + m = &sbpmodes[PLAY16]; + } else + swcode = ulinear8_to_mulaw; + bmode = SB_BMODE_UNSIGNED; + break; + case AUDIO_ENCODING_ALAW: + if (mode == AUMODE_PLAY) { + swcode = alaw_to_ulinear16; + factor = 2; + m = &sbpmodes[PLAY16]; + } else + swcode = ulinear8_to_alaw; + bmode = SB_BMODE_UNSIGNED; + break; + default: + return EINVAL; + } + if (p->channels == 2) + bmode |= SB_BMODE_STEREO; + } else if (m->model == SB_JAZZ && m->precision == 16) { + switch (p->encoding) { + case AUDIO_ENCODING_SLINEAR_LE: + break; + case AUDIO_ENCODING_ULINEAR_LE: + swcode = change_sign16; + break; + case AUDIO_ENCODING_SLINEAR_BE: + swcode = swap_bytes; + break; + case AUDIO_ENCODING_ULINEAR_BE: + swcode = mode == AUMODE_PLAY ? + swap_bytes_change_sign16 : change_sign16_swap_bytes; + break; + case AUDIO_ENCODING_ULAW: + swcode = mode == AUMODE_PLAY ? + mulaw_to_ulinear8 : ulinear8_to_mulaw; + break; + case AUDIO_ENCODING_ALAW: + swcode = mode == AUMODE_PLAY ? + alaw_to_ulinear8 : ulinear8_to_alaw; + break; + default: + return EINVAL; + } + tc = SB_RATE_TO_TC(p->sample_rate * p->channels); + p->sample_rate = SB_TC_TO_RATE(tc) / p->channels; + } else { + switch (p->encoding) { + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_SLINEAR_LE: + swcode = change_sign8; + break; + case AUDIO_ENCODING_ULINEAR_BE: + case AUDIO_ENCODING_ULINEAR_LE: + break; + case AUDIO_ENCODING_ULAW: + swcode = mode == AUMODE_PLAY ? + mulaw_to_ulinear8 : ulinear8_to_mulaw; + break; + case AUDIO_ENCODING_ALAW: + swcode = mode == AUMODE_PLAY ? + alaw_to_ulinear8 : ulinear8_to_alaw; + break; + default: + return EINVAL; + } + tc = SB_RATE_TO_TC(p->sample_rate * p->channels); + p->sample_rate = SB_TC_TO_RATE(tc) / p->channels; + } - return (sc->sc_precision); -} + chan = m->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; + if (mode == AUMODE_PLAY) { + sc->sc_o.rate = rate; + sc->sc_o.tc = tc; + sc->sc_o.modep = m; + sc->sc_o.bmode = bmode; + sc->sc_o.dmachan = chan; + } else { + sc->sc_i.rate = rate; + sc->sc_i.tc = tc; + sc->sc_i.modep = m; + sc->sc_i.bmode = bmode; + sc->sc_i.dmachan = chan; + } -int -sbdsp_set_channels(addr, channels) - void *addr; - int channels; -{ - register struct sbdsp_softc *sc = addr; + p->sw_code = swcode; + p->factor = factor; + DPRINTF(("sbdsp_set_params: model=%d, mode=%d, rate=%ld, prec=%d, chan=%d, enc=%d -> tc=%02x, cmd=%02x, bmode=%02x, cmdchan=%02x, swcode=%p, factor=%d\n", + sc->sc_model, mode, p->sample_rate, p->precision, p->channels, + p->encoding, tc, m->cmd, bmode, m->cmdchan, swcode, factor)); - if (ISSBPROCLASS(sc)) { - if (channels != 1 && channels != 2) - return (EINVAL); - sc->sc_channels = channels; - sc->sc_dmadir = SB_DMA_NONE; - /* - * XXXX - * With 2 channels, SBPro can't do more than 22kHz. - * No framework to check this. - */ - } else { - if (channels != 1) - return (EINVAL); - sc->sc_channels = channels; } - - return (0); -} + /* + * XXX + * Should wait for chip to be idle. + */ + sc->sc_i.run = SB_NOTRUNNING; + sc->sc_o.run = SB_NOTRUNNING; + + if (sc->sc_fullduplex && + (usemode & (AUMODE_PLAY | AUMODE_RECORD)) == (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)); + if (sc->sc_o.dmachan == sc->sc_drq8) { + /* Use 16 bit DMA for playing by expanding the samples. */ + play->sw_code = linear8_to_linear16; + play->factor = 2; + sc->sc_o.modep = &sbpmodes[PLAY16]; + sc->sc_o.dmachan = sc->sc_drq16; + } else { + return EINVAL; + } + } + DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n", sc->sc_i.dmachan, sc->sc_o.dmachan)); -int -sbdsp_get_channels(addr) - void *addr; -{ - register struct sbdsp_softc *sc = addr; - - return (sc->sc_channels); + return 0; } -int +void sbdsp_set_ifilter(addr, which) void *addr; int which; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; int mixval; - /* XXXX SB16 */ - if (ISSBPROCLASS(sc)) { - mixval = sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK; - switch (which) { - case 0: - mixval |= SBP_FILTER_OFF; - break; - case SBP_TREBLE_EQ: - mixval |= SBP_FILTER_ON | SBP_IFILTER_HIGH; - break; - case SBP_BASS_EQ: - mixval |= SBP_FILTER_ON | SBP_IFILTER_LOW; - break; - default: - return (EINVAL); - } - sc->in_filter = mixval & SBP_IFILTER_MASK; - sbdsp_mix_write(sc, SBP_INFILTER, mixval); - return (0); - } else - return (EINVAL); + mixval = sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK; + switch (which) { + case 0: + mixval |= SBP_FILTER_OFF; + break; + case SB_TREBLE: + mixval |= SBP_FILTER_ON | SBP_IFILTER_HIGH; + break; + case SB_BASS: + mixval |= SBP_FILTER_ON | SBP_IFILTER_LOW; + break; + default: + return; + } + sc->in_filter = mixval & SBP_IFILTER_MASK; + sbdsp_mix_write(sc, SBP_INFILTER, mixval); } int sbdsp_get_ifilter(addr) void *addr; { - register struct sbdsp_softc *sc = addr; - - /* XXXX SB16 */ - if (ISSBPROCLASS(sc)) { - sc->in_filter = - sbdsp_mix_read(sc, SBP_INFILTER) & SBP_IFILTER_MASK; - switch (sc->in_filter) { - case SBP_FILTER_ON|SBP_IFILTER_HIGH: - return (SBP_TREBLE_EQ); - case SBP_FILTER_ON|SBP_IFILTER_LOW: - return (SBP_BASS_EQ); - case SBP_FILTER_OFF: - default: - return (0); - } - } else - return (0); -} - -int -sbdsp_set_out_port(addr, port) - void *addr; - int port; -{ - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; - sc->out_port = port; /* Just record it */ - - return (0); + sc->in_filter = + sbdsp_mix_read(sc, SBP_INFILTER) & SBP_IFILTER_MASK; + switch (sc->in_filter) { + case SBP_FILTER_ON|SBP_IFILTER_HIGH: + return SB_TREBLE; + case SBP_FILTER_ON|SBP_IFILTER_LOW: + return SB_BASS; + default: + return 0; + } } int -sbdsp_get_out_port(addr) - void *addr; +sbdsp_set_in_ports(sc, mask) + struct sbdsp_softc *sc; + int mask; { - register struct sbdsp_softc *sc = addr; - - return (sc->out_port); -} + int bitsl, bitsr; + int sbport; + DPRINTF(("sbdsp_set_in_ports: model=%d, mask=%x\n", + sc->sc_mixer_model, mask)); -int -sbdsp_set_in_port(addr, port) - void *addr; - int port; -{ - register struct sbdsp_softc *sc = addr; - int mixport, sbport; - - if (ISSBPROCLASS(sc)) { - switch (port) { - case SB_MIC_PORT: + switch(sc->sc_mixer_model) { + case SBM_NONE: + return EINVAL; + case SBM_CT1335: + if (mask != (1 << SB_MIC_VOL)) + return EINVAL; + break; + case SBM_CT1345: + switch (mask) { + case 1 << SB_MIC_VOL: sbport = SBP_FROM_MIC; - mixport = SBP_MIC_VOL; break; - case SB_LINE_IN_PORT: + case 1 << SB_LINE_IN_VOL: sbport = SBP_FROM_LINE; - mixport = SBP_LINE_VOL; break; - case SB_CD_PORT: + case 1 << SB_CD_VOL: sbport = SBP_FROM_CD; - mixport = SBP_CD_VOL; break; - case SB_DAC_PORT: - case SB_FM_PORT: default: return (EINVAL); } - } else { - switch (port) { - case SB_MIC_PORT: - sbport = SBP_FROM_MIC; - mixport = SBP_MIC_VOL; - break; - default: - return (EINVAL); + sbdsp_mix_write(sc, SBP_RECORD_SOURCE, sbport | sc->in_filter); + break; + case SBM_CT1XX5: + case SBM_CT1745: + if (mask & ~((1<<SB_MIDI_VOL) | (1<<SB_LINE_IN_VOL) | + (1<<SB_CD_VOL) | (1<<SB_MIC_VOL))) + return EINVAL; + bitsr = 0; + if (mask & (1<<SB_MIDI_VOL)) bitsr |= SBP_MIDI_SRC_R; + if (mask & (1<<SB_LINE_IN_VOL)) bitsr |= SBP_LINE_SRC_R; + if (mask & (1<<SB_CD_VOL)) bitsr |= SBP_CD_SRC_R; + bitsl = SB_SRC_R_TO_L(bitsr); + if (mask & (1<<SB_MIC_VOL)) { + bitsl |= SBP_MIC_SRC; + bitsr |= SBP_MIC_SRC; } - } - - sc->in_port = port; /* Just record it */ - - /* XXXX SB16 */ - if (ISSBPROCLASS(sc)) { - /* record from that port */ - sbdsp_mix_write(sc, SBP_RECORD_SOURCE, - SBP_RECORD_FROM(sbport, SBP_FILTER_OFF, SBP_IFILTER_HIGH)); - /* fetch gain from that port */ - sc->gain[port] = sbdsp_mix_read(sc, mixport); + sbdsp_mix_write(sc, SBP_RECORD_SOURCE_L, bitsl); + sbdsp_mix_write(sc, SBP_RECORD_SOURCE_R, bitsr); + break; } - return (0); -} - -int -sbdsp_get_in_port(addr) - void *addr; -{ - register struct sbdsp_softc *sc = addr; + sc->in_mask = mask; - return (sc->in_port); + return 0; } - int sbdsp_speaker_ctl(addr, newstate) void *addr; int newstate; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; if ((newstate == SPKR_ON) && (sc->spkr_state == SPKR_OFF)) { @@ -636,7 +809,7 @@ sbdsp_speaker_ctl(addr, newstate) sbdsp_spkroff(sc); sc->spkr_state = SPKR_OFF; } - return(0); + return 0; } int @@ -644,83 +817,26 @@ sbdsp_round_blocksize(addr, blk) void *addr; int blk; { - register struct sbdsp_softc *sc = addr; - - sc->sc_last_hs_size = 0; - - /* Don't try to DMA too much at once. */ - if (blk > NBPG) - blk = NBPG; - - /* Round to a multiple of the sample size. */ - blk &= -(sc->sc_channels * sc->sc_precision / 8); - - return (blk); + blk &= -4; /* round to biggest sample size */ + return blk; } int -sbdsp_commit_settings(addr) +sbdsp_open(addr, flags) void *addr; -{ - register struct sbdsp_softc *sc = addr; - - /* due to potentially unfortunate ordering in the above layers, - re-do a few sets which may be important--input gains - (adjust the proper channels), number of input channels (hit the - record rate and set mode) */ - - if (ISSBPRO(sc)) { - /* - * With 2 channels, SBPro can't do more than 22kHz. - * Whack the rates down to speed if necessary. - * Reset the time constant anyway - * because it may have been adjusted with a different number - * of channels, which means it might have computed the wrong - * mode (low/high speed). - */ - if (sc->sc_channels == 2 && - sbdsp_tctosr(sc, sc->sc_itc) > 22727) { - sbdsp_srtotc(sc, 22727, SB_INPUT_RATE, - &sc->sc_itc, &sc->sc_imode); - } else - sbdsp_srtotc(sc, sbdsp_tctosr(sc, sc->sc_itc), - SB_INPUT_RATE, &sc->sc_itc, - &sc->sc_imode); - - if (sc->sc_channels == 2 && - sbdsp_tctosr(sc, sc->sc_otc) > 22727) { - sbdsp_srtotc(sc, 22727, SB_OUTPUT_RATE, - &sc->sc_otc, &sc->sc_omode); - } else - sbdsp_srtotc(sc, sbdsp_tctosr(sc, sc->sc_otc), - SB_OUTPUT_RATE, &sc->sc_otc, - &sc->sc_omode); - } - - /* - * XXX - * Should wait for chip to be idle. - */ - sc->sc_dmadir = SB_DMA_NONE; - - return 0; -} - - -int -sbdsp_open(sc, dev, flags) - register struct sbdsp_softc *sc; - dev_t dev; int flags; { - DPRINTF(("sbdsp_open: sc=0x%x\n", sc)); + struct sbdsp_softc *sc = addr; + + DPRINTF(("sbdsp_open: sc=%p\n", sc)); if (sc->sc_open != 0 || sbdsp_reset(sc) != 0) return ENXIO; sc->sc_open = 1; + sc->sc_openflags = flags; sc->sc_mintr = 0; - if (ISSBPROCLASS(sc) && + if (ISSBPRO(sc) && sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) { DPRINTF(("sbdsp_open: can't set mono mode\n")); /* we'll readjust when it's time for DMA. */ @@ -743,11 +859,13 @@ sbdsp_close(addr) { struct sbdsp_softc *sc = addr; - DPRINTF(("sbdsp_close: sc=0x%x\n", sc)); + DPRINTF(("sbdsp_close: sc=%p\n", sc)); sc->sc_open = 0; sbdsp_spkroff(sc); sc->spkr_state = SPKR_OFF; + sc->sc_intr8 = 0; + sc->sc_intr16 = 0; sc->sc_mintr = 0; sbdsp_haltdma(sc); @@ -764,17 +882,21 @@ sbdsp_close(addr) */ int sbdsp_reset(sc) - register struct sbdsp_softc *sc; + struct sbdsp_softc *sc; { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - sc->sc_intr = 0; - if (sc->sc_dmadir != SB_DMA_NONE) { - isadma_abort(sc->dmachan); - sc->sc_dmadir = SB_DMA_NONE; + sc->sc_intr8 = 0; + sc->sc_intr16 = 0; + if (sc->sc_i.run != SB_NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_i.dmachan); + sc->sc_i.run = SB_NOTRUNNING; + } + if (sc->sc_o.run != SB_NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_o.dmachan); + sc->sc_o.run = SB_NOTRUNNING; } - sc->sc_last_hs_size = 0; /* * See SBK, section 11.3. @@ -791,29 +913,9 @@ sbdsp_reset(sc) return 0; } -int -sbdsp16_wait(sc) - struct sbdsp_softc *sc; -{ - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - register int i; - - for (i = SBDSP_NPOLL; --i >= 0; ) { - register u_char x; - x = bus_space_read_1(iot, ioh, SBP_DSP_WSTAT); - delay(10); - if ((x & SB_DSP_BUSY) == 0) - continue; - return 0; - } - ++sberr.wdsp; - return -1; -} - /* * Write a byte to the dsp. - * XXX We are at the mercy of the card as we use a + * We are at the mercy of the card as we use a * polling loop and wait until it can take the byte. */ int @@ -823,17 +925,17 @@ sbdsp_wdsp(sc, v) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - register int i; + int i; + u_char x; for (i = SBDSP_NPOLL; --i >= 0; ) { - register u_char x; x = bus_space_read_1(iot, ioh, SBP_DSP_WSTAT); delay(10); - if ((x & SB_DSP_BUSY) != 0) - continue; - bus_space_write_1(iot, ioh, SBP_DSP_WRITE, v); - delay(10); - return 0; + if ((x & SB_DSP_BUSY) == 0) { + bus_space_write_1(iot, ioh, SBP_DSP_WRITE, v); + delay(10); + return 0; + } } ++sberr.wdsp; return -1; @@ -848,17 +950,17 @@ sbdsp_rdsp(sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - register int i; + int i; + u_char x; for (i = SBDSP_NPOLL; --i >= 0; ) { - register u_char x; x = bus_space_read_1(iot, ioh, SBP_DSP_RSTAT); delay(10); - if ((x & SB_DSP_READY) == 0) - continue; - x = bus_space_read_1(iot, ioh, SBP_DSP_READ); - delay(10); - return x; + if (x & SB_DSP_READY) { + x = bus_space_read_1(iot, ioh, SBP_DSP_READ); + delay(10); + return x; + } } ++sberr.rdsp; return -1; @@ -915,187 +1017,166 @@ sbdsp_spkroff(sc) } /* - * Read the version number out of the card. Return major code - * in high byte, and minor code in low byte. + * Read the version number out of the card. + * Store version information in the softc. */ -short +void sbversion(sc) struct sbdsp_softc *sc; { - short v; + int v; + sc->sc_model = SB_UNK; + sc->sc_version = 0; if (sbdsp_wdsp(sc, SB_DSP_VERSION) < 0) - return 0; + return; v = sbdsp_rdsp(sc) << 8; v |= sbdsp_rdsp(sc); - return ((v >= 0) ? v : 0); + if (v < 0) + return; + sc->sc_version = v; + switch(SBVER_MAJOR(v)) { + case 1: + sc->sc_mixer_model = SBM_NONE; + sc->sc_model = SB_1; + break; + case 2: + /* Some SB2 have a mixer, some don't. */ + sbdsp_mix_write(sc, SBP_1335_MASTER_VOL, 0x04); + sbdsp_mix_write(sc, SBP_1335_MIDI_VOL, 0x06); + /* Check if we can read back the mixer values. */ + if ((sbdsp_mix_read(sc, SBP_1335_MASTER_VOL) & 0x0e) == 0x04 && + (sbdsp_mix_read(sc, SBP_1335_MIDI_VOL) & 0x0e) == 0x06) + sc->sc_mixer_model = SBM_CT1335; + else + sc->sc_mixer_model = SBM_NONE; + if (SBVER_MINOR(v) == 0) + sc->sc_model = SB_20; + else + sc->sc_model = SB_2x; + break; + case 3: + sc->sc_mixer_model = SBM_CT1345; + sc->sc_model = SB_PRO; + break; + case 4: +#if 0 +/* XXX This does not work */ + /* Most SB16 have a tone controls, but some don't. */ + sbdsp_mix_write(sc, SB16P_TREBLE_L, 0x80); + /* Check if we can read back the mixer value. */ + if ((sbdsp_mix_read(sc, SB16P_TREBLE_L) & 0xf0) == 0x80) + sc->sc_mixer_model = SBM_CT1745; + else + sc->sc_mixer_model = SBM_CT1XX5; +#else + sc->sc_mixer_model = SBM_CT1745; +#endif +#if 0 +/* XXX figure out a good way of determining the model */ + /* XXX what about SB_32 */ + if (SBVER_MINOR(v) == 16) + sc->sc_model = SB_64; + else +#endif + sc->sc_model = SB_16; + break; + } } /* - * Halt a DMA in progress. A low-speed transfer can be - * resumed with sbdsp_contdma(). + * Halt a DMA in progress. */ int sbdsp_haltdma(addr) void *addr; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; - DPRINTF(("sbdsp_haltdma: sc=0x%x\n", sc)); + DPRINTF(("sbdsp_haltdma: sc=%p\n", sc)); sbdsp_reset(sc); return 0; } int -sbdsp_contdma(addr) - void *addr; +sbdsp_set_timeconst(sc, tc) + struct sbdsp_softc *sc; + int tc; { - register struct sbdsp_softc *sc = addr; - - DPRINTF(("sbdsp_contdma: sc=0x%x\n", sc)); + DPRINTF(("sbdsp_set_timeconst: sc=%p tc=%d\n", sc, tc)); - /* XXX how do we reinitialize the DMA controller state? do we care? */ - (void)sbdsp_wdsp(sc, SB_DSP_CONT); - return(0); + if (sbdsp_wdsp(sc, SB_DSP_TIMECONST) < 0 || + sbdsp_wdsp(sc, tc) < 0) + return EIO; + + return 0; } int -sbdsp16_setrate(sc, sr, isdac, ratep) - register struct sbdsp_softc *sc; - int sr; - int isdac; - int *ratep; +sbdsp16_set_rate(sc, cmd, rate) + struct sbdsp_softc *sc; + int cmd, rate; { + DPRINTF(("sbdsp16_set_rate: sc=%p cmd=0x%02x rate=%d\n", sc, cmd, rate)); - /* - * XXXX - * More checks here? - */ - if (sr < 5000 || sr > 45454) - return (EINVAL); - *ratep = sr; - return (0); + if (sbdsp_wdsp(sc, cmd) < 0 || + sbdsp_wdsp(sc, rate >> 8) < 0 || + sbdsp_wdsp(sc, rate) < 0) + return EIO; + return 0; } -/* - * Convert a linear sampling rate into the DAC time constant. - * Set *mode to indicate the high/low-speed DMA operation. - * Because of limitations of the card, not all rates are possible. - * We return the time constant of the closest possible rate. - * The sampling rate limits are different for the DAC and ADC, - * so isdac indicates output, and !isdac indicates input. - */ int -sbdsp_srtotc(sc, sr, isdac, tcp, modep) - register struct sbdsp_softc *sc; - int sr; - int isdac; - int *tcp, *modep; +sbdsp_dma_init_input(addr, buf, cc) + void *addr; + void *buf; + int cc; { - int tc, realtc, mode; + struct sbdsp_softc *sc = addr; - /* - * Don't forget to compute which mode we'll be in based on whether - * we need to double the rate for stereo on SBPRO. - */ - - if (sr == 0) { - tc = SB_LS_MIN; - mode = SB_ADAC_LS; - goto out; - } + 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; +} - tc = 256 - (1000000 / sr); +static int +sbdsp_dma_setup_input(sc) + struct sbdsp_softc *sc; +{ + int stereo = sc->sc_i.modep->channels == 2; + int filter; - if (sc->sc_channels == 2 && ISSBPRO(sc)) - /* compute based on 2x sample rate when needed */ - realtc = 256 - ( 500000 / sr); - else - realtc = tc; + /* Initialize the PCM */ + if (ISSBPRO(sc)) { + if (sbdsp_wdsp(sc, sc->sc_i.modep->cmdchan) < 0) + return 0; + filter = stereo ? SBP_FILTER_OFF : sc->in_filter; + sbdsp_mix_write(sc, SBP_INFILTER, + (sbdsp_mix_read(sc, SBP_INFILTER) & + ~SBP_IFILTER_MASK) | filter); + } - if (tc < SB_LS_MIN) { - tc = SB_LS_MIN; - mode = SB_ADAC_LS; /* NB: 2x minimum speed is still low - * speed mode. */ - goto out; - } else if (isdac) { - if (realtc <= SB_DAC_LS_MAX) - mode = SB_ADAC_LS; - else { - mode = SB_ADAC_HS; - if (tc > SB_DAC_HS_MAX) - tc = SB_DAC_HS_MAX; + 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", + sc->sc_i.rate)); + return 0; } } else { - int adc_ls_max, adc_hs_max; - - /* XXX use better rounding--compare distance to nearest tc on both - sides of requested speed */ - if (ISSBPROCLASS(sc)) { - adc_ls_max = SBPRO_ADC_LS_MAX; - adc_hs_max = SBPRO_ADC_HS_MAX; - } else { - adc_ls_max = SBCLA_ADC_LS_MAX; - adc_hs_max = SBCLA_ADC_HS_MAX; - } - - if (realtc <= adc_ls_max) - mode = SB_ADAC_LS; - else { - mode = SB_ADAC_HS; - if (tc > adc_hs_max) - tc = adc_hs_max; + if (sbdsp_set_timeconst(sc, sc->sc_i.tc)) { + DPRINTF(("sbdsp_dma_setup_input: tc=%d set failed\n", + sc->sc_i.rate)); + return 0; } } - -out: - *tcp = tc; - *modep = mode; - return (0); -} - -/* - * Convert a DAC time constant to a sampling rate. - * See SBK, section 12. - */ -int -sbdsp_tctosr(sc, tc) - register struct sbdsp_softc *sc; - int tc; -{ - int adc; - - if (ISSBPROCLASS(sc)) - adc = SBPRO_ADC_HS_MAX; - else - adc = SBCLA_ADC_HS_MAX; - - if (tc > adc) - tc = adc; - - return (1000000 / (256 - tc)); -} - -int -sbdsp_set_timeconst(sc, tc) - register struct sbdsp_softc *sc; - int tc; -{ - /* - * A SBPro in stereo mode uses time constants at double the - * actual rate. - */ - if (ISSBPRO(sc) && sc->sc_channels == 2) - tc = 256 - ((256 - tc) / 2); - - DPRINTF(("sbdsp_set_timeconst: sc=%p tc=%d\n", sc, tc)); - - if (sbdsp_wdsp(sc, SB_DSP_TIMECONST) < 0 || - sbdsp_wdsp(sc, tc) < 0) - return (EIO); - - return (0); + return 1; } int @@ -1106,119 +1187,171 @@ sbdsp_dma_input(addr, p, cc, intr, arg) void (*intr) __P((void *)); void *arg; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_dma_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("sbdsp_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n", + addr, p, cc, intr, arg); #endif - if (sc->sc_channels == 2 && (cc & 1)) { - DPRINTF(("sbdsp_dma_input: stereo input, odd bytecnt\n")); +#ifdef DIAGNOSTIC + if (sc->sc_i.modep->channels == 2 && (cc & 1)) { + DPRINTF(("stereo record odd bytes (%d)\n", cc)); return EIO; } +#endif - if (sc->sc_dmadir != SB_DMA_IN) { - if (ISSBPRO(sc)) { - if (sc->sc_channels == 2) { - if (ISJAZZ16(sc) && sc->sc_precision == 16) { - if (sbdsp_wdsp(sc, - JAZZ16_RECORD_STEREO) < 0) { - goto badmode; - } - } else if (sbdsp_wdsp(sc, - SB_DSP_RECORD_STEREO) < 0) - goto badmode; - sbdsp_mix_write(sc, SBP_INFILTER, - (sbdsp_mix_read(sc, SBP_INFILTER) & - ~SBP_IFILTER_MASK) | SBP_FILTER_OFF); - } else { - if (ISJAZZ16(sc) && sc->sc_precision == 16) { - if (sbdsp_wdsp(sc, - JAZZ16_RECORD_MONO) < 0) - { - goto badmode; - } - } else if (sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) - goto badmode; - sbdsp_mix_write(sc, SBP_INFILTER, - (sbdsp_mix_read(sc, SBP_INFILTER) & - ~SBP_IFILTER_MASK) | sc->in_filter); - } + 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; } - - if (ISSB16CLASS(sc)) { - if (sbdsp_wdsp(sc, SB_DSP16_INPUTRATE) < 0 || - sbdsp_wdsp(sc, sc->sc_irate >> 8) < 0 || - sbdsp_wdsp(sc, sc->sc_irate) < 0) - goto giveup; - } else - sbdsp_set_timeconst(sc, sc->sc_itc); - - sc->sc_dmadir = SB_DMA_IN; - sc->dmaflags = DMAMODE_READ; - if (ISSB2CLASS(sc)) - sc->dmaflags |= DMAMODE_LOOP; +#endif + sc->sc_intr8 = intr; + sc->sc_arg8 = arg; } else { - /* Already started; just return. */ - if (ISSB2CLASS(sc)) - return 0; +#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; } - - sc->dmaaddr = p; - sc->dmacnt = ISSB2CLASS(sc) ? (NBPG/cc)*cc : cc; - sc->dmachan = sc->sc_precision == 16 ? sc->sc_drq16 : sc->sc_drq8; - isadma_start(sc->dmaaddr, sc->dmacnt, sc->dmachan, sc->dmaflags); - sc->sc_intr = intr; - sc->sc_arg = arg; - - if (sc->sc_precision == 16) - cc >>= 1; - --cc; - if (ISSB16CLASS(sc)) { - if (sbdsp_wdsp(sc, sc->sc_precision == 16 ? SB_DSP16_RDMA_16 : - SB_DSP16_RDMA_8) < 0 || - sbdsp_wdsp(sc, (sc->sc_precision == 16 ? 0x10 : 0x00) | - (sc->sc_channels == 2 ? 0x20 : 0x00)) < 0 || - sbdsp16_wait(sc) || + + 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: + /* 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: SB16 DMA start failed\n")); + DPRINTF(("sbdsp_dma_input: SB1 DMA start failed\n")); goto giveup; } - } else if (ISSB2CLASS(sc)) { - if (cc != sc->sc_last_hs_size) { + 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; + /* 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 + 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; + } + } else { + DPRINTF(("sbdsp_dma_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; + } + if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0) { DPRINTF(("sbdsp_dma_input: SB2 DMA start failed\n")); goto giveup; } - sc->sc_last_hs_size = cc; - } - if (sbdsp_wdsp(sc, - sc->sc_imode == SB_ADAC_LS ? SB_DSP_RDMA_LOOP : - SB_DSP_HS_INPUT) < 0) { - DPRINTF(("sbdsp_dma_input: SB2 DMA restart failed\n")); - goto giveup; - } - } else { - if (sbdsp_wdsp(sc, SB_DSP_RDMA) < 0 || - sbdsp_wdsp(sc, cc) < 0 || - sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_input: SB1 DMA start failed\n")); - goto giveup; } + break; + case SB_PCMRUNNING: + /* Looping mode, nothing to do */ + break; } return 0; giveup: sbdsp_reset(sc); return EIO; +} -badmode: - DPRINTF(("sbdsp_dma_input: can't set %s mode\n", - sc->sc_channels == 2 ? "stereo" : "mono")); - return EIO; +int +sbdsp_dma_init_output(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct sbdsp_softc *sc = addr; + + 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; +} + +static int +sbdsp_dma_setup_output(sc) + struct sbdsp_softc *sc; +{ + int stereo = sc->sc_o.modep->channels == 2; + int cmd; + + 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)); + cmd = sc->sc_o.modep->cmdchan; + if (cmd && sbdsp_wdsp(sc, cmd) < 0) + return 0; + } + + 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", + sc->sc_o.rate)); + return 0; + } + } else { + if (sbdsp_set_timeconst(sc, sc->sc_o.tc)) { + DPRINTF(("sbdsp_dma_setup_output: tc=%d set failed\n", + sc->sc_o.rate)); + return 0; + } + } + return 1; } int @@ -1229,103 +1362,105 @@ sbdsp_dma_output(addr, p, cc, intr, arg) void (*intr) __P((void *)); void *arg; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_dma_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("sbdsp_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n", addr, p, cc, intr, arg); #endif - if (sc->sc_channels == 2 && (cc & 1)) { +#ifdef DIAGNOSTIC + if (sc->sc_o.modep->channels == 2 && (cc & 1)) { DPRINTF(("stereo playback odd bytes (%d)\n", cc)); return EIO; } +#endif - if (sc->sc_dmadir != SB_DMA_OUT) { - 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) | - (sc->sc_channels == 2 ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO)); - if (ISJAZZ16(sc)) { - /* Yes, we write the record mode to set - 16-bit playback mode. weird, huh? */ - if (sc->sc_precision == 16) { - sbdsp_wdsp(sc, - sc->sc_channels == 2 ? - JAZZ16_RECORD_STEREO : - JAZZ16_RECORD_MONO); - } else { - sbdsp_wdsp(sc, - sc->sc_channels == 2 ? - SB_DSP_RECORD_STEREO : - SB_DSP_RECORD_MONO); - } - } + 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; } - - if (ISSB16CLASS(sc)) { - if (sbdsp_wdsp(sc, SB_DSP16_OUTPUTRATE) < 0 || - sbdsp_wdsp(sc, sc->sc_orate >> 8) < 0 || - sbdsp_wdsp(sc, sc->sc_orate) < 0) - goto giveup; - } else - sbdsp_set_timeconst(sc, sc->sc_otc); - - sc->sc_dmadir = SB_DMA_OUT; - sc->dmaflags = DMAMODE_WRITE; - if (ISSB2CLASS(sc)) - sc->dmaflags |= DMAMODE_LOOP; +#endif + sc->sc_intr8 = intr; + sc->sc_arg8 = arg; } else { - /* Already started; just return. */ - if (ISSB2CLASS(sc)) - return 0; +#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; } - sc->dmaaddr = p; - sc->dmacnt = ISSB2CLASS(sc) ? (NBPG/cc)*cc : cc; - sc->dmachan = sc->sc_precision == 16 ? sc->sc_drq16 : sc->sc_drq8; - isadma_start(sc->dmaaddr, sc->dmacnt, sc->dmachan, sc->dmaflags); - sc->sc_intr = intr; - sc->sc_arg = arg; - - if (sc->sc_precision == 16) - cc >>= 1; - --cc; - if (ISSB16CLASS(sc)) { - if (sbdsp_wdsp(sc, sc->sc_precision == 16 ? SB_DSP16_WDMA_16 : - SB_DSP16_WDMA_8) < 0 || - sbdsp_wdsp(sc, (sc->sc_precision == 16 ? 0x10 : 0x00) | - (sc->sc_channels == 2 ? 0x20 : 0x00)) < 0 || - sbdsp16_wait(sc) || + 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: + /* 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: SB16 DMA start failed\n")); + DPRINTF(("sbdsp_dma_output: SB1 DMA start failed\n")); goto giveup; } - } else if (ISSB2CLASS(sc)) { - if (cc != sc->sc_last_hs_size) { + 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; + /* 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)); + 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; + } + } else { + DPRINTF(("sbdsp_dma_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; + } + if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0) { DPRINTF(("sbdsp_dma_output: SB2 DMA start failed\n")); goto giveup; } - sc->sc_last_hs_size = cc; - } - if (sbdsp_wdsp(sc, - sc->sc_omode == SB_ADAC_LS ? SB_DSP_WDMA_LOOP : - SB_DSP_HS_OUTPUT) < 0) { - DPRINTF(("sbdsp_dma_output: SB2 DMA restart failed\n")); - goto giveup; - } - } else { - if (sbdsp_wdsp(sc, SB_DSP_WDMA) < 0 || - sbdsp_wdsp(sc, cc) < 0 || - sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_output: SB1 DMA start failed\n")); - goto giveup; } + break; + case SB_PCMRUNNING: + /* Looping mode, nothing to do */ + break; } return 0; @@ -1338,44 +1473,61 @@ giveup: * Only the DSP unit on the sound blaster generates interrupts. * There are three cases of interrupt: reception of a midi byte * (when mode is enabled), completion of dma transmission, or - * completion of a dma reception. The three modes are mutually - * exclusive so we know a priori which event has occurred. + * completion of a dma reception. + * + * If there is interrupt sharing or a spurious interrupt occurs + * there is no way to distinguish this on an SB2. So if you have + * an SB2 and experience problems, buy an SB16 (it's only $40). */ int sbdsp_intr(arg) void *arg; { - register struct sbdsp_softc *sc = arg; - u_char x; + struct sbdsp_softc *sc = arg; + int loop = sc->sc_model != SB_1; + u_char irq; #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_intr: intr=0x%x\n", sc->sc_intr); + printf("sbdsp_intr: intr8=%p, intr16=%p\n", + sc->sc_intr8, sc->sc_intr16); #endif if (ISSB16CLASS(sc)) { - x = sbdsp_mix_read(sc, SBP_IRQ_STATUS); - if ((x & 3) == 0) + irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS); + if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16)) == 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; + irq = SBP_IRQ_DMA8; } - /* isadma_finished() moved to isadma.c */ sc->sc_interrupts++; - delay(10); + 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_intr != 0) { - /* clear interrupt */ - x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, - sc->sc_precision == 16 ? SBP_DSP_IRQACK16 : - SBP_DSP_IRQACK8); - if (!ISSB2CLASS(sc)) - isadma_done(sc->dmachan); - (*sc->sc_intr)(sc->sc_arg); - } else { - return 0; + 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); + } + 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); } return 1; } @@ -1419,13 +1571,120 @@ sbdsp_midi_output(sc, v) } #endif -int -sbdsp_setfd(addr, flag) - void *addr; - int flag; +/* Mask a value 0-255, but round it first */ +#define MAXVAL 256 +static int +sbdsp_adjust(val, mask) + int val, mask; { - /* Can't do full-duplex */ - return(ENOTTY); + val += (MAXVAL - mask) >> 1; + if (val >= MAXVAL) + val = MAXVAL-1; + return val & mask; +} + +void +sbdsp_set_mixer_gain(sc, port) + struct sbdsp_softc *sc; + int port; +{ + int src, gain; + + switch(sc->sc_mixer_model) { + case SBM_NONE: + return; + case SBM_CT1335: + gain = SB_1335_GAIN(sc->gain[port][SB_LEFT]); + switch(port) { + case SB_MASTER_VOL: + src = SBP_1335_MASTER_VOL; + break; + case SB_MIDI_VOL: + src = SBP_1335_MIDI_VOL; + break; + case SB_CD_VOL: + src = SBP_1335_CD_VOL; + break; + case SB_VOICE_VOL: + src = SBP_1335_VOICE_VOL; + gain = SB_1335_MASTER_GAIN(sc->gain[port][SB_LEFT]); + break; + default: + return; + } + sbdsp_mix_write(sc, src, gain); + break; + case SBM_CT1345: + gain = SB_STEREO_GAIN(sc->gain[port][SB_LEFT], + sc->gain[port][SB_RIGHT]); + switch (port) { + case SB_MIC_VOL: + src = SBP_MIC_VOL; + gain = SB_MIC_GAIN(sc->gain[port][SB_LEFT]); + break; + case SB_MASTER_VOL: + src = SBP_MASTER_VOL; + break; + case SB_LINE_IN_VOL: + src = SBP_LINE_VOL; + break; + case SB_VOICE_VOL: + src = SBP_VOICE_VOL; + break; + case SB_MIDI_VOL: + src = SBP_MIDI_VOL; + break; + case SB_CD_VOL: + src = SBP_CD_VOL; + break; + default: + return; + } + sbdsp_mix_write(sc, src, gain); + break; + case SBM_CT1XX5: + case SBM_CT1745: + switch (port) { + case SB_MIC_VOL: + src = SB16P_MIC_L; + break; + case SB_MASTER_VOL: + src = SB16P_MASTER_L; + break; + case SB_LINE_IN_VOL: + src = SB16P_LINE_L; + break; + case SB_VOICE_VOL: + src = SB16P_VOICE_L; + break; + case SB_MIDI_VOL: + src = SB16P_MIDI_L; + break; + case SB_CD_VOL: + src = SB16P_CD_L; + break; + case SB_INPUT_GAIN: + src = SB16P_INPUT_GAIN_L; + break; + case SB_OUTPUT_GAIN: + src = SB16P_OUTPUT_GAIN_L; + break; + case SB_TREBLE: + src = SB16P_TREBLE_L; + break; + case SB_BASS: + src = SB16P_BASS_L; + break; + case SB_PCSPEAKER: + sbdsp_mix_write(sc, SB16P_PCSPEAKER, sc->gain[port][SB_LEFT]); + return; + default: + return; + } + sbdsp_mix_write(sc, src, sc->gain[port][SB_LEFT]); + sbdsp_mix_write(sc, SB16P_L_TO_R(src), sc->gain[port][SB_RIGHT]); + break; + } } int @@ -1433,27 +1692,46 @@ sbdsp_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct sbdsp_softc *sc = addr; - int src, gain; + struct sbdsp_softc *sc = addr; + int lgain, rgain; + int mask, bits; + int lmask, rmask, lbits, rbits; + int mute, swap; DPRINTF(("sbdsp_mixer_set_port: port=%d num_channels=%d\n", cp->dev, cp->un.value.num_channels)); - if (!ISSBPROCLASS(sc)) + if (sc->sc_mixer_model == SBM_NONE) return EINVAL; - /* - * Everything is a value except for SBPro BASS/TREBLE and - * RECORD_SOURCE - */ switch (cp->dev) { - case SB_SPEAKER: - cp->dev = SB_MASTER_VOL; - case SB_MIC_PORT: - case SB_LINE_IN_PORT: - case SB_DAC_PORT: - case SB_FM_PORT: - case SB_CD_PORT: + case SB_TREBLE: + case SB_BASS: + if (sc->sc_mixer_model == SBM_CT1345 || + sc->sc_mixer_model == SBM_CT1XX5) { + if (cp->type != AUDIO_MIXER_ENUM) + return EINVAL; + switch (cp->dev) { + case SB_TREBLE: + sbdsp_set_ifilter(addr, cp->un.ord ? SB_TREBLE : 0); + return 0; + case SB_BASS: + sbdsp_set_ifilter(addr, cp->un.ord ? SB_BASS : 0); + return 0; + } + } + case SB_PCSPEAKER: + case SB_INPUT_GAIN: + case SB_OUTPUT_GAIN: + if (!ISSBM1745(sc)) + return EINVAL; + case SB_MIC_VOL: + case SB_LINE_IN_VOL: + if (sc->sc_mixer_model == SBM_CT1335) + return EINVAL; + case SB_VOICE_VOL: + case SB_MIDI_VOL: + case SB_CD_VOL: case SB_MASTER_VOL: if (cp->type != AUDIO_MIXER_VALUE) return EINVAL; @@ -1465,83 +1743,136 @@ sbdsp_mixer_set_port(addr, cp) */ switch (cp->dev) { - case SB_MIC_PORT: + case SB_MIC_VOL: if (cp->un.value.num_channels != 1) return EINVAL; - /* handle funny microphone gain */ - gain = SBP_AGAIN_TO_MICGAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + lgain = rgain = SB_ADJUST_MIC_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); break; - case SB_LINE_IN_PORT: - case SB_DAC_PORT: - case SB_FM_PORT: - case SB_CD_PORT: - case SB_MASTER_VOL: + case SB_PCSPEAKER: + if (cp->un.value.num_channels != 1) + return EINVAL; + /* fall into */ + case SB_INPUT_GAIN: + case SB_OUTPUT_GAIN: + lgain = rgain = SB_ADJUST_2_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + break; + default: switch (cp->un.value.num_channels) { case 1: - gain = sbdsp_mono_vol(SBP_AGAIN_TO_SBGAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_MONO])); + lgain = rgain = SB_ADJUST_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); break; case 2: - gain = sbdsp_stereo_vol(SBP_AGAIN_TO_SBGAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]), - SBP_AGAIN_TO_SBGAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT])); + if (sc->sc_mixer_model == SBM_CT1335) + return EINVAL; + lgain = SB_ADJUST_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); + rgain = SB_ADJUST_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]); break; default: return EINVAL; } break; - default: - return EINVAL; } + sc->gain[cp->dev][SB_LEFT] = lgain; + sc->gain[cp->dev][SB_RIGHT] = rgain; - switch (cp->dev) { - case SB_MIC_PORT: - src = SBP_MIC_VOL; - break; - case SB_MASTER_VOL: - src = SBP_MASTER_VOL; - break; - case SB_LINE_IN_PORT: - src = SBP_LINE_VOL; - break; - case SB_DAC_PORT: - src = SBP_DAC_VOL; - break; - case SB_FM_PORT: - src = SBP_FM_VOL; - break; - case SB_CD_PORT: - src = SBP_CD_VOL; - break; - default: - return EINVAL; + sbdsp_set_mixer_gain(sc, cp->dev); + break; + + case SB_RECORD_SOURCE: + if (ISSBM1745(sc)) { + if (cp->type != AUDIO_MIXER_SET) + return EINVAL; + return sbdsp_set_in_ports(sc, cp->un.mask); + } else { + if (cp->type != AUDIO_MIXER_ENUM) + return EINVAL; + sc->in_port = cp->un.ord; + return sbdsp_set_in_ports(sc, 1 << cp->un.ord); } + break; - sbdsp_mix_write(sc, src, gain); - sc->gain[cp->dev] = gain; + case SB_AGC: + if (!ISSBM1745(sc) || cp->type != AUDIO_MIXER_ENUM) + return EINVAL; + sbdsp_mix_write(sc, SB16P_AGC, cp->un.ord & 1); break; - case SB_TREBLE: - case SB_BASS: - case SB_RECORD_SOURCE: + case SB_CD_OUT_MUTE: + mask = SB16P_SW_CD; + goto omute; + case SB_MIC_OUT_MUTE: + mask = SB16P_SW_MIC; + goto omute; + case SB_LINE_OUT_MUTE: + mask = SB16P_SW_LINE; + omute: if (cp->type != AUDIO_MIXER_ENUM) return EINVAL; + bits = sbdsp_mix_read(sc, SB16P_OSWITCH); + sc->gain[cp->dev][SB_LR] = cp->un.ord != 0; + if (cp->un.ord) + bits = bits & ~mask; + else + bits = bits | mask; + sbdsp_mix_write(sc, SB16P_OSWITCH, bits); + break; - switch (cp->dev) { - case SB_TREBLE: - return sbdsp_set_ifilter(addr, cp->un.ord ? SBP_TREBLE_EQ : 0); - case SB_BASS: - return sbdsp_set_ifilter(addr, cp->un.ord ? SBP_BASS_EQ : 0); - case SB_RECORD_SOURCE: - return sbdsp_set_in_port(addr, cp->un.ord); + case SB_MIC_IN_MUTE: + case SB_MIC_SWAP: + lmask = rmask = SB16P_SW_MIC; + goto imute; + case SB_CD_IN_MUTE: + case SB_CD_SWAP: + lmask = SB16P_SW_CD_L; + rmask = SB16P_SW_CD_R; + goto imute; + case SB_LINE_IN_MUTE: + case SB_LINE_SWAP: + lmask = SB16P_SW_LINE_L; + rmask = SB16P_SW_LINE_R; + goto imute; + case SB_MIDI_IN_MUTE: + case SB_MIDI_SWAP: + lmask = SB16P_SW_MIDI_L; + rmask = SB16P_SW_MIDI_R; + imute: + if (cp->type != AUDIO_MIXER_ENUM) + return EINVAL; + mask = lmask | rmask; + lbits = sbdsp_mix_read(sc, SB16P_ISWITCH_L) & ~mask; + rbits = sbdsp_mix_read(sc, SB16P_ISWITCH_R) & ~mask; + sc->gain[cp->dev][SB_LR] = cp->un.ord != 0; + if (SB_IS_IN_MUTE(cp->dev)) { + mute = cp->dev; + swap = mute - SB_CD_IN_MUTE + SB_CD_SWAP; + } else { + swap = cp->dev; + mute = swap + SB_CD_IN_MUTE - SB_CD_SWAP; } - + if (sc->gain[swap][SB_LR]) { + mask = lmask; + lmask = rmask; + rmask = mask; + } + if (!sc->gain[mute][SB_LR]) { + lbits = lbits | lmask; + rbits = rbits | rmask; + } + sbdsp_mix_write(sc, SB16P_ISWITCH_L, lbits); + sbdsp_mix_write(sc, SB16P_ISWITCH_L, rbits); break; default: return EINVAL; } - return (0); + return 0; } int @@ -1549,223 +1880,441 @@ sbdsp_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct sbdsp_softc *sc = addr; - int gain; + struct sbdsp_softc *sc = addr; - DPRINTF(("sbdsp_mixer_get_port: port=%d", cp->dev)); + DPRINTF(("sbdsp_mixer_get_port: port=%d\n", cp->dev)); - if (!ISSBPROCLASS(sc)) + if (sc->sc_mixer_model == SBM_NONE) return EINVAL; switch (cp->dev) { - case SB_SPEAKER: - cp->dev = SB_MASTER_VOL; - case SB_MIC_PORT: - case SB_LINE_IN_PORT: - case SB_DAC_PORT: - case SB_FM_PORT: - case SB_CD_PORT: + case SB_TREBLE: + case SB_BASS: + if (sc->sc_mixer_model == SBM_CT1345 || + sc->sc_mixer_model == SBM_CT1XX5) { + switch (cp->dev) { + case SB_TREBLE: + cp->un.ord = sbdsp_get_ifilter(addr) == SB_TREBLE; + return 0; + case SB_BASS: + cp->un.ord = sbdsp_get_ifilter(addr) == SB_BASS; + return 0; + } + } + case SB_PCSPEAKER: + case SB_INPUT_GAIN: + case SB_OUTPUT_GAIN: + if (!ISSBM1745(sc)) + return EINVAL; + case SB_MIC_VOL: + case SB_LINE_IN_VOL: + if (sc->sc_mixer_model == SBM_CT1335) + return EINVAL; + case SB_VOICE_VOL: + case SB_MIDI_VOL: + case SB_CD_VOL: case SB_MASTER_VOL: - gain = sc->gain[cp->dev]; - switch (cp->dev) { - case SB_MIC_PORT: + case SB_MIC_VOL: + case SB_PCSPEAKER: if (cp->un.value.num_channels != 1) return EINVAL; - - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = SBP_MICGAIN_TO_AGAIN(gain); - break; - case SB_LINE_IN_PORT: - case SB_DAC_PORT: - case SB_FM_PORT: - case SB_CD_PORT: - case SB_MASTER_VOL: + /* fall into */ + default: switch (cp->un.value.num_channels) { case 1: - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = SBP_SBGAIN_TO_AGAIN(gain); + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = + sc->gain[cp->dev][SB_LEFT]; break; case 2: - cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = SBP_LEFTGAIN(gain); - cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = SBP_RIGHTGAIN(gain); + cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = + sc->gain[cp->dev][SB_LEFT]; + cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = + sc->gain[cp->dev][SB_RIGHT]; break; default: return EINVAL; } break; } - break; - case SB_TREBLE: - case SB_BASS: case SB_RECORD_SOURCE: - switch (cp->dev) { - case SB_TREBLE: - cp->un.ord = sbdsp_get_ifilter(addr) == SBP_TREBLE_EQ; - return 0; - case SB_BASS: - cp->un.ord = sbdsp_get_ifilter(addr) == SBP_BASS_EQ; - return 0; - case SB_RECORD_SOURCE: - cp->un.ord = sbdsp_get_in_port(addr); - return 0; - } + if (ISSBM1745(sc)) + cp->un.mask = sc->in_mask; + else + cp->un.ord = sc->in_port; + break; + case SB_AGC: + if (!ISSBM1745(sc)) + return EINVAL; + cp->un.ord = sbdsp_mix_read(sc, SB16P_AGC); + break; + + case SB_CD_IN_MUTE: + case SB_MIC_IN_MUTE: + case SB_LINE_IN_MUTE: + case SB_MIDI_IN_MUTE: + case SB_CD_SWAP: + case SB_MIC_SWAP: + case SB_LINE_SWAP: + case SB_MIDI_SWAP: + case SB_CD_OUT_MUTE: + case SB_MIC_OUT_MUTE: + case SB_LINE_OUT_MUTE: + cp->un.ord = sc->gain[cp->dev][SB_LR]; break; default: return EINVAL; } - return (0); + return 0; } int sbdsp_mixer_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { - register struct sbdsp_softc *sc = addr; + struct sbdsp_softc *sc = addr; + int chan, class, is1745; - DPRINTF(("sbdsp_mixer_query_devinfo: index=%d\n", dip->index)); + DPRINTF(("sbdsp_mixer_query_devinfo: model=%d index=%d\n", + sc->sc_mixer_model, dip->index)); + + if (sc->sc_mixer_model == SBM_NONE) + return ENXIO; + + chan = sc->sc_mixer_model == SBM_CT1335 ? 1 : 2; + is1745 = ISSBM1745(sc); + class = is1745 ? SB_INPUT_CLASS : SB_OUTPUT_CLASS; switch (dip->index) { - case SB_MIC_PORT: + case SB_MASTER_VOL: dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_INPUT_CLASS; + dip->mixer_class = SB_OUTPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNmaster); + dip->un.v.num_channels = chan; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; + case SB_MIDI_VOL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = class; dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNmicrophone); - dip->un.v.num_channels = 1; + dip->next = is1745 ? SB_MIDI_IN_MUTE : AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNfmsynth); + dip->un.v.num_channels = chan; strcpy(dip->un.v.units.name, AudioNvolume); return 0; - - case SB_SPEAKER: + case SB_CD_VOL: dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_OUTPUT_CLASS; + dip->mixer_class = class; dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNspeaker); - dip->un.v.num_channels = 1; + dip->next = is1745 ? SB_CD_IN_MUTE : AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNcd); + dip->un.v.num_channels = chan; strcpy(dip->un.v.units.name, AudioNvolume); return 0; - - case SB_INPUT_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SB_INPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + case SB_VOICE_VOL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = class; + dip->prev = AUDIO_MIXER_LAST; + dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNdac); + dip->un.v.num_channels = chan; + strcpy(dip->un.v.units.name, AudioNvolume); return 0; - case SB_OUTPUT_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = SB_OUTPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCOutputs); + strcpy(dip->label.name, AudioCoutputs); return 0; } - if (ISSBPROCLASS(sc)) { - switch (dip->index) { - case SB_LINE_IN_PORT: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNline); - dip->un.v.num_channels = 2; - strcpy(dip->un.v.units.name, AudioNvolume); - return 0; - - case SB_DAC_PORT: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNdac); - dip->un.v.num_channels = 2; - strcpy(dip->un.v.units.name, AudioNvolume); - return 0; - - case SB_CD_PORT: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNcd); - dip->un.v.num_channels = 2; - strcpy(dip->un.v.units.name, AudioNvolume); - return 0; + if (sc->sc_mixer_model == SBM_CT1335) + return ENXIO; - case SB_FM_PORT: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNfmsynth); - dip->un.v.num_channels = 2; - strcpy(dip->un.v.units.name, AudioNvolume); - return 0; + switch (dip->index) { + case SB_MIC_VOL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = class; + dip->prev = AUDIO_MIXER_LAST; + dip->next = is1745 ? SB_MIC_IN_MUTE : AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNmicrophone); + dip->un.v.num_channels = 1; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; - case SB_MASTER_VOL: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SB_OUTPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNvolume); - dip->un.v.num_channels = 2; - strcpy(dip->un.v.units.name, AudioNvolume); - return 0; + case SB_LINE_IN_VOL: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = class; + dip->prev = AUDIO_MIXER_LAST; + dip->next = is1745 ? SB_LINE_IN_MUTE : AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNline); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; - case SB_RECORD_SOURCE: - dip->mixer_class = SB_RECORD_CLASS; + case SB_RECORD_SOURCE: + dip->mixer_class = SB_RECORD_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNsource); + if (ISSBM1745(sc)) { + dip->type = AUDIO_MIXER_SET; + dip->un.s.num_mem = 4; + strcpy(dip->un.s.member[0].label.name, AudioNmicrophone); + dip->un.s.member[0].mask = 1 << SB_MIC_VOL; + strcpy(dip->un.s.member[1].label.name, AudioNcd); + dip->un.s.member[1].mask = 1 << SB_CD_VOL; + strcpy(dip->un.s.member[2].label.name, AudioNline); + dip->un.s.member[2].mask = 1 << SB_LINE_IN_VOL; + strcpy(dip->un.s.member[3].label.name, AudioNfmsynth); + dip->un.s.member[3].mask = 1 << SB_MIDI_VOL; + } else { dip->type = AUDIO_MIXER_ENUM; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNsource); dip->un.e.num_mem = 3; strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); - dip->un.e.member[0].ord = SB_MIC_PORT; + dip->un.e.member[0].ord = SB_MIC_VOL; strcpy(dip->un.e.member[1].label.name, AudioNcd); - dip->un.e.member[1].ord = SB_CD_PORT; + dip->un.e.member[1].ord = SB_CD_VOL; strcpy(dip->un.e.member[2].label.name, AudioNline); - dip->un.e.member[2].ord = SB_LINE_IN_PORT; - return 0; + dip->un.e.member[2].ord = SB_LINE_IN_VOL; + } + return 0; - case SB_BASS: + case SB_BASS: + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNbass); + if (sc->sc_mixer_model == SBM_CT1745) { + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = SB_EQUALIZATION_CLASS; + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNbass); + } else { dip->type = AUDIO_MIXER_ENUM; dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNbass); dip->un.e.num_mem = 2; strcpy(dip->un.e.member[0].label.name, AudioNoff); dip->un.e.member[0].ord = 0; strcpy(dip->un.e.member[1].label.name, AudioNon); dip->un.e.member[1].ord = 1; - return 0; - - case SB_TREBLE: + } + return 0; + + case SB_TREBLE: + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNtreble); + if (sc->sc_mixer_model == SBM_CT1745) { + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = SB_EQUALIZATION_CLASS; + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNtreble); + } else { dip->type = AUDIO_MIXER_ENUM; dip->mixer_class = SB_INPUT_CLASS; - dip->prev = AUDIO_MIXER_LAST; - dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNtreble); dip->un.e.num_mem = 2; strcpy(dip->un.e.member[0].label.name, AudioNoff); dip->un.e.member[0].ord = 0; strcpy(dip->un.e.member[1].label.name, AudioNon); dip->un.e.member[1].ord = 1; - return 0; + } + return 0; + + case SB_RECORD_CLASS: /* record source class */ + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = SB_RECORD_CLASS; + dip->next = dip->prev = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioCrecord); + return 0; + + case SB_INPUT_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = SB_INPUT_CLASS; + dip->next = dip->prev = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioCinputs); + return 0; + + } + + if (sc->sc_mixer_model == SBM_CT1345) + return ENXIO; + + switch(dip->index) { + case SB_PCSPEAKER: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = SB_INPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, "pc_speaker"); + dip->un.v.num_channels = 1; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; + + case SB_INPUT_GAIN: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = SB_INPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNinput); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; + + case SB_OUTPUT_GAIN: + dip->type = AUDIO_MIXER_VALUE; + dip->mixer_class = SB_OUTPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioNoutput); + dip->un.v.num_channels = 2; + strcpy(dip->un.v.units.name, AudioNvolume); + return 0; + + case SB_AGC: + dip->type = AUDIO_MIXER_ENUM; + dip->mixer_class = SB_INPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + 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; + strcpy(dip->un.e.member[1].label.name, AudioNon); + dip->un.e.member[1].ord = 1; + return 0; + + case SB_EQUALIZATION_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = SB_EQUALIZATION_CLASS; + dip->next = dip->prev = AUDIO_MIXER_LAST; + strcpy(dip->label.name, AudioCequalization); + return 0; + + case SB_CD_IN_MUTE: + dip->prev = SB_CD_VOL; + dip->next = SB_CD_SWAP; + dip->mixer_class = SB_INPUT_CLASS; + goto mute; + + case SB_MIC_IN_MUTE: + dip->prev = SB_MIC_VOL; + dip->next = SB_MIC_SWAP; + dip->mixer_class = SB_INPUT_CLASS; + goto mute; + + case SB_LINE_IN_MUTE: + dip->prev = SB_LINE_IN_VOL; + dip->next = SB_LINE_SWAP; + dip->mixer_class = SB_INPUT_CLASS; + goto mute; + + case SB_MIDI_IN_MUTE: + dip->prev = SB_MIDI_VOL; + dip->next = SB_MIDI_SWAP; + dip->mixer_class = SB_INPUT_CLASS; + goto mute; + + case SB_CD_SWAP: + dip->prev = SB_CD_IN_MUTE; + dip->next = SB_CD_OUT_MUTE; + goto swap; + + case SB_MIC_SWAP: + dip->prev = SB_MIC_IN_MUTE; + dip->next = SB_MIC_OUT_MUTE; + goto swap; + + case SB_LINE_SWAP: + dip->prev = SB_LINE_IN_MUTE; + dip->next = SB_LINE_OUT_MUTE; + goto swap; + + case SB_MIDI_SWAP: + dip->prev = SB_MIDI_IN_MUTE; + dip->next = AUDIO_MIXER_LAST; + swap: + dip->mixer_class = SB_INPUT_CLASS; + strcpy(dip->label.name, AudioNswap); + goto mute1; + + case SB_CD_OUT_MUTE: + dip->prev = SB_CD_SWAP; + dip->next = AUDIO_MIXER_LAST; + dip->mixer_class = SB_OUTPUT_CLASS; + goto mute; + + case SB_MIC_OUT_MUTE: + dip->prev = SB_MIC_SWAP; + dip->next = AUDIO_MIXER_LAST; + dip->mixer_class = SB_OUTPUT_CLASS; + goto mute; + + case SB_LINE_OUT_MUTE: + dip->prev = SB_LINE_SWAP; + dip->next = AUDIO_MIXER_LAST; + dip->mixer_class = SB_OUTPUT_CLASS; + mute: + strcpy(dip->label.name, AudioNmute); + mute1: + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strcpy(dip->un.e.member[0].label.name, AudioNoff); + dip->un.e.member[0].ord = 0; + strcpy(dip->un.e.member[1].label.name, AudioNon); + dip->un.e.member[1].ord = 1; + return 0; - case SB_RECORD_CLASS: /* record source class */ - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SB_RECORD_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCRecord); - return 0; - } } return ENXIO; } + +void * +sb_malloc(addr, size, pool, flags) + void *addr; + unsigned long size; + int pool; + int flags; +{ + struct sbdsp_softc *sc = addr; + + return isa_malloc(sc->sc_isa, 4, size, pool, flags); +} + +void +sb_free(addr, ptr, pool) + void *addr; + void *ptr; + int pool; +{ + isa_free(ptr, pool); +} + +unsigned long +sb_round(addr, size) + void *addr; + unsigned long size; +{ + if (size > MAX_ISADMA) + size = MAX_ISADMA; + return size; +} + +int +sb_mappage(addr, mem, off, prot) + void *addr; + void *mem; + int off; + int prot; +{ + return isa_mappage(mem, off, prot); +} + +int +sbdsp_get_props(addr) + void *addr; +{ + struct sbdsp_softc *sc = addr; + return AUDIO_PROP_MMAP | + (sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0); +} diff --git a/sys/dev/isa/sbdspvar.h b/sys/dev/isa/sbdspvar.h index 5279e227ef5..c70a012f447 100644 --- a/sys/dev/isa/sbdspvar.h +++ b/sys/dev/isa/sbdspvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: sbdspvar.h,v 1.7 1997/07/10 23:06:38 provos Exp $ */ -/* $NetBSD: sbdspvar.h,v 1.13 1996/04/29 20:28:50 christos Exp $ */ +/* $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 $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -35,29 +35,43 @@ * */ -#define SB_MIC_PORT 0 -#define SB_SPEAKER 1 -#define SB_INPUT_CLASS 2 -#define SB_OUTPUT_CLASS 3 -#define SB_LINE_IN_PORT 4 -#define SB_DAC_PORT 5 -#define SB_FM_PORT 6 -#define SB_CD_PORT 7 -#define SB_MASTER_VOL 8 -#define SB_TREBLE 9 -#define SB_BASS 10 -#define SB_NDEVS 11 /* XXX include classes above for - contiguous number space on - original SB */ +#define SB_MASTER_VOL 0 +#define SB_MIDI_VOL 1 +#define SB_CD_VOL 2 +#define SB_VOICE_VOL 3 +#define SB_OUTPUT_CLASS 4 -/*#define SB_OUTPUT_MODE 9 -#define SB_SPKR_MONO 0 -#define SB_SPKR_STEREO 1*/ +#define SB_MIC_VOL 5 +#define SB_LINE_IN_VOL 6 +#define SB_RECORD_SOURCE 7 +#define SB_TREBLE 8 +#define SB_BASS 9 +#define SB_RECORD_CLASS 10 +#define SB_INPUT_CLASS 11 -#define SB_RECORD_SOURCE 11 +#define SB_PCSPEAKER 12 +#define SB_INPUT_GAIN 13 +#define SB_OUTPUT_GAIN 14 +#define SB_AGC 15 +#define SB_EQUALIZATION_CLASS 16 -#define SB_RECORD_CLASS 12 +#define SB_CD_IN_MUTE 17 +#define SB_MIC_IN_MUTE 18 +#define SB_LINE_IN_MUTE 19 +#define SB_MIDI_IN_MUTE 20 +#define SB_CD_SWAP 21 +#define SB_MIC_SWAP 22 +#define SB_LINE_SWAP 23 +#define SB_MIDI_SWAP 24 + +#define SB_CD_OUT_MUTE 25 +#define SB_MIC_OUT_MUTE 26 +#define SB_LINE_OUT_MUTE 27 + +#define SB_NDEVS 28 + +#define SB_IS_IN_MUTE(x) ((x) < SB_CD_SWAP) /* * Software state, per SoundBlaster card. @@ -86,70 +100,75 @@ struct sbdsp_softc { 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_openflags; /* flags used on open */ + u_char sc_fullduplex; /* can do full duplex */ - u_int gain[SB_NDEVS]; /* kept in SB levels: right/left each - in a nibble */ + u_char gain[SB_NDEVS][2]; /* kept in input levels */ +#define SB_LEFT 0 +#define SB_RIGHT 1 +#define SB_LR 0 - u_int out_port; /* output port */ - u_int in_port; /* input port */ + u_int in_mask; /* input ports */ + u_int in_port; /* XXX needed for MI interface */ u_int in_filter; /* one of SB_TREBLE_EQ, SB_BASS_EQ, 0 */ u_int spkr_state; /* non-null is on */ - int sc_irate, sc_itc; /* Sample rate for input */ - int sc_orate, sc_otc; /* ...and output */ - - int sc_imode; - int sc_omode; -#define SB_ADAC_LS 0 -#define SB_ADAC_HS 1 + struct sbdsp_state { + u_int rate; /* Sample rate */ + u_char tc; /* Time constant */ + struct sbmode *modep; + u_char bmode; + int dmachan; /* DMA channel */ + 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 */ + } sc_i, sc_o; /* Input and output state */ u_long sc_interrupts; /* number of interrupts taken */ - void (*sc_intr)(void*); /* dma completion intr handler */ + void (*sc_intr8)(void*); /* dma completion intr handler */ + void *sc_arg8; /* arg for sc_intr8() */ + void (*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_arg; /* arg for sc_intr() */ - - int dmaflags; - caddr_t dmaaddr; - vm_size_t dmacnt; - int dmachan; /* active DMA channel */ - int sc_last_hs_size; /* last HS dma size */ - u_int sc_encoding; /* ulaw/linear -- keep track */ - u_int sc_precision; /* size of samples */ - int sc_channels; /* # of channels */ - - int sc_dmadir; /* DMA direction */ -#define SB_DMA_NONE 0 -#define SB_DMA_IN 1 -#define SB_DMA_OUT 2 + u_int sc_mixer_model; +#define SBM_NONE 0 +#define SBM_CT1335 1 +#define SBM_CT1345 2 +#define SBM_CT1XX5 3 +#define SBM_CT1745 4 +#define ISSBM1745(x) ((x)->sc_mixer_model >= SBM_CT1XX5) u_int sc_model; /* DSP model */ +#define SB_UNK -1 +#define SB_1 0 /* original SB */ +#define SB_20 1 /* SB 2 */ +#define SB_2x 2 /* SB 2, new version */ +#define SB_PRO 3 /* SB Pro */ +#define SB_JAZZ 4 /* Jazz 16 */ +#define SB_16 5 /* SB 16 */ +#define SB_32 6 /* SB AWE 32 */ +#define SB_64 7 /* SB AWE 64 */ + +#define SB_NAMES { "SB_1", "SB_2.0", "SB_2.x", "SB_Pro", "Jazz_16", "SB_16", "SB_AWE_32", "SB_AWE_64" } + + u_int sc_version; /* DSP version */ #define SBVER_MAJOR(v) (((v)>>8) & 0xff) #define SBVER_MINOR(v) ((v)&0xff) - -#define MODEL_JAZZ16 0x80000000 }; -#define ISSB2CLASS(sc) \ - (SBVER_MAJOR((sc)->sc_model) >= 2) - -#define ISSBPROCLASS(sc) \ - (SBVER_MAJOR((sc)->sc_model) > 2) - -#define ISSBPRO(sc) \ - (SBVER_MAJOR((sc)->sc_model) == 3) - -#define ISSB16CLASS(sc) \ - (SBVER_MAJOR((sc)->sc_model) > 3) - -#define ISJAZZ16(sc) \ - ((sc)->sc_model & MODEL_JAZZ16) - +#define ISSBPRO(sc) ((sc)->sc_model == SB_PRO || (sc)->sc_model == SB_JAZZ) +#define ISSBPROCLASS(sc) ((sc)->sc_model >= SB_PRO) +#define ISSB16CLASS(sc) ((sc)->sc_model >= SB_16) #ifdef _KERNEL -int sbdsp_open __P((struct sbdsp_softc *, dev_t, int)); +int sbdsp_open __P((void *, int)); void sbdsp_close __P((void *)); int sbdsp_probe __P((struct sbdsp_softc *)); @@ -163,35 +182,20 @@ int sbdsp_set_out_gain_real __P((void *, u_int, u_char)); int sbdsp_get_out_gain __P((void *)); int sbdsp_set_monitor_gain __P((void *, u_int)); int sbdsp_get_monitor_gain __P((void *)); -int sbdsp_set_in_sr __P((void *, u_long)); -int sbdsp_set_in_sr_real __P((void *, u_long)); -u_long sbdsp_get_in_sr __P((void *)); -int sbdsp_set_out_sr __P((void *, u_long)); -int sbdsp_set_out_sr_real __P((void *, u_long)); -u_long sbdsp_get_out_sr __P((void *)); int sbdsp_query_encoding __P((void *, struct audio_encoding *)); -int sbdsp_set_format __P((void *, u_int, u_int)); -int sbdsp_get_encoding __P((void *)); -int sbdsp_get_precision __P((void *)); -int sbdsp_set_channels __P((void *, int)); -int sbdsp_get_channels __P((void *)); -int sbdsp_set_ifilter __P((void *, int)); -int sbdsp_get_ifilter __P((void *)); +int sbdsp_set_params __P((void *, int, int, struct audio_params *, struct audio_params *)); int sbdsp_round_blocksize __P((void *, int)); -int sbdsp_set_out_port __P((void *, int)); -int sbdsp_get_out_port __P((void *)); -int sbdsp_set_in_port __P((void *, int)); -int sbdsp_get_in_port __P((void *)); int sbdsp_get_avail_in_ports __P((void *)); int sbdsp_get_avail_out_ports __P((void *)); int sbdsp_speaker_ctl __P((void *, int)); -int sbdsp_commit_settings __P((void *)); +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_haltdma __P((void *)); -int sbdsp_contdma __P((void *)); void sbdsp_compress __P((int, u_char *, int)); void sbdsp_expand __P((int, u_char *, int)); @@ -204,10 +208,8 @@ int sbdsp_wdsp __P((struct sbdsp_softc *, int v)); int sbdsp_rdsp __P((struct sbdsp_softc *)); int sbdsp_intr __P((void *)); -short sbversion __P((struct sbdsp_softc *)); int sbdsp_set_sr __P((struct sbdsp_softc *, u_long *, int)); -int sbdsp_setfd __P((void *, int)); void sbdsp_mix_write __P((struct sbdsp_softc *, int, int)); int sbdsp_mix_read __P((struct sbdsp_softc *, int)); @@ -216,4 +218,11 @@ int sbdsp_mixer_set_port __P((void *, mixer_ctrl_t *)); int sbdsp_mixer_get_port __P((void *, mixer_ctrl_t *)); int sbdsp_mixer_query_devinfo __P((void *, mixer_devinfo_t *)); +void *sb_malloc __P((void *, unsigned long, int, int)); +void sb_free __P((void *, void *, int)); +unsigned long sb_round __P((void *, unsigned long)); +int sb_mappage __P((void *, void *, int, int)); + +int sbdsp_get_props __P((void *)); + #endif diff --git a/sys/dev/isa/sbreg.h b/sys/dev/isa/sbreg.h index b8bd566accf..e4c8bc3d9e6 100644 --- a/sys/dev/isa/sbreg.h +++ b/sys/dev/isa/sbreg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: sbreg.h,v 1.3 1997/07/10 23:06:39 provos Exp $ */ -/* $NetBSD: sbreg.h,v 1.16 1996/03/16 04:00:14 jtk Exp $ */ +/* $OpenBSD: sbreg.h,v 1.4 1998/04/26 21:03:02 provos Exp $ */ +/* $NetBSD: sbreg.h,v 1.24 1997/08/24 23:24:51 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -71,21 +71,19 @@ #define SBP_FM_DATA 9 /* RW FM data port */ #define SBP_MIXER_ADDR 4 /* W mixer address register */ #define SBP_MIXER_DATA 5 /* RW mixer data port */ -#define SBP_MIX_RESET 0 /* mixer reset port, value */ + +#define SBP_MIX_RESET 0x00 /* mixer reset port, value */ +#define SBP_1335_MASTER_VOL 0x02 +#define SBP_1335_MIDI_VOL 0x06 +#define SBP_1335_CD_VOL 0x08 +#define SBP_1335_VOICE_VOL 0x0A + +#define SBP_VOICE_VOL 0x04 +#define SBP_MIC_VOL 0x0A /* warning: only one channel of volume... */ #define SBP_MASTER_VOL 0x22 -#define SBP_FM_VOL 0x26 +#define SBP_MIDI_VOL 0x26 #define SBP_CD_VOL 0x28 #define SBP_LINE_VOL 0x2E -#define SBP_DAC_VOL 0x04 -#define SBP_MIC_VOL 0x0A /* warning: only one channel of - volume... */ -#define SBP_SPEAKER_VOL 0x42 -#define SBP_TREBLE_EQ 0x44 -#define SBP_BASS_EQ 0x46 - -#define SBP_SET_IRQ 0x80 /* Soft-configured irq (SB16-) */ -#define SBP_SET_DRQ 0x81 /* Soft-configured drq (SB16-) */ -#define SBP_IRQ_STATUS 0x82 /* Pending IRQ status (SB16-) */ #define SBP_RECORD_SOURCE 0x0C #define SBP_STEREO 0x0E @@ -105,17 +103,60 @@ #define SBP_FROM_MIC 0x00 #define SBP_FROM_CD 0x02 #define SBP_FROM_LINE 0x06 -#define sbdsp_mono_vol(left) (((left) << 4) | (left)) -#define sbdsp_stereo_vol(left, right) (((left) << 4) | (right)) -#define SBP_MAXVOL 0xf /* per channel */ -#define SBP_MINVOL 0x0 /* per channel */ -#define SBP_AGAIN_TO_SBGAIN(again) ((again) >> 4) /* per channel */ -#define SBP_AGAIN_TO_MICGAIN(again) ((again) >> 5) /* mic has only 3 bits, - sorry! */ -#define SBP_LEFTGAIN(sbgain) (sbgain & 0xf0) /* left channel */ -#define SBP_RIGHTGAIN(sbgain) ((sbgain & 0xf) << 4) /* right channel */ -#define SBP_SBGAIN_TO_AGAIN(sbgain) SBP_LEFTGAIN(sbgain) -#define SBP_MICGAIN_TO_AGAIN(micgain) (micgain << 5) + +#define SBP_SET_IRQ 0x80 /* Soft-configured irq (SB16-) */ +#define SBP_SET_DRQ 0x81 /* Soft-configured drq (SB16-) */ +#define SBP_IRQ_STATUS 0x82 /* Pending IRQ status (SB16-) */ +#define SBP_IRQ_MPU401 0x04 +#define SBP_IRQ_DMA16 0x02 +#define SBP_IRQ_DMA8 0x01 + +#define SB16P_MASTER_L 0x30 +#define SB16P_VOICE_L 0x32 +#define SB16P_MIDI_L 0x34 +#define SB16P_CD_L 0x36 +#define SB16P_LINE_L 0x38 +#define SB16P_MIC_L 0x3a +#define SB16P_PCSPEAKER 0x3b +#define SB16P_OSWITCH 0x3c +#define SB16P_ISWITCH_L 0x3d +#define SB16P_ISWITCH_R 0x3e +#define SB16P_SW_MIC 0x01 +#define SB16P_SW_CD_R 0x02 +#define SB16P_SW_CD_L 0x04 +#define SB16P_SW_CD (SB16P_SW_CD_L|SB16P_SW_CD_R) +#define SB16P_SW_LINE_R 0x08 +#define SB16P_SW_LINE_L 0x10 +#define SB16P_SW_LINE (SB16P_SW_LINE_L|SB16P_SW_LINE_R) +#define SB16P_SW_MIDI_R 0x20 +#define SB16P_SW_MIDI_L 0x40 +#define SB16P_SW_MIDI (SB16P_SW_MIDI_L|SB16P_SW_MIDI_R) +#define SB16P_INPUT_GAIN_L 0x3f +#define SB16P_OUTPUT_GAIN_L 0x41 +#define SB16P_TREBLE_L 0x44 +#define SB16P_BASS_L 0x46 +#define SB16P_L_TO_R(l) ((l)+1) + +#define SB16P_AGC 0x43 + +#define SBP_RECORD_SOURCE_L 0x3d +#define SBP_RECORD_SOURCE_R 0x3e +#define SBP_MIDI_SRC_R 0x20 +#define SBP_LINE_SRC_R 0x08 +#define SBP_CD_SRC_R 0x02 +#define SBP_MIC_SRC 0x01 +#define SB_SRC_R_TO_L(x) ((x) << 1) + +#define SB_STEREO_GAIN(left, right) ((left) | ((right) >> 4)) +#define SB_MIC_GAIN(v) ((v) >> 5) + +#define SB_ADJUST_MIC_GAIN(sc, x) sbdsp_adjust((x), ISSB16CLASS(sc) ? 0xf8 : 0xc0) +#define SB_ADJUST_GAIN(sc, x) sbdsp_adjust((x), ISSB16CLASS(sc) ? 0xf8 : 0xe0) +#define SB_ADJUST_2_GAIN(sc, x) sbdsp_adjust((x), 0xc0) + +#define SB_1335_GAIN(x) ((x) >> 4) +#define SB_1335_MASTER_GAIN(x) ((x) >> 5) + #define SBP_DSP_RESET 6 /* W reset port */ #define SB_MAGIC 0xaa /* card outputs on successful reset */ #define SBP_DSP_READ 10 /* R read port */ @@ -179,6 +220,10 @@ #define SB_SPKR_ON 0xff #define SB_DSP_VERSION 0xe1 /* get version number */ +#define SB_BMODE_UNSIGNED 0x00 +#define SB_BMODE_SIGNED 0x10 +#define SB_BMODE_STEREO 0x20 + /* Some of these come from linux driver (It serves as convenient unencumbered documentation) */ #define JAZZ16_READ_VER 0xFA /* 0x12 means ProSonic/Jazz16? */ diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c index 930516b0ec1..e14338bdd44 100644 --- a/sys/dev/isa/wss.c +++ b/sys/dev/isa/wss.c @@ -1,5 +1,5 @@ -/* $OpenBSD: wss.c,v 1.14 1997/07/10 23:06:40 provos Exp $ */ -/* $NetBSD: wss.c,v 1.13 1996/05/12 23:54:16 mycroft Exp $ */ +/* $OpenBSD: wss.c,v 1.15 1998/04/26 21:03:03 provos Exp $ */ +/* $NetBSD: wss.c,v 1.42 1998/01/19 22:18:23 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -47,6 +47,7 @@ #include <machine/cpu.h> #include <machine/intr.h> +#include <machine/bus.h> #include <machine/pio.h> #include <sys/audioio.h> @@ -58,26 +59,8 @@ #include <dev/ic/ad1848reg.h> #include <dev/isa/ad1848var.h> #include <dev/isa/wssreg.h> -#include <dev/isa/opti.h> - -/* - * Mixer devices - */ -#define WSS_MIC_IN_LVL 0 -#define WSS_LINE_IN_LVL 1 -#define WSS_DAC_LVL 2 -#define WSS_REC_LVL 3 -#define WSS_MON_LVL 4 -#define WSS_MIC_IN_MUTE 5 -#define WSS_LINE_IN_MUTE 6 -#define WSS_DAC_MUTE 7 - -#define WSS_RECORD_SOURCE 8 - -/* Classes */ -#define WSS_INPUT_CLASS 9 -#define WSS_RECORD_CLASS 10 -#define WSS_MONITOR_CLASS 11 +#include <dev/isa/wssvar.h> +#include <dev/isa/madreg.h> #ifdef AUDIO_DEBUG #define DPRINTF(x) if (wssdebug) printf x @@ -86,191 +69,92 @@ int wssdebug = 0; #define DPRINTF(x) #endif -struct wss_softc { - struct device sc_dev; /* base device */ - struct isadev sc_id; /* ISA device */ - void *sc_ih; /* interrupt vectoring */ - - struct ad1848_softc sc_ad1848; -#define wss_irq sc_ad1848.sc_irq -#define wss_drq sc_ad1848.sc_drq - - int mic_mute, cd_mute, dac_mute; -}; - struct audio_device wss_device = { "wss,ad1848", "", "WSS" }; -int wssopen __P((dev_t, int)); int wss_getdev __P((void *, struct audio_device *)); -int wss_setfd __P((void *, int)); -int wss_set_out_port __P((void *, int)); -int wss_get_out_port __P((void *)); -int wss_set_in_port __P((void *, int)); -int wss_get_in_port __P((void *)); int wss_mixer_set_port __P((void *, mixer_ctrl_t *)); int wss_mixer_get_port __P((void *, mixer_ctrl_t *)); int wss_query_devinfo __P((void *, mixer_devinfo_t *)); static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); + /* * Define our interface to the higher level audio driver. */ struct audio_hw_if wss_hw_if = { - wssopen, + ad1848_open, ad1848_close, NULL, - ad1848_set_in_sr, - ad1848_get_in_sr, - ad1848_set_out_sr, - ad1848_get_out_sr, ad1848_query_encoding, - ad1848_set_format, - ad1848_get_encoding, - ad1848_get_precision, - ad1848_set_channels, - ad1848_get_channels, + ad1848_set_params, ad1848_round_blocksize, - wss_set_out_port, - wss_get_out_port, - wss_set_in_port, - wss_get_in_port, ad1848_commit_settings, - NULL, - NULL, + ad1848_dma_init_output, + ad1848_dma_init_input, ad1848_dma_output, ad1848_dma_input, ad1848_halt_out_dma, ad1848_halt_in_dma, - ad1848_cont_out_dma, - ad1848_cont_in_dma, NULL, wss_getdev, - wss_setfd, + NULL, wss_mixer_set_port, wss_mixer_get_port, wss_query_devinfo, - 0, /* not full-duplex */ - 0 + ad1848_malloc, + ad1848_free, + ad1848_round, + ad1848_mappage, + ad1848_get_props, }; -int wssprobe __P((struct device *, void *, void *)); -void wssattach __P((struct device *, struct device *, void *)); - -struct cfattach wss_ca = { - sizeof(struct wss_softc), wssprobe, wssattach -}; - -struct cfdriver wss_cd = { - NULL, "wss", DV_DULL -}; - -/* - * Probe for the Microsoft Sound System hardware. - */ -int -wssprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - register struct wss_softc *sc = match; - register struct isa_attach_args *ia = aux; - register int iobase = ia->ia_iobase; - static u_char interrupt_bits[12] = { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - static u_char dma_bits[4] = {1, 2, 0, 3}; - - if (!WSS_BASE_VALID(ia->ia_iobase)) { - DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); - return 0; - } - - if( !opti_snd_setup( OPTI_WSS, iobase, ia->ia_irq, ia->ia_drq ) ) - DPRINTF(("ad_detect_A: could not setup OPTi chipset.\n")); - - sc->sc_ad1848.sc_iobase = iobase + WSS_CODEC; - - /* Is there an ad1848 chip at the WSS iobase ? */ - if (ad1848_probe(&sc->sc_ad1848) == 0) { -#if 0 - DPRINTF(("ad_detect_A: no ad1848 found.\n")); -#endif - return 0; - } - - ia->ia_iosize = WSS_NPORT; - - /* Setup WSS interrupt and DMA */ - if (!WSS_DRQ_VALID(ia->ia_drq)) { - DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq)); - return 0; - } - sc->wss_drq = ia->ia_drq; - -#ifdef NEWCONFIG - /* - * If the IRQ wasn't compiled in, auto-detect it. - */ - if (ia->ia_irq == IRQUNK) { - ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848); - if (!WSS_IRQ_VALID(ia->ia_irq)) { - printf("wss: couldn't auto-detect interrupt\n"); - return 0; - } - } - else -#endif - if (!WSS_IRQ_VALID(ia->ia_irq)) { - DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq)); - return 0; - } - - sc->wss_irq = ia->ia_irq; - - outb(iobase+WSS_CONFIG, - (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq])); - - return 1; -} - /* * Attach hardware to driver, attach hardware driver to audio * pseudo-device driver . */ void -wssattach(parent, self, aux) - struct device *parent, *self; - void *aux; +wssattach(sc) + struct wss_softc *sc; { - register struct wss_softc *sc = (struct wss_softc *)self; - struct isa_attach_args *ia = (struct isa_attach_args *)aux; - register int iobase = ia->ia_iobase; - int err; + int version; - sc->sc_ad1848.sc_recdrq = ia->ia_drq; + madattach(sc); -#ifdef NEWCONFIG - isa_establish(&sc->sc_id, &sc->sc_dev); -#endif - sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, + sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->wss_irq, IST_EDGE, IPL_AUDIO, ad1848_intr, &sc->sc_ad1848, sc->sc_dev.dv_xname); ad1848_attach(&sc->sc_ad1848); - printf(" (vers %d)", inb(iobase+WSS_STATUS) & WSS_VERSMASK); + version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK; + printf(" (vers %d)", version); + switch(sc->mad_chip_type) { + case MAD_82C928: + printf(", 82C928"); + break; + case MAD_OTI601D: + printf(", OTI-601D"); + break; + case MAD_82C929: + printf(", 82C929"); + break; + case MAD_82C931: + printf(", 82C931"); + break; + default: + break; + } printf("\n"); sc->sc_ad1848.parent = sc; - if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0) - printf("wss: could not attach to audio pseudo-device driver (%d)\n", err); + audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev); } static int @@ -308,24 +192,6 @@ wss_from_vol(cp, vol) } int -wssopen(dev, flags) - dev_t dev; - int flags; -{ - struct wss_softc *sc; - int unit = AUDIOUNIT(dev); - - if (unit >= wss_cd.cd_ndevs) - return ENODEV; - - sc = wss_cd.cd_devs[unit]; - if (!sc) - return ENXIO; - - return ad1848_open(&sc->sc_ad1848, dev, flags); -} - -int wss_getdev(addr, retp) void *addr; struct audio_device *retp; @@ -335,90 +201,12 @@ wss_getdev(addr, retp) } int -wss_setfd(addr, flag) - void *addr; - int flag; -{ - /* Can't do full-duplex */ - return(ENOTTY); -} - - -int -wss_set_out_port(addr, port) - void *addr; - int port; -{ - DPRINTF(("wss_set_out_port:\n")); - return(EINVAL); -} - -int -wss_get_out_port(addr) - void *addr; -{ - DPRINTF(("wss_get_out_port:\n")); - return(WSS_DAC_LVL); -} - -int -wss_set_in_port(addr, port) - void *addr; - int port; -{ - register struct ad1848_softc *ac = addr; - - DPRINTF(("wss_set_in_port: %d\n", port)); - - switch(port) { - case WSS_MIC_IN_LVL: - port = MIC_IN_PORT; - break; - case WSS_LINE_IN_LVL: - port = LINE_IN_PORT; - break; - case WSS_DAC_LVL: - port = DAC_IN_PORT; - break; - default: - return(EINVAL); - /*NOTREACHED*/ - } - - return(ad1848_set_rec_port(ac, port)); -} - -int -wss_get_in_port(addr) - void *addr; -{ - register struct ad1848_softc *ac = addr; - int port = WSS_MIC_IN_LVL; - - switch(ad1848_get_rec_port(ac)) { - case MIC_IN_PORT: - port = WSS_MIC_IN_LVL; - break; - case LINE_IN_PORT: - port = WSS_LINE_IN_LVL; - break; - case DAC_IN_PORT: - port = WSS_DAC_LVL; - break; - } - - DPRINTF(("wss_get_in_port: %d\n", port)); - - return(port); -} - -int wss_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct wss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct wss_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -503,8 +291,8 @@ wss_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { - register struct ad1848_softc *ac = addr; - register struct wss_softc *sc = ac->parent; + struct ad1848_softc *ac = addr; + struct wss_softc *sc = ac->parent; struct ad1848_volume vol; int error = EINVAL; @@ -590,7 +378,7 @@ wss_mixer_get_port(addr, cp) int wss_query_devinfo(addr, dip) void *addr; - register mixer_devinfo_t *dip; + mixer_devinfo_t *dip; { DPRINTF(("wss_query_devinfo: index=%d\n", dip->index)); @@ -648,21 +436,21 @@ wss_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_INPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCInputs); + strcpy(dip->label.name, AudioCinputs); break; case WSS_MONITOR_CLASS: /* monitor class descriptor */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_MONITOR_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNmonitor); + strcpy(dip->label.name, AudioCmonitor); break; case WSS_RECORD_CLASS: /* record source class */ dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = WSS_RECORD_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNrecord); + strcpy(dip->label.name, AudioCrecord); break; case WSS_MIC_IN_MUTE: @@ -716,3 +504,136 @@ wss_query_devinfo(addr, dip) return 0; } + + +/* + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * Initialization code for OPTi MAD16 compatible audio chips. Including + * + * OPTi 82C928 MAD16 (replaced by C929) + * OAK OTI-601D Mozart + * OPTi 82C929 MAD16 Pro + * + */ + +u_int +mad_read(sc, port) + struct wss_softc *sc; + int port; +{ + u_int tmp; + int pwd; + int s; + + switch (sc->mad_chip_type) { /* Output password */ + case MAD_82C928: + case MAD_OTI601D: + pwd = M_PASSWD_928; + break; + case MAD_82C929: + pwd = M_PASSWD_929; + break; + case MAD_82C931: + pwd = M_PASSWD_931; + break; + default: + panic("mad_read: Bad chip type=%d\n", sc->mad_chip_type); + } + s = splaudio(); /* don't want an interrupt between outb&inb */ + bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); + tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port); + splx(s); + return tmp; +} + +void +mad_write(sc, port, value) + struct wss_softc *sc; + int port; + int value; +{ + int pwd; + int s; + + switch (sc->mad_chip_type) { /* Output password */ + case MAD_82C928: + case MAD_OTI601D: + pwd = M_PASSWD_928; + break; + case MAD_82C929: + pwd = M_PASSWD_929; + break; + case MAD_82C931: + pwd = M_PASSWD_931; + break; + default: + panic("mad_write: Bad chip type=%d\n", sc->mad_chip_type); + } + s = splaudio(); + bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); + bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff); + splx(s); +} + +void +madattach(sc) + struct wss_softc *sc; +{ + unsigned char cs4231_mode; + int joy; + + if (sc->mad_chip_type == MAD_NONE) + return; + + /* Do we want the joystick disabled? */ + joy = sc->sc_dev.dv_cfdata->cf_flags & 2 ? MC1_JOYDISABLE : 0; + + /* enable WSS emulation at the I/O port */ + mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(sc->mad_ioindex) | joy); + mad_write(sc, MC2_PORT, 0x03); /* ? */ + mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */ + + cs4231_mode = + strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 || + strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0; + + if (sc->mad_chip_type == MAD_82C929) { + mad_write(sc, MC4_PORT, 0x92); + mad_write(sc, MC5_PORT, 0xA5 | cs4231_mode); + mad_write(sc, MC6_PORT, 0x03); /* Disable MPU401 */ + } else { + mad_write(sc, MC4_PORT, 0x02); + mad_write(sc, MC5_PORT, 0x30 | cs4231_mode); + } + +#ifdef AUDIO_DEBUG + if (wssdebug) { + int i; + for (i = MC1_PORT; i <= MC7_PORT; i++) + DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, i))); + } +#endif +} diff --git a/sys/dev/isa/wss_isa.c b/sys/dev/isa/wss_isa.c new file mode 100644 index 00000000000..61df0bc35f1 --- /dev/null +++ b/sys/dev/isa/wss_isa.c @@ -0,0 +1,376 @@ +/* $OpenBSD: wss_isa.c,v 1.1 1998/04/26 21:02:38 provos Exp $ */ +/* $NetBSD: wss_isa.c,v 1.1 1998/01/19 22:18:24 augustss Exp $ */ + +/* + * Copyright (c) 1994 John Brezak + * Copyright (c) 1991-1993 Regents of the University of California. + * All rights reserved. + * + * MAD support: + * Copyright (c) 1996 Lennart Augustsson + * Based on code which is + * Copyright (c) 1994 Hannu Savolainen + * + * 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> +#include <machine/pio.h> + +#include <sys/audioio.h> +#include <dev/audio_if.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> + +#include <dev/ic/ad1848reg.h> +#include <dev/isa/ad1848var.h> +#include <dev/isa/wssreg.h> +#include <dev/isa/wssvar.h> +#include <dev/isa/madreg.h> + +#ifdef AUDIO_DEBUG +#define DPRINTF(x) if (wssdebug) printf x +extern int wssdebug; +#else +#define DPRINTF(x) +#endif + +static int wssfind __P((struct device *, struct wss_softc *, struct isa_attach_args *)); + +static void madprobe __P((struct wss_softc *, int)); +static void madunmap __P((struct wss_softc *)); +static int detect_mad16 __P((struct wss_softc *, int)); + +int wss_isa_probe __P((struct device *, void *, void *)); +void wss_isa_attach __P((struct device *, struct device *, void *)); + +struct cfattach wss_isa_ca = { + sizeof(struct wss_softc), wss_isa_probe, wss_isa_attach +}; + +struct cfdriver wss_cd = { + NULL, "wss", DV_DULL +}; + +/* + * Probe for the Microsoft Sound System hardware. + */ +int +wss_isa_probe(parent, match, aux) + struct device *parent; +#define __BROKEN_INDIRECT_CONFIG +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; +{ + struct wss_softc probesc, *sc = &probesc; + + bzero(sc, sizeof *sc); +#ifdef __BROKEN_INDIRECT_CONFIG + sc->sc_dev.dv_cfdata = ((struct device *)match)->dv_cfdata; +#else + sc->sc_dev.dv_cfdata = match; +#endif + if (wssfind(parent, sc, aux)) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); + ad1848_unmap(&sc->sc_ad1848); + madunmap(sc); + return 1; + } else + /* Everything is already unmapped */ + return 0; +} + +static int +wssfind(parent, sc, ia) + struct device *parent; + struct wss_softc *sc; + struct isa_attach_args *ia; +{ + static u_char interrupt_bits[12] = { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; + static u_char dma_bits[4] = {1, 2, 0, 3}; + + sc->sc_iot = ia->ia_iot; + if (sc->sc_dev.dv_cfdata->cf_flags & 1) + madprobe(sc, ia->ia_iobase); + else + sc->mad_chip_type = MAD_NONE; + + if (!WSS_BASE_VALID(ia->ia_iobase)) { + DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); + goto bad1; + } + + /* Map the ports upto the AD1848 port */ + if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh)) + goto bad1; + + sc->sc_ad1848.sc_iot = sc->sc_iot; + + /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */ + if (ad1848_mapprobe(&sc->sc_ad1848, ia->ia_iobase + WSS_CODEC) == 0) + goto bad; + + ia->ia_iosize = WSS_NPORT; + + /* Setup WSS interrupt and DMA */ + if (!WSS_DRQ_VALID(ia->ia_drq)) { + DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq)); + goto bad; + } + sc->wss_drq = ia->ia_drq; + + if (sc->wss_drq != DRQUNK && !isa_drq_isfree(parent, sc->wss_drq)) + goto bad; + + if (!WSS_IRQ_VALID(ia->ia_irq)) { + DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq)); + goto bad; + } + + sc->wss_irq = ia->ia_irq; + + if (sc->sc_ad1848.mode <= 1) + ia->ia_drq2 = DRQUNK; + sc->wss_recdrq = + sc->sc_ad1848.mode > 1 && ia->ia_drq2 != DRQUNK ? + ia->ia_drq2 : ia->ia_drq; + if (sc->wss_recdrq != sc->wss_drq && !isa_drq_isfree(parent, sc->wss_recdrq)) + goto bad; + + /* XXX recdrq */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG, + (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq])); + + return 1; + +bad: + bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); +bad1: + madunmap(sc); + return 0; +} + +/* + * Attach hardware to driver, attach hardware driver to audio + * pseudo-device driver . + */ +void +wss_isa_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct wss_softc *sc = (struct wss_softc *)self; + struct isa_attach_args *ia = (struct isa_attach_args *)aux; + + if (!wssfind(parent, sc, ia)) { + printf("%s: wssfind failed\n", sc->sc_dev.dv_xname); + return; + } + + sc->sc_ic = ia->ia_ic; + sc->sc_ad1848.sc_isa = parent; + + wssattach(sc); +} + +/* + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Initialization code for OPTi MAD16 compatible audio chips. Including + * + * OPTi 82C928 MAD16 (replaced by C929) + * OAK OTI-601D Mozart + * OPTi 82C929 MAD16 Pro + * OPTi 82C931 + */ + +static int +detect_mad16(sc, chip_type) + struct wss_softc *sc; + int chip_type; +{ + unsigned char tmp, tmp2; + + sc->mad_chip_type = chip_type; + /* + * Check that reading a register doesn't return bus float (0xff) + * when the card is accessed using password. This may fail in case + * the card is in low power mode. Normally at least the power saving mode + * bit should be 0. + */ + if ((tmp = mad_read(sc, MC1_PORT)) == 0xff) { + DPRINTF(("MC1_PORT returned 0xff\n")); + return 0; + } + + /* + * Now check that the gate is closed on first I/O after writing + * the password. (This is how a MAD16 compatible card works). + */ + if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->mad_ioh, MC1_PORT)) == tmp) { + DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); + return 0; + } + + mad_write(sc, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ + + /* Compare the bit */ + if ((tmp2 = mad_read(sc, MC1_PORT)) != (tmp ^ 0x80)) { + mad_write(sc, MC1_PORT, tmp); /* Restore */ + DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); + return 0; + } + + mad_write(sc, MC1_PORT, tmp); /* Restore */ + return 1; +} + +static void +madprobe(sc, iobase) + struct wss_softc *sc; + int iobase; +{ + static int valid_ports[M_WSS_NPORTS] = + { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 }; + int i; + + /* Allocate bus space that the MAD chip wants */ + if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->mad_ioh)) + goto bad0; + if (bus_space_map(sc->sc_iot, MAD_REG1, MAD_LEN1, 0, &sc->mad_ioh1)) + goto bad1; + if (bus_space_map(sc->sc_iot, MAD_REG2, MAD_LEN2, 0, &sc->mad_ioh2)) + goto bad2; + if (bus_space_map(sc->sc_iot, MAD_REG3, MAD_LEN3, 0, &sc->mad_ioh3)) + goto bad3; + + DPRINTF(("mad: Detect using password = 0xE2\n")); + if (!detect_mad16(sc, MAD_82C928)) { + /* No luck. Try different model */ + DPRINTF(("mad: Detect using password = 0xE3\n")); + if (!detect_mad16(sc, MAD_82C929)) + goto bad; + sc->mad_chip_type = MAD_82C929; + DPRINTF(("mad: 82C929 detected\n")); + } else { + sc->mad_chip_type = MAD_82C928; + if ((mad_read(sc, MC3_PORT) & 0x03) == 0x03) { + DPRINTF(("mad: Mozart detected\n")); + sc->mad_chip_type = MAD_OTI601D; + } else { + DPRINTF(("mad: 82C928 detected?\n")); + sc->mad_chip_type = MAD_82C928; + } + } + +#ifdef AUDIO_DEBUG + if (wssdebug) + for (i = MC1_PORT; i <= MC7_PORT; i++) + printf("mad: port %03x = %02x\n", i, mad_read(sc, i)); +#endif + + /* Set the WSS address. */ + for (i = 0; i < M_WSS_NPORTS; i++) + if (valid_ports[i] == iobase) + break; + if (i >= M_WSS_NPORTS) { /* Not a valid port */ + printf("mad: Bad WSS base address 0x%x\n", iobase); + goto bad; + } + sc->mad_ioindex = i; + /* enable WSS emulation at the I/O port, no joystick */ + mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(i) | MC1_JOYDISABLE); + mad_write(sc, MC2_PORT, 0x03); /* ? */ + mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */ + return; + +bad: + bus_space_unmap(sc->sc_iot, sc->mad_ioh3, MAD_LEN3); +bad3: + bus_space_unmap(sc->sc_iot, sc->mad_ioh2, MAD_LEN2); +bad2: + bus_space_unmap(sc->sc_iot, sc->mad_ioh1, MAD_LEN1); +bad1: + bus_space_unmap(sc->sc_iot, sc->mad_ioh, MAD_NPORT); +bad0: + sc->mad_chip_type = MAD_NONE; +} + +static void +madunmap(sc) + struct wss_softc *sc; +{ + if (sc->mad_chip_type == MAD_NONE) + return; + bus_space_unmap(sc->sc_iot, sc->mad_ioh, MAD_NPORT); + bus_space_unmap(sc->sc_iot, sc->mad_ioh1, MAD_LEN1); + bus_space_unmap(sc->sc_iot, sc->mad_ioh2, MAD_LEN2); + bus_space_unmap(sc->sc_iot, sc->mad_ioh3, MAD_LEN3); +} diff --git a/sys/dev/isa/wssvar.h b/sys/dev/isa/wssvar.h new file mode 100644 index 00000000000..bd290f89476 --- /dev/null +++ b/sys/dev/isa/wssvar.h @@ -0,0 +1,83 @@ +/* $OpenBSD: wssvar.h,v 1.1 1998/04/26 21:02:38 provos Exp $ */ +/* $NetBSD: wssvar.h,v 1.1 1998/01/19 22:18:25 augustss Exp $ */ + +/* + * Copyright (c) 1994 John Brezak + * Copyright (c) 1991-1993 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* + * Mixer devices + */ +#define WSS_MIC_IN_LVL 0 +#define WSS_LINE_IN_LVL 1 +#define WSS_DAC_LVL 2 +#define WSS_REC_LVL 3 +#define WSS_MON_LVL 4 +#define WSS_MIC_IN_MUTE 5 +#define WSS_LINE_IN_MUTE 6 +#define WSS_DAC_MUTE 7 + +#define WSS_RECORD_SOURCE 8 + +/* Classes */ +#define WSS_INPUT_CLASS 9 +#define WSS_RECORD_CLASS 10 +#define WSS_MONITOR_CLASS 11 + +struct wss_softc { + struct device sc_dev; /* base device */ + struct isadev sc_id; /* ISA device */ + void *sc_ih; /* interrupt vectoring */ + bus_space_tag_t sc_iot; /* tag */ + bus_space_handle_t sc_ioh; /* handle */ + isa_chipset_tag_t sc_ic; + + struct ad1848_softc sc_ad1848; +#define wss_irq sc_ad1848.sc_irq +#define wss_drq sc_ad1848.sc_drq +#define wss_recdrq sc_ad1848.sc_recdrq + + int mic_mute, cd_mute, dac_mute; + + int mad_chip_type; /* chip type if MAD emulation of WSS */ + int mad_ioindex; + bus_space_handle_t mad_ioh; /* MAD handle */ + bus_space_handle_t mad_ioh1, mad_ioh2, mad_ioh3; +}; + +void wssattach __P((struct wss_softc *)); + +u_int mad_read __P((struct wss_softc *, int)); +void mad_write __P((struct wss_softc *, int, int)); +void madattach __P((struct wss_softc *)); |