diff options
author | 1998-04-26 21:02:37 +0000 | |
---|---|---|
committer | 1998-04-26 21:02:37 +0000 | |
commit | e99cab2be4365da63b86b0d86d6cce79f3103c64 (patch) | |
tree | 33a2d4aa3f5856eca15ef5c699b9965fbacbe977 | |
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>
36 files changed, 6702 insertions, 4357 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 31a2caa0336..8fc49f6e4be 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.39 1998/01/06 02:35:19 deraadt Exp $ +# $OpenBSD: files.i386,v 1.40 1998/04/26 21:03:14 provos Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -231,6 +231,9 @@ include "../../../compat/bsdos/files.bsdos" include "../../../compat/freebsd/files.freebsd" file arch/i386/i386/freebsd_machdep.c compat_freebsd +# OSS audio driver compatibility +include "compat/ossaudio/files.ossaudio" + device bios {} attach bios at mainbus file arch/i386/i386/bios.c bios needs-count diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 9b5699e9c3e..2cda7503f22 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.85 1998/04/25 20:31:27 mickey Exp $ */ +/* $OpenBSD: machdep.c,v 1.86 1998/04/26 21:03:15 provos Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -2504,8 +2504,28 @@ _bus_dmamem_mmap(t, segs, nsegs, off, prot, flags) bus_dma_segment_t *segs; int nsegs, off, prot, flags; { + int i; + + for (i = 0; i < nsegs; i++) { +#ifdef DIAGNOSTIC + if (off & PGOFSET) + panic("_bus_dmamem_mmap: offset unaligned"); + if (segs[i].ds_addr & PGOFSET) + panic("_bus_dmamem_mmap: segment unaligned"); + if (segs[i].ds_len & PGOFSET) + panic("_bus_dmamem_mmap: segment size not multiple" + " of page size"); +#endif + if (off >= segs[i].ds_len) { + off -= segs[i].ds_len; + continue; + } + + return (i386_btop((caddr_t)segs[i].ds_addr + off)); + } - panic("_bus_dmamem_mmap: not implemented"); + /* Page not found. */ + return (-1); } /********************************************************************** diff --git a/sys/conf/files b/sys/conf/files index e88734697e2..fc2821d63d3 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.77 1998/03/24 03:26:03 deraadt Exp $ +# $OpenBSD: files,v 1.78 1998/04/26 21:03:05 provos Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -9,11 +9,16 @@ define disk define tape define ifnet define tty -define audio +define audio {} define scsi {} # audio device attributes define mulaw +define auconv + +# audio device, attaches to audio hardware driver +device audio +attach audio at audio # net device attributes - we have generic code for arc(net), ether(net), # and fddi. @@ -129,6 +134,7 @@ file ddb/db_watch.c ddb file ddb/db_write_cmd.c ddb file ddb/db_usrreq.c ddb file ddb/db_hangman.c ddb +file dev/auconv.c auconv file dev/audio.c audio needs-flag file dev/ccd.c ccd needs-flag file dev/ic/ncr5380sbc.c ncr5380sbc @@ -235,6 +241,8 @@ file miscfs/procfs/procfs_fpregs.c file miscfs/procfs/procfs_mem.c file miscfs/procfs/procfs_note.c procfs file miscfs/procfs/procfs_regs.c +file miscfs/procfs/procfs_environ.c procfs +file miscfs/procfs/procfs_eproc.c procfs file miscfs/procfs/procfs_status.c procfs file miscfs/procfs/procfs_subr.c procfs file miscfs/procfs/procfs_vfsops.c procfs diff --git a/sys/dev/audio.c b/sys/dev/audio.c index de2ce90db06..e05a3af02df 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,5 +1,5 @@ -/* $OpenBSD: audio.c,v 1.11 1998/04/25 04:57:13 millert Exp $ */ -/* $NetBSD: audio.c,v 1.26 1996/05/13 02:26:15 mycroft Exp $ */ +/* $OpenBSD: audio.c,v 1.12 1998/04/26 21:03:06 provos Exp $ */ +/* $NetBSD: audio.c,v 1.71 1997/09/06 01:14:48 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -57,11 +57,8 @@ /* * Todo: - * - Add softaudio() isr processing for wakeup, select and signals. - * - Allow opens for READ and WRITE (one open each) - * - Setup for single isr for full-duplex - * - Add SIGIO generation for changes in the mixer device - * - Fixup SunOS compat for mixer device changes in ioctl. + * - Add softaudio() isr processing for wakeup, poll, signals, + * and silence fill. */ #include "audio.h" @@ -72,6 +69,7 @@ #include <sys/fcntl.h> #include <sys/vnode.h> #include <sys/select.h> +#include <sys/poll.h> #include <sys/malloc.h> #include <sys/proc.h> #include <sys/systm.h> @@ -80,42 +78,26 @@ #include <sys/signalvar.h> #include <sys/conf.h> #include <sys/audioio.h> +#include <sys/device.h> -#include <dev/audiovar.h> #include <dev/audio_if.h> +#include <dev/audiovar.h> -#ifdef AUDIO_DEBUG -#include <machine/stdarg.h> +#include <vm/vm.h> +#include <vm/vm_prot.h> -void Dprintf __P((const char *, ...)); +#include <machine/endian.h> -void -#ifdef __STDC__ -Dprintf(const char *fmt, ...) -#else -Dprintf(fmt, va_alist) - char *fmt; -#endif -{ - va_list ap; - - va_start(ap, fmt); - log(LOG_DEBUG, "%:", fmt, ap); - va_end(ap); -} - -#define DPRINTF(x) if (audiodebug) Dprintf x +#ifdef AUDIO_DEBUG +#define DPRINTF(x) if (audiodebug) printf x int audiodebug = 0; #else #define DPRINTF(x) #endif -int naudio; /* Count of attached hardware drivers */ +#define ROUNDSIZE(x) x &= -16 /* round to nice boundary */ -int audio_blk_ms = AUDIO_BLK_MS; -int audio_backlog = AUDIO_BACKLOG; - -struct audio_softc *audio_softc[NAUDIO]; +int audio_blk_ms = AUDIO_BLK_MS; int audiosetinfo __P((struct audio_softc *, struct audio_info *)); int audiogetinfo __P((struct audio_softc *, struct audio_info *)); @@ -131,174 +113,388 @@ int audio_mmap __P((dev_t, int, int)); int mixer_open __P((dev_t, int, int, struct proc *)); int mixer_close __P((dev_t, int, int, struct proc *)); int mixer_ioctl __P((dev_t, int, caddr_t, int, struct proc *)); +static void mixer_remove __P((struct audio_softc *, struct proc *p)); +static void mixer_signal __P((struct audio_softc *)); void audio_init_record __P((struct audio_softc *)); void audio_init_play __P((struct audio_softc *)); -void audiostartr __P((struct audio_softc *)); -void audiostartp __P((struct audio_softc *)); +int audiostartr __P((struct audio_softc *)); +int audiostartp __P((struct audio_softc *)); void audio_rint __P((void *)); void audio_pint __P((void *)); -void audio_rpint __P((void *)); -int audio_check_format __P((u_int *, u_int *)); +int audio_check_params __P((struct audio_params *)); -int audio_calc_blksize __P((struct audio_softc *)); -void audio_fill_silence __P((int, u_char *, int)); +void audio_calc_blksize __P((struct audio_softc *, int)); +void audio_fill_silence __P((struct audio_params *, u_char *, int)); int audio_silence_copyout __P((struct audio_softc *, int, struct uio *)); -void audio_alloc_auzero __P((struct audio_softc *, int)); -void audio_printsc __P((struct audio_softc *)); -void audioattach __P((int)); -int audio_hardware_attach __P((struct audio_hw_if *, void *)); -void audio_init_ring __P((struct audio_buffer *, int)); -void audio_initbufs __P((struct audio_softc *)); +void audio_init_ringbuffer __P((struct audio_ringbuffer *)); +int audio_initbufs __P((struct audio_softc *)); +void audio_calcwater __P((struct audio_softc *)); static __inline int audio_sleep_timo __P((int *, char *, int)); static __inline int audio_sleep __P((int *, char *)); static __inline void audio_wakeup __P((int *)); int audio_drain __P((struct audio_softc *)); void audio_clear __P((struct audio_softc *)); +static __inline void audio_pint_silence __P((struct audio_softc *, struct audio_ringbuffer *, u_char *, int)); -#ifdef AUDIO_DEBUG -void -audio_printsc(sc) - struct audio_softc *sc; -{ - printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if); - printf("open %x mode %x\n", sc->sc_open, sc->sc_mode); - printf("rchan %x wchan %x ", sc->sc_rchan, sc->sc_wchan); - printf("rring blk %x pring nblk %x\n", sc->rr.nblk, sc->pr.nblk); - printf("rbus %x pbus %x ", sc->sc_rbus, sc->sc_pbus); - printf("blksz %d sib %d ", sc->sc_blksize, sc->sc_smpl_in_blk); - printf("sp50ms %d backlog %d\n", sc->sc_50ms, sc->sc_backlog); - printf("hiwat %d lowat %d rblks %d\n", sc->sc_hiwat, sc->sc_lowat, - sc->sc_rblks); -} +int audio_alloc_ring __P((struct audio_softc *, struct audio_ringbuffer *, int)); +void audio_free_ring __P((struct audio_softc *, struct audio_ringbuffer *)); + +int audioprint __P((void *, const char *)); + +#define __BROKEN_INDIRECT_CONFIG /* XXX */ +#ifdef __BROKEN_INDIRECT_CONFIG +int audioprobe __P((struct device *, void *, void *)); +#else +int audioprobe __P((struct device *, struct cfdata *, void *)); #endif +void audioattach __P((struct device *, struct device *, void *)); + +struct portname { + char *name; + int mask; +}; +static struct portname itable[] = { + { AudioNmicrophone, AUDIO_MICROPHONE }, + { AudioNline, AUDIO_LINE_IN }, + { AudioNcd, AUDIO_CD }, + { 0 } +}; +static struct portname otable[] = { + { AudioNspeaker, AUDIO_SPEAKER }, + { AudioNheadphone, AUDIO_HEADPHONE }, + { AudioNline, AUDIO_LINE_OUT }, + { 0 } +}; +void au_check_ports __P((struct audio_softc *, struct au_mixer_ports *, + mixer_devinfo_t *, int, char *, char *, + struct portname *)); +int au_set_gain __P((struct audio_softc *, struct au_mixer_ports *, + int, int)); +void au_get_gain __P((struct audio_softc *, struct au_mixer_ports *, + u_int *, u_char *)); +int au_set_port __P((struct audio_softc *, struct au_mixer_ports *, + u_int)); +int au_get_port __P((struct audio_softc *, struct au_mixer_ports *)); +int au_get_lr_value __P((struct audio_softc *, mixer_ctrl_t *, + int *, int *r)); +int au_set_lr_value __P((struct audio_softc *, mixer_ctrl_t *, + int, int)); +int au_portof __P((struct audio_softc *, char *)); + + +/* The default audio mode: 8 kHz mono ulaw */ +struct audio_params audio_default = + { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1 }; + +struct cfattach audio_ca = { + sizeof(struct audio_softc), audioprobe, audioattach +}; + +struct cfdriver audio_cd = { + NULL, "audio", DV_DULL +}; -void -audioattach(num) - int num; +int +audioprobe(parent, match, aux) + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *match; +#endif + void *aux; { + struct audio_attach_args *sa = aux; + + DPRINTF(("audioprobe: type=%d sa=%p hw=%p\n", + sa->type, sa, sa->hwif)); + return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; } -/* - * Called from hardware driver. - */ -int -audio_hardware_attach(hwp, hdlp) - struct audio_hw_if *hwp; - void *hdlp; +void +audioattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - struct audio_softc *sc; - - if (naudio >= NAUDIO) { - DPRINTF(("audio_hardware_attach: not enough audio devices: %d > %d\n", - naudio, NAUDIO)); - return(EINVAL); - } + struct audio_softc *sc = (void *)self; + struct audio_attach_args *sa = aux; + struct audio_hw_if *hwp = sa->hwif; + void *hdlp = sa->hdl; + int error; + mixer_devinfo_t mi; + int iclass, oclass; - /* - * Malloc a softc for the device - */ - /* XXX Find the first free slot */ - audio_softc[naudio] = malloc(sizeof(struct audio_softc), M_DEVBUF, M_WAITOK); - sc = audio_softc[naudio]; - bzero(sc, sizeof(struct audio_softc)); + printf("\n"); - /* XXX too paranoid? */ - if (hwp->open == 0 || +#ifdef DIAGNOSTIC + if (hwp == 0 || + hwp->open == 0 || hwp->close == 0 || - hwp->set_in_sr == 0 || - hwp->get_in_sr == 0 || - hwp->set_out_sr == 0 || - hwp->get_out_sr == 0 || - hwp->set_format == 0 || - hwp->get_encoding == 0 || - hwp->get_precision == 0 || - hwp->set_channels == 0 || - hwp->get_channels == 0 || - hwp->round_blocksize == 0 || - hwp->set_out_port == 0 || - hwp->get_out_port == 0 || - hwp->set_in_port == 0 || - hwp->get_in_port == 0 || - hwp->commit_settings == 0 || + hwp->query_encoding == 0 || + hwp->set_params == 0 || hwp->start_output == 0 || hwp->start_input == 0 || hwp->halt_output == 0 || hwp->halt_input == 0 || - hwp->cont_output == 0 || - hwp->cont_input == 0 || hwp->getdev == 0 || hwp->set_port == 0 || hwp->get_port == 0 || - hwp->query_devinfo == 0) - return(EINVAL); + hwp->query_devinfo == 0 || + hwp->get_props == 0) { + printf("audio: missing method\n"); + sc->hw_if = 0; + return; + } +#endif sc->hw_if = hwp; sc->hw_hdl = hdlp; - - /* - * Alloc DMA play and record buffers - */ - sc->rr.bp = malloc(AU_RING_SIZE, M_DEVBUF, M_WAITOK); - if (sc->rr.bp == 0) { - return (ENOMEM); + sc->sc_dev = parent; + + error = audio_alloc_ring(sc, &sc->sc_pr, AU_RING_SIZE); + if (error) { + sc->hw_if = 0; + return; } - sc->pr.bp = malloc(AU_RING_SIZE, M_DEVBUF, M_WAITOK); - if (sc->pr.bp == 0) { - free(sc->rr.bp, M_DEVBUF); - return (ENOMEM); + error = audio_alloc_ring(sc, &sc->sc_rr, AU_RING_SIZE); + if (error) { + audio_free_ring(sc, &sc->sc_pr); + sc->hw_if = 0; + return; } - + /* * Set default softc params */ - sc->sc_pencoding = sc->sc_rencoding = AUDIO_ENCODING_LINEAR; + sc->sc_pparams = audio_default; + sc->sc_rparams = audio_default; + + /* Set up some default values */ + sc->sc_blkset = 0; + audio_calc_blksize(sc, AUMODE_RECORD); + audio_calc_blksize(sc, AUMODE_PLAY); + audio_init_ringbuffer(&sc->sc_rr); + audio_init_ringbuffer(&sc->sc_pr); + audio_calcwater(sc); + + iclass = oclass = -1; + sc->sc_inports.index = -1; + sc->sc_inports.nports = 0; + sc->sc_inports.isenum = 0; + sc->sc_inports.allports = 0; + sc->sc_outports.index = -1; + sc->sc_outports.nports = 0; + sc->sc_outports.isenum = 0; + sc->sc_outports.allports = 0; + sc->sc_monitor_port = -1; + for(mi.index = 0; ; mi.index++) { + if (hwp->query_devinfo(hdlp, &mi) != 0) + break; + if (mi.type == AUDIO_MIXER_CLASS && + strcmp(mi.label.name, AudioCrecord) == 0) + iclass = mi.index; + if (mi.type == AUDIO_MIXER_CLASS && + strcmp(mi.label.name, AudioCmonitor) == 0) + oclass = mi.index; + } + for(mi.index = 0; ; mi.index++) { + if (hwp->query_devinfo(hdlp, &mi) != 0) + break; + au_check_ports(sc, &sc->sc_inports, &mi, iclass, + AudioNsource, AudioNrecord, itable); + au_check_ports(sc, &sc->sc_outports, &mi, oclass, + AudioNoutput, AudioNmaster, otable); + if (mi.mixer_class == oclass && + strcmp(mi.label.name, AudioNmonitor)) + sc->sc_monitor_port = mi.index; + } + DPRINTF(("audio_attach: inputs ports=0x%x, output ports=0x%x\n", + sc->sc_inports.allports, sc->sc_outports.allports)); +} - /* - * Return the audio unit number - */ - hwp->audio_unit = naudio++; +int +au_portof(sc, name) + struct audio_softc *sc; + char *name; +{ + mixer_devinfo_t mi; + + for(mi.index = 0; + sc->hw_if->query_devinfo(sc->hw_hdl, &mi) == 0; + mi.index++) + if (strcmp(mi.label.name, name) == 0) + return mi.index; + return -1; +} -#ifdef AUDIO_DEBUG - printf("audio: unit %d attached\n", hwp->audio_unit); -#endif - - return(0); +void +au_check_ports(sc, ports, mi, cls, name, mname, tbl) + struct audio_softc *sc; + struct au_mixer_ports *ports; + mixer_devinfo_t *mi; + int cls; + char *name; + char *mname; + struct portname *tbl; +{ + int i, j; + + if (mi->mixer_class != cls) + return; + if (strcmp(mi->label.name, mname) == 0) { + ports->master = mi->index; + return; + } + if (strcmp(mi->label.name, name) != 0) + return; + if (mi->type == AUDIO_MIXER_ENUM) { + ports->index = mi->index; + for(i = 0; tbl[i].name; i++) { + for(j = 0; j < mi->un.e.num_mem; j++) { + if (strcmp(mi->un.e.member[j].label.name, + tbl[i].name) == 0) { + ports->aumask[ports->nports] = tbl[i].mask; + ports->misel [ports->nports] = mi->un.e.member[j].ord; + ports->miport[ports->nports++] = + au_portof(sc, mi->un.e.member[j].label.name); + ports->allports |= tbl[i].mask; + } + } + } + ports->isenum = 1; + } else if (mi->type == AUDIO_MIXER_SET) { + ports->index = mi->index; + for(i = 0; tbl[i].name; i++) { + for(j = 0; j < mi->un.s.num_mem; j++) { + if (strcmp(mi->un.s.member[j].label.name, + tbl[i].name) == 0) { + ports->aumask[ports->nports] = tbl[i].mask; + ports->misel [ports->nports] = mi->un.s.member[j].mask; + ports->miport[ports->nports++] = + au_portof(sc, mi->un.s.member[j].label.name); + ports->allports |= tbl[i].mask; + } + } + } + } } -int -audio_hardware_detach(hwp) - struct audio_hw_if *hwp; +/* + * Called from hardware driver. This is where the MI audio driver gets + * probed/attached to the hardware driver. + */ +void +audio_attach_mi(ahwp, mhwp, hdlp, dev) + struct audio_hw_if *ahwp; + struct midi_hw_if *mhwp; + void *hdlp; + struct device *dev; { - struct audio_softc *sc; - -#ifdef DIAGNOSTIC - if (!hwp) - panic("audio_hardware_detach: null hwp"); - - if (hwp->audio_unit > naudio) - panic("audio_hardware_detach: invalid audio unit"); -#endif + struct audio_attach_args arg; + + if (ahwp != NULL) { + arg.type = AUDIODEV_TYPE_AUDIO; + arg.hwif = ahwp; + arg.hdl = hdlp; + (void)config_found(dev, &arg, audioprint); + } + if (mhwp != NULL) { + arg.type = AUDIODEV_TYPE_MIDI; + arg.hwif = mhwp; + arg.hdl = hdlp; + (void)config_found(dev, &arg, audioprint); + } +} - sc = audio_softc[hwp->audio_unit]; +int +audioprint(aux, pnp) + void *aux; + const char *pnp; +{ + struct audio_attach_args *arg = aux; + const char *type; + + if (pnp != NULL) { + switch (arg->type) { + case AUDIODEV_TYPE_AUDIO: + type = "audio"; + break; + case AUDIODEV_TYPE_MIDI: + type = "midi"; + break; + default: + panic("audioprint: unknown type %d", arg->type); + } + printf("%s at %s", type, pnp); + } + return (UNCONF); +} - if (hwp != sc->hw_if) - return(EINVAL); - - if (sc->sc_open != 0) - return(EBUSY); +#ifdef AUDIO_DEBUG +void audio_printsc __P((struct audio_softc *)); +void audio_print_params __P((char *, struct audio_params *)); - sc->hw_if = 0; +void +audio_printsc(sc) + struct audio_softc *sc; +{ + printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if); + printf("open 0x%x mode 0x%x\n", sc->sc_open, sc->sc_mode); + printf("rchan 0x%x wchan 0x%x ", sc->sc_rchan, sc->sc_wchan); + printf("rring used 0x%x pring used=%d\n", sc->sc_rr.used, sc->sc_pr.used); + printf("rbus 0x%x pbus 0x%x ", sc->sc_rbus, sc->sc_pbus); + printf("blksize %d", sc->sc_pr.blksize); + printf("hiwat %d lowat %d\n", sc->sc_pr.usedhigh, sc->sc_pr.usedlow); +} - /* Free audio buffers */ - free(sc->rr.bp, M_DEVBUF); - free(sc->pr.bp, M_DEVBUF); +void +audio_print_params(s, p) + char *s; + struct audio_params *p; +{ + printf("audio: %s sr=%ld, enc=%d, chan=%d, prec=%d\n", s, + p->sample_rate, p->encoding, p->channels, p->precision); +} +#endif - free(sc, M_DEVBUF); - audio_softc[hwp->audio_unit] = NULL; +int +audio_alloc_ring(sc, r, bufsize) + struct audio_softc *sc; + struct audio_ringbuffer *r; + int bufsize; +{ + struct audio_hw_if *hw = sc->hw_if; + void *hdl = sc->hw_hdl; + /* + * Alloc DMA play and record buffers + */ + ROUNDSIZE(bufsize); + if (bufsize < AUMINBUF) + bufsize = AUMINBUF; + if (hw->round_buffersize) + bufsize = hw->round_buffersize(hdl, bufsize); + r->bufsize = bufsize; + if (hw->alloc) + r->start = hw->alloc(hdl, r->bufsize, M_DEVBUF, M_WAITOK); + else + r->start = malloc(bufsize, M_DEVBUF, M_WAITOK); + if (r->start == 0) + return ENOMEM; + return 0; +} - return(0); +void +audio_free_ring(sc, r) + struct audio_softc *sc; + struct audio_ringbuffer *r; +{ + if (sc->hw_if->free) { + sc->hw_if->free(sc->hw_hdl, r->start, M_DEVBUF); + } else { + free(r->start, M_DEVBUF); + } } int @@ -311,6 +507,7 @@ audioopen(dev, flags, ifmt, p) switch (AUDIODEV(dev)) { case SOUND_DEVICE: case AUDIO_DEVICE: + case AUDIOCTL_DEVICE: return (audio_open(dev, flags, ifmt, p)); case MIXER_DEVICE: return (mixer_open(dev, flags, ifmt, p)); @@ -332,6 +529,8 @@ audioclose(dev, flags, ifmt, p) return (audio_close(dev, flags, ifmt, p)); case MIXER_DEVICE: return (mixer_close(dev, flags, ifmt, p)); + case AUDIOCTL_DEVICE: + return 0; default: return (ENXIO); } @@ -348,6 +547,7 @@ audioread(dev, uio, ioflag) case SOUND_DEVICE: case AUDIO_DEVICE: return (audio_read(dev, uio, ioflag)); + case AUDIOCTL_DEVICE: case MIXER_DEVICE: return (ENODEV); default: @@ -366,6 +566,7 @@ audiowrite(dev, uio, ioflag) case SOUND_DEVICE: case AUDIO_DEVICE: return (audio_write(dev, uio, ioflag)); + case AUDIOCTL_DEVICE: case MIXER_DEVICE: return (ENODEV); default: @@ -385,6 +586,7 @@ audioioctl(dev, cmd, addr, flag, p) switch (AUDIODEV(dev)) { case SOUND_DEVICE: case AUDIO_DEVICE: + case AUDIOCTL_DEVICE: return (audio_ioctl(dev, cmd, addr, flag, p)); case MIXER_DEVICE: return (mixer_ioctl(dev, cmd, addr, flag, p)); @@ -404,6 +606,7 @@ audioselect(dev, events, p) case SOUND_DEVICE: case AUDIO_DEVICE: return (audio_select(dev, events, p)); + case AUDIOCTL_DEVICE: case MIXER_DEVICE: return (0); default: @@ -416,15 +619,15 @@ audiommap(dev, off, prot) dev_t dev; int off, prot; { - switch (AUDIODEV(dev)) { case SOUND_DEVICE: case AUDIO_DEVICE: return (audio_mmap(dev, off, prot)); + case AUDIOCTL_DEVICE: case MIXER_DEVICE: - return (ENODEV); + return -1; default: - return (ENXIO); + return -1; } } @@ -432,30 +635,91 @@ audiommap(dev, off, prot) * Audio driver */ void -audio_init_ring(rp, blksize) - struct audio_buffer *rp; - int blksize; +audio_init_ringbuffer(rp) + struct audio_ringbuffer *rp; { - int nblk = AU_RING_SIZE / blksize; - - rp->ep = rp->bp + nblk * blksize; - rp->hp = rp->tp = rp->bp; - rp->maxblk = nblk; - rp->nblk = 0; - rp->cb_drops = 0; - rp->cb_pdrops = 0; + int nblks; + int blksize = rp->blksize; + + if (blksize < AUMINBLK) + blksize = AUMINBLK; + nblks = rp->bufsize / blksize; + if (nblks < AUMINNOBLK) { + nblks = AUMINNOBLK; + blksize = rp->bufsize / nblks; + ROUNDSIZE(blksize); + } + DPRINTF(("audio_init_ringbuffer: blksize=%d\n", blksize)); + rp->blksize = blksize; + rp->maxblks = nblks; + rp->used = 0; + rp->end = rp->start + nblks * blksize; + rp->inp = rp->outp = rp->start; + rp->stamp = 0; + rp->drops = 0; + rp->pause = 0; + rp->copying = 0; + rp->needfill = 0; + rp->mmapped = 0; } -void +int audio_initbufs(sc) struct audio_softc *sc; { - int nblk = AU_RING_SIZE / sc->sc_blksize; + struct audio_hw_if *hw = sc->hw_if; + int error; - audio_init_ring(&sc->rr, sc->sc_blksize); - audio_init_ring(&sc->pr, sc->sc_blksize); - sc->sc_lowat = nblk / 2; - sc->sc_hiwat = nblk; + DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode)); + audio_init_ringbuffer(&sc->sc_rr); + if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { + error = hw->init_input(sc->hw_hdl, sc->sc_rr.start, + sc->sc_rr.end - sc->sc_rr.start); + if (error) + return error; + } + + audio_init_ringbuffer(&sc->sc_pr); + sc->sc_sil_count = 0; + if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { + error = hw->init_output(sc->hw_hdl, sc->sc_pr.start, + sc->sc_pr.end - sc->sc_pr.start); + if (error) + return error; + } + +#ifdef AUDIO_INTR_TIME + sc->sc_pnintr = 0; + sc->sc_pblktime = (u_long)( + (double)sc->sc_pr.blksize * 1e6 / + (double)(sc->sc_pparams.precision / NBBY * + sc->sc_pparams.channels * + sc->sc_pparams.sample_rate)); + DPRINTF(("audio: play blktime = %lu for %d\n", + sc->sc_pblktime, sc->sc_pr.blksize)); + sc->sc_rnintr = 0; + sc->sc_rblktime = (u_long)( + (double)sc->sc_rr.blksize * 1e6 / + (double)(sc->sc_rparams.precision / NBBY * + sc->sc_rparams.channels * + sc->sc_rparams.sample_rate)); + DPRINTF(("audio: record blktime = %lu for %d\n", + sc->sc_rblktime, sc->sc_rr.blksize)); +#endif + + return 0; +} + +void +audio_calcwater(sc) + struct audio_softc *sc; +{ + sc->sc_pr.usedhigh = sc->sc_pr.end - sc->sc_pr.start; + sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; /* set lowater at 75% */ + if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) + sc->sc_pr.usedlow -= sc->sc_pr.blksize; + sc->sc_rr.usedhigh = sc->sc_pr.end - sc->sc_pr.start - sc->sc_pr.blksize; + sc->sc_rr.usedlow = 0; } static __inline int @@ -468,13 +732,14 @@ audio_sleep_timo(chan, label, timo) if (!label) label = "audio"; - + *chan = 1; - st = (tsleep(chan, PWAIT | PCATCH, label, timo)); + st = tsleep(chan, PWAIT | PCATCH, label, timo); *chan = 0; - if (st != 0) { - DPRINTF(("audio_sleep: %d\n", st)); - } +#ifdef AUDIO_DEBUG + if (st != 0) + printf("audio_sleep: %d\n", st); +#endif return (st); } @@ -483,9 +748,10 @@ audio_sleep(chan, label) int *chan; char *label; { - return audio_sleep_timo(chan, label, 0); + return audio_sleep_timo(chan, label, 0); } +/* call at splaudio() */ static __inline void audio_wakeup(chan) int *chan; @@ -504,31 +770,56 @@ audio_open(dev, flags, ifmt, p) { int unit = AUDIOUNIT(dev); struct audio_softc *sc; - int s, error; + int error; + int mode; struct audio_hw_if *hw; + struct audio_info ai; - if (unit >= NAUDIO || !audio_softc[unit]) { - DPRINTF(("audio_open: invalid device unit - %d\n", unit)); - return (ENODEV); - } + if (unit >= audio_cd.cd_ndevs || + (sc = audio_cd.cd_devs[unit]) == NULL) + return ENXIO; - sc = audio_softc[unit]; hw = sc->hw_if; + if (!hw) + return ENXIO; - DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=0x%x hdl=0x%x\n", dev, flags, sc, sc->hw_hdl)); - if (hw == 0) /* Hardware has not attached to us... */ - return (ENXIO); + DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=%p hdl=%p\n", dev, flags, sc, sc->hw_hdl)); - if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0) /* XXX use flags */ + if (ISDEVAUDIOCTL(dev)) + return 0; + + if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0) return (EBUSY); - if ((error = hw->open(dev, flags)) != 0) + error = hw->open(sc->hw_hdl, flags); + if (error) return (error); - if (flags&FREAD) + sc->sc_async_audio = 0; + sc->sc_rchan = 0; + sc->sc_wchan = 0; + sc->sc_blkset = 0; /* Block sizes not set yet */ + sc->sc_sil_count = 0; + sc->sc_rbus = 0; + sc->sc_pbus = 0; + sc->sc_eof = 0; + sc->sc_playdrop = 0; + + sc->sc_full_duplex = 0; +/* doesn't always work right on SB. + (flags & (FWRITE|FREAD)) == (FWRITE|FREAD) && + (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX); +*/ + + mode = 0; + if (flags & FREAD) { sc->sc_open |= AUOPEN_READ; - if (flags&FWRITE) + mode |= AUMODE_RECORD; + } + if (flags & FWRITE) { sc->sc_open |= AUOPEN_WRITE; + mode |= AUMODE_PLAY | AUMODE_PLAY_ALL; + } /* * Multiplex device: /dev/audio (MU-Law) and /dev/sound (linear) @@ -537,79 +828,46 @@ audio_open(dev, flags, ifmt, p) */ if (ISDEVAUDIO(dev)) { /* /dev/audio */ - hw->set_format(sc->hw_hdl, AUDIO_ENCODING_ULAW, 8); - hw->set_in_sr(sc->hw_hdl, 8000); - hw->set_out_sr(sc->hw_hdl, 8000); - hw->set_channels(sc->hw_hdl, 1); - - sc->sc_pencoding = sc->sc_rencoding = AUDIO_ENCODING_ULAW; + sc->sc_rparams = audio_default; + sc->sc_pparams = audio_default; } - +#ifdef DIAGNOSTIC /* * Sample rate and precision are supposed to be set to proper * default values by the hardware driver, so that it may give * us these values. */ -#ifdef DIAGNOSTIC - if (hw->get_precision(sc->hw_hdl) == 0) - panic("audio_open: hardware driver returned 0 for get_precision"); + if (sc->sc_rparams.precision == 0 || sc->sc_pparams.precision == 0) { + printf("audio_open: 0 precision\n"); + return EINVAL; + } #endif - sc->sc_50ms = 50 * hw->get_out_sr(sc->hw_hdl) / 1000; - - sc->sc_blksize = audio_calc_blksize(sc); - audio_alloc_auzero(sc, sc->sc_blksize); - sc->sc_smpl_in_blk = sc->sc_blksize / - (hw->get_precision(sc->hw_hdl) / NBBY); - audio_initbufs(sc); - sc->sc_backlog = audio_backlog; + AUDIO_INITINFO(&ai); + ai.record.sample_rate = sc->sc_rparams.sample_rate; + ai.record.encoding = sc->sc_rparams.encoding; + ai.record.channels = sc->sc_rparams.channels; + ai.record.precision = sc->sc_rparams.precision; + ai.play.sample_rate = sc->sc_pparams.sample_rate; + ai.play.encoding = sc->sc_pparams.encoding; + ai.play.channels = sc->sc_pparams.channels; + ai.play.precision = sc->sc_pparams.precision; + ai.mode = mode; + sc->sc_pr.blksize = sc->sc_rr.blksize = 0; /* force recalculation */ + error = audiosetinfo(sc, &ai); + if (error) + goto bad; - DPRINTF(("audio_open: rr.bp=%x-%x pr.bp=%x-%x\n", - sc->rr.bp, sc->rr.ep, sc->pr.bp, sc->pr.ep)); + DPRINTF(("audio_open: done sc_mode = 0x%x\n", sc->sc_mode)); - hw->commit_settings(sc->hw_hdl); - - s = splaudio(); - - /* nothing read or written yet */ - sc->sc_rseek = 0; - sc->sc_wseek = 0; - - sc->sc_rchan = 0; - sc->sc_wchan = 0; + return 0; - sc->sc_rbus = 0; - sc->sc_pbus = 0; - - if ((flags & FWRITE) != 0) { - audio_init_play(sc); - /* audio_pint(sc); ??? */ - } - if ((flags & FREAD) != 0) { - /* Play takes precedence if HW is half-duplex */ - if (hw->full_duplex || ((flags & FWRITE) == 0)) { - audio_init_record(sc); - /* audiostartr(sc); don't start recording until read */ - } - } - if (ISDEVAUDIO(dev)) { - /* if open only for read or only for write, then set specific mode */ - if ((flags & (FWRITE|FREAD)) == FWRITE) { - sc->sc_mode = AUMODE_PLAY; - sc->pr.cb_pause = 0; - sc->rr.cb_pause = 1; - audiostartp(sc); - } else if ((flags & (FWRITE|FREAD)) == FREAD) { - sc->sc_mode = AUMODE_RECORD; - sc->rr.cb_pause = 0; - sc->pr.cb_pause = 1; - audiostartr(sc); - } - } - /* Play all sample, and don't pad short writes by default */ - sc->sc_mode |= AUMODE_PLAY_ALL; - splx(s); - return (0); +bad: + hw->close(sc->hw_hdl); + sc->sc_open = 0; + sc->sc_mode = 0; + sc->sc_full_duplex = 0; + return error; } /* @@ -621,9 +879,8 @@ audio_init_record(sc) { int s = splaudio(); - sc->sc_mode |= AUMODE_RECORD; if (sc->hw_if->speaker_ctl && - (!sc->hw_if->full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0)) + (!sc->sc_full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0)) sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF); splx(s); } @@ -637,8 +894,7 @@ audio_init_play(sc) { int s = splaudio(); - sc->sc_mode |= AUMODE_PLAY; - sc->sc_rblks = sc->sc_wblks = 0; + sc->sc_wstamp = sc->sc_pr.stamp; if (sc->hw_if->speaker_ctl) sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON); splx(s); @@ -648,21 +904,57 @@ int audio_drain(sc) struct audio_softc *sc; { - int error; + int error, drops; + struct audio_ringbuffer *cb = &sc->sc_pr; + int s; - while (sc->pr.nblk > 0) { - DPRINTF(("audio_drain: nblk=%d\n", sc->pr.nblk)); + if (sc->sc_pr.mmapped || sc->sc_pr.used <= 0) + return 0; + if (!sc->sc_pbus) { + /* We've never started playing, probably because the + * block was too short. Pad it and start now. + */ + int cc; + u_char *inp = cb->inp; + + cc = cb->blksize - (inp - cb->start) % cb->blksize; + audio_fill_silence(&sc->sc_pparams, inp, cc); + inp += cc; + if (inp >= cb->end) + inp = cb->start; + s = splaudio(); + cb->used += cc; + cb->inp = inp; + error = audiostartp(sc); + splx(s); + if (error) + return error; + } + /* + * Play until a silence block has been played, then we + * know all has been drained. + * XXX This should be done some other way to avoid + * playing silence. + */ +#ifdef DIAGNOSTIC + if (cb->copying) { + printf("audio_drain: copying in progress!?!\n"); + cb->copying = 0; + } +#endif + drops = cb->drops; + error = 0; + s = splaudio(); + while (cb->drops == drops && !error) { + DPRINTF(("audio_drain: used=%d, drops=%ld\n", sc->sc_pr.used, cb->drops)); /* - * XXX * When the process is exiting, it ignores all signals and - * we can't interrupt this sleep, so we set a 1-minute - * timeout. + * we can't interrupt this sleep, so we set a timeout just in case. */ - error = audio_sleep_timo(&sc->sc_wchan, "aud_dr", 60*hz); - if (error) - return (error); + error = audio_sleep_timo(&sc->sc_wchan, "aud_dr", 30*hz); } - return (0); + splx(s); + return error; } /* @@ -676,34 +968,47 @@ audio_close(dev, flags, ifmt, p) struct proc *p; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; + struct audio_softc *sc = audio_cd.cd_devs[unit]; struct audio_hw_if *hw = sc->hw_if; int s; DPRINTF(("audio_close: unit=%d\n", unit)); + /* Stop recording. */ + if (sc->sc_rbus) { + /* + * XXX Some drivers (e.g. SB) use the same routine + * to halt input and output so don't halt input if + * in full duplex mode. These drivers should be fixed. + */ + if (!sc->sc_full_duplex || sc->hw_if->halt_input != sc->hw_if->halt_output) + sc->hw_if->halt_input(sc->hw_hdl); + sc->sc_rbus = 0; + } /* * Block until output drains, but allow ^C interrupt. */ - sc->sc_lowat = 0; /* avoid excessive wakeups */ + sc->sc_pr.usedlow = sc->sc_pr.blksize; /* avoid excessive wakeups */ s = splaudio(); /* * If there is pending output, let it drain (unless * the output is paused). */ - if (sc->sc_pbus && sc->pr.nblk > 0 && !sc->pr.cb_pause) { + if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pr.pause) { if (!audio_drain(sc) && hw->drain) (void)hw->drain(sc->hw_hdl); } hw->close(sc->hw_hdl); - if (flags&FREAD) + if (flags & FREAD) sc->sc_open &= ~AUOPEN_READ; - if (flags&FWRITE) + if (flags & FWRITE) sc->sc_open &= ~AUOPEN_WRITE; - sc->sc_async = 0; + sc->sc_async_audio = 0; + sc->sc_mode = 0; + sc->sc_full_duplex = 0; splx(s); DPRINTF(("audio_close: done\n")); @@ -717,83 +1022,110 @@ audio_read(dev, uio, ioflag) int ioflag; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; - struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->rr; - u_char *hp; - int blocksize = sc->sc_blksize; - int error, s; - - DPRINTF(("audio_read: cc=%d mode=%d rblks=%d\n", - uio->uio_resid, sc->sc_mode, sc->sc_rblks)); - - if (uio->uio_resid == 0) - return (0); + struct audio_softc *sc = audio_cd.cd_devs[unit]; + struct audio_ringbuffer *cb = &sc->sc_rr; + u_char *outp; + int error, s, used, cc, n; - if (uio->uio_resid < blocksize) - return (EINVAL); + if (cb->mmapped) + return EINVAL; - /* First sample we'll read in sample space */ - sc->sc_rseek = cb->au_stamp - AU_RING_LEN(cb); +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_read: cc=%d mode=%d\n", uio->uio_resid, sc->sc_mode); +#endif + error = 0; /* * If hardware is half-duplex and currently playing, return * silence blocks based on the number of blocks we have output. */ - if ((!hw->full_duplex) && + if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY)) { - do { + while (uio->uio_resid > 0 && !error) { s = splaudio(); - while (sc->sc_rblks <= 0) { - DPRINTF(("audio_read: sc_rblks=%d\n", sc->sc_rblks)); + for(;;) { + cc = sc->sc_pr.stamp - sc->sc_wstamp; + if (cc > 0) + break; + DPRINTF(("audio_read: stamp=%lu, wstamp=%lu\n", + sc->sc_pr.stamp, sc->sc_wstamp)); if (ioflag & IO_NDELAY) { splx(s); - return (EWOULDBLOCK); + return EWOULDBLOCK; } - error = audio_sleep(&sc->sc_rchan, "aud hr"); + error = audio_sleep(&sc->sc_rchan, "aud_hr"); if (error) { splx(s); - return (error); + return error; } } splx(s); - error = audio_silence_copyout(sc, blocksize, uio); - if (error) - break; - s = splaudio(); - --sc->sc_rblks; - splx(s); - } while (uio->uio_resid >= blocksize); + + if (uio->uio_resid < cc) + cc = uio->uio_resid; +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_read: reading in write mode, cc=%d\n", cc); +#endif + error = audio_silence_copyout(sc, cc, uio); + sc->sc_wstamp += cc; + } return (error); } - error = 0; - do { - while (cb->nblk <= 0) { + while (uio->uio_resid > 0 && !error) { + s = splaudio(); + while (cb->used <= 0) { if (ioflag & IO_NDELAY) { - error = EWOULDBLOCK; - return (error); + splx(s); + return EWOULDBLOCK; + } + if (!sc->sc_rbus) { + error = audiostartr(sc); + if (error) { + splx(s); + return error; + } + } +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_read: sleep used=%d\n", cb->used); +#endif + error = audio_sleep(&sc->sc_rchan, "aud_rd"); + if (error) { + splx(s); + return error; } - s = splaudio(); - if (!sc->sc_rbus) - audiostartr(sc); - error = audio_sleep(&sc->sc_rchan, "aud rd"); - splx(s); - if (error) - return (error); } - hp = cb->hp; - if (hw->sw_decode) - hw->sw_decode(sc->hw_hdl, sc->sc_rencoding, hp, blocksize); - error = uiomove(hp, blocksize, uio); - if (error) - break; - hp += blocksize; - if (hp >= cb->ep) - hp = cb->bp; - cb->hp = hp; - --cb->nblk; - } while (uio->uio_resid >= blocksize); + used = cb->used; + outp = cb->outp; + cb->copying = 1; + splx(s); + cc = used - cb->usedlow; /* maximum to read */ + n = cb->end - outp; + if (n < cc) + cc = n; /* don't read beyond end of buffer */ + + if (uio->uio_resid < cc) + cc = uio->uio_resid; /* and no more than we want */ + if (sc->sc_rparams.sw_code) + sc->sc_rparams.sw_code(sc->hw_hdl, outp, cc); +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_read: outp=%p, cc=%d\n", outp, cc); +#endif + error = uiomove(outp, cc, uio); + used -= cc; + outp += cc; + if (outp >= cb->end) + outp = cb->start; + s = splaudio(); + cb->outp = outp; + cb->used = used; + cb->copying = 0; + splx(s); + } return (error); } @@ -803,132 +1135,131 @@ audio_clear(sc) { int s = splaudio(); - if (sc->sc_rbus || sc->sc_pbus) { - sc->hw_if->halt_output(sc->hw_hdl); + if (sc->sc_rbus) { + audio_wakeup(&sc->sc_rchan); sc->hw_if->halt_input(sc->hw_hdl); sc->sc_rbus = 0; + } + if (sc->sc_pbus) { + audio_wakeup(&sc->sc_wchan); + sc->hw_if->halt_output(sc->hw_hdl); sc->sc_pbus = 0; } - AU_RING_INIT(&sc->rr); - AU_RING_INIT(&sc->pr); - sc->sc_rblks = sc->sc_wblks = 0; - splx(s); } -int -audio_calc_blksize(sc) +void +audio_calc_blksize(sc, mode) struct audio_softc *sc; + int mode; { struct audio_hw_if *hw = sc->hw_if; + struct audio_params *parm; + struct audio_ringbuffer *rb; int bs; + + if (sc->sc_blkset) + return; + + if (mode == AUMODE_PLAY) { + parm = &sc->sc_pparams; + rb = &sc->sc_pr; + } else { + parm = &sc->sc_rparams; + rb = &sc->sc_rr; + } - bs = hw->get_out_sr(sc->hw_hdl) * audio_blk_ms / 1000; - if (bs == 0) - bs = 1; - bs *= hw->get_channels(sc->hw_hdl); - bs *= hw->get_precision(sc->hw_hdl) / NBBY; - if (bs > AU_RING_SIZE/2) - bs = AU_RING_SIZE/2; - bs = hw->round_blocksize(sc->hw_hdl, bs); - if (bs > AU_RING_SIZE) - bs = AU_RING_SIZE; - - return(bs); + bs = parm->sample_rate * audio_blk_ms / 1000 * + parm->channels * parm->precision / NBBY * + parm->factor; + ROUNDSIZE(bs); + if (hw->round_blocksize) + bs = hw->round_blocksize(sc->hw_hdl, bs); + rb->blksize = bs; + + DPRINTF(("audio_calc_blksize: %s blksize=%d\n", + mode == AUMODE_PLAY ? "play" : "record", bs)); } void -audio_fill_silence(encoding, p, n) - int encoding; +audio_fill_silence(params, p, n) + struct audio_params *params; u_char *p; int n; { - u_int auzero; - u_char *q; - - switch (encoding) { + u_char auzero0, auzero1 = 0; /* initialize to please gcc */ + int nfill = 1; + + switch (params->encoding) { case AUDIO_ENCODING_ULAW: - auzero = 0x7f; + auzero0 = 0x7f; break; case AUDIO_ENCODING_ALAW: - auzero = 0x55; + auzero0 = 0x55; break; + case AUDIO_ENCODING_MPEG_L1_STREAM: + case AUDIO_ENCODING_MPEG_L1_PACKETS: + case AUDIO_ENCODING_MPEG_L1_SYSTEM: + case AUDIO_ENCODING_MPEG_L2_STREAM: + case AUDIO_ENCODING_MPEG_L2_PACKETS: + case AUDIO_ENCODING_MPEG_L2_SYSTEM: case AUDIO_ENCODING_ADPCM: /* is this right XXX */ - case AUDIO_ENCODING_PCM8: - case AUDIO_ENCODING_PCM16: + case AUDIO_ENCODING_SLINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + auzero0 = 0; /* fortunately this works for both 8 and 16 bits */ + break; + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_ULINEAR_BE: + if (params->precision == 16) { + nfill = 2; + if (params->encoding == AUDIO_ENCODING_ULINEAR_LE) { + auzero0 = 0; + auzero1 = 0x80; + } else { + auzero0 = 0x80; + auzero1 = 0; + } + } else + auzero0 = 0x80; + break; default: - auzero = 0; /* fortunately this works for both 8 and 16 bits */ + DPRINTF(("audio: bad encoding %d\n", params->encoding)); + auzero0 = 0; break; } - q = p; - while (--n >= 0) - *q++ = auzero; + if (nfill == 1) { + while (--n >= 0) + *p++ = auzero0; /* XXX memset */ + } else /* nfill must be 2 */ { + while (n > 1) { + *p++ = auzero0; + *p++ = auzero1; + n -= 2; + } + } } -#define NSILENCE 128 /* An arbitrary even constant >= 2 */ int audio_silence_copyout(sc, n, uio) struct audio_softc *sc; int n; struct uio *uio; { - struct iovec *iov; - int error = 0; - u_char zerobuf[NSILENCE]; + int error; int k; + u_char zerobuf[128]; - audio_fill_silence(sc->sc_rencoding, zerobuf, NSILENCE); - - while (n > 0 && uio->uio_resid) { - iov = uio->uio_iov; - if (iov->iov_len == 0) { - uio->uio_iov++; - uio->uio_iovcnt--; - continue; - } - k = min(min(n, iov->iov_len), NSILENCE); - switch (uio->uio_segflg) { - case UIO_USERSPACE: - error = copyout(zerobuf, iov->iov_base, k); - if (error) - return (error); - break; - - case UIO_SYSSPACE: - bcopy(zerobuf, iov->iov_base, k); - break; - } - iov->iov_base += k; - iov->iov_len -= k; - uio->uio_resid -= k; - uio->uio_offset += k; - n -= k; - } - return (error); -} - -void -audio_alloc_auzero(sc, bs) - struct audio_softc *sc; - int bs; -{ - struct audio_hw_if *hw = sc->hw_if; - - if (sc->auzero_block) - free(sc->auzero_block, M_DEVBUF); + audio_fill_silence(&sc->sc_rparams, zerobuf, sizeof zerobuf); - sc->auzero_block = malloc(bs, M_DEVBUF, M_WAITOK); -#ifdef DIAGNOSTIC - if (sc->auzero_block == 0) { - panic("audio_alloc_auzero: malloc auzero_block failed"); + error = 0; + while (n > 0 && uio->uio_resid > 0 && !error) { + k = min(n, min(uio->uio_resid, sizeof zerobuf)); + error = uiomove(zerobuf, k, uio); + n -= k; } -#endif - audio_fill_silence(sc->sc_pencoding, sc->auzero_block, bs); - if (hw->sw_encode) - hw->sw_encode(sc->hw_hdl, sc->sc_pencoding, sc->auzero_block, bs); + return (error); } - int audio_write(dev, uio, ioflag) dev_t dev; @@ -936,171 +1267,159 @@ audio_write(dev, uio, ioflag) int ioflag; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; - struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->pr; - u_char *tp; - int error, s, cc; - int blocksize = sc->sc_blksize; + struct audio_softc *sc = audio_cd.cd_devs[unit]; + struct audio_ringbuffer *cb = &sc->sc_pr; + u_char *inp, *einp; + int error, s, n, cc, used; + + DPRINTF(("audio_write: sc=%p(unit=%d) count=%d used=%d(hi=%d)\n", sc, unit, + uio->uio_resid, sc->sc_pr.used, sc->sc_pr.usedhigh)); + + if (cb->mmapped) + return EINVAL; + + if (uio->uio_resid == 0) { + sc->sc_eof++; + return 0; + } - DPRINTF(("audio_write: cc=%d hiwat=%d\n", uio->uio_resid, sc->sc_hiwat)); /* * If half-duplex and currently recording, throw away data. */ - if (!hw->full_duplex && + if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_RECORD)) { uio->uio_offset += uio->uio_resid; uio->uio_resid = 0; DPRINTF(("audio_write: half-dpx read busy\n")); return (0); } - error = 0; - while (uio->uio_resid > 0) { - if (cb->fill > 0) { - if (sc->sc_pbus == 0) { - /* playing has stopped, ignore fill */ - cb->fill = 0; - } else { - /* Write samples in the silence fill space. - * We don't know where the DMA is - * happening in the buffer, but if we - * are lucky we will fill the buffer before - * playing has reached the point we move to. - * If we are unlucky some sample will - * not be played. - */ - cc = min(cb->fill, uio->uio_resid); - error = uiomove(cb->otp, cc, uio); - if (error == 0) { - if (hw->sw_encode) - hw->sw_encode(sc->hw_hdl, - sc->sc_pencoding, cb->otp, - cc); - cb->fill -= cc; - cb->otp += cc; - } - continue; - } - } - if (cb->nblk >= sc->sc_hiwat) { - do { - DPRINTF(("audio_write: nblk=%d hiwat=%d lowat=%d\n", cb->nblk, sc->sc_hiwat, sc->sc_lowat)); - if (ioflag & IO_NDELAY) - return (EWOULDBLOCK); - error = audio_sleep(&sc->sc_wchan, "aud wr"); - if (error) - return (error); - } while (cb->nblk >= sc->sc_lowat); - } -#if 0 - if (cb->nblk == 0 && - cb->maxblk > sc->sc_backlog && - uio->uio_resid <= blocksize && - (cb->au_stamp - sc->sc_wseek) > sc->sc_50ms) { - /* - * the write is 'small', the buffer is empty - * and we have been silent for at least 50ms - * so we might be dealing with an application - * that writes frames synchronously with - * reading them. If so, we need an output - * backlog to cover scheduling delays or - * there will be gaps in the sound output. - * Also take this opportunity to reset the - * buffer pointers in case we ended up on - * a bad boundary (odd byte, blksize bytes - * from end, etc.). - */ - DPRINTF(("audiowrite: set backlog %d\n", sc->sc_backlog)); - s = splaudio(); - cb->hp = cb->bp; - cb->nblk = sc->sc_backlog; - cb->tp = cb->hp + sc->sc_backlog * blocksize; - splx(s); - audio_fill_silence(sc->sc_pencoding, cb->hp, sc->sc_backlog * blocksize); - } + if (!(sc->sc_mode & AUMODE_PLAY_ALL) && sc->sc_playdrop > 0) { + n = min(sc->sc_playdrop, uio->uio_resid); + DPRINTF(("audio_write: playdrop %d\n", n)); + uio->uio_offset += n; + uio->uio_resid -= n; + sc->sc_playdrop -= n; + if (uio->uio_resid == 0) + return 0; + } + +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_write: sr=%ld, enc=%d, prec=%d, chan=%d, sw=%p, fact=%d\n", + sc->sc_pparams.sample_rate, sc->sc_pparams.encoding, + sc->sc_pparams.precision, sc->sc_pparams.channels, + sc->sc_pparams.sw_code, sc->sc_pparams.factor); #endif - /* Calculate sample number of first sample in block we write */ + + error = 0; + while (uio->uio_resid > 0 && !error) { s = splaudio(); - sc->sc_wseek = AU_RING_LEN(cb) + cb->au_stamp; + while (cb->used >= cb->usedhigh) { + DPRINTF(("audio_write: sleep used=%d lowat=%d hiwat=%d\n", + cb->used, cb->usedlow, cb->usedhigh)); + if (ioflag & IO_NDELAY) { + splx(s); + return (EWOULDBLOCK); + } + error = audio_sleep(&sc->sc_wchan, "aud_wr"); + if (error) { + splx(s); + return error; + } + } + used = cb->used; + inp = cb->inp; + cb->copying = 1; splx(s); - - tp = cb->tp; - cc = uio->uio_resid; - -#ifdef AUDIO_DEBUG - if (audiodebug > 1) { - int left = cb->ep - tp; - Dprintf("audio_write: cc=%d tp=%p bs=%d nblk=%d left=%d\n", cc, tp, blocksize, cb->nblk, left); + cc = cb->usedhigh - used; /* maximum to write */ + n = cb->end - inp; + if (sc->sc_pparams.factor != 1) { + /* Compensate for software coding expansion factor. */ + n /= sc->sc_pparams.factor; + cc /= sc->sc_pparams.factor; } -#endif + if (n < cc) + cc = n; /* don't write beyond end of buffer */ + if (uio->uio_resid < cc) + cc = uio->uio_resid; /* and no more than we have */ + #ifdef DIAGNOSTIC - { - int towrite = (cc < blocksize)?cc:blocksize; - - /* check for an overwrite. Should never happen */ - if ((tp + towrite) > cb->ep) { - DPRINTF(("audio_write: overwrite tp=%p towrite=%d ep=0x%x bs=%d\n", - tp, towrite, cb->ep, blocksize)); - printf("audio_write: overwrite tp=%p towrite=%d ep=%p\n", - tp, towrite, cb->ep); - tp = cb->bp; + /* + * This should never happen since the block size and and + * block pointers are always nicely aligned. + */ + if (cc == 0) { + printf("audio_write: cc == 0, swcode=%p, factor=%d\n", + sc->sc_pparams.sw_code, sc->sc_pparams.factor); + cb->copying = 0; + return EINVAL; } - } #endif - if (cc < blocksize) { - error = uiomove(tp, cc, uio); - if (error == 0) { - /* fill with audio silence */ - tp += cc; - cc = blocksize - cc; - cb->fill = cc; - cb->otp = tp; - audio_fill_silence(sc->sc_pencoding, tp, cc); - DPRINTF(("audio_write: auzero 0x%x %d 0x%x\n", - tp, cc, *(int *)tp)); - tp += cc; - } - } else { - error = uiomove(tp, blocksize, uio); - if (error == 0) { - tp += blocksize; - } - } - if (error) { #ifdef AUDIO_DEBUG - printf("audio_write:(1) uiomove failed %d; cc=%d tp=%p bs=%d\n", error, cc, tp, blocksize); + if (audiodebug > 1) + printf("audio_write: uiomove cc=%d inp=%p, left=%d\n", cc, inp, uio->uio_resid); #endif - break; - } + n = uio->uio_resid; + error = uiomove(inp, cc, uio); + cc = n - uio->uio_resid; /* number of bytes actually moved */ +#ifdef AUDIO_DEBUG + if (error) + printf("audio_write:(1) uiomove failed %d; cc=%d inp=%p\n", + error, cc, inp); +#endif + /* + * Continue even if uiomove() failed because we may have + * gotten a partial block. + */ - if (hw->sw_encode) - hw->sw_encode(sc->hw_hdl, sc->sc_pencoding, cb->tp, - blocksize); + if (sc->sc_pparams.sw_code) { + sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc); + /* Adjust count after the expansion. */ + cc *= sc->sc_pparams.factor; +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_write: expanded cc=%d\n", cc); +#endif + } + + einp = cb->inp + cc; + if (einp >= cb->end) + einp = cb->start; - /* wrap the ring buffer if at end */ s = splaudio(); - if ((sc->sc_mode & AUMODE_PLAY_ALL) == 0 && sc->sc_wblks) - /* - * discard the block if we sent out a silence - * packet that hasn't yet been countered - * by user data. (They must supply enough - * data to catch up to "real time"). - */ - sc->sc_wblks--; - else { - if (tp >= cb->ep) - tp = cb->bp; - cb->tp = tp; - ++cb->nblk; /* account for buffer filled */ - - /* - * If output isn't active, start it up. - */ - if (sc->sc_pbus == 0) - audiostartp(sc); - } + /* + * This is a very suboptimal way of keeping track of + * silence in the buffer, but it is simple. + */ + sc->sc_sil_count = 0; + + cb->inp = einp; + cb->used += cc; + /* If the interrupt routine wants the last block filled AND + * the copy did not fill the last block completely it needs to + * be padded. + */ + if (cb->needfill && + (inp - cb->start) / cb->blksize == + (einp - cb->start) / cb->blksize) { + /* Figure out how many bytes there is to a block boundary. */ + cc = cb->blksize - (einp - cb->start) % cb->blksize; + DPRINTF(("audio_write: partial fill %d\n", cc)); + } else + cc = 0; + cb->needfill = 0; + cb->copying = 0; + if (!sc->sc_pbus && !cb->pause) + error = audiostartp(sc); /* XXX should not clobber error */ splx(s); + if (cc) { +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_write: fill %d\n", cc); +#endif + audio_fill_silence(&sc->sc_pparams, einp, cc); + } } return (error); } @@ -1114,34 +1433,45 @@ audio_ioctl(dev, cmd, addr, flag, p) struct proc *p; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; + struct audio_softc *sc = audio_cd.cd_devs[unit]; struct audio_hw_if *hw = sc->hw_if; - int error = 0, s; + struct audio_offset *ao; + int error = 0, s, offs, fd; + int rbus, pbus; DPRINTF(("audio_ioctl(%d,'%c',%d)\n", IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff)); switch (cmd) { + case FIONBIO: + /* All handled in the upper FS layer. */ + break; case FIOASYNC: if (*(int *)addr) { - if (sc->sc_async) + if (sc->sc_async_audio) return (EBUSY); - sc->sc_async = p; + sc->sc_async_audio = p; + DPRINTF(("audio_ioctl: FIOASYNC %p\n", p)); } else - sc->sc_async = 0; + sc->sc_async_audio = 0; break; case AUDIO_FLUSH: DPRINTF(("AUDIO_FLUSH\n")); + rbus = sc->sc_rbus; + pbus = sc->sc_pbus; audio_clear(sc); s = splaudio(); - if ((sc->sc_mode & AUMODE_PLAY) && (sc->sc_pbus == 0)) - audiostartp(sc); - /* Again, play takes precedence on half-duplex hardware */ - if ((sc->sc_mode & AUMODE_RECORD) && - (hw->full_duplex || - ((sc->sc_mode & AUMODE_PLAY) == 0))) - audiostartr(sc); + error = audio_initbufs(sc); + if (error) { + splx(s); + return error; + } + if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pbus && pbus) + error = audiostartp(sc); + if (!error && + (sc->sc_mode & AUMODE_RECORD) && !sc->sc_rbus && rbus) + error = audiostartr(sc); splx(s); break; @@ -1150,25 +1480,51 @@ audio_ioctl(dev, cmd, addr, flag, p) * when they were dropped. */ case AUDIO_RERROR: - *(int *)addr = sc->rr.cb_drops; + *(int *)addr = sc->sc_rr.drops; break; case AUDIO_PERROR: - *(int *)addr = sc->pr.cb_drops; + *(int *)addr = sc->sc_pr.drops; break; /* - * How many samples will elapse until mike hears the first - * sample of what we last wrote? + * Offsets into buffer. */ - case AUDIO_WSEEK: + case AUDIO_GETIOFFS: + s = splaudio(); + /* figure out where next DMA will start */ + ao = (struct audio_offset *)addr; + ao->samples = sc->sc_rr.stamp; + ao->deltablks = (sc->sc_rr.stamp - sc->sc_rr.stamp_last) / sc->sc_rr.blksize; + sc->sc_rr.stamp_last = sc->sc_rr.stamp; + ao->offset = sc->sc_rr.inp - sc->sc_rr.start; + splx(s); + break; + + case AUDIO_GETOOFFS: s = splaudio(); - *(u_long *)addr = sc->sc_wseek - sc->pr.au_stamp - + AU_RING_LEN(&sc->rr); + /* figure out where next DMA will start */ + ao = (struct audio_offset *)addr; + offs = sc->sc_pr.outp - sc->sc_pr.start + sc->sc_pr.blksize; + if (sc->sc_pr.start + offs >= sc->sc_pr.end) + offs = 0; + ao->samples = sc->sc_pr.stamp; + ao->deltablks = (sc->sc_pr.stamp - sc->sc_pr.stamp_last) / sc->sc_pr.blksize; + sc->sc_pr.stamp_last = sc->sc_pr.stamp; + ao->offset = offs; splx(s); break; + + /* + * How many bytes will elapse until mike hears the first + * sample of what we write next? + */ + case AUDIO_WSEEK: + *(u_long *)addr = sc->sc_rr.used; + break; + case AUDIO_SETINFO: - DPRINTF(("AUDIO_SETINFO\n")); + DPRINTF(("AUDIO_SETINFO mode=0x%x\n", sc->sc_mode)); error = audiosetinfo(sc, (struct audio_info *)addr); break; @@ -1196,12 +1552,30 @@ audio_ioctl(dev, cmd, addr, flag, p) case AUDIO_GETFD: DPRINTF(("AUDIO_GETFD\n")); - *(int *)addr = hw->full_duplex; + *(int *)addr = sc->sc_full_duplex; break; case AUDIO_SETFD: DPRINTF(("AUDIO_SETFD\n")); - error = hw->setfd(sc->hw_hdl, *(int *)addr); + fd = *(int *)addr; + if (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX) { + if (hw->setfd) + error = hw->setfd(sc->hw_hdl, fd); + else + error = 0; + if (!error) + sc->sc_full_duplex = fd; + } else { + if (fd) + error = ENOTTY; + else + error = 0; + } + break; + + case AUDIO_GETPROPS: + DPRINTF(("AUDIO_GETPROPS\n")); + *(int *)addr = hw->get_props(sc->hw_hdl); break; default: @@ -1221,22 +1595,17 @@ audio_select(dev, rw, p) struct proc *p; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; + struct audio_softc *sc = audio_cd.cd_devs[unit]; int s = splaudio(); -#if 0 - DPRINTF(("audio_select: rw=%d mode=%d rblks=%d rr.nblk=%d\n", - rw, sc->sc_mode, sc->sc_rblks, sc->rr.nblk)); -#endif + DPRINTF(("audio_select: rw=0x%x mode=%d\n", rw, sc->sc_mode)); + switch (rw) { case FREAD: - if (sc->sc_mode & AUMODE_PLAY) { - if (sc->sc_rblks > 0) { - splx(s); - return (1); - } - } else if (sc->rr.nblk > 0) { + if ((sc->sc_mode & AUMODE_PLAY) ? + sc->sc_pr.stamp > sc->sc_wstamp : + sc->sc_rr.used > sc->sc_rr.usedlow) { splx(s); return (1); } @@ -1244,18 +1613,8 @@ audio_select(dev, rw, p) break; case FWRITE: - /* - * Can write if we're recording because it gets preempted. - * Otherwise, can write when below low water. - * XXX this won't work right if we're in - * record mode -- we need to note that a write - * select has happed and flip the speaker. - * - * XXX The above XXX-comment is SoundBlaster-dependent, - * right? Or maybe specific to half-duplex devices? - */ if (sc->sc_mode & AUMODE_RECORD || - sc->pr.nblk <= sc->sc_lowat) { + sc->sc_pr.used <= sc->sc_pr.usedlow) { splx(s); return (1); } @@ -1271,64 +1630,159 @@ audio_mmap(dev, off, prot) dev_t dev; int off, prot; { - /* XXX placeholder */ - return (-1); + int s; + int unit = AUDIOUNIT(dev); + struct audio_softc *sc = audio_cd.cd_devs[unit]; + struct audio_hw_if *hw = sc->hw_if; + struct audio_ringbuffer *cb; + + DPRINTF(("audio_mmap: off=%d, prot=%d\n", off, prot)); + + if (!(hw->get_props(sc->hw_hdl) & AUDIO_PROP_MMAP) || !hw->mappage) + return -1; +#if 0 +/* XXX + * The idea here was to use the protection to determine if + * we are mapping the read or write buffer, but it fails. + * The VM system is broken in (at least) two ways. + * 1) If you map memory VM_PROT_WRITE you SIGSEGV + * when writing to it, so VM_PROT_READ|VM_PROT_WRITE + * has to be used for mmapping the play buffer. + * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE + * audio_mmap will get called at some point with VM_PROT_READ + * only. + * So, alas, we always map the play buffer for now. + */ + if (prot == (VM_PROT_READ|VM_PROT_WRITE) || + prot == VM_PROT_WRITE) + cb = &sc->sc_pr; + else if (prot == VM_PROT_READ) + cb = &sc->sc_rr; + else + return -1; +#else + cb = &sc->sc_pr; +#endif + + if (off >= cb->bufsize) + return -1; + if (!cb->mmapped) { + cb->mmapped = 1; + if (cb == &sc->sc_pr) { + audio_fill_silence(&sc->sc_pparams, cb->start, cb->bufsize); + s = splaudio(); + if (!sc->sc_pbus) + (void)audiostartp(sc); + splx(s); + } else { + s = splaudio(); + if (!sc->sc_rbus) + (void)audiostartr(sc); + splx(s); + } + } + + return hw->mappage(sc->hw_hdl, cb->start, off, prot); } -void +int audiostartr(sc) struct audio_softc *sc; { int error; - DPRINTF(("audiostartr: tp=%p\n", sc->rr.tp)); + DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n", + sc->sc_rr.start, sc->sc_rr.used, sc->sc_rr.usedhigh, + sc->sc_rr.mmapped)); - error = sc->hw_if->start_input(sc->hw_hdl, sc->rr.tp, sc->sc_blksize, - audio_rint, (void *)sc); + error = sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.start, + sc->sc_rr.blksize, audio_rint, (void *)sc); if (error) { DPRINTF(("audiostartr failed: %d\n", error)); - audio_clear(sc); + return error; } - else - sc->sc_rbus = 1; + sc->sc_rbus = 1; + return 0; } -void +int audiostartp(sc) struct audio_softc *sc; { int error; - DPRINTF(("audiostartp: hp=0x%x nblk=%d\n", sc->pr.hp, sc->pr.nblk)); + DPRINTF(("audiostartp: start=%p used=%d(hi=%d) mmapped=%d\n", + sc->sc_pr.start, sc->sc_pr.used, sc->sc_pr.usedhigh, + sc->sc_pr.mmapped)); - if (sc->pr.nblk > 0) { - u_char *hp = sc->pr.hp; - error = sc->hw_if->start_output(sc->hw_hdl, hp, sc->sc_blksize, - audio_rpint, (void *)sc); + if (sc->sc_pr.used >= sc->sc_pr.blksize || sc->sc_pr.mmapped) { + error = sc->hw_if->start_output(sc->hw_hdl, sc->sc_pr.outp, + sc->sc_pr.blksize, audio_pint, (void *)sc); if (error) { - DPRINTF(("audiostartp: failed: %d\n", error)); - } - else { - sc->sc_pbus = 1; - hp += sc->sc_blksize; - if (hp >= sc->pr.ep) - hp = sc->pr.bp; - sc->pr.hp = hp; + DPRINTF(("audiostartp failed: %d\n", error)); + return error; } + sc->sc_pbus = 1; } + return 0; } /* - * Use this routine as DMA callback if we played user data. We need to - * account for user data and silence separately. + * When the play interrupt routine finds that the write isn't keeping + * the buffer filled it will insert silence in the buffer to make up + * for this. The part of the buffer that is filled with silence + * is kept track of in a very approcimate way: it starts at sc_sil_start + * and extends sc_sil_count bytes. If the writer doesn't write sc_sil_count + * get to encompass the whole buffer after which no more filling needs + * to be done. When the writer starts again sc_sil_count is set to 0. */ -void -audio_rpint(v) - void *v; +/* XXX + * Putting silence into the output buffer should not really be done + * at splaudio, but there is no softaudio level to do it at yet. + */ +static __inline void +audio_pint_silence(sc, cb, inp, cc) + struct audio_softc *sc; + struct audio_ringbuffer *cb; + u_char *inp; + int cc; { - struct audio_softc *sc = v; - sc->pr.nblk--; - audio_pint(v); /* 'twas a real audio block */ + u_char *s, *e, *p, *q; + + if (sc->sc_sil_count > 0) { + s = sc->sc_sil_start; /* start of silence */ + e = s + sc->sc_sil_count; /* end of silence, may be beyond end */ + p = inp; /* adjusted pointer to area to fill */ + if (p < s) + p += cb->end - cb->start; + q = p+cc; + /* Check if there is already silence. */ + if (!(s <= p && p < e && + s <= q && q <= e)) { + if (s <= p) + sc->sc_sil_count = max(sc->sc_sil_count, q - s); +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: fill cc=%d inp=%p, count=%d size=%d\n", + cc, inp, sc->sc_sil_count, (int)(cb->end - cb->start)); +#endif + audio_fill_silence(&sc->sc_pparams, inp, cc); + } else { +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: already silent cc=%d inp=%p\n", cc, inp); +#endif + + } + } else { + sc->sc_sil_start = inp; + sc->sc_sil_count = cc; +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: start fill %p %d\n", inp, cc); +#endif + audio_fill_silence(&sc->sc_pparams, inp, cc); + } } /* @@ -1342,90 +1796,128 @@ audio_pint(v) void *v; { struct audio_softc *sc = v; - u_char *hp; - int cc = sc->sc_blksize; struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->pr; + struct audio_ringbuffer *cb = &sc->sc_pr; + u_char *inp; + int cc, ccr; int error; - - /* - * XXX - * if there is only one buffer in the ring, this test - * always fails and the output is always silence after the - * first block. - */ - if (cb->nblk > 0) { - hp = cb->hp; - if (cb->cb_pause) { - cb->cb_pdrops++; + + if (!sc->sc_open) + return; /* ignore interrupt if not open */ + + cb->outp += cb->blksize; + if (cb->outp >= cb->end) + cb->outp = cb->start; + cb->stamp += cb->blksize / sc->sc_pparams.factor; + if (cb->mmapped) { #ifdef AUDIO_DEBUG - if (audiodebug > 1) - Dprintf("audio_pint: paused %d\n", cb->cb_pdrops); + if (audiodebug > 2) + printf("audio_pint: mmapped outp=%p cc=%d inp=%p\n", + cb->outp, cb->blksize, cb->inp); #endif - goto psilence; - } - else { + (void)hw->start_output(sc->hw_hdl, cb->outp, cb->blksize, + audio_pint, (void *)sc); + return; + } + +#ifdef AUDIO_INTR_TIME + { + struct timeval tv; + u_long t; + microtime(&tv); + t = tv.tv_usec + 1000000 * tv.tv_sec; + if (sc->sc_pnintr) { + long lastdelta, totdelta; + lastdelta = t - sc->sc_plastintr - sc->sc_pblktime; + if (lastdelta > sc->sc_pblktime / 5) { + printf("audio: play interrupt(%d) off relative by %ld us (%lu)\n", + sc->sc_pnintr, lastdelta, sc->sc_pblktime); + } + totdelta = t - sc->sc_pfirstintr - sc->sc_pblktime * sc->sc_pnintr; + if (totdelta > sc->sc_pblktime / 2) { + sc->sc_pnintr++; + printf("audio: play interrupt(%d) off absolute by %ld us (%lu)\n", + sc->sc_pnintr, totdelta, sc->sc_pblktime); + sc->sc_pnintr++; /* avoid repeated messages */ + } + } else + sc->sc_pfirstintr = t; + sc->sc_plastintr = t; + sc->sc_pnintr++; + } +#endif + + cb->used -= cb->blksize; + if (cb->used < cb->blksize) { + /* we don't have a full block to use */ + if (cb->copying) { + /* writer is in progress, don't disturb */ + cb->needfill = 1; #ifdef AUDIO_DEBUG - if (audiodebug > 1) - Dprintf("audio_pint: hp=0x%x cc=%d\n", hp, cc); + if (audiodebug > 1) + printf("audio_pint: copying in progress\n"); #endif - error = hw->start_output(sc->hw_hdl, hp, cc, - audio_rpint, (void *)sc); - if (error) { - DPRINTF(("audio_pint restart failed: %d\n", error)); - audio_clear(sc); - } - else { - hp += cc; - if (hp >= cb->ep) - hp = cb->bp; - cb->hp = hp; - cb->au_stamp += sc->sc_smpl_in_blk; - - ++sc->sc_rblks; - } + } else { + inp = cb->inp; + cc = cb->blksize - (inp - cb->start) % cb->blksize; + ccr = cc / sc->sc_pparams.factor; + if (cb->pause) + cb->pdrops += ccr; + else { + cb->drops += ccr; + sc->sc_playdrop += ccr; + } + audio_pint_silence(sc, cb, inp, cc); + inp += cc; + if (inp >= cb->end) + inp = cb->start; + cb->inp = inp; + cb->used += cc; + + /* Clear next block so we keep ahead of the DMA. */ + if (cb->used + cc < cb->usedhigh) + audio_pint_silence(sc, cb, inp, cb->blksize); } } - else { - cb->cb_drops++; + #ifdef AUDIO_DEBUG - if (audiodebug > 1) - Dprintf("audio_pint: drops=%d auzero %d 0x%x\n", cb->cb_drops, cc, *(int *)sc->auzero_block); + if (audiodebug > 3) + printf("audio_pint: outp=%p cc=%d\n", cb->outp, cb->blksize); #endif - psilence: - error = hw->start_output(sc->hw_hdl, - sc->auzero_block, cc, - audio_pint, (void *)sc); - if (error) { - DPRINTF(("audio_pint zero failed: %d\n", error)); - audio_clear(sc); - } else - ++sc->sc_wblks; + error = hw->start_output(sc->hw_hdl, cb->outp, cb->blksize, + audio_pint, (void *)sc); + if (error) { + /* XXX does this really help? */ + DPRINTF(("audio_pint restart failed: %d\n", error)); + audio_clear(sc); } #ifdef AUDIO_DEBUG - DPRINTF(("audio_pint: mode=%d pause=%d nblk=%d lowat=%d\n", - sc->sc_mode, cb->cb_pause, cb->nblk, sc->sc_lowat)); + if (audiodebug > 3) + printf("audio_pint: mode=%d pause=%d used=%d lowat=%d\n", + sc->sc_mode, cb->pause, cb->used, cb->usedlow); #endif - if ((sc->sc_mode & AUMODE_PLAY) && !cb->cb_pause) { - if (cb->nblk <= sc->sc_lowat) { + if ((sc->sc_mode & AUMODE_PLAY) && !cb->pause) { + if (cb->used <= cb->usedlow) { audio_wakeup(&sc->sc_wchan); selwakeup(&sc->sc_wsel); - if (sc->sc_async) - psignal(sc->sc_async, SIGIO); + if (sc->sc_async_audio) { +#ifdef AUDIO_DEBUG + if (audiodebug > 3) + printf("audio_pint: sending SIGIO %p\n", + sc->sc_async_audio); +#endif + psignal(sc->sc_async_audio, SIGIO); + } } } - /* - * XXX - * possible to return one or more "phantom blocks" now. - * Only in half duplex? - */ - if (hw->full_duplex) { + /* Possible to return one or more "phantom blocks" now. */ + if (!sc->sc_full_duplex && sc->sc_rchan) { audio_wakeup(&sc->sc_rchan); selwakeup(&sc->sc_rsel); - if (sc->sc_async) - psignal(sc->sc_async, SIGIO); + if (sc->sc_async_audio) + psignal(sc->sc_async_audio, SIGIO); } } @@ -1439,196 +1931,564 @@ audio_rint(v) void *v; { struct audio_softc *sc = v; - u_char *tp; - int cc = sc->sc_blksize; struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->rr; + struct audio_ringbuffer *cb = &sc->sc_rr; int error; - - tp = cb->tp; - if (cb->cb_pause) { - cb->cb_pdrops++; - DPRINTF(("audio_rint: pdrops %d\n", cb->cb_pdrops)); - } - else { - tp += cc; - if (tp >= cb->ep) - tp = cb->bp; - if (++cb->nblk < cb->maxblk) { + + if (!sc->sc_open) + return; /* ignore interrupt if not open */ + + cb->inp += cb->blksize; + if (cb->inp >= cb->end) + cb->inp = cb->start; + cb->stamp += cb->blksize; + if (cb->mmapped) { #ifdef AUDIO_DEBUG - if (audiodebug > 1) - Dprintf("audio_rint: tp=%p cc=%d\n", tp, cc); + if (audiodebug > 2) + printf("audio_rint: mmapped inp=%p cc=%d\n", + cb->inp, cb->blksize); #endif - error = hw->start_input(sc->hw_hdl, tp, cc, - audio_rint, (void *)sc); - if (error) { - DPRINTF(("audio_rint: start failed: %d\n", - error)); - audio_clear(sc); + (void)hw->start_input(sc->hw_hdl, cb->inp, cb->blksize, + audio_rint, (void *)sc); + return; + } + +#ifdef AUDIO_INTR_TIME + { + struct timeval tv; + u_long t; + microtime(&tv); + t = tv.tv_usec + 1000000 * tv.tv_sec; + if (sc->sc_rnintr) { + long lastdelta, totdelta; + lastdelta = t - sc->sc_rlastintr - sc->sc_rblktime; + if (lastdelta > sc->sc_rblktime / 5) { + printf("audio: record interrupt(%d) off relative by %ld us (%lu)\n", + sc->sc_rnintr, lastdelta, sc->sc_rblktime); } - cb->au_stamp += sc->sc_smpl_in_blk; - } else { - /* - * XXX - * How do we count dropped input samples due to overrun? - * Start a "dummy DMA transfer" when the input ring buffer - * is full and count # of these? Seems pretty lame to - * me, but how else are we going to do this? - */ - cb->cb_drops++; - sc->sc_rbus = 0; - DPRINTF(("audio_rint: drops %d\n", cb->cb_drops)); - } - cb->tp = tp; - - audio_wakeup(&sc->sc_rchan); - selwakeup(&sc->sc_rsel); - if (sc->sc_async) - psignal(sc->sc_async, SIGIO); + totdelta = t - sc->sc_rfirstintr - sc->sc_rblktime * sc->sc_rnintr; + if (totdelta > sc->sc_rblktime / 2) { + sc->sc_rnintr++; + printf("audio: record interrupt(%d) off absolute by %ld us (%lu)\n", + sc->sc_rnintr, totdelta, sc->sc_rblktime); + sc->sc_rnintr++; /* avoid repeated messages */ + } + } else + sc->sc_rfirstintr = t; + sc->sc_rlastintr = t; + sc->sc_rnintr++; + } +#endif + + cb->used += cb->blksize; + if (cb->pause) { +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_rint: pdrops %lu\n", cb->pdrops); +#endif + cb->pdrops += cb->blksize; + cb->outp += cb->blksize; + cb->used -= cb->blksize; + } else if (cb->used + cb->blksize >= cb->usedhigh && !cb->copying) { +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_rint: drops %lu\n", cb->drops); +#endif + cb->drops += cb->blksize; + cb->outp += cb->blksize; + cb->used -= cb->blksize; + } + +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_rint: inp=%p cc=%d used=%d\n", + cb->inp, cb->blksize, cb->used); +#endif + error = hw->start_input(sc->hw_hdl, cb->inp, cb->blksize, + audio_rint, (void *)sc); + if (error) { + /* XXX does this really help? */ + DPRINTF(("audio_rint: restart failed: %d\n", error)); + audio_clear(sc); } + + audio_wakeup(&sc->sc_rchan); + selwakeup(&sc->sc_rsel); + if (sc->sc_async_audio) + psignal(sc->sc_async_audio, SIGIO); } int -audio_check_format(encodingp, precisionp) - u_int *encodingp, *precisionp; +audio_check_params(p) + struct audio_params *p; { +#if defined(COMPAT_12) + if (p->encoding == AUDIO_ENCODING_PCM16) { + if (p->precision == 8) + p->encoding = AUDIO_ENCODING_ULINEAR; + else + p->encoding = AUDIO_ENCODING_SLINEAR; + } else if (p->encoding == AUDIO_ENCODING_PCM8) { + if (p->precision == 8) + p->encoding = AUDIO_ENCODING_ULINEAR; + else + return EINVAL; + } +#endif - if (*encodingp == AUDIO_ENCODING_LINEAR) - switch (*precisionp) { - case 8: - *encodingp = AUDIO_ENCODING_PCM8; - return (0); - case 16: - *encodingp = AUDIO_ENCODING_PCM16; - return (0); - default: - return (EINVAL); - } + if (p->encoding == AUDIO_ENCODING_SLINEAR) +#if BYTE_ORDER == LITTLE_ENDIAN + p->encoding = AUDIO_ENCODING_SLINEAR_LE; +#else + p->encoding = AUDIO_ENCODING_SLINEAR_BE; +#endif + if (p->encoding == AUDIO_ENCODING_ULINEAR) +#if BYTE_ORDER == LITTLE_ENDIAN + p->encoding = AUDIO_ENCODING_ULINEAR_LE; +#else + p->encoding = AUDIO_ENCODING_ULINEAR_BE; +#endif - switch (*encodingp) { + switch (p->encoding) { case AUDIO_ENCODING_ULAW: case AUDIO_ENCODING_ALAW: - case AUDIO_ENCODING_PCM8: case AUDIO_ENCODING_ADPCM: - if (*precisionp != 8) + if (p->precision != 8) return (EINVAL); break; - case AUDIO_ENCODING_PCM16: - if (*precisionp != 16) + case AUDIO_ENCODING_SLINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_ULINEAR_BE: + if (p->precision != 8 && p->precision != 16) return (EINVAL); break; + case AUDIO_ENCODING_MPEG_L1_STREAM: + case AUDIO_ENCODING_MPEG_L1_PACKETS: + case AUDIO_ENCODING_MPEG_L1_SYSTEM: + case AUDIO_ENCODING_MPEG_L2_STREAM: + case AUDIO_ENCODING_MPEG_L2_PACKETS: + case AUDIO_ENCODING_MPEG_L2_SYSTEM: + break; default: return (EINVAL); } + if (p->channels < 1 || p->channels > 8) /* sanity check # of channels */ + return (EINVAL); + return (0); } int +au_set_lr_value(sc, ct, l, r) + struct audio_softc *sc; + mixer_ctrl_t *ct; + int l, r; +{ + ct->type = AUDIO_MIXER_VALUE; + ct->un.value.num_channels = 2; + ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; + ct->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; + if (sc->hw_if->set_port(sc->hw_hdl, ct) == 0) + return 0; + ct->un.value.num_channels = 1; + ct->un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2; + return sc->hw_if->set_port(sc->hw_hdl, ct); +} + +int +au_set_gain(sc, ports, gain, balance) + struct audio_softc *sc; + struct au_mixer_ports *ports; + int gain; + int balance; +{ + mixer_ctrl_t ct; + int i, error; + int l, r; + u_int mask; + int nset; + + if (balance == AUDIO_MID_BALANCE) { + l = r = gain; + } else if (balance < AUDIO_MID_BALANCE) { + r = gain; + l = (balance * gain) / AUDIO_MID_BALANCE; + } else { + l = gain; + r = ((AUDIO_RIGHT_BALANCE - balance) * gain) + / AUDIO_MID_BALANCE; + } + DPRINTF(("au_set_gain: gain=%d balance=%d, l=%d r=%d\n", + gain, balance, l, r)); + + if (ports->index == -1) { + usemaster: + if (ports->master == -1) + return 0; /* just ignore it silently */ + ct.dev = ports->master; + error = au_set_lr_value(sc, &ct, l, r); + } else { + ct.dev = ports->index; + if (ports->isenum) { + ct.type = AUDIO_MIXER_ENUM; + error = sc->hw_if->get_port(sc->hw_hdl, &ct); + if (error) + return error; + for(i = 0; i < ports->nports; i++) { + if (ports->misel[i] == ct.un.ord) { + ct.dev = ports->miport[i]; + if (ct.dev == -1 || + au_set_lr_value(sc, &ct, l, r)) + goto usemaster; + else + break; + } + } + } else { + ct.type = AUDIO_MIXER_SET; + error = sc->hw_if->get_port(sc->hw_hdl, &ct); + if (error) + return error; + mask = ct.un.mask; + nset = 0; + for(i = 0; i < ports->nports; i++) { + if (ports->misel[i] & mask) { + ct.dev = ports->miport[i]; + if (ct.dev != -1 && + au_set_lr_value(sc, &ct, l, r) == 0) + nset++; + } + } + if (nset == 0) + goto usemaster; + } + } + if (!error) + mixer_signal(sc); + return error; +} + +int +au_get_lr_value(sc, ct, l, r) + struct audio_softc *sc; + mixer_ctrl_t *ct; + int *l, *r; +{ + int error; + + ct->un.value.num_channels = 2; + if (sc->hw_if->get_port(sc->hw_hdl, ct) == 0) { + *l = ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; + *r = ct->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; + } else { + ct->un.value.num_channels = 1; + error = sc->hw_if->get_port(sc->hw_hdl, ct); + if (error) + return error; + *r = *l = ct->un.value.level[AUDIO_MIXER_LEVEL_MONO]; + } + return 0; +} + +void +au_get_gain(sc, ports, pgain, pbalance) + struct audio_softc *sc; + struct au_mixer_ports *ports; + u_int *pgain; + u_char *pbalance; +{ + mixer_ctrl_t ct; + int i, l, r, n; + int lgain = AUDIO_MAX_GAIN/2, rgain = AUDIO_MAX_GAIN/2; + + if (ports->index == -1) { + usemaster: + if (ports->master == -1) + goto bad; + ct.dev = ports->master; + ct.type = AUDIO_MIXER_VALUE; + if (au_get_lr_value(sc, &ct, &lgain, &rgain)) + goto bad; + } else { + ct.dev = ports->index; + if (ports->isenum) { + ct.type = AUDIO_MIXER_ENUM; + if (sc->hw_if->get_port(sc->hw_hdl, &ct)) + goto bad; + ct.type = AUDIO_MIXER_VALUE; + for(i = 0; i < ports->nports; i++) { + if (ports->misel[i] == ct.un.ord) { + ct.dev = ports->miport[i]; + if (ct.dev == -1 || + au_get_lr_value(sc, &ct, + &lgain, &rgain)) + goto usemaster; + else + break; + } + } + } else { + ct.type = AUDIO_MIXER_SET; + if (sc->hw_if->get_port(sc->hw_hdl, &ct)) + goto bad; + ct.type = AUDIO_MIXER_VALUE; + lgain = rgain = n = 0; + for(i = 0; i < ports->nports; i++) { + if (ports->misel[i] & ct.un.mask) { + ct.dev = ports->miport[i]; + if (ct.dev == -1 || + au_get_lr_value(sc, &ct, &l, &r)) + goto usemaster; + else { + lgain += l; + rgain += r; + n++; + } + } + } + if (n != 0) { + lgain /= n; + rgain /= n; + } + } + } +bad: + if (lgain == rgain) { /* handles lgain==rgain==0 */ + *pgain = lgain; + *pbalance = AUDIO_MID_BALANCE; + } else if (lgain < rgain) { + *pgain = rgain; + *pbalance = (AUDIO_MID_BALANCE * lgain) / rgain; + } else /* lgain > rgain */ { + *pgain = lgain; + *pbalance = AUDIO_RIGHT_BALANCE - + (AUDIO_MID_BALANCE * rgain) / lgain; + } +} + +int +au_set_port(sc, ports, port) + struct audio_softc *sc; + struct au_mixer_ports *ports; + u_int port; +{ + mixer_ctrl_t ct; + int i, error; + + if (port == 0 && ports->allports == 0) + return 0; /* allow this special case */ + + if (ports->index == -1) + return EINVAL; + ct.dev = ports->index; + if (ports->isenum) { + if (port & (port-1)) + return EINVAL; /* Only one port allowed */ + ct.type = AUDIO_MIXER_ENUM; + error = EINVAL; + for(i = 0; i < ports->nports; i++) + if (ports->aumask[i] == port) { + ct.un.ord = ports->misel[i]; + error = sc->hw_if->set_port(sc->hw_hdl, &ct); + break; + } + } else { + ct.type = AUDIO_MIXER_SET; + ct.un.mask = 0; + for(i = 0; i < ports->nports; i++) + if (ports->aumask[i] & port) + ct.un.mask |= ports->misel[i]; + if (port != 0 && ct.un.mask == 0) + error = EINVAL; + else + error = sc->hw_if->set_port(sc->hw_hdl, &ct); + } + if (!error) + mixer_signal(sc); + return error; +} + +int +au_get_port(sc, ports) + struct audio_softc *sc; + struct au_mixer_ports *ports; +{ + mixer_ctrl_t ct; + int i, aumask; + + if (ports->index == -1) + return 0; + ct.dev = ports->index; + ct.type = ports->isenum ? AUDIO_MIXER_ENUM : AUDIO_MIXER_SET; + if (sc->hw_if->get_port(sc->hw_hdl, &ct)) + return 0; + aumask = 0; + if (ports->isenum) { + for(i = 0; i < ports->nports; i++) + if (ct.un.ord == ports->misel[i]) + aumask = ports->aumask[i]; + } else { + for(i = 0; i < ports->nports; i++) + if (ct.un.mask & ports->misel[i]) + aumask |= ports->aumask[i]; + } + return aumask; +} + +int audiosetinfo(sc, ai) struct audio_softc *sc; struct audio_info *ai; { struct audio_prinfo *r = &ai->record, *p = &ai->play; - int cleared = 0, init = 0; - int bsize, error = 0; + int cleared; + int s, setmode; + int error; struct audio_hw_if *hw = sc->hw_if; - mixer_ctrl_t ct; - int s; + struct audio_params pp, rp; + int np, nr; + unsigned int blks; + int oldpblksize, oldrblksize; + int rbus, pbus; + u_int gain; + u_char balance; if (hw == 0) /* HW has not attached */ return(ENXIO); - if (p->sample_rate != ~0) { - if (!cleared) - audio_clear(sc); - cleared = 1; + rbus = sc->sc_rbus; + pbus = sc->sc_pbus; + error = 0; + cleared = 0; - error = hw->set_out_sr(sc->hw_hdl, p->sample_rate); - if (error) - return(error); + pp = sc->sc_pparams; /* Temporary encoding storage in */ + rp = sc->sc_rparams; /* case setting the modes fails. */ + nr = np = 0; - sc->sc_50ms = 50 * hw->get_out_sr(sc->hw_hdl) / 1000; - init = 1; + if (p->sample_rate != ~0) { + pp.sample_rate = p->sample_rate; + np++; } if (r->sample_rate != ~0) { - if (!cleared) - audio_clear(sc); - cleared = 1; - - error = hw->set_in_sr(sc->hw_hdl, r->sample_rate); - if (error) - return(error); - - sc->sc_50ms = 50 * hw->get_in_sr(sc->hw_hdl) / 1000; - init = 1; + rp.sample_rate = r->sample_rate; + nr++; } - if (p->encoding != ~0 || p->precision != ~0) { - if (!cleared) - audio_clear(sc); - cleared = 1; - - if (p->encoding == ~0) - p->encoding = hw->get_encoding(sc->hw_hdl); - if (p->precision == ~0) - p->precision = hw->get_precision(sc->hw_hdl); - error = audio_check_format(&p->encoding, &p->precision); - if (error) - return(error); - error = hw->set_format(sc->hw_hdl, p->encoding, p->precision); - if (error) - return(error); - - sc->sc_pencoding = p->encoding; - init = 1; + if (p->encoding != ~0) { + pp.encoding = p->encoding; + np++; } - if (r->encoding != ~0 || r->precision != ~0) { + if (r->encoding != ~0) { + rp.encoding = r->encoding; + nr++; + } + if (p->precision != ~0) { + pp.precision = p->precision; + np++; + } + if (r->precision != ~0) { + rp.precision = r->precision; + nr++; + } + if (p->channels != ~0) { + pp.channels = p->channels; + np++; + } + if (r->channels != ~0) { + rp.channels = r->channels; + nr++; + } +#ifdef AUDIO_DEBUG + if (audiodebug && nr) + audio_print_params("Setting record params", &rp); + if (audiodebug && np) + audio_print_params("Setting play params", &pp); +#endif + if (nr && (error = audio_check_params(&rp))) + return error; + if (np && (error = audio_check_params(&pp))) + return error; + setmode = 0; + if (nr) { if (!cleared) audio_clear(sc); cleared = 1; - - if (r->encoding == ~0) - r->encoding = hw->get_encoding(sc->hw_hdl); - if (r->precision == ~0) - r->precision = hw->get_precision(sc->hw_hdl); - error = audio_check_format(&r->encoding, &r->precision); - if (error) - return(error); - error = hw->set_format(sc->hw_hdl, r->encoding, r->precision); - if (error) - return(error); - - sc->sc_rencoding = r->encoding; - init = 1; + rp.sw_code = 0; + rp.factor = 1; + setmode |= AUMODE_RECORD; } - if (p->channels != ~0) { + if (np) { if (!cleared) audio_clear(sc); cleared = 1; - - error = hw->set_channels(sc->hw_hdl, p->channels); - if (error) - return(error); - - init = 1; + pp.sw_code = 0; + pp.factor = 1; + setmode |= AUMODE_PLAY; } - if (r->channels != ~0) { + + if (ai->mode != ~0) { if (!cleared) audio_clear(sc); cleared = 1; + sc->sc_mode = ai->mode; + if (sc->sc_mode & AUMODE_PLAY_ALL) + sc->sc_mode |= AUMODE_PLAY; + if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_full_duplex) + /* Play takes precedence */ + sc->sc_mode &= ~AUMODE_RECORD; + } - error = hw->set_channels(sc->hw_hdl, r->channels); + if (setmode) { + int indep = hw->get_props(sc->hw_hdl) & AUDIO_PROP_INDEPENDENT; + if (!indep) { + if (setmode == AUMODE_RECORD) + pp = rp; + else if (setmode == AUMODE_PLAY) + rp = pp; + } + error = hw->set_params(sc->hw_hdl, setmode, sc->sc_mode, &pp, &rp); if (error) - return(error); + return (error); + if (!indep) { + if (setmode == AUMODE_RECORD) { + pp.sample_rate = rp.sample_rate; + pp.encoding = rp.encoding; + pp.channels = rp.channels; + pp.precision = rp.precision; + } else if (setmode == AUMODE_PLAY) { + rp.sample_rate = pp.sample_rate; + rp.encoding = pp.encoding; + rp.channels = pp.channels; + rp.precision = pp.precision; + } + } + if (setmode & AUMODE_RECORD) + sc->sc_rparams = rp; + if (setmode & AUMODE_PLAY) + sc->sc_pparams = pp; + } - init = 1; + oldpblksize = sc->sc_pr.blksize; + oldrblksize = sc->sc_rr.blksize; + /* Play params can affect the record params, so recalculate blksize. */ + if (nr || np) { + audio_calc_blksize(sc, AUMODE_RECORD); + audio_calc_blksize(sc, AUMODE_PLAY); } +#ifdef AUDIO_DEBUG + if (audiodebug > 1 && nr) + audio_print_params("After setting record params", &sc->sc_rparams); + if (audiodebug > 1 && np) + audio_print_params("After setting play params", &sc->sc_pparams); +#endif + if (p->port != ~0) { if (!cleared) audio_clear(sc); cleared = 1; - error = hw->set_out_port(sc->hw_hdl, p->port); + error = au_set_port(sc, &sc->sc_outports, p->port); if (error) return(error); } @@ -1637,43 +2497,67 @@ audiosetinfo(sc, ai) audio_clear(sc); cleared = 1; - error = hw->set_in_port(sc->hw_hdl, r->port); + error = au_set_port(sc, &sc->sc_inports, r->port); if (error) return(error); } if (p->gain != ~0) { - ct.dev = hw->get_out_port(sc->hw_hdl); - ct.type = AUDIO_MIXER_VALUE; - ct.un.value.num_channels = 1; - ct.un.value.level[AUDIO_MIXER_LEVEL_MONO] = p->gain; - error = hw->set_port(sc->hw_hdl, &ct); + au_get_gain(sc, &sc->sc_outports, &gain, &balance); + error = au_set_gain(sc, &sc->sc_outports, p->gain, balance); if (error) return(error); } if (r->gain != ~0) { - ct.dev = hw->get_in_port(sc->hw_hdl); + au_get_gain(sc, &sc->sc_inports, &gain, &balance); + error = au_set_gain(sc, &sc->sc_inports, r->gain, balance); + if (error) + return(error); + } + + if (p->balance != (u_char)~0) { + au_get_gain(sc, &sc->sc_outports, &gain, &balance); + error = au_set_gain(sc, &sc->sc_outports, gain, p->balance); + if (error) + return(error); + } + if (r->balance != (u_char)~0) { + au_get_gain(sc, &sc->sc_inports, &gain, &balance); + error = au_set_gain(sc, &sc->sc_inports, gain, r->balance); + if (error) + return(error); + } + + if (ai->monitor_gain != ~0 && + sc->sc_monitor_port != -1) { + mixer_ctrl_t ct; + + ct.dev = sc->sc_monitor_port; ct.type = AUDIO_MIXER_VALUE; ct.un.value.num_channels = 1; - ct.un.value.level[AUDIO_MIXER_LEVEL_MONO] = r->gain; - error = hw->set_port(sc->hw_hdl, &ct); + ct.un.value.level[AUDIO_MIXER_LEVEL_MONO] = ai->monitor_gain; + error = sc->hw_if->get_port(sc->hw_hdl, &ct); if (error) return(error); } if (p->pause != (u_char)~0) { - sc->pr.cb_pause = p->pause; - if (!p->pause) { + sc->sc_pr.pause = p->pause; + if (!p->pause && !sc->sc_pbus && (sc->sc_mode & AUMODE_PLAY)) { s = splaudio(); - audiostartp(sc); + error = audiostartp(sc); splx(s); + if (error) + return error; } } if (r->pause != (u_char)~0) { - sc->rr.cb_pause = r->pause; - if (!r->pause) { + sc->sc_rr.pause = r->pause; + if (!r->pause && !sc->sc_rbus && (sc->sc_mode & AUMODE_RECORD)) { s = splaudio(); - audiostartr(sc); + error = audiostartr(sc); splx(s); + if (error) + return error; } } @@ -1683,74 +2567,72 @@ audiosetinfo(sc, ai) audio_clear(sc); cleared = 1; - if (ai->blocksize == 0) - bsize = sc->sc_blksize; - else if (ai->blocksize > AU_RING_SIZE/2) - bsize = AU_RING_SIZE/2; - else - bsize = ai->blocksize; - bsize = hw->round_blocksize(sc->hw_hdl, bsize); - if (bsize > AU_RING_SIZE) - bsize = AU_RING_SIZE; - - sc->sc_blksize = bsize; - init = 1; - } else if (init) { - /* Block size calculated from other parameter changes. */ - sc->sc_blksize = audio_calc_blksize(sc); - } - - if (init) { - audio_alloc_auzero(sc, sc->sc_blksize); - sc->sc_smpl_in_blk = sc->sc_blksize / - (hw->get_precision(sc->hw_hdl) / NBBY); - audio_initbufs(sc); + if (ai->blocksize == 0) { + audio_calc_blksize(sc, AUMODE_RECORD); + audio_calc_blksize(sc, AUMODE_PLAY); + sc->sc_blkset = 0; + } else { + int bs = ai->blocksize; + if (hw->round_blocksize) + bs = hw->round_blocksize(sc->hw_hdl, bs); + sc->sc_pr.blksize = sc->sc_rr.blksize = bs; + sc->sc_blkset = 1; + } } - if (ai->hiwat != ~0) { - if ((unsigned)ai->hiwat > sc->pr.maxblk) - ai->hiwat = sc->pr.maxblk; - if (sc->sc_hiwat != 0) - sc->sc_hiwat = ai->hiwat; - } - if (ai->lowat != ~0) { - if ((unsigned)ai->lowat > sc->pr.maxblk) - ai->lowat = sc->pr.maxblk; - sc->sc_lowat = ai->lowat; - } - if (ai->backlog != ~0) { - if ((unsigned)ai->backlog > (sc->pr.maxblk/2)) - ai->backlog = sc->pr.maxblk/2; - sc->sc_backlog = ai->backlog; - } if (ai->mode != ~0) { - if (!cleared) - audio_clear(sc); - cleared = 1; - - sc->sc_mode = ai->mode; - if (sc->sc_mode & AUMODE_PLAY) { + if (sc->sc_mode & AUMODE_PLAY) audio_init_play(sc); - if (!hw->full_duplex) /* Play takes precedence */ - sc->sc_mode &= ~(AUMODE_RECORD); - } if (sc->sc_mode & AUMODE_RECORD) audio_init_record(sc); } - error = hw->commit_settings(sc->hw_hdl); - if (error) - return (error); + if (hw->commit_settings) { + error = hw->commit_settings(sc->hw_hdl); + if (error) + return (error); + } if (cleared) { s = splaudio(); - if (sc->sc_mode & AUMODE_PLAY) - audiostartp(sc); - if (sc->sc_mode & AUMODE_RECORD) - audiostartr(sc); + error = audio_initbufs(sc); + if (error) goto err; + if (sc->sc_pr.blksize != oldpblksize || + sc->sc_rr.blksize != oldrblksize) + audio_calcwater(sc); + if ((sc->sc_mode & AUMODE_PLAY) && + pbus && !sc->sc_pbus) + error = audiostartp(sc); + if (!error && + (sc->sc_mode & AUMODE_RECORD) && + rbus && !sc->sc_rbus) + error = audiostartr(sc); + err: splx(s); + if (error) + return error; } + /* Change water marks after initializing the buffers. */ + if (ai->hiwat != ~0) { + blks = ai->hiwat; + if (blks > sc->sc_pr.maxblks) + blks = sc->sc_pr.maxblks; + if (blks < 2) + blks = 2; + sc->sc_pr.usedhigh = blks * sc->sc_pr.blksize; + } + if (ai->lowat != ~0) { + blks = ai->lowat; + if (blks > sc->sc_pr.maxblks - 1) + blks = sc->sc_pr.maxblks - 1; + sc->sc_pr.usedlow = blks * sc->sc_pr.blksize; + } + if (ai->hiwat != ~0 || ai->lowat != ~0) { + if (sc->sc_pr.usedlow > sc->sc_pr.usedhigh - sc->sc_pr.blksize) + sc->sc_pr.usedlow = sc->sc_pr.usedhigh - sc->sc_pr.blksize; + } + return (0); } @@ -1761,54 +2643,71 @@ audiogetinfo(sc, ai) { struct audio_prinfo *r = &ai->record, *p = &ai->play; struct audio_hw_if *hw = sc->hw_if; - mixer_ctrl_t ct; if (hw == 0) /* HW has not attached */ return(ENXIO); - p->sample_rate = hw->get_out_sr(sc->hw_hdl); - r->sample_rate = hw->get_in_sr(sc->hw_hdl); - p->channels = r->channels = hw->get_channels(sc->hw_hdl); - p->precision = r->precision = hw->get_precision(sc->hw_hdl); - p->encoding = hw->get_encoding(sc->hw_hdl); - r->encoding = hw->get_encoding(sc->hw_hdl); - - r->port = hw->get_in_port(sc->hw_hdl); - p->port = hw->get_out_port(sc->hw_hdl); - - ct.dev = r->port; - ct.type = AUDIO_MIXER_VALUE; - ct.un.value.num_channels = 1; - if (hw->get_port(sc->hw_hdl, &ct) == 0) - r->gain = ct.un.value.level[AUDIO_MIXER_LEVEL_MONO]; - else - r->gain = AUDIO_MAX_GAIN/2; + p->sample_rate = sc->sc_pparams.sample_rate; + r->sample_rate = sc->sc_rparams.sample_rate; + p->channels = sc->sc_pparams.channels; + r->channels = sc->sc_rparams.channels; + p->precision = sc->sc_pparams.precision; + r->precision = sc->sc_rparams.precision; + p->encoding = sc->sc_pparams.encoding; + r->encoding = sc->sc_rparams.encoding; + + r->port = au_get_port(sc, &sc->sc_inports); + p->port = au_get_port(sc, &sc->sc_outports); + + r->avail_ports = sc->sc_inports.allports; + p->avail_ports = sc->sc_outports.allports; + + au_get_gain(sc, &sc->sc_inports, &r->gain, &r->balance); + au_get_gain(sc, &sc->sc_outports, &p->gain, &p->balance); + + if (sc->sc_monitor_port != -1) { + mixer_ctrl_t ct; + + ct.dev = sc->sc_monitor_port; + ct.type = AUDIO_MIXER_VALUE; + ct.un.value.num_channels = 1; + if (sc->hw_if->get_port(sc->hw_hdl, &ct)) + ai->monitor_gain = 0; + else + ai->monitor_gain = + ct.un.value.level[AUDIO_MIXER_LEVEL_MONO]; + } else + ai->monitor_gain = 0; - ct.dev = p->port; - ct.un.value.num_channels = 1; - if (hw->get_port(sc->hw_hdl, &ct) == 0) - p->gain = ct.un.value.level[AUDIO_MIXER_LEVEL_MONO]; - else - p->gain = AUDIO_MAX_GAIN/2; + p->seek = sc->sc_pr.used; + r->seek = sc->sc_rr.used; + + p->samples = sc->sc_pr.stamp - sc->sc_pr.drops; + r->samples = sc->sc_rr.stamp - sc->sc_rr.drops; - p->pause = sc->pr.cb_pause; - r->pause = sc->rr.cb_pause; - p->error = sc->pr.cb_drops != 0; - r->error = sc->rr.cb_drops != 0; + p->eof = sc->sc_eof; + r->eof = 0; - p->open = ((sc->sc_open & AUOPEN_WRITE) != 0); - r->open = ((sc->sc_open & AUOPEN_READ) != 0); + p->pause = sc->sc_pr.pause; + r->pause = sc->sc_rr.pause; - p->samples = sc->pr.au_stamp - sc->pr.cb_pdrops; - r->samples = sc->rr.au_stamp - sc->rr.cb_pdrops; + p->error = sc->sc_pr.drops != 0; + r->error = sc->sc_rr.drops != 0; - p->seek = sc->sc_wseek; - r->seek = sc->sc_rseek; + p->waiting = r->waiting = 0; /* open never hangs */ - ai->blocksize = sc->sc_blksize; - ai->hiwat = sc->sc_hiwat; - ai->lowat = sc->sc_lowat; - ai->backlog = sc->sc_backlog; + p->open = (sc->sc_open & AUOPEN_WRITE) != 0; + r->open = (sc->sc_open & AUOPEN_READ) != 0; + + p->active = sc->sc_pbus; + r->active = sc->sc_rbus; + + p->buffer_size = sc->sc_pr.bufsize; + r->buffer_size = sc->sc_rr.bufsize; + + ai->blocksize = sc->sc_pr.blksize; + ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize; + ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize; ai->mode = sc->sc_mode; return (0); @@ -1825,24 +2724,53 @@ mixer_open(dev, flags, ifmt, p) { int unit = AUDIOUNIT(dev); struct audio_softc *sc; - struct audio_hw_if *hw; - if (unit >= NAUDIO || !audio_softc[unit]) { - DPRINTF(("mixer_open: invalid device unit - %d\n", unit)); - return (ENODEV); - } + if (unit >= audio_cd.cd_ndevs || + (sc = audio_cd.cd_devs[unit]) == NULL) + return ENXIO; - sc = audio_softc[unit]; - hw = sc->hw_if; - - DPRINTF(("mixer_open: dev=%x flags=0x%x sc=0x%x\n", dev, flags, sc)); - if (hw == 0) /* Hardware has not attached to us... */ + if (!sc->hw_if) return (ENXIO); + DPRINTF(("mixer_open: dev=0x%x flags=0x%x sc=%p\n", dev, flags, sc)); + return (0); } /* + * Remove a process from those to be signalled on mixer activity. + */ +static void +mixer_remove(sc, p) + struct audio_softc *sc; + struct proc *p; +{ + struct mixer_asyncs **pm, *m; + + for(pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) { + if ((*pm)->proc == p) { + m = *pm; + *pm = m->next; + free(m, M_DEVBUF); + return; + } + } +} + +/* + * Signal all processes waiting for the mixer. + */ +static void +mixer_signal(sc) + struct audio_softc *sc; +{ + struct mixer_asyncs *m; + + for(m = sc->sc_async_mixer; m; m = m->next) + psignal(m->proc, SIGIO); +} + +/* * Close a mixer device */ /* ARGSUSED */ @@ -1852,8 +2780,13 @@ mixer_close(dev, flags, ifmt, p) int flags, ifmt; struct proc *p; { + int unit = AUDIOUNIT(dev); + struct audio_softc *sc = audio_cd.cd_devs[unit]; + DPRINTF(("mixer_close: unit %d\n", AUDIOUNIT(dev))); + mixer_remove(sc, p); + return (0); } @@ -1866,42 +2799,56 @@ mixer_ioctl(dev, cmd, addr, flag, p) struct proc *p; { int unit = AUDIOUNIT(dev); - struct audio_softc *sc = audio_softc[unit]; + struct audio_softc *sc = audio_cd.cd_devs[unit]; struct audio_hw_if *hw = sc->hw_if; int error = EINVAL; DPRINTF(("mixer_ioctl(%d,'%c',%d)\n", - IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff)); + IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff)); switch (cmd) { + case FIOASYNC: + mixer_remove(sc, p); /* remove old entry */ + if (*(int *)addr) { + struct mixer_asyncs *ma; + ma = malloc(sizeof (struct mixer_asyncs), M_DEVBUF, M_WAITOK); + ma->next = sc->sc_async_mixer; + ma->proc = p; + sc->sc_async_mixer = ma; + } + error = 0; + break; + case AUDIO_GETDEV: - DPRINTF(("AUDIO_GETDEV\n")); - error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr); - break; + DPRINTF(("AUDIO_GETDEV\n")); + error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr); + break; case AUDIO_MIXER_DEVINFO: - DPRINTF(("AUDIO_MIXER_DEVINFO\n")); - error = hw->query_devinfo(sc->hw_hdl, (mixer_devinfo_t *)addr); - break; + DPRINTF(("AUDIO_MIXER_DEVINFO\n")); + error = hw->query_devinfo(sc->hw_hdl, (mixer_devinfo_t *)addr); + break; case AUDIO_MIXER_READ: - DPRINTF(("AUDIO_MIXER_READ\n")); - error = hw->get_port(sc->hw_hdl, (mixer_ctrl_t *)addr); - break; + DPRINTF(("AUDIO_MIXER_READ\n")); + error = hw->get_port(sc->hw_hdl, (mixer_ctrl_t *)addr); + break; case AUDIO_MIXER_WRITE: - DPRINTF(("AUDIO_MIXER_WRITE\n")); - error = hw->set_port(sc->hw_hdl, (mixer_ctrl_t *)addr); - if (error == 0) - error = hw->commit_settings(sc->hw_hdl); - break; + DPRINTF(("AUDIO_MIXER_WRITE\n")); + error = hw->set_port(sc->hw_hdl, (mixer_ctrl_t *)addr); + if (!error && hw->commit_settings) + error = hw->commit_settings(sc->hw_hdl); + if (!error) + mixer_signal(sc); + break; default: - error = EINVAL; - break; + error = EINVAL; + break; } DPRINTF(("mixer_ioctl(%d,'%c',%d) result %d\n", - IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error)); + IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error)); return (error); } #endif diff --git a/sys/dev/audio_if.h b/sys/dev/audio_if.h index ac6c67440ce..5d042eb0086 100644 --- a/sys/dev/audio_if.h +++ b/sys/dev/audio_if.h @@ -1,5 +1,5 @@ -/* $OpenBSD: audio_if.h,v 1.5 1997/07/10 23:06:30 provos Exp $ */ -/* $NetBSD: audio_if.h,v 1.7 1996/03/07 15:00:10 christos Exp $ */ +/* $OpenBSD: audio_if.h,v 1.6 1998/04/26 21:03:08 provos Exp $ */ +/* $NetBSD: audio_if.h,v 1.24 1998/01/10 14:07:25 tv Exp $ */ /* * Copyright (c) 1994 Havard Eidnes. @@ -41,38 +41,39 @@ struct audio_softc; +struct audio_params { + u_long sample_rate; /* sample rate */ + u_int encoding; /* e.g. ulaw, linear, etc */ + u_int precision; /* bits/sample */ + u_int channels; /* mono(1), stereo(2) */ + /* Software en/decode functions, set if SW coding required by HW */ + void (*sw_code)__P((void *, u_char *, int)); + int factor; /* coding space change */ +}; + +/* The default audio mode: 8 kHz mono ulaw */ +extern struct audio_params audio_default; + struct audio_hw_if { - int (*open)__P((dev_t, int)); /* open hardware */ + int (*open)__P((void *, int)); /* open hardware */ void (*close)__P((void *)); /* close hardware */ int (*drain)__P((void *)); /* Optional: drain buffers */ - /* Sample rate */ - int (*set_in_sr)__P((void *, u_long)); - u_long (*get_in_sr)__P((void *)); - int (*set_out_sr)__P((void *, u_long)); - u_long (*get_out_sr)__P((void *)); - /* Encoding. */ - /* Precision = bits/sample, usually 8 or 16 */ /* XXX should we have separate in/out? */ int (*query_encoding)__P((void *, struct audio_encoding *)); - int (*set_format)__P((void *, u_int, u_int)); - int (*get_encoding)__P((void *)); - int (*get_precision)__P((void *)); - - /* Channels - mono(1), stereo(2) */ - int (*set_channels)__P((void *, int)); - int (*get_channels)__P((void *)); + /* Set the audio encoding parameters (record and play). + * Return 0 on success, or an error code if the + * requested parameters are impossible. + * The values in the params struct may be changed (e.g. rounding + * to the nearest sample rate.) + */ + int (*set_params)__P((void *, int, int, struct audio_params *, struct audio_params *)); + /* Hardware may have some say in the blocksize to choose */ int (*round_blocksize)__P((void *, int)); - /* Ports (in/out ports) */ - int (*set_out_port)__P((void *, int)); - int (*get_out_port)__P((void *)); - int (*set_in_port)__P((void *, int)); - int (*get_in_port)__P((void *)); - /* * Changing settings may require taking device out of "data mode", * which can be quite expensive. Also, audiosetinfo() may @@ -83,19 +84,15 @@ struct audio_hw_if { */ int (*commit_settings)__P((void *)); - /* Software en/decode functions, set if SW coding required by HW */ - void (*sw_encode)__P((void *, int, u_char *, int)); - void (*sw_decode)__P((void *, int, u_char *, int)); - /* Start input/output routines. These usually control DMA. */ + int (*init_output)__P((void *, void *, int)); + int (*init_input)__P((void *, void *, int)); int (*start_output)__P((void *, void *, int, void (*)(void *), void *)); int (*start_input)__P((void *, void *, int, void (*)(void *), void *)); int (*halt_output)__P((void *)); int (*halt_input)__P((void *)); - int (*cont_output)__P((void *)); - int (*cont_input)__P((void *)); int (*speaker_ctl)__P((void *, int)); #define SPKR_ON 1 @@ -110,25 +107,59 @@ struct audio_hw_if { int (*query_devinfo)__P((void *, mixer_devinfo_t *)); - int full_duplex; /* non-null if HW is able to do full-duplex */ - int audio_unit; + /* Allocate/free memory for the ring buffer. Usually malloc/free. */ + void *(*alloc)__P((void *, unsigned long, int, int)); + void (*free)__P((void *, void *, int)); + unsigned long (*round_buffersize)__P((void *, unsigned long)); + int (*mappage)__P((void *, void *, int, int)); + + int (*get_props)__P((void *)); /* device properties */ }; -/* Register / deregister hardware driver */ -extern int audio_hardware_attach __P((struct audio_hw_if *, void *)); -extern int audio_hardware_detach __P((struct audio_hw_if *)); +struct midi_info { + char *name; /* Name of MIDI hardware */ + int props; +}; +#define MIDI_PROP_OUT_INTR 1 + +struct midi_hw_if { + int (*open)__P((void *, int, /* open hardware */ + void (*)__P((void *, int)), + void (*)__P((void *)), + void *)); + void (*close)__P((void *)); /* close hardware */ + int (*output)__P((void *, int)); /* output a byte */ + void (*getinfo)__P((void *, struct midi_info *)); + int (*ioctl)__P((u_long, caddr_t, int, struct proc *)); +}; + +struct audio_attach_args { + int type; + void *hwif; /* either audio_hw_if * or midi_hw_if * */ + void *hdl; +}; +#define AUDIODEV_TYPE_AUDIO 0 +#define AUDIODEV_TYPE_MIDI 1 + +/* Attach the MI driver(s) to the MD driver. */ +extern void audio_attach_mi __P((struct audio_hw_if *, struct midi_hw_if *, void *, struct device *)); /* Device identity flags */ #define SOUND_DEVICE 0 #define AUDIO_DEVICE 0x80 +#define AUDIOCTL_DEVICE 0xc0 #define MIXER_DEVICE 0x10 -#define ISDEVAUDIO(x) ((minor(x)&0xf0) == AUDIO_DEVICE) -#define ISDEVSOUND(x) ((minor(x)&0xf0) == SOUND_DEVICE) -#define ISDEVMIXER(x) ((minor(x)&0xf0) == MIXER_DEVICE) - #define AUDIOUNIT(x) (minor(x)&0x0f) #define AUDIODEV(x) (minor(x)&0xf0) +#define ISDEVSOUND(x) (AUDIODEV((x)) == SOUND_DEVICE) +#define ISDEVAUDIO(x) (AUDIODEV((x)) == AUDIO_DEVICE) +#define ISDEVAUDIOCTL(x) (AUDIODEV((x)) == AUDIOCTL_DEVICE) +#define ISDEVMIXER(x) (AUDIODEV((x)) == MIXER_DEVICE) + +/*#ifndef __i386__*/ #define splaudio splbio /* XXX */ #define IPL_AUDIO IPL_BIO /* XXX */ +/*#endif*/ + diff --git a/sys/dev/audiovar.h b/sys/dev/audiovar.h index 4cda887e095..f712205c9a2 100644 --- a/sys/dev/audiovar.h +++ b/sys/dev/audiovar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: audiovar.h,v 1.4 1997/07/10 23:06:30 provos Exp $ */ -/* $NetBSD: audiovar.h,v 1.7 1996/02/20 10:00:33 mycroft Exp $ */ +/* $OpenBSD: audiovar.h,v 1.5 1998/04/26 21:03:09 provos Exp $ */ +/* $NetBSD: audiovar.h,v 1.17 1997/10/19 07:42:01 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -40,56 +40,58 @@ * Initial/default block duration is both configurable and patchable. */ #ifndef AUDIO_BLK_MS -#define AUDIO_BLK_MS 20 /* 20 ms */ +#define AUDIO_BLK_MS 50 /* 50 ms */ #endif -#ifndef AUDIO_BACKLOG -#define AUDIO_BACKLOG 3 /* 60 ms */ -#endif - -/* - * Use a single page as the size of the audio ring buffers, so that - * the data won't cross a page boundary. This way the dma carried out - * in the hardware module will be efficient (i.e., at_dma() won't have - * to make a copy). - */ #ifndef AU_RING_SIZE -#define AU_RING_SIZE NBPG +#define AU_RING_SIZE 65536 #endif -#define AU_RING_MOD(k) ((k) & (AU_RING_SIZE - 1)) -#define AU_RING_EMPTY(rp) ((rp)->hp == (rp)->tp) -#define AU_RING_FULL(rp) (AU_RING_MOD((rp)->tp + 1) == (rp)->hp) -#define AU_RING_LEN(rp) (AU_RING_MOD((rp)->tp - (rp)->hp)) -#define AU_RING_INIT(rp) { \ - (rp)->nblk = (rp)->au_stamp = 0; \ - (rp)->hp = (rp)->tp = (rp)->bp; \ - } - -struct audio_buffer { - u_char *hp; /* head */ - u_char *tp; /* tail */ - u_char *bp; /* start of buffer */ - u_char *ep; /* end of buffer */ - - int nblk; /* number of active blocks in buffer */ - int maxblk; /* max # of active blocks in buffer */ - u_long au_stamp; /* number of audio samples read/written */ - - u_short cb_pause; /* io paused */ - u_long cb_drops; /* missed samples from over/underrun */ - u_long cb_pdrops; /* paused samples */ - - int fill; /* number of silence pad bytes */ - u_char *otp; /* point where silence padding started */ +#define AUMINBUF 512 +#define AUMINBLK 32 +#define AUMINNOBLK 3 +struct audio_ringbuffer { + int bufsize; /* allocated memory */ + int blksize; /* I/O block size */ + int maxblks; /* no of blocks in ring */ + u_char *start; /* start of buffer area */ + u_char *end; /* end of buffer area */ + u_char *inp; /* input pointer (to buffer) */ + u_char *outp; /* output pointer (from buffer) */ + int used; /* no of used bytes */ + int usedlow; /* start writer when used falls below this */ + int usedhigh; /* stop writer when used goes above this */ + u_long stamp; /* bytes transferred */ + u_long stamp_last; /* old value of bytes transferred */ + u_long drops; /* missed samples from over/underrun */ + u_long pdrops; /* paused samples */ + char pause; /* transfer is paused */ + char copying; /* data is being copied */ + char needfill; /* buffer needs filling when copying is done */ + char mmapped; /* device is mmap()-ed */ +}; + +#define AUDIO_N_PORTS 4 + +struct au_mixer_ports { + int index; + int master; + int nports; + u_char isenum; + u_int allports; + u_int aumask[AUDIO_N_PORTS]; + u_int misel [AUDIO_N_PORTS]; + u_int miport[AUDIO_N_PORTS]; }; /* * Software state, per audio device. */ struct audio_softc { - void *hw_hdl; /* Hardware driver handle */ + struct device dev; + void *hw_hdl; /* Hardware driver handle */ struct audio_hw_if *hw_if; /* Hardware interface */ + struct device *sc_dev; /* Hardware device struct */ u_char sc_open; /* single use device */ #define AUOPEN_READ 0x01 #define AUOPEN_WRITE 0x02 @@ -97,33 +99,48 @@ struct audio_softc { struct selinfo sc_wsel; /* write selector */ struct selinfo sc_rsel; /* read selector */ - struct proc *sc_async; /* process who wants SIGIO */ + struct proc *sc_async_audio; /* process who wants audio SIGIO */ + struct mixer_asyncs { + struct mixer_asyncs *next; + struct proc *proc; + } *sc_async_mixer; /* processes who want mixer SIGIO */ /* Sleep channels for reading and writing. */ int sc_rchan; int sc_wchan; /* Ring buffers, separate for record and play. */ - struct audio_buffer rr; /* Record ring */ - struct audio_buffer pr; /* Play ring */ + struct audio_ringbuffer sc_rr; /* Record ring */ + struct audio_ringbuffer sc_pr; /* Play ring */ + + u_char sc_blkset; /* Blocksize has been set */ + + u_char *sc_sil_start; /* start of silence in buffer */ + int sc_sil_count; /* # of silence bytes */ - u_char *auzero_block; /* a block of silence */ - u_char sc_rbus; /* input dma in progress */ u_char sc_pbus; /* output dma in progress */ - u_long sc_wseek; /* timestamp of last frame written */ - u_long sc_rseek; /* timestamp of last frame read */ + struct audio_params sc_pparams; /* play encoding parameters */ + struct audio_params sc_rparams; /* record encoding parameters */ + + int sc_eof; /* EOF, i.e. zero sixed write, counter */ + u_long sc_wstamp; + u_long sc_playdrop; - int sc_blksize; /* recv block (chunk) size in bytes */ - int sc_smpl_in_blk; /* # samples in a block */ - int sc_50ms; /* # of samples for 50ms? */ - int sc_backlog; /* # blks of xmit backlog to generate */ - int sc_lowat; /* xmit low water mark (for wakeup) */ - int sc_hiwat; /* xmit high water mark (for wakeup) */ + int sc_full_duplex; /* device in full duplex mode */ - int sc_rblks; /* number of phantom record blocks */ - int sc_wblks; /* number of output silence blocks */ - int sc_pencoding; /* current encoding; play */ - int sc_rencoding; /* current encoding; record */ + struct au_mixer_ports sc_inports, sc_outports; + int sc_monitor_port; + +#ifdef AUDIO_INTR_TIME + u_long sc_pfirstintr; /* first time we saw a xmit interrupt */ + int sc_pnintr; /* number of interrupts */ + u_long sc_plastintr; /* last time we saw a xmit interrupt */ + long sc_pblktime; /* nominal time between interrupts */ + u_long sc_rfirstintr; /* first time we saw a rec interrupt */ + int sc_rnintr; /* number of interrupts */ + u_long sc_rlastintr; /* last time we saw a xrec interrupt */ + long sc_rblktime; /* nominal time between interrupts */ +#endif }; diff --git a/sys/dev/ic/ad1848reg.h b/sys/dev/ic/ad1848reg.h index 6d0f45dba67..7c7c927ce0e 100644 --- a/sys/dev/ic/ad1848reg.h +++ b/sys/dev/ic/ad1848reg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: ad1848reg.h,v 1.4 1996/10/31 01:01:22 niklas Exp $ */ -/* $NetBSD: ad1848reg.h,v 1.1 1995/07/07 02:11:45 brezak Exp $ */ +/* $OpenBSD: ad1848reg.h,v 1.5 1998/04/26 21:03:12 provos Exp $ */ +/* $NetBSD: ad1848reg.h,v 1.4 1997/05/07 20:23:53 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -37,17 +37,16 @@ */ /* * Copyright (c) 1993 Analog Devices Inc. All rights reserved - * (http://www.analog.com, mike.long@analog.com) */ /* parent driver is primarily responsible for checking this */ #define AD1848_BASE_VALID(base) (((base) & 0x003) == 0) /* AD1848 direct registers */ -#define AD1848_IADDR 0x04 -#define AD1848_IDATA 0x05 -#define AD1848_STATUS 0x06 -#define AD1848_PIO 0x07 +#define AD1848_IADDR 0x00 +#define AD1848_IDATA 0x01 +#define AD1848_STATUS 0x02 +#define AD1848_PIO 0x03 /* Gain constants */ #define GAIN_0 0x00 @@ -89,9 +88,7 @@ /* AD1848 Sound Port bit defines */ #define SP_IN_INIT 0x80 #define MODE_CHANGE_ENABLE 0x40 -#define MODE_CHANGE_MASK 0xbf #define TRANSFER_DISABLE 0x20 -#define TRANSFER_DISABLE_MASK 0xdf #define ADDRESS_MASK 0xe0 /* Status bits */ @@ -101,7 +98,6 @@ /* pbright is not left */ #define PLAYBACK_UPPER 0x08 /* bplower is not upper */ - #define SAMPLE_ERROR 0x10 #define CAPTURE_READY 0x20 #define CAPTURE_LEFT 0x40 @@ -113,53 +109,42 @@ #define LINE_INPUT 0x00 #define AUX_INPUT 0x40 #define MIC_INPUT 0x80 -#define MIXED_DAC_INPUT 0xC0 +#define MIXED_DAC_INPUT 0xc0 #define INPUT_GAIN_MASK 0xf0 #define INPUT_MIC_GAIN_ENABLE 0x20 -#define INPUT_MIC_GAIN_MASK 0xdf #define INPUT_SOURCE_MASK 0x3f #define AUX_INPUT_ATTEN_BITS 0x1f #define AUX_INPUT_ATTEN_MASK 0xe0 #define AUX_INPUT_MUTE 0x80 -#define AUX_INPUT_MUTE_MASK 0x7f #define OUTPUT_MUTE 0x80 -#define OUTPUT_MUTE_MASK 0x7f #define OUTPUT_ATTEN_BITS 0x3f #define OUTPUT_ATTEN_MASK 0xc0 /* Clock and Data format reg bits (some also Capture Data format) */ -#define CLOCK_SELECT_MASK 0xfe #define CLOCK_XTAL2 0x01 #define CLOCK_XTAL1 0x00 #define CLOCK_FREQ_MASK 0xf1 -#define STEREO_MONO_MASK 0xef -#define FMT_STEREO 0x10 #define FMT_MONO 0x00 +#define FMT_STEREO 0x10 #define FORMAT_MASK 0x1f #define FMT_PCM8 0x00 /* 8-bit unsigned */ #define FMT_ULAW 0x20 /* 8-bit mu-law */ #define FMT_TWOS_COMP 0x40 /* 16-bit signed */ #define FMT_ALAW 0x60 /* 8-bit alaw */ -#define FMT_TWOS_COMP_BE 0xC0 /* 16-bit signed, big endian */ +#define FMT_ADPCM 0xa0 /* IMA ADPCM */ +#define FMT_TWOS_COMP_BE 0xc0 /* 16-bit signed, big endian */ /* Interface Configuration reg bits */ #define PLAYBACK_ENABLE 0x01 -#define PLAYBACK_ENABLE_MASK 0xfe #define CAPTURE_ENABLE 0x02 -#define CAPTURE_ENABLE_MASK 0xfd -#define SINGLE_DMA 0x04 -#define SINGLE_DMA_MASK 0xfb #define DUAL_DMA 0x00 +#define SINGLE_DMA 0x04 #define AUTO_CAL_ENABLE 0x08 -#define AUTO_CAL_DISABLE_MASK 0xf7 #define PLAYBACK_PIO_ENABLE 0x40 -#define PLAYBACK_DMA_MASK 0xbf #define CAPTURE_PIO_ENABLE 0x80 -#define CAPTURE_DMA_MASK 0x7f /* Pin control bits */ #define INTERRUPT_ENABLE 0x02 -#define INTERRUPT_MASK 0xfd #define XCTL0_ENABLE 0x40 #define XCTL1_ENABLE 0x80 @@ -176,7 +161,6 @@ #define MODE2 0x40 /* Digital Mix Control reg bits */ -#define DIGITAL_MIX1_MUTE_MASK 0xfe #define DIGITAL_MIX1_ENABLE 0x01 #define MIX_ATTEN_MASK 0xfc 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 *)); diff --git a/sys/dev/mulaw.c b/sys/dev/mulaw.c index dd865ba9d89..8747c5e51ae 100644 --- a/sys/dev/mulaw.c +++ b/sys/dev/mulaw.c @@ -1,4 +1,5 @@ -/* $OpenBSD: mulaw.c,v 1.2 1997/11/07 08:06:36 niklas Exp $ */ +/* $OpenBSD: mulaw.c,v 1.3 1998/04/26 21:03:10 provos Exp $ */ +/* $NetBSD: mulaw.c,v 1.8 1997/08/04 09:29:53 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -36,120 +37,304 @@ #include <sys/types.h> #include <sys/audioio.h> +#include <machine/endian.h> #include <dev/mulaw.h> -static u_char mulawtolin[256] = { - 128, 4, 8, 12, 16, 20, 24, 28, - 32, 36, 40, 44, 48, 52, 56, 60, - 64, 66, 68, 70, 72, 74, 76, 78, - 80, 82, 84, 86, 88, 90, 92, 94, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 116, 117, 117, 118, 118, 119, 119, - 120, 120, 120, 121, 121, 121, 121, 122, - 122, 122, 122, 123, 123, 123, 123, 124, - 124, 124, 124, 124, 125, 125, 125, 125, - 125, 125, 125, 125, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 255, 251, 247, 243, 239, 235, 231, 227, - 223, 219, 215, 211, 207, 203, 199, 195, - 191, 189, 187, 185, 183, 181, 179, 177, - 175, 173, 171, 169, 167, 165, 163, 161, - 159, 158, 157, 156, 155, 154, 153, 152, - 151, 150, 149, 148, 147, 146, 145, 144, - 143, 143, 142, 142, 141, 141, 140, 140, - 139, 139, 138, 138, 137, 137, 136, 136, - 135, 135, 135, 134, 134, 134, 134, 133, - 133, 133, 133, 132, 132, 132, 132, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, +#if BYTE_ORDER == LITTLE_ENDIAN +#define LO 0 +#define HI 1 +#else +#define LO 1 +#define HI 0 +#endif + +/* + * This table converts a (8 bit) mulaw value two a 16 bit value. + * The 16 bits are represented as an array of two butes for easier access + * to the individual bytes. + */ +static u_char mulawtolin16[256][2] = { + {0x02,0x84}, {0x06,0x84}, {0x0a,0x84}, {0x0e,0x84}, + {0x12,0x84}, {0x16,0x84}, {0x1a,0x84}, {0x1e,0x84}, + {0x22,0x84}, {0x26,0x84}, {0x2a,0x84}, {0x2e,0x84}, + {0x32,0x84}, {0x36,0x84}, {0x3a,0x84}, {0x3e,0x84}, + {0x41,0x84}, {0x43,0x84}, {0x45,0x84}, {0x47,0x84}, + {0x49,0x84}, {0x4b,0x84}, {0x4d,0x84}, {0x4f,0x84}, + {0x51,0x84}, {0x53,0x84}, {0x55,0x84}, {0x57,0x84}, + {0x59,0x84}, {0x5b,0x84}, {0x5d,0x84}, {0x5f,0x84}, + {0x61,0x04}, {0x62,0x04}, {0x63,0x04}, {0x64,0x04}, + {0x65,0x04}, {0x66,0x04}, {0x67,0x04}, {0x68,0x04}, + {0x69,0x04}, {0x6a,0x04}, {0x6b,0x04}, {0x6c,0x04}, + {0x6d,0x04}, {0x6e,0x04}, {0x6f,0x04}, {0x70,0x04}, + {0x70,0xc4}, {0x71,0x44}, {0x71,0xc4}, {0x72,0x44}, + {0x72,0xc4}, {0x73,0x44}, {0x73,0xc4}, {0x74,0x44}, + {0x74,0xc4}, {0x75,0x44}, {0x75,0xc4}, {0x76,0x44}, + {0x76,0xc4}, {0x77,0x44}, {0x77,0xc4}, {0x78,0x44}, + {0x78,0xa4}, {0x78,0xe4}, {0x79,0x24}, {0x79,0x64}, + {0x79,0xa4}, {0x79,0xe4}, {0x7a,0x24}, {0x7a,0x64}, + {0x7a,0xa4}, {0x7a,0xe4}, {0x7b,0x24}, {0x7b,0x64}, + {0x7b,0xa4}, {0x7b,0xe4}, {0x7c,0x24}, {0x7c,0x64}, + {0x7c,0x94}, {0x7c,0xb4}, {0x7c,0xd4}, {0x7c,0xf4}, + {0x7d,0x14}, {0x7d,0x34}, {0x7d,0x54}, {0x7d,0x74}, + {0x7d,0x94}, {0x7d,0xb4}, {0x7d,0xd4}, {0x7d,0xf4}, + {0x7e,0x14}, {0x7e,0x34}, {0x7e,0x54}, {0x7e,0x74}, + {0x7e,0x8c}, {0x7e,0x9c}, {0x7e,0xac}, {0x7e,0xbc}, + {0x7e,0xcc}, {0x7e,0xdc}, {0x7e,0xec}, {0x7e,0xfc}, + {0x7f,0x0c}, {0x7f,0x1c}, {0x7f,0x2c}, {0x7f,0x3c}, + {0x7f,0x4c}, {0x7f,0x5c}, {0x7f,0x6c}, {0x7f,0x7c}, + {0x7f,0x88}, {0x7f,0x90}, {0x7f,0x98}, {0x7f,0xa0}, + {0x7f,0xa8}, {0x7f,0xb0}, {0x7f,0xb8}, {0x7f,0xc0}, + {0x7f,0xc8}, {0x7f,0xd0}, {0x7f,0xd8}, {0x7f,0xe0}, + {0x7f,0xe8}, {0x7f,0xf0}, {0x7f,0xf8}, {0x80,0x00}, + {0xfd,0x7c}, {0xf9,0x7c}, {0xf5,0x7c}, {0xf1,0x7c}, + {0xed,0x7c}, {0xe9,0x7c}, {0xe5,0x7c}, {0xe1,0x7c}, + {0xdd,0x7c}, {0xd9,0x7c}, {0xd5,0x7c}, {0xd1,0x7c}, + {0xcd,0x7c}, {0xc9,0x7c}, {0xc5,0x7c}, {0xc1,0x7c}, + {0xbe,0x7c}, {0xbc,0x7c}, {0xba,0x7c}, {0xb8,0x7c}, + {0xb6,0x7c}, {0xb4,0x7c}, {0xb2,0x7c}, {0xb0,0x7c}, + {0xae,0x7c}, {0xac,0x7c}, {0xaa,0x7c}, {0xa8,0x7c}, + {0xa6,0x7c}, {0xa4,0x7c}, {0xa2,0x7c}, {0xa0,0x7c}, + {0x9e,0xfc}, {0x9d,0xfc}, {0x9c,0xfc}, {0x9b,0xfc}, + {0x9a,0xfc}, {0x99,0xfc}, {0x98,0xfc}, {0x97,0xfc}, + {0x96,0xfc}, {0x95,0xfc}, {0x94,0xfc}, {0x93,0xfc}, + {0x92,0xfc}, {0x91,0xfc}, {0x90,0xfc}, {0x8f,0xfc}, + {0x8f,0x3c}, {0x8e,0xbc}, {0x8e,0x3c}, {0x8d,0xbc}, + {0x8d,0x3c}, {0x8c,0xbc}, {0x8c,0x3c}, {0x8b,0xbc}, + {0x8b,0x3c}, {0x8a,0xbc}, {0x8a,0x3c}, {0x89,0xbc}, + {0x89,0x3c}, {0x88,0xbc}, {0x88,0x3c}, {0x87,0xbc}, + {0x87,0x5c}, {0x87,0x1c}, {0x86,0xdc}, {0x86,0x9c}, + {0x86,0x5c}, {0x86,0x1c}, {0x85,0xdc}, {0x85,0x9c}, + {0x85,0x5c}, {0x85,0x1c}, {0x84,0xdc}, {0x84,0x9c}, + {0x84,0x5c}, {0x84,0x1c}, {0x83,0xdc}, {0x83,0x9c}, + {0x83,0x6c}, {0x83,0x4c}, {0x83,0x2c}, {0x83,0x0c}, + {0x82,0xec}, {0x82,0xcc}, {0x82,0xac}, {0x82,0x8c}, + {0x82,0x6c}, {0x82,0x4c}, {0x82,0x2c}, {0x82,0x0c}, + {0x81,0xec}, {0x81,0xcc}, {0x81,0xac}, {0x81,0x8c}, + {0x81,0x74}, {0x81,0x64}, {0x81,0x54}, {0x81,0x44}, + {0x81,0x34}, {0x81,0x24}, {0x81,0x14}, {0x81,0x04}, + {0x80,0xf4}, {0x80,0xe4}, {0x80,0xd4}, {0x80,0xc4}, + {0x80,0xb4}, {0x80,0xa4}, {0x80,0x94}, {0x80,0x84}, + {0x80,0x78}, {0x80,0x70}, {0x80,0x68}, {0x80,0x60}, + {0x80,0x58}, {0x80,0x50}, {0x80,0x48}, {0x80,0x40}, + {0x80,0x38}, {0x80,0x30}, {0x80,0x28}, {0x80,0x20}, + {0x80,0x18}, {0x80,0x10}, {0x80,0x08}, {0x80,0x00}, }; static u_char lintomulaw[256] = { - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 2, 2, 2, 2, 3, 3, 3, - 3, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, - 7, 8, 8, 8, 8, 9, 9, 9, - 9, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 13, 14, 14, 14, 14, 15, 15, 15, - 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, - 23, 24, 24, 25, 25, 26, 26, 27, - 27, 28, 28, 29, 29, 30, 30, 31, - 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 50, 52, 54, 56, 58, 60, - 62, 65, 69, 73, 77, 83, 91, 103, - 255, 231, 219, 211, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 175, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 165, 164, 163, 162, 161, 160, - 159, 159, 158, 158, 157, 157, 156, 156, - 155, 155, 154, 154, 153, 153, 152, 152, - 151, 151, 150, 150, 149, 149, 148, 148, - 147, 147, 146, 146, 145, 145, 144, 144, - 143, 143, 143, 143, 142, 142, 142, 142, - 141, 141, 141, 141, 140, 140, 140, 140, - 139, 139, 139, 139, 138, 138, 138, 138, - 137, 137, 137, 137, 136, 136, 136, 136, - 135, 135, 135, 135, 134, 134, 134, 134, - 133, 133, 133, 133, 132, 132, 132, 132, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 129, 128, 128, 128, 128, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, + 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, + 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, + 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, + 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, + 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, + 0x3e, 0x41, 0x45, 0x49, 0x4d, 0x53, 0x5b, 0x67, + 0xff, 0xe7, 0xdb, 0xd3, 0xcd, 0xc9, 0xc5, 0xc1, + 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, + 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8, + 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, + 0x9f, 0x9f, 0x9e, 0x9e, 0x9d, 0x9d, 0x9c, 0x9c, + 0x9b, 0x9b, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98, + 0x97, 0x97, 0x96, 0x96, 0x95, 0x95, 0x94, 0x94, + 0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x90, 0x90, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, + 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, + 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, +}; + +static u_char alawtolin16[256][2] = { + {0x6a,0x80}, {0x6b,0x80}, {0x68,0x80}, {0x69,0x80}, + {0x6e,0x80}, {0x6f,0x80}, {0x6c,0x80}, {0x6d,0x80}, + {0x62,0x80}, {0x63,0x80}, {0x60,0x80}, {0x61,0x80}, + {0x66,0x80}, {0x67,0x80}, {0x64,0x80}, {0x65,0x80}, + {0x75,0x40}, {0x75,0xc0}, {0x74,0x40}, {0x74,0xc0}, + {0x77,0x40}, {0x77,0xc0}, {0x76,0x40}, {0x76,0xc0}, + {0x71,0x40}, {0x71,0xc0}, {0x70,0x40}, {0x70,0xc0}, + {0x73,0x40}, {0x73,0xc0}, {0x72,0x40}, {0x72,0xc0}, + {0x2a,0x00}, {0x2e,0x00}, {0x22,0x00}, {0x26,0x00}, + {0x3a,0x00}, {0x3e,0x00}, {0x32,0x00}, {0x36,0x00}, + {0x0a,0x00}, {0x0e,0x00}, {0x02,0x00}, {0x06,0x00}, + {0x1a,0x00}, {0x1e,0x00}, {0x12,0x00}, {0x16,0x00}, + {0x55,0x00}, {0x57,0x00}, {0x51,0x00}, {0x53,0x00}, + {0x5d,0x00}, {0x5f,0x00}, {0x59,0x00}, {0x5b,0x00}, + {0x45,0x00}, {0x47,0x00}, {0x41,0x00}, {0x43,0x00}, + {0x4d,0x00}, {0x4f,0x00}, {0x49,0x00}, {0x4b,0x00}, + {0x7e,0xa8}, {0x7e,0xb8}, {0x7e,0x88}, {0x7e,0x98}, + {0x7e,0xe8}, {0x7e,0xf8}, {0x7e,0xc8}, {0x7e,0xd8}, + {0x7e,0x28}, {0x7e,0x38}, {0x7e,0x08}, {0x7e,0x18}, + {0x7e,0x68}, {0x7e,0x78}, {0x7e,0x48}, {0x7e,0x58}, + {0x7f,0xa8}, {0x7f,0xb8}, {0x7f,0x88}, {0x7f,0x98}, + {0x7f,0xe8}, {0x7f,0xf8}, {0x7f,0xc8}, {0x7f,0xd8}, + {0x7f,0x28}, {0x7f,0x38}, {0x7f,0x08}, {0x7f,0x18}, + {0x7f,0x68}, {0x7f,0x78}, {0x7f,0x48}, {0x7f,0x58}, + {0x7a,0xa0}, {0x7a,0xe0}, {0x7a,0x20}, {0x7a,0x60}, + {0x7b,0xa0}, {0x7b,0xe0}, {0x7b,0x20}, {0x7b,0x60}, + {0x78,0xa0}, {0x78,0xe0}, {0x78,0x20}, {0x78,0x60}, + {0x79,0xa0}, {0x79,0xe0}, {0x79,0x20}, {0x79,0x60}, + {0x7d,0x50}, {0x7d,0x70}, {0x7d,0x10}, {0x7d,0x30}, + {0x7d,0xd0}, {0x7d,0xf0}, {0x7d,0x90}, {0x7d,0xb0}, + {0x7c,0x50}, {0x7c,0x70}, {0x7c,0x10}, {0x7c,0x30}, + {0x7c,0xd0}, {0x7c,0xf0}, {0x7c,0x90}, {0x7c,0xb0}, + {0x95,0x80}, {0x94,0x80}, {0x97,0x80}, {0x96,0x80}, + {0x91,0x80}, {0x90,0x80}, {0x93,0x80}, {0x92,0x80}, + {0x9d,0x80}, {0x9c,0x80}, {0x9f,0x80}, {0x9e,0x80}, + {0x99,0x80}, {0x98,0x80}, {0x9b,0x80}, {0x9a,0x80}, + {0x8a,0xc0}, {0x8a,0x40}, {0x8b,0xc0}, {0x8b,0x40}, + {0x88,0xc0}, {0x88,0x40}, {0x89,0xc0}, {0x89,0x40}, + {0x8e,0xc0}, {0x8e,0x40}, {0x8f,0xc0}, {0x8f,0x40}, + {0x8c,0xc0}, {0x8c,0x40}, {0x8d,0xc0}, {0x8d,0x40}, + {0xd6,0x00}, {0xd2,0x00}, {0xde,0x00}, {0xda,0x00}, + {0xc6,0x00}, {0xc2,0x00}, {0xce,0x00}, {0xca,0x00}, + {0xf6,0x00}, {0xf2,0x00}, {0xfe,0x00}, {0xfa,0x00}, + {0xe6,0x00}, {0xe2,0x00}, {0xee,0x00}, {0xea,0x00}, + {0xab,0x00}, {0xa9,0x00}, {0xaf,0x00}, {0xad,0x00}, + {0xa3,0x00}, {0xa1,0x00}, {0xa7,0x00}, {0xa5,0x00}, + {0xbb,0x00}, {0xb9,0x00}, {0xbf,0x00}, {0xbd,0x00}, + {0xb3,0x00}, {0xb1,0x00}, {0xb7,0x00}, {0xb5,0x00}, + {0x81,0x58}, {0x81,0x48}, {0x81,0x78}, {0x81,0x68}, + {0x81,0x18}, {0x81,0x08}, {0x81,0x38}, {0x81,0x28}, + {0x81,0xd8}, {0x81,0xc8}, {0x81,0xf8}, {0x81,0xe8}, + {0x81,0x98}, {0x81,0x88}, {0x81,0xb8}, {0x81,0xa8}, + {0x80,0x58}, {0x80,0x48}, {0x80,0x78}, {0x80,0x68}, + {0x80,0x18}, {0x80,0x08}, {0x80,0x38}, {0x80,0x28}, + {0x80,0xd8}, {0x80,0xc8}, {0x80,0xf8}, {0x80,0xe8}, + {0x80,0x98}, {0x80,0x88}, {0x80,0xb8}, {0x80,0xa8}, + {0x85,0x60}, {0x85,0x20}, {0x85,0xe0}, {0x85,0xa0}, + {0x84,0x60}, {0x84,0x20}, {0x84,0xe0}, {0x84,0xa0}, + {0x87,0x60}, {0x87,0x20}, {0x87,0xe0}, {0x87,0xa0}, + {0x86,0x60}, {0x86,0x20}, {0x86,0xe0}, {0x86,0xa0}, + {0x82,0xb0}, {0x82,0x90}, {0x82,0xf0}, {0x82,0xd0}, + {0x82,0x30}, {0x82,0x10}, {0x82,0x70}, {0x82,0x50}, + {0x83,0xb0}, {0x83,0x90}, {0x83,0xf0}, {0x83,0xd0}, + {0x83,0x30}, {0x83,0x10}, {0x83,0x70}, {0x83,0x50}, }; +static u_char lintoalaw[256] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, + 0x3a, 0x3a, 0x3b, 0x3b, 0x38, 0x38, 0x39, 0x39, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3c, 0x3c, 0x3d, 0x3d, + 0x32, 0x32, 0x33, 0x33, 0x30, 0x30, 0x31, 0x31, + 0x36, 0x36, 0x37, 0x37, 0x34, 0x34, 0x35, 0x35, + 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, + 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, + 0x1a, 0x18, 0x1e, 0x1c, 0x12, 0x10, 0x16, 0x14, + 0x6a, 0x6e, 0x62, 0x66, 0x7a, 0x72, 0x4a, 0x5a, + 0xd5, 0xc5, 0xf5, 0xfd, 0xe5, 0xe1, 0xed, 0xe9, + 0x95, 0x97, 0x91, 0x93, 0x9d, 0x9f, 0x99, 0x9b, + 0x85, 0x84, 0x87, 0x86, 0x81, 0x80, 0x83, 0x82, + 0x8d, 0x8c, 0x8f, 0x8e, 0x89, 0x88, 0x8b, 0x8a, + 0xb5, 0xb5, 0xb4, 0xb4, 0xb7, 0xb7, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb0, 0xb0, 0xb3, 0xb3, 0xb2, 0xb2, + 0xbd, 0xbd, 0xbc, 0xbc, 0xbf, 0xbf, 0xbe, 0xbe, + 0xb9, 0xb9, 0xb8, 0xb8, 0xbb, 0xbb, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, +}; + +void +mulaw_to_ulinear8(v, p, cc) + void *v; + u_char *p; + int cc; +{ + /* Use the 16 bit table for 8 bits too. */ + while (--cc >= 0) { + *p = mulawtolin16[*p][0]; + ++p; + } +} + +void +mulaw_to_ulinear16(v, p, cc) + void *v; + u_char *p; + int cc; +{ + u_char *q = p; + + p += cc; + q += cc * 2; + while (--cc >= 0) { + *--q = mulawtolin16[*--p][LO]; + *--q = mulawtolin16[*p ][HI]; + } +} + void -mulaw_compress(hdl, e, p, cc) - void *hdl; - int e; +ulinear8_to_mulaw(v, p, cc) + void *v; u_char *p; int cc; { - u_char *tab; - - switch (e) { - case AUDIO_ENCODING_ULAW: - tab = lintomulaw; - break; - default: - return; + while (--cc >= 0) { + *p = lintomulaw[*p]; + ++p; } +} +void +alaw_to_ulinear8(v, p, cc) + void *v; + u_char *p; + int cc; +{ + /* Use the 16 bit table for 8 bits too. */ while (--cc >= 0) { - *p = tab[*p]; + *p = alawtolin16[*p][0]; ++p; } } void -mulaw_expand(hdl, e, p, cc) - void *hdl; - int e; +alaw_to_ulinear16(v, p, cc) + void *v; u_char *p; int cc; { - u_char *tab; - - switch (e) { - case AUDIO_ENCODING_ULAW: - tab = mulawtolin; - break; - default: - return; + u_char *q = p; + + p += cc; + q += cc * 2; + while (--cc >= 0) { + *--q = alawtolin16[*--p][LO]; + *--q = alawtolin16[*p ][HI]; } - +} + +void +ulinear8_to_alaw(v, p, cc) + void *v; + u_char *p; + int cc; +{ while (--cc >= 0) { - *p = tab[*p]; + *p = lintoalaw[*p]; ++p; } } diff --git a/sys/dev/mulaw.h b/sys/dev/mulaw.h index a7c310aeecb..bf70d089a67 100644 --- a/sys/dev/mulaw.h +++ b/sys/dev/mulaw.h @@ -1,5 +1,5 @@ -/* $OpenBSD: mulaw.h,v 1.2 1996/04/18 23:47:03 niklas Exp $ */ -/* $NetBSD: mulaw.h,v 1.2 1996/02/27 22:29:42 jtc Exp $ */ +/* $OpenBSD: mulaw.h,v 1.3 1998/04/26 21:03:11 provos Exp $ */ +/* $NetBSD: mulaw.h,v 1.8 1997/10/09 08:11:10 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 @@ -37,8 +37,13 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * Convert 8-bit mu-law to/from 8 bit unsigned linear (PCM8) - */ -extern void mulaw_compress __P((void *hw_hdl, int encoding, unsigned char *buf, int cnt)); -extern void mulaw_expand __P((void *hw_hdl, int encoding, unsigned char *buf, int cnt)); +/* Convert 8-bit mu-law to 16 bit unsigned linear. */ +extern void mulaw_to_ulinear16 __P((void *, u_char *buf, int cnt)); +/* Convert 8-bit mu-law to/from 8 bit unsigned linear. */ +extern void mulaw_to_ulinear8 __P((void *, u_char *buf, int cnt)); +extern void ulinear8_to_mulaw __P((void *, u_char *buf, int cnt)); +/* Convert 8-bit a-law to 16 bit unsigned linear. */ +extern void alaw_to_ulinear16 __P((void *, u_char *buf, int cnt)); +/* Convert 8-bit a-law to/from 8 bit unsigned linear. */ +extern void alaw_to_ulinear8 __P((void *, u_char *buf, int cnt)); +extern void ulinear8_to_alaw __P((void *, u_char *buf, int cnt)); diff --git a/sys/sys/audioio.h b/sys/sys/audioio.h index 0c775418596..dcdae1a95b0 100644 --- a/sys/sys/audioio.h +++ b/sys/sys/audioio.h @@ -1,5 +1,5 @@ -/* $OpenBSD: audioio.h,v 1.6 1997/07/11 22:24:32 provos Exp $ */ -/* $NetBSD: audioio.h,v 1.6 1996/04/09 20:55:22 cgd Exp $ */ +/* $OpenBSD: audioio.h,v 1.7 1998/04/26 21:03:17 provos Exp $ */ +/* $NetBSD: audioio.h,v 1.18 1997/10/28 03:26:45 mikel Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -45,18 +45,21 @@ struct audio_prinfo { u_int sample_rate; /* sample rate in bit/s */ u_int channels; /* number of channels, usually 1 or 2 */ u_int precision; /* number of bits/sample */ - u_int encoding; /* data encoding (AUDIO_ENCODING_* above) */ + u_int encoding; /* data encoding (AUDIO_ENCODING_* below) */ u_int gain; /* volume level */ u_int port; /* selected I/O port */ u_long seek; /* BSD extension */ - u_int ispare[3]; + u_int avail_ports; /* available I/O ports */ + u_int buffer_size; /* total size audio buffer */ + u_int _ispare[1]; /* Current state of device: */ u_int samples; /* number of samples */ u_int eof; /* End Of File (zero-size writes) counter */ u_char pause; /* non-zero if paused, zero to resume */ u_char error; /* non-zero if underflow/overflow ocurred */ u_char waiting; /* non-zero if another process hangs in open */ - u_char cspare[3]; + u_char balance; /* stereo channel balance */ + u_char cspare[2]; u_char open; /* non-zero if currently open */ u_char active; /* non-zero if I/O is currently active */ }; @@ -65,23 +68,24 @@ typedef struct audio_prinfo audio_prinfo_t; struct audio_info { struct audio_prinfo play; /* Info for play (output) side */ struct audio_prinfo record; /* Info for record (input) side */ - u_int __spare; + + u_int monitor_gain; /* input to output mix */ /* BSD extensions */ - u_int blocksize; /* input blocking threshold */ + u_int blocksize; /* H/W read/write block size */ u_int hiwat; /* output high water mark */ u_int lowat; /* output low water mark */ - u_int backlog; /* samples of output backlog to gen. */ + u_int _ispare1; u_int mode; /* current device mode */ #define AUMODE_PLAY 0x01 #define AUMODE_RECORD 0x02 -#define AUMODE_PLAY_ALL 0x04 /* play all samples--no real-time correction */ +#define AUMODE_PLAY_ALL 0x04 /* don't do real-time correction */ }; typedef struct audio_info audio_info_t; #ifdef _KERNEL #define AUDIO_INITINFO(p)\ - { register int n = sizeof(struct audio_info); \ - register u_char *q = (u_char *) p; \ + { int n = sizeof(struct audio_info); \ + u_char *q = (u_char *) p; \ while (n-- > 0) *q++ = 0xff; } #else @@ -100,25 +104,70 @@ typedef struct audio_device { char config[MAX_AUDIO_DEV_LEN]; } audio_device_t; +typedef struct audio_offset { + u_int samples; /* Total number of bytes transferred */ + u_int deltablks; /* Blocks transferred since last checked */ + u_int offset; /* Physical transfer offset in buffer */ +} audio_offset_t; + /* * Supported audio encodings */ /* Encoding ID's */ -#define AUDIO_ENCODING_NONE 0 /* no encoding assigned */ -#define AUDIO_ENCODING_ULAW 1 -#define AUDIO_ENCODING_ALAW 2 -#define AUDIO_ENCODING_PCM16 3 -#define AUDIO_ENCODING_LINEAR AUDIO_ENCODING_PCM16 -#define AUDIO_ENCODING_PCM8 4 -#define AUDIO_ENCODING_ADPCM 5 +#define AUDIO_ENCODING_NONE 0 /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW 1 /* ITU G.711 mu-law */ +#define AUDIO_ENCODING_ALAW 2 /* ITU G.711 A-law */ +#define AUDIO_ENCODING_PCM16 3 /* signed linear PCM, obsolete */ +#define AUDIO_ENCODING_LINEAR AUDIO_ENCODING_PCM16 /* SunOS compat */ +#define AUDIO_ENCODING_PCM8 4 /* unsigned linear PCM, obsolete */ +#define AUDIO_ENCODING_LINEAR8 AUDIO_ENCODING_PCM8 /* SunOS compat */ +#define AUDIO_ENCODING_ADPCM 5 /* adaptive differential PCM */ +#define AUDIO_ENCODING_SLINEAR_LE 6 +#define AUDIO_ENCODING_SLINEAR_BE 7 +#define AUDIO_ENCODING_ULINEAR_LE 8 +#define AUDIO_ENCODING_ULINEAR_BE 9 +#define AUDIO_ENCODING_SLINEAR 10 +#define AUDIO_ENCODING_ULINEAR 11 +#define AUDIO_ENCODING_MPEG_L1_STREAM 12 +#define AUDIO_ENCODING_MPEG_L1_PACKETS 13 +#define AUDIO_ENCODING_MPEG_L1_SYSTEM 14 +#define AUDIO_ENCODING_MPEG_L2_STREAM 15 +#define AUDIO_ENCODING_MPEG_L2_PACKETS 16 +#define AUDIO_ENCODING_MPEG_L2_SYSTEM 17 typedef struct audio_encoding { - int index; - char name[MAX_AUDIO_DEV_LEN]; - int format_id; + int index; + char name[MAX_AUDIO_DEV_LEN]; + int encoding; + int precision; + int flags; +#define AUDIO_ENCODINGFLAG_EMULATED 1 /* software emulation mode */ } audio_encoding_t; /* + * Balance settings. + */ +#define AUDIO_LEFT_BALANCE 0 /* left channel only */ +#define AUDIO_MID_BALANCE 32 /* equal left/right channel */ +#define AUDIO_RIGHT_BALANCE 64 /* right channel only */ +#define AUDIO_BALANCE_SHIFT 3 + +/* + * Output ports + */ +#define AUDIO_SPEAKER 0x01 /* built-in speaker */ +#define AUDIO_HEADPHONE 0x02 /* headphone jack */ +#define AUDIO_LINE_OUT 0x04 /* line out */ + +/* + * Input ports + */ +#define AUDIO_MICROPHONE 0x01 /* microphone */ +#define AUDIO_LINE_IN 0x02 /* line in */ +#define AUDIO_CD 0x04 /* on-board CD inputs */ +#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* internal CDROM */ + +/* * Audio device operations */ #define AUDIO_GETINFO _IOR('A', 21, struct audio_info) @@ -132,6 +181,12 @@ typedef struct audio_encoding { #define AUDIO_GETFD _IOR('A', 29, int) #define AUDIO_SETFD _IOWR('A', 30, int) #define AUDIO_PERROR _IOR('A', 31, int) +#define AUDIO_GETIOFFS _IOR('A', 32, struct audio_offset) +#define AUDIO_GETOOFFS _IOR('A', 33, struct audio_offset) +#define AUDIO_GETPROPS _IOR('A', 34, int) +#define AUDIO_PROP_FULLDUPLEX 0x01 +#define AUDIO_PROP_MMAP 0x02 +#define AUDIO_PROP_INDEPENDENT 0x04 /* * Mixer device @@ -212,8 +267,8 @@ typedef struct mixer_ctrl { */ #define AudioNmicrophone "mic" #define AudioNline "line" -#define AudioNcd "CD" -#define AudioNdac "DAC" +#define AudioNcd "cd" +#define AudioNdac "dac" #define AudioNrecord "record" #define AudioNvolume "volume" #define AudioNmonitor "monitor" @@ -239,18 +294,28 @@ typedef struct mixer_ctrl { #define AudioNwave "wave" #define AudioNmidi "midi" #define AudioNmixerout "mixerout" +#define AudioNswap "swap" /* swap left and right channels */ -#define AudioElinear "linear" -#define AudioEmulaw "mulaw" -#define AudioEalaw "alaw" -#define AudioEpcm16 "PCM-16" -#define AudioEpcm8 "PCM-8" -#define AudioEadpcm "ADPCM" +#define AudioEmulaw "mulaw" +#define AudioEalaw "alaw" +#define AudioEadpcm "adpcm" +#define AudioEslinear "slinear" +#define AudioEslinear_le "slinear_le" +#define AudioEslinear_be "slinear_be" +#define AudioEulinear "ulinear" +#define AudioEulinear_le "ulinear_le" +#define AudioEulinear_be "ulinear_be" +#define AudioEmpeg_l1_stream "mpeg_l1_stream" +#define AudioEmpeg_l1_packets "mpeg_l1_packets" +#define AudioEmpeg_l1_system "mpeg_l1_system" +#define AudioEmpeg_l2_stream "mpeg_l2_stream" +#define AudioEmpeg_l2_packets "mpeg_l2_packets" +#define AudioEmpeg_l2_system "mpeg_l2_system" -#define AudioCInputs "Inputs" -#define AudioCOutputs "Outputs" -#define AudioCRecord "Record" -#define AudioCMonitor "Monitor" -#define AudioCEqualization "Equalization" +#define AudioCinputs "inputs" +#define AudioCoutputs "outputs" +#define AudioCrecord "record" +#define AudioCmonitor "monitor" +#define AudioCequalization "equalization" -#endif /* _SYS_AUDIOIO_H_ */ +#endif /* !_SYS_AUDIOIO_H_ */ diff --git a/sys/sys/conf.h b/sys/sys/conf.h index b7549a27e34..ab0eec54ce9 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.24 1998/04/01 20:14:16 matthieu Exp $ */ +/* $OpenBSD: conf.h,v 1.25 1998/04/26 21:03:18 provos Exp $ */ /* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */ /*- @@ -317,7 +317,7 @@ extern struct cdevsw cdevsw[]; #define cdev_audio_init(c,n) { \ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \ - 0, dev_init(c,n,select), (dev_type_mmap((*))) enodev } + 0, dev_init(c,n,select), dev_init(c,n,mmap) } #define cdev_svr4_net_init(c,n) { \ dev_init(c,n,open), (dev_type_close((*))) enodev, \ |