diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-04-26 22:31:11 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-04-26 22:31:11 +0000 |
commit | 57ac98438bc1c769d1b9410e73c57bdf24e578ba (patch) | |
tree | c7059380ab4f60d9df5b0eb9775cf931aa598e9a /sys/arch/amiga | |
parent | 863410555c46c321a02002a7da8d93946b7b619d (diff) |
Get audio framework from MI-land, scrap the local variant. Some NetBSD merging
Diffstat (limited to 'sys/arch/amiga')
-rw-r--r-- | sys/arch/amiga/amiga/conf.c | 6 | ||||
-rw-r--r-- | sys/arch/amiga/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/amiga/conf/files.amiga | 17 | ||||
-rw-r--r-- | sys/arch/amiga/dev/aucc.c | 101 | ||||
-rw-r--r-- | sys/arch/amiga/dev/audio.c | 2377 | ||||
-rw-r--r-- | sys/arch/amiga/dev/audio_if.h | 172 | ||||
-rw-r--r-- | sys/arch/amiga/dev/audiovar.h | 130 |
7 files changed, 29 insertions, 2778 deletions
diff --git a/sys/arch/amiga/amiga/conf.c b/sys/arch/amiga/amiga/conf.c index 6d2d7408ef9..196e24b7750 100644 --- a/sys/arch/amiga/amiga/conf.c +++ b/sys/arch/amiga/amiga/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.19 1997/10/16 06:48:12 niklas Exp $ */ +/* $OpenBSD: conf.c,v 1.20 1998/04/26 22:30:57 niklas Exp $ */ /* $NetBSD: conf.c,v 1.42 1997/01/07 11:35:03 mrg Exp $ */ /*- @@ -101,7 +101,7 @@ dev_decl(filedesc,open); #include "com.h" #include "lpt.h" #include "uk.h" -#include "new_audio.h" +#include "audio.h" cdev_decl(audio); struct cdevsw cdevsw[] = @@ -145,7 +145,7 @@ struct cdevsw cdevsw[] = cdev_uk_init(NUK,uk), /* 36: unknown SCSI */ cdev_disk_init(NWD,wd), /* 37: ST506/ESDI/IDE disk */ cdev_disk_init(NACD,acd), /* 38: ATAPI CD-ROM */ - cdev_audio_init(NNEW_AUDIO,audio), /* 39: cc audio interface */ + cdev_audio_init(NAUDIO,audio), /* 39: cc audio interface */ cdev_ch_init(NCH,ch), /* 40: SCSI autochanger */ cdev_disk_init(NRD,rd), /* 41: RAM disk */ }; diff --git a/sys/arch/amiga/conf/GENERIC b/sys/arch/amiga/conf/GENERIC index 72c11a46a3a..95d0fbabfc2 100644 --- a/sys/arch/amiga/conf/GENERIC +++ b/sys/arch/amiga/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.23 1997/10/07 11:04:52 niklas Exp $ +# $OpenBSD: GENERIC,v 1.24 1998/04/26 22:30:59 niklas Exp $ # $NetBSD: GENERIC,v 1.85 1997/08/27 19:32:49 is Exp $ # @@ -148,7 +148,7 @@ com* at drsupio? port ? # DraCo serial a2kbbc0 at mainbus0 # A2000 battery backed clock a34kbbc0 at mainbus0 # A3000/A4000 battery backed clock aucc* at mainbus0 # Amiga CC audio -new_audio* at aucc? +audio* at aucc? # Ethernet cards le* at zbus0 # Lance ethernet. diff --git a/sys/arch/amiga/conf/files.amiga b/sys/arch/amiga/conf/files.amiga index 1a403a7ca14..9ba612d74d0 100644 --- a/sys/arch/amiga/conf/files.amiga +++ b/sys/arch/amiga/conf/files.amiga @@ -1,4 +1,4 @@ -# $OpenBSD: files.amiga,v 1.27 1998/04/05 09:09:09 niklas Exp $ +# $OpenBSD: files.amiga,v 1.28 1998/04/26 22:31:01 niklas Exp $ # $NetBSD: files.amiga,v 1.62 1997/08/27 19:32:47 is Exp $ @@ -7,17 +7,6 @@ maxpartitions 16 maxusers 2 8 64 -# Transient audio stuff that will end up in the MI parts -define new_audio {} -define auconv - -# audio device, attaches to audio hardware driver -device new_audio -attach new_audio at new_audio - -file dev/auconv.c auconv -file arch/amiga/dev/audio.c new_audio needs-flag - device mainbus {} attach mainbus at root @@ -62,8 +51,8 @@ device par attach par at mainbus file arch/amiga/dev/par.c par needs-count -# audio XXX s/new_audio/audio/ after the new audio is generally used. -device aucc: new_audio +# audio +device aucc: audio attach aucc at mainbus file arch/amiga/dev/aucc.c aucc needs-flag diff --git a/sys/arch/amiga/dev/aucc.c b/sys/arch/amiga/dev/aucc.c index 391e710a192..38593edb6f1 100644 --- a/sys/arch/amiga/dev/aucc.c +++ b/sys/arch/amiga/dev/aucc.c @@ -1,6 +1,6 @@ -/* $OpenBSD: aucc.c,v 1.2 1997/10/07 11:04:56 niklas Exp $ */ -/* $NetBSD: aucc.c,v 1.18 1997/08/24 22:31:23 augustss Exp $ */ -#undef AUDIO_DEBUG +/* $OpenBSD: aucc.c,v 1.3 1998/04/26 22:31:03 niklas Exp $ */ +/* $NetBSD: aucc.c,v 1.22 1998/01/12 10:39:10 thorpej Exp $ */ + /* * Copyright (c) 1997 Stephan Thesing * All rights reserved. @@ -40,15 +40,16 @@ #include <sys/ioctl.h> #include <sys/device.h> #include <sys/proc.h> +#include <sys/audioio.h> + +#include <dev/audio_if.h> #include <machine/cpu.h> -#include <machine/audioio.h> #include <amiga/amiga/cc.h> #include <amiga/amiga/custom.h> #include <amiga/amiga/device.h> -#include <amiga/dev/audio_if.h> #include <amiga/dev/auccvar.h> #ifdef LEV6_DEFER @@ -169,10 +170,6 @@ void aucc_close __P((void *)); int aucc_set_out_sr __P((void *, u_long)); int aucc_query_encoding __P((void *, struct audio_encoding *)); int aucc_round_blocksize __P((void *, int)); -int aucc_set_out_port __P((void *, int)); -int aucc_get_out_port __P((void *)); -int aucc_set_in_port __P((void *, int)); -int aucc_get_in_port __P((void *)); int aucc_commit_settings __P((void *)); int aucc_start_output __P((void *, void *, int, void (*)(void *), void *)); @@ -180,8 +177,6 @@ int aucc_start_input __P((void *, void *, int, void (*)(void *), void *)); int aucc_halt_output __P((void *)); int aucc_halt_input __P((void *)); -int aucc_cont_output __P((void *)); -int aucc_cont_input __P((void *)); int aucc_getdev __P((void *, struct audio_device *)); int aucc_set_port __P((void *, mixer_ctrl_t *)); int aucc_get_port __P((void *, mixer_ctrl_t *)); @@ -198,10 +193,6 @@ struct audio_hw_if sa_hw_if = { aucc_query_encoding, aucc_set_params, aucc_round_blocksize, - aucc_set_out_port, - aucc_get_out_port, - aucc_set_in_port, - aucc_get_in_port, aucc_commit_settings, NULL, NULL, @@ -209,8 +200,6 @@ struct audio_hw_if sa_hw_if = { aucc_start_input, aucc_halt_output, aucc_halt_input, - aucc_cont_output, - aucc_cont_input, NULL, aucc_getdev, NULL, @@ -378,7 +367,7 @@ aucc_query_encoding(addr, fp) { switch (fp->index) { case 0: - strcpy(fp->name, AudioElinear); + strcpy(fp->name, AudioEslinear); fp->encoding = AUDIO_ENCODING_SLINEAR; fp->precision = 8; fp->flags = 0; @@ -460,46 +449,6 @@ aucc_round_blocksize(addr, blk) } int -aucc_set_out_port(addr, port) /* can set channels */ - void *addr; - int port; -{ - struct aucc_softc *sc = addr; - - /* port is mask for channels 0..3 */ - if ((port < 0) || (port > 15)) - return (EINVAL); - - sc->sc_channelmask = port; - - return (0); -} - -int -aucc_get_out_port(addr) - void *addr; -{ - struct aucc_softc *sc = addr; - - return (sc->sc_channelmask); -} - -int -aucc_set_in_port(addr, port) - void *addr; - int port; -{ - return (EINVAL); /* no input possible */ -} - -int -aucc_get_in_port(addr) - void *addr; -{ - return (0); -} - -int aucc_commit_settings(addr) void *addr; { @@ -679,23 +628,6 @@ aucc_halt_input(addr) } int -aucc_cont_output(addr) - void *addr; -{ - DPRINTF(("aucc_cont_output: never called, what should it do?!\n")); - /* reenable DMA XXX */ - return (ENXIO); -} - -int -aucc_cont_input(addr) - void *addr; -{ - DPRINTF(("aucc_cont_input: never called, what should it do?!\n")); - return (0); -} - -int aucc_getdev(addr, retp) void *addr; struct audio_device *retp; @@ -735,11 +667,20 @@ aucc_set_port(addr, cp) #endif /* set volume for channel 0..i-1 */ - if (i > 1) + + /* evil workaround for xanim bug, IMO */ + if ((sc->sc_channels == 1) && (i == 2)) { + sc->sc_channel[0].nd_volume = + sc->sc_channel[3].nd_volume = + cp->un.value.level[0] >> 2; + sc->sc_channel[1].nd_volume = + sc->sc_channel[2].nd_volume = + cp->un.value.level[1] >> 2; + } else if (i > 1) { for (j = 0; j < i; j++) sc->sc_channel[j].nd_volume = cp->un.value.level[j] >> 2; - else if (sc->sc_channels > 1) + } else if (sc->sc_channels > 1) for (j = 0; j < sc->sc_channels; j++) sc->sc_channel[j].nd_volume = cp->un.value.level[0] >> 2; @@ -809,7 +750,7 @@ aucc_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_SET; dip->mixer_class = AUCC_OUTPUT_CLASS; dip->prev = dip->next = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioNspeaker); + strcpy(dip->label.name, AudioNmaster); for (i = 0; i < 16; i++) { sprintf(dip->un.s.member[i].label.name, "channelmask%d", i); @@ -831,11 +772,11 @@ aucc_query_devinfo(addr, dip) dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = AUCC_OUTPUT_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; - strcpy(dip->label.name, AudioCOutputs); + strcpy(dip->label.name, AudioCoutputs); break; + default: return (ENXIO); - /*NOTREACHED*/ } DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); diff --git a/sys/arch/amiga/dev/audio.c b/sys/arch/amiga/dev/audio.c deleted file mode 100644 index 538615a72c0..00000000000 --- a/sys/arch/amiga/dev/audio.c +++ /dev/null @@ -1,2377 +0,0 @@ -/* $OpenBSD: audio.c,v 1.1 1997/10/07 11:04:57 niklas 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. - * 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. - */ - -/* - * This is a (partially) SunOS-compatible /dev/audio driver for Net- & OpenBSD. - * - * This code tries to do something half-way sensible with - * half-duplex hardware, such as with the SoundBlaster hardware. With - * half-duplex hardware allowing O_RDWR access doesn't really make - * sense. However, closing and opening the device to "turn around the - * line" is relatively expensive and costs a card reset (which can - * take some time, at least for the SoundBlaster hardware). Instead - * we allow O_RDWR access, and provide an ioctl to set the "mode", - * i.e. playing or recording. - * - * If you write to a half-duplex device in record mode, the data is - * tossed. If you read from the device in play mode, you get silence - * filled buffers at the rate at which samples are naturally - * generated. - * - * If you try to set both play and record mode on a half-duplex - * device, playing takes precedence. - */ - -/* - * Todo: - * - Add softaudio() isr processing for wakeup, poll, signals, - * and silence fill. - */ - -#include "new_audio.h" -#if NNEW_AUDIO > 0 - -#include <sys/param.h> -#include <sys/ioctl.h> -#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> -#include <sys/syslog.h> -#include <sys/kernel.h> -#include <sys/signalvar.h> -#include <sys/conf.h> -#include <sys/device.h> - -#include <machine/audioio.h> -#include <machine/endian.h> - -#include <amiga/dev/audio_if.h> -#include <amiga/dev/audiovar.h> - -#include <vm/vm.h> -#include <vm/vm_prot.h> - -#ifdef AUDIO_DEBUG -#define DPRINTF(x) if (audiodebug) printf x -int audiodebug = 0; -#else -#define DPRINTF(x) -#endif - -#define ROUNDSIZE(x) x &= -16 /* round to nice boundary */ - -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 *)); - -int audio_open __P((dev_t, int, int, struct proc *)); -int audio_close __P((dev_t, int, int, struct proc *)); -int audio_read __P((dev_t, struct uio *, int)); -int audio_write __P((dev_t, struct uio *, int)); -int audio_ioctl __P((dev_t, int, caddr_t, int, struct proc *)); -int audio_select __P((dev_t, int, struct proc *)); -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 *)); -int audiostartr __P((struct audio_softc *)); -int audiostartp __P((struct audio_softc *)); -void audio_rint __P((void *)); -void audio_pint __P((void *)); -int audio_check_params __P((struct audio_params *)); - -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_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)); - -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 *)); - -int audioprobe __P((struct device *, void *, void *)); -void audioattach __P((struct device *, struct device *, void *)); - -/* The default audio mode: 8 kHz mono ulaw */ -struct audio_params audio_default = - { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1 }; - -struct cfattach new_audio_ca = { - sizeof(struct audio_softc), audioprobe, audioattach -}; - -struct cfdriver new_audio_cd = { - NULL, "audio", DV_DULL -}; - -int -audioprobe(parent, match, aux) - struct device *parent; - void *match; - void *aux; -{ - struct audio_attach_args *sa = aux; - - DPRINTF(("audioprobe: done=%d sa=%p hw=%p\n", - sa->audiodone, sa, sa->ahw)); - if (sa->audiodone) - return 0; - return sa->ahw != 0; -} - -void -audioattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct audio_softc *sc = (void *)self; - struct audio_attach_args *sa = aux; - struct audio_hw_if *hwp = sa->ahw; - void *hdlp = sa->hdl; - int error; - - printf("\n"); - - sa->audiodone++; - -#ifdef DIAGNOSTIC - if (hwp == 0 || - hwp->open == 0 || - hwp->close == 0 || - hwp->query_encoding == 0 || - hwp->set_params == 0 || - hwp->set_out_port == 0 || - hwp->get_out_port == 0 || - hwp->set_in_port == 0 || - hwp->get_in_port == 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 || - hwp->get_props == 0) { - printf("audio: missing method\n"); - sc->hw_if = 0; - return; - } -#endif - - sc->hw_if = hwp; - sc->hw_hdl = hdlp; - sc->sc_dev = parent; - - error = audio_alloc_ring(sc, &sc->sc_pr, AU_RING_SIZE); - if (error) { - sc->hw_if = 0; - return; - } - 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_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); -} - -/* - * 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_attach_args arg; - - arg.ahw = ahwp; - arg.mhw = mhwp; - arg.hdl = hdlp; - arg.audiodone = arg.mididone = 0; - while(config_found(dev, &arg, 0)) - ; -} - -#ifdef AUDIO_DEBUG -void audio_printsc __P((struct audio_softc *)); -void audio_print_params __P((char *, struct audio_params *)); - -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); -} - -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 - -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; -} - -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 -audioopen(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *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)); - default: - return (ENXIO); - } -} - -int -audioclose(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *p; -{ - - switch (AUDIODEV(dev)) { - case SOUND_DEVICE: - case AUDIO_DEVICE: - 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); - } -} - -int -audioread(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - - switch (AUDIODEV(dev)) { - case SOUND_DEVICE: - case AUDIO_DEVICE: - return (audio_read(dev, uio, ioflag)); - case AUDIOCTL_DEVICE: - case MIXER_DEVICE: - return (ENODEV); - default: - return (ENXIO); - } -} - -int -audiowrite(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - - switch (AUDIODEV(dev)) { - case SOUND_DEVICE: - case AUDIO_DEVICE: - return (audio_write(dev, uio, ioflag)); - case AUDIOCTL_DEVICE: - case MIXER_DEVICE: - return (ENODEV); - default: - return (ENXIO); - } -} - -int -audioioctl(dev, cmd, addr, flag, p) - dev_t dev; - u_long cmd; - caddr_t addr; - int flag; - struct proc *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)); - default: - return (ENXIO); - } -} - -int -audioselect(dev, events, p) - dev_t dev; - int events; - struct proc *p; -{ - - switch (AUDIODEV(dev)) { - case SOUND_DEVICE: - case AUDIO_DEVICE: - return (audio_select(dev, events, p)); - case AUDIOCTL_DEVICE: - case MIXER_DEVICE: - return (0); - default: - return (0); - } -} - -int -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 -1; - default: - return -1; - } -} - -/* - * Audio driver - */ -void -audio_init_ringbuffer(rp) - struct audio_ringbuffer *rp; -{ - 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; -} - -int -audio_initbufs(sc) - struct audio_softc *sc; -{ - struct audio_hw_if *hw = sc->hw_if; - int error; - - 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 -audio_sleep_timo(chan, label, timo) - int *chan; - char *label; - int timo; -{ - int st; - - if (!label) - label = "audio"; - - *chan = 1; - st = tsleep(chan, PWAIT | PCATCH, label, timo); - *chan = 0; -#ifdef AUDIO_DEBUG - if (st != 0) - printf("audio_sleep: %d\n", st); -#endif - return (st); -} - -static __inline int -audio_sleep(chan, label) - int *chan; - char *label; -{ - return audio_sleep_timo(chan, label, 0); -} - -/* call at splaudio() */ -static __inline void -audio_wakeup(chan) - int *chan; -{ - if (*chan) { - wakeup(chan); - *chan = 0; - } -} - -int -audio_open(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc; - int error; - int mode; - struct audio_hw_if *hw; - struct audio_info ai; - - if (unit >= new_audio_cd.cd_ndevs || - (sc = new_audio_cd.cd_devs[unit]) == NULL) - return ENXIO; - - hw = sc->hw_if; - if (!hw) - return ENXIO; - - DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=%p hdl=%p\n", dev, flags, sc, sc->hw_hdl)); - - if (ISDEVAUDIOCTL(dev)) - return 0; - - if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0) - return (EBUSY); - - error = hw->open(sc->hw_hdl, flags); - if (error) - return (error); - - 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; - 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) - * The /dev/audio is always (re)set to 8-bit MU-Law mono - * For the other devices, you get what they were last set to. - */ - if (ISDEVAUDIO(dev)) { - /* /dev/audio */ - 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. - */ - if (sc->sc_rparams.precision == 0 || sc->sc_pparams.precision == 0) { - printf("audio_open: 0 precision\n"); - return EINVAL; - } -#endif - - 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: done sc_mode = 0x%x\n", sc->sc_mode)); - - return 0; - -bad: - hw->close(sc->hw_hdl); - sc->sc_open = 0; - sc->sc_mode = 0; - sc->sc_full_duplex = 0; - return error; -} - -/* - * Must be called from task context. - */ -void -audio_init_record(sc) - struct audio_softc *sc; -{ - int s = splaudio(); - - if (sc->hw_if->speaker_ctl && - (!sc->sc_full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0)) - sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF); - splx(s); -} - -/* - * Must be called from task context. - */ -void -audio_init_play(sc) - struct audio_softc *sc; -{ - int s = splaudio(); - - 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); -} - -int -audio_drain(sc) - struct audio_softc *sc; -{ - int error, drops; - struct audio_ringbuffer *cb = &sc->sc_pr; - int s; - - 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)); - /* - * When the process is exiting, it ignores all signals and - * we can't interrupt this sleep, so we set a timeout just in case. - */ - error = audio_sleep_timo(&sc->sc_wchan, "aud_dr", 30*hz); - } - splx(s); - return error; -} - -/* - * Close an audio chip. - */ -/* ARGSUSED */ -int -audio_close(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_audio_cd.cd_devs[unit]; - struct audio_hw_if *hw = sc->hw_if; - int s; - - DPRINTF(("audio_close: unit=%d\n", unit)); - - /* - * Block until output drains, but allow ^C interrupt. - */ - 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_pr.pause) { - if (!audio_drain(sc) && hw->drain) - (void)hw->drain(sc->hw_hdl); - } - - hw->close(sc->hw_hdl); - - if (flags & FREAD) - sc->sc_open &= ~AUOPEN_READ; - if (flags & FWRITE) - sc->sc_open &= ~AUOPEN_WRITE; - - sc->sc_async_audio = 0; - sc->sc_mode = 0; - sc->sc_full_duplex = 0; - splx(s); - DPRINTF(("audio_close: done\n")); - - return (0); -} - -int -audio_read(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_audio_cd.cd_devs[unit]; - struct audio_ringbuffer *cb = &sc->sc_rr; - u_char *outp; - int error, s, used, cc, n; - - if (cb->mmapped) - return EINVAL; - -#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 (!sc->sc_full_duplex && - (sc->sc_mode & AUMODE_PLAY)) { - while (uio->uio_resid > 0 && !error) { - s = splaudio(); - 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; - } - error = audio_sleep(&sc->sc_rchan, "aud_hr"); - if (error) { - splx(s); - return error; - } - } - splx(s); - - 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); - } - while (uio->uio_resid > 0 && !error) { - s = splaudio(); - while (cb->used <= 0) { - if (ioflag & IO_NDELAY) { - 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; - } - } - 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); -} - -void -audio_clear(sc) - struct audio_softc *sc; -{ - int s = splaudio(); - - 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; - } - splx(s); -} - -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 = 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(params, p, n) - struct audio_params *params; - u_char *p; - int n; -{ - u_char auzero0, auzero1 = 0; /* initialize to please gcc */ - int nfill = 1; - - switch (params->encoding) { - case AUDIO_ENCODING_ULAW: - auzero0 = 0x7f; - break; - case AUDIO_ENCODING_ALAW: - auzero0 = 0x55; - break; - case AUDIO_ENCODING_ADPCM: /* is this right XXX */ - 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: - printf("audio: bad encoding %d\n", params->encoding); - auzero0 = 0; - break; - } - if (nfill == 1) { - while (--n >= 0) - *p++ = auzero0; /* XXX memset */ - } else /* nfill must be 2 */ { - while (n > 1) { - *p++ = auzero0; - *p++ = auzero1; - n -= 2; - } - } -} - -int -audio_silence_copyout(sc, n, uio) - struct audio_softc *sc; - int n; - struct uio *uio; -{ - int error; - int k; - u_char zerobuf[128]; - - audio_fill_silence(&sc->sc_rparams, zerobuf, sizeof zerobuf); - - 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; - } - return (error); -} - -int -audio_write(dev, uio, ioflag) - dev_t dev; - struct uio *uio; - int ioflag; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_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; - } - - /* - * If half-duplex and currently recording, throw away data. - */ - 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); - } - - 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 - - error = 0; - while (uio->uio_resid > 0 && !error) { - s = splaudio(); - 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); - 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; - } - 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 - /* - * 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 -#ifdef AUDIO_DEBUG - if (audiodebug > 1) - printf("audio_write: uiomove cc=%d inp=%p, left=%d\n", cc, inp, uio->uio_resid); -#endif - 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 (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; - - s = splaudio(); - /* - * 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); -} - -int -audio_ioctl(dev, cmd, addr, flag, p) - dev_t dev; - int cmd; - caddr_t addr; - int flag; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_audio_cd.cd_devs[unit]; - struct audio_hw_if *hw = sc->hw_if; - struct audio_offset *ao; - int error = 0, s, offs, fd; - - 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_audio) - return (EBUSY); - sc->sc_async_audio = p; - DPRINTF(("audio_ioctl: FIOASYNC %p\n", p)); - } else - sc->sc_async_audio = 0; - break; - - case AUDIO_FLUSH: - DPRINTF(("AUDIO_FLUSH\n")); - audio_clear(sc); - s = splaudio(); - error = audio_initbufs(sc); - if (error) { - splx(s); - return error; - } - if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pbus) - error = audiostartp(sc); - if (!error && - (sc->sc_mode & AUMODE_RECORD) && !sc->sc_rbus) - error = audiostartr(sc); - splx(s); - break; - - /* - * Number of read (write) samples dropped. We don't know where or - * when they were dropped. - */ - case AUDIO_RERROR: - *(int *)addr = sc->sc_rr.drops; - break; - - case AUDIO_PERROR: - *(int *)addr = sc->sc_pr.drops; - break; - - /* - * Offsets into buffer. - */ - 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(); - /* 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 mode=0x%x\n", sc->sc_mode)); - error = audiosetinfo(sc, (struct audio_info *)addr); - break; - - case AUDIO_GETINFO: - DPRINTF(("AUDIO_GETINFO\n")); - error = audiogetinfo(sc, (struct audio_info *)addr); - break; - - case AUDIO_DRAIN: - DPRINTF(("AUDIO_DRAIN\n")); - error = audio_drain(sc); - if (!error && hw->drain) - error = hw->drain(sc->hw_hdl); - break; - - case AUDIO_GETDEV: - DPRINTF(("AUDIO_GETDEV\n")); - error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr); - break; - - case AUDIO_GETENC: - DPRINTF(("AUDIO_GETENC\n")); - error = hw->query_encoding(sc->hw_hdl, (struct audio_encoding *)addr); - break; - -#ifdef COMPAT_12 - /* GETPROPS contains the same info (and more) */ - case AUDIO_GETFD: - DPRINTF(("AUDIO_GETFD\n")); - *(int *)addr = - (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX) != 0; - break; -#endif - case AUDIO_SETFD: - DPRINTF(("AUDIO_SETFD\n")); - 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: - DPRINTF(("audio_ioctl: unknown ioctl\n")); - error = EINVAL; - break; - } - DPRINTF(("audio_ioctl(%d,'%c',%d) result %d\n", - IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error)); - return (error); -} - -int -audio_select(dev, rw, p) - dev_t dev; - int rw; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_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 - switch (rw) { - - case FREAD: - 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); - } - selrecord(p, &sc->sc_rsel); - break; - - case FWRITE: - if (sc->sc_mode & AUMODE_RECORD || - sc->sc_pr.used <= sc->sc_pr.usedlow) { - splx(s); - return (1); - } - selrecord(p, &sc->sc_wsel); - break; - } - splx(s); - return (0); -} - -int -audio_mmap(dev, off, prot) - dev_t dev; - int off, prot; -{ - int s; - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_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); -} - -int -audiostartr(sc) - struct audio_softc *sc; -{ - int error; - - 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->sc_rr.start, - sc->sc_rr.blksize, audio_rint, (void *)sc); - if (error) { - DPRINTF(("audiostartr failed: %d\n", error)); - return error; - } - sc->sc_rbus = 1; - return 0; -} - -int -audiostartp(sc) - struct audio_softc *sc; -{ - int error; - - 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->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)); - return error; - } - sc->sc_pbus = 1; - } - return 0; -} - -/* - * 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. - */ -/* 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; -{ - 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); - } -} - -/* - * Called from HW driver module on completion of dma output. - * Start output of new block, wrap in ring buffer if needed. - * If no more buffers to play, output zero instead. - * Do a wakeup if necessary. - */ -void -audio_pint(v) - void *v; -{ - struct audio_softc *sc = v; - struct audio_hw_if *hw = sc->hw_if; - struct audio_ringbuffer *cb = &sc->sc_pr; - u_char *inp; - int cc, ccr; - int error; - - 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 > 2) - printf("audio_pint: mmapped outp=%p cc=%d inp=%p\n", - cb->outp, cb->blksize, cb->inp); -#endif - (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) - printf("audio_pint: copying in progress\n"); -#endif - } 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); - } - } - -#ifdef AUDIO_DEBUG - if (audiodebug > 3) - printf("audio_pint: outp=%p cc=%d\n", cb->outp, cb->blksize); -#endif - 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 - 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->pause) { - if (cb->used <= cb->usedlow) { - audio_wakeup(&sc->sc_wchan); - selwakeup(&sc->sc_wsel); - 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); - } - } - } - - /* 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_audio) - psignal(sc->sc_async_audio, SIGIO); - } -} - -/* - * Called from HW driver module on completion of dma input. - * Mark it as input in the ring buffer (fiddle pointers). - * Do a wakeup if necessary. - */ -void -audio_rint(v) - void *v; -{ - struct audio_softc *sc = v; - struct audio_hw_if *hw = sc->hw_if; - struct audio_ringbuffer *cb = &sc->sc_rr; - int error; - - 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 > 2) - printf("audio_rint: mmapped inp=%p cc=%d\n", - cb->inp, cb->blksize); -#endif - (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); - } - 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_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 (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 (p->encoding) { - case AUDIO_ENCODING_ULAW: - case AUDIO_ENCODING_ALAW: - case AUDIO_ENCODING_ADPCM: - if (p->precision != 8) - return (EINVAL); - break; - 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; - default: - return (EINVAL); - } - - if (p->channels < 1 || p->channels > 8) /* sanity check # of channels */ - return (EINVAL); - - return (0); -} - -int -audiosetinfo(sc, ai) - struct audio_softc *sc; - struct audio_info *ai; -{ - struct audio_prinfo *r = &ai->record, *p = &ai->play; - int cleared; - int s, setmode; - int error; - struct audio_hw_if *hw = sc->hw_if; - mixer_ctrl_t ct; - struct audio_params pp, rp; - int np, nr; - unsigned int blks; - int oldpblksize, oldrblksize; - int rbus, pbus; - - if (hw == 0) /* HW has not attached */ - return(ENXIO); - - rbus = sc->sc_rbus; - pbus = sc->sc_pbus; - error = 0; - cleared = 0; - - pp = sc->sc_pparams; /* Temporary encoding storage in */ - rp = sc->sc_rparams; /* case setting the modes fails. */ - nr = np = 0; - - if (p->sample_rate != ~0) { - pp.sample_rate = p->sample_rate; - np++; - } - if (r->sample_rate != ~0) { - rp.sample_rate = r->sample_rate; - nr++; - } - if (p->encoding != ~0) { - pp.encoding = p->encoding; - np++; - } - 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; - rp.sw_code = 0; - rp.factor = 1; - setmode |= AUMODE_RECORD; - } - if (np) { - if (!cleared) - audio_clear(sc); - cleared = 1; - pp.sw_code = 0; - pp.factor = 1; - setmode |= AUMODE_PLAY; - } - - 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; - } - - 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); - 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; - } - - 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); - if (error) - return(error); - } - if (r->port != ~0) { - if (!cleared) - audio_clear(sc); - cleared = 1; - - error = hw->set_in_port(sc->hw_hdl, 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); - if (error) - return(error); - } - if (r->gain != ~0) { - ct.dev = hw->get_in_port(sc->hw_hdl); - 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); - if (error) - return(error); - } - - if (p->pause != (u_char)~0) { - sc->sc_pr.pause = p->pause; - if (!p->pause && !sc->sc_pbus) { - s = splaudio(); - error = audiostartp(sc); - splx(s); - if (error) - return error; - } - } - if (r->pause != (u_char)~0) { - sc->sc_rr.pause = r->pause; - if (!r->pause && !sc->sc_rbus) { - s = splaudio(); - error = audiostartr(sc); - splx(s); - if (error) - return error; - } - } - - if (ai->blocksize != ~0) { - /* Block size specified explicitly. */ - if (!cleared) - audio_clear(sc); - cleared = 1; - - 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->mode != ~0) { - if (sc->sc_mode & AUMODE_PLAY) - audio_init_play(sc); - if (sc->sc_mode & AUMODE_RECORD) - audio_init_record(sc); - } - - if (hw->commit_settings) { - error = hw->commit_settings(sc->hw_hdl); - if (error) - return (error); - if (p->gain != ~0 || r->gain != ~0) - mixer_signal(sc); - } - - if (cleared) { - s = splaudio(); - 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 < 1) - blks = 1; - 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; - } - - return (0); -} - -int -audiogetinfo(sc, ai) - struct audio_softc *sc; - struct audio_info *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 = 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 = 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; - - 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->eof = sc->sc_eof; - r->eof = 0; - - p->pause = sc->sc_pr.pause; - r->pause = sc->sc_rr.pause; - - p->error = sc->sc_pr.drops != 0; - r->error = sc->sc_rr.drops != 0; - - p->waiting = r->waiting = 0; /* open never hangs */ - - 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; - - ai->buffersize = sc->sc_pr.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->backlog = 0; /* unused */ - ai->mode = sc->sc_mode; - - return (0); -} - -/* - * Mixer driver - */ -int -mixer_open(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc; - - if (unit >= new_audio_cd.cd_ndevs || - (sc = new_audio_cd.cd_devs[unit]) == NULL) - return ENXIO; - - 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 waitinf 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 */ -int -mixer_close(dev, flags, ifmt, p) - dev_t dev; - int flags, ifmt; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_audio_cd.cd_devs[unit]; - - DPRINTF(("mixer_close: unit %d\n", AUDIOUNIT(dev))); - - mixer_remove(sc, p); - - return (0); -} - -int -mixer_ioctl(dev, cmd, addr, flag, p) - dev_t dev; - int cmd; - caddr_t addr; - int flag; - struct proc *p; -{ - int unit = AUDIOUNIT(dev); - struct audio_softc *sc = new_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)); - - 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; - - case AUDIO_MIXER_DEVINFO: - 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; - - case AUDIO_MIXER_WRITE: - 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; - } - DPRINTF(("mixer_ioctl(%d,'%c',%d) result %d\n", - IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error)); - return (error); -} -#endif diff --git a/sys/arch/amiga/dev/audio_if.h b/sys/arch/amiga/dev/audio_if.h deleted file mode 100644 index 7daecc79b34..00000000000 --- a/sys/arch/amiga/dev/audio_if.h +++ /dev/null @@ -1,172 +0,0 @@ -/* $OpenBSD: audio_if.h,v 1.1 1997/10/07 11:04:59 niklas Exp $ */ -/* $NetBSD: audio_if.h,v 1.21 1997/09/06 01:14:49 augustss Exp $ */ - -/* - * Copyright (c) 1994 Havard Eidnes. - * 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. - * - */ - -/* - * Generic interface to hardware driver. - */ - -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((void *, int)); /* open hardware */ - void (*close)__P((void *)); /* close hardware */ - int (*drain)__P((void *)); /* Optional: drain buffers */ - - /* Encoding. */ - /* XXX should we have separate in/out? */ - int (*query_encoding)__P((void *, struct audio_encoding *)); - - /* 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 - * change several settings in quick succession. To avoid - * having to take the device in/out of "data mode", we provide - * this function which indicates completion of settings - * adjustment. - */ - int (*commit_settings)__P((void *)); - - /* 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 -#define SPKR_OFF 0 - - int (*getdev)__P((void *, struct audio_device *)); - int (*setfd)__P((void *, int)); - - /* Mixer (in/out ports) */ - int (*set_port)__P((void *, mixer_ctrl_t *)); - int (*get_port)__P((void *, mixer_ctrl_t *)); - - int (*query_devinfo)__P((void *, mixer_devinfo_t *)); - - /* 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 */ -}; - -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 { - struct audio_hw_if *ahw; - struct midi_hw_if *mhw; - void *hdl; - char audiodone, mididone; -}; - -/* 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 AUDIOUNIT(x) (minor(x)&0x0f) -#define AUDIODEV(x) (minor(x)&0xf0) - -#define ISDEVSOUND(x) (AUDIODEV(minor(x)) == SOUND_DEVICE) -#define ISDEVAUDIO(x) (AUDIODEV(minor(x)) == AUDIO_DEVICE) -#define ISDEVAUDIOCTL(x) (AUDIODEV(minor(x)) == AUDIOCTL_DEVICE) -#define ISDEVMIXER(x) (AUDIODEV(minor(x)) == MIXER_DEVICE) - -#ifndef __i386__ -#define splaudio splbio /* XXX */ -#define IPL_AUDIO IPL_BIO /* XXX */ -#endif - diff --git a/sys/arch/amiga/dev/audiovar.h b/sys/arch/amiga/dev/audiovar.h deleted file mode 100644 index 6e91e1c3b82..00000000000 --- a/sys/arch/amiga/dev/audiovar.h +++ /dev/null @@ -1,130 +0,0 @@ -/* $OpenBSD: audiovar.h,v 1.1 1997/10/07 11:04:59 niklas Exp $ */ -/* $NetBSD: audiovar.h,v 1.16 1997/08/19 23:49:58 augustss Exp $ */ - -/* - * 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. - * - * From: Header: audiovar.h,v 1.3 93/07/18 14:07:25 mccanne Exp (LBL) - */ - -/* - * Initial/default block duration is both configurable and patchable. - */ -#ifndef AUDIO_BLK_MS -#define AUDIO_BLK_MS 50 /* 50 ms */ -#endif - -#ifndef AU_RING_SIZE -#define AU_RING_SIZE 65536 -#endif - -#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 */ -}; - -/* - * Software state, per audio device. - */ -struct audio_softc { - 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 - u_char sc_mode; /* bitmask for RECORD/PLAY */ - - struct selinfo sc_wsel; /* write selector */ - struct selinfo sc_rsel; /* read selector */ - 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_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 sc_rbus; /* input dma in progress */ - u_char sc_pbus; /* output dma in progress */ - - 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_full_duplex; /* device in full duplex mode */ - -#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 -}; |