summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2015-06-25 06:43:47 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2015-06-25 06:43:47 +0000
commitd3c89d57cc9744309198d69d69ad7451818f4756 (patch)
tree3bc9bda508be4272edac36844e21d1d1118ae356
parent19f7d9bf41229ddef9c786f31c523116638e1475 (diff)
Reimplement the audio driver in a simpler way, removing unused/unusable
functionality. Same API and ABI except for the removed bits and no behaviour change for programs using libsndio. With help from armani@ and mpi@, thanks.
-rw-r--r--sys/arch/luna88k/cbus/nec86hw.c9
-rw-r--r--sys/dev/audio.c4631
-rw-r--r--sys/dev/audio_if.h27
-rw-r--r--sys/dev/isa/ad1848.c9
-rw-r--r--sys/dev/isa/ess.c9
-rw-r--r--sys/dev/isa/sbdsp.c9
-rw-r--r--sys/dev/mulaw.c10
-rw-r--r--sys/dev/mulaw.h12
-rw-r--r--sys/dev/pci/envy.c24
-rw-r--r--sys/sys/audioio.h67
-rw-r--r--sys/sys/conf.h4
11 files changed, 1544 insertions, 3267 deletions
diff --git a/sys/arch/luna88k/cbus/nec86hw.c b/sys/arch/luna88k/cbus/nec86hw.c
index 1e60ab8ff1c..ba6718f2165 100644
--- a/sys/arch/luna88k/cbus/nec86hw.c
+++ b/sys/arch/luna88k/cbus/nec86hw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nec86hw.c,v 1.2 2015/05/11 06:46:21 ratchov Exp $ */
+/* $OpenBSD: nec86hw.c,v 1.3 2015/06/25 06:43:45 ratchov Exp $ */
/* $NecBSD: nec86hw.c,v 1.13 1998/03/14 07:04:54 kmatsuda Exp $ */
/* $NetBSD$ */
@@ -94,6 +94,9 @@ static int nec86hw_rate_table[NEC86HW_NRATE_TYPE][NEC86_NRATE] = {
{ 44100, 33075, 22050, 16000, 11025, 8000, 5513, 4000 },
};
+static struct audio_params nec86hw_audio_default =
+ {44100, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};
+
int nec86hw_set_output_block(struct nec86hw_softc *, int);
int nec86hw_set_input_block(struct nec86hw_softc *, int);
@@ -130,9 +133,9 @@ nec86hw_attach(struct nec86hw_softc *sc)
sc->func_fifo_output = nec86fifo_output_mono_8_direct;
sc->func_fifo_input = nec86fifo_input_mono_8_direct;
(void) nec86hw_set_params(sc, AUMODE_RECORD, 0,
- &audio_default, &audio_default);
+ &nec86hw_audio_default, &nec86hw_audio_default);
(void) nec86hw_set_params(sc, AUMODE_PLAY, 0,
- &audio_default, &audio_default);
+ &nec86hw_audio_default, &nec86hw_audio_default);
/* Set default ports. */
(void) nec86hw_set_in_port(sc, NEC86HW_INPUT_MIXER);
diff --git a/sys/dev/audio.c b/sys/dev/audio.c
index 712c2ed7ff3..427222758c7 100644
--- a/sys/dev/audio.c
+++ b/sys/dev/audio.c
@@ -1,348 +1,137 @@
-/* $OpenBSD: audio.c,v 1.131 2015/05/22 12:46:38 jsg Exp $ */
-/* $NetBSD: audio.c,v 1.119 1999/11/09 16:50:47 augustss Exp $ */
-
+/* $OpenBSD: audio.c,v 1.132 2015/06/25 06:43:45 ratchov Exp $ */
/*
- * Copyright (c) 1991-1993 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the 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.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-
#include <sys/param.h>
-#include <sys/ioctl.h>
#include <sys/fcntl.h>
-#include <sys/vnode.h>
-#include <sys/selinfo.h>
-#include <sys/poll.h>
-#include <sys/malloc.h>
#include <sys/systm.h>
-#include <sys/syslog.h>
-#include <sys/kernel.h>
-#include <sys/signalvar.h>
+#include <sys/ioctl.h>
#include <sys/conf.h>
-#include <sys/audioio.h>
-#include <sys/device.h>
+#include <sys/poll.h>
+#include <sys/kernel.h>
#include <sys/task.h>
-#include <sys/endian.h>
-
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/audioio.h>
#include <dev/audio_if.h>
#include <dev/mulaw.h>
-#include <dev/rndvar.h>
-
-#include "wskbd.h" /* NWSKBD (mixer tuning using keyboard) */
+#include "audio.h"
+#include "wskbd.h"
#ifdef AUDIO_DEBUG
-#define DPRINTF(x) if (audiodebug) printf x
-#define DPRINTFN(n,x) if (audiodebug>(n)) printf x
-int audiodebug = 0;
+#define DPRINTF(...) \
+ do { \
+ if (audio_debug) \
+ printf(__VA_ARGS__); \
+ } while(0)
+#define DPRINTFN(n, ...) \
+ do { \
+ if (audio_debug > (n)) \
+ printf(__VA_ARGS__); \
+ } while(0)
#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
+#define DPRINTF(...) do {} while(0)
+#define DPRINTFN(n, ...) do {} while(0)
#endif
-#define ROUNDSIZE(x) x &= -16 /* round to nice boundary */
+#define DEVNAME(sc) ((sc)->dev.dv_xname)
+#define AUDIO_UNIT(n) (minor(n) & 0x0f)
+#define AUDIO_DEV(n) (minor(n) & 0xf0)
+#define AUDIO_DEV_SOUND 0 /* minor of /dev/sound0 */
+#define AUDIO_DEV_MIXER 0x10 /* minor of /dev/mixer0 */
+#define AUDIO_DEV_AUDIO 0x80 /* minor of /dev/audio0 */
+#define AUDIO_DEV_AUDIOCTL 0xc0 /* minor of /dev/audioctl */
+#define AUDIO_BUFSZ 65536 /* buffer size in bytes */
/*
- * Initial/default block duration is both configurable and patchable.
+ * dma buffer
*/
-#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 2
-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 mmapped; /* device is mmap()-ed */
- u_char blkset; /* blksize has been set, for stickiness */
-};
-
-#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];
+struct audio_buf {
+ unsigned char *data; /* DMA memory block */
+ size_t datalen; /* size of DMA memory block */
+ size_t len; /* size of DMA FIFO */
+ size_t start; /* first byte used in the FIFO */
+ size_t used; /* bytes used in the FIFO */
+ size_t blksz; /* DMA block size */
+ unsigned long pos; /* bytes transferred */
+ unsigned long xrun; /* bytes lost by xruns */
+ struct selinfo sel; /* to record & wakeup poll(2) */
+ int blocking; /* read/write blocking */
};
-struct audio_emu {
- void (*sw_code)(void *, u_char *, int); /* conv routine */
- int encoding; /* emulated encoding */
+#if NWSKBD > 0
+struct wskbd_vol
+{
+ int val; /* index of the value control */
+ int mute; /* index of the mute control */
+ int step; /* increment/decrement step */
+ int nch; /* channels in the value control */
+ int val_pending; /* pending change of val */
+ int mute_pending; /* pending mute toggles */
};
+#endif
/*
- * Software state, per audio device.
+ * device structure
*/
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_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 */
-
- u_char sc_rqui; /* input dma quiesced */
- u_char sc_pqui; /* output dma quiesced */
-
- struct audio_params sc_pparams; /* play encoding parameters */
- struct audio_params sc_rparams; /* record encoding parameters */
-
- struct audio_emu sc_pemu; /* play conversion params */
- struct audio_emu sc_remu; /* record conversion params */
-
- int sc_eof; /* EOF, i.e. zero sized write, counter */
- u_long sc_wstamp;
- u_long sc_playdrop;
-
- int sc_full_duplex; /* device in full duplex mode */
-
- struct au_mixer_ports sc_inports, sc_outports;
- int sc_monitor_port;
-
- int sc_refcnt;
- int sc_dying;
-
- int sc_quiesce;
-#define AUDIO_QUIESCE_START 1
-#define AUDIO_QUIESCE_SILENT 2
- struct task sc_mixer_task;
- u_char sc_mute;
-
-#ifdef AUDIO_INTR_TIME
- u_long sc_pfirstintr; /* first time we saw a play interrupt */
- int sc_pnintr; /* number of interrupts */
- u_long sc_plastintr; /* last time we saw a play 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 rec interrupt */
- long sc_rblktime; /* nominal time between interrupts */
+ struct device dev;
+ struct audio_hw_if *ops; /* driver funcs */
+ void *arg; /* first arg to driver funcs */
+ int mode; /* bitmask of AUMODE_* */
+ int quiesce; /* device suspended */
+ struct audio_buf play, rec;
+ unsigned int sw_enc; /* user exposed AUDIO_ENCODING_* */
+ unsigned int hw_enc; /* harware AUDIO_ENCODING_* */
+ unsigned int bits; /* bits per sample */
+ unsigned int bps; /* bytes-per-sample */
+ unsigned int msb; /* sample are MSB aligned */
+ unsigned int rate; /* rate in Hz */
+ unsigned int round; /* block size in frames */
+ unsigned int nblks; /* number of play blocks */
+ unsigned int pchan, rchan; /* number of channels */
+ unsigned char silence[4]; /* a sample of silence */
+ int pause; /* not trying to start DMA */
+ int active; /* DMA in process */
+ void (*conv_enc)(unsigned char *, int); /* encode to native */
+ void (*conv_dec)(unsigned char *, int); /* decode to user */
+#if NWSKBD > 0
+ struct wskbd_vol spkr, mic;
+ struct task wskbd_task;
+ int wskbd_taskset;
#endif
};
-int audio_blk_ms = AUDIO_BLK_MS;
-
-int audiosetinfo(struct audio_softc *, struct audio_info *);
-int audiogetinfo(struct audio_softc *, struct audio_info *);
-int audiogetbufinfo(struct audio_softc *, struct audio_bufinfo *, int);
-int audio_open(dev_t, struct audio_softc *, int, int, struct proc *);
-int audio_close(dev_t, int, int, struct proc *);
-int audio_read(dev_t, struct uio *, int);
-int audio_write(dev_t, struct uio *, int);
-int audio_ioctl(dev_t, u_long, caddr_t, int, struct proc *);
-int audio_poll(dev_t, int, struct proc *);
-paddr_t audio_mmap(dev_t, off_t, int);
-
-int mixer_open(dev_t, struct audio_softc *, int, int, struct proc *);
-int mixer_close(dev_t, int, int, struct proc *);
-int mixer_ioctl(dev_t, u_long, caddr_t, int, struct proc *);
-static void mixer_remove(struct audio_softc *, struct proc *p);
-static void mixer_signal(struct audio_softc *);
-
-void audio_init_record(struct audio_softc *);
-void audio_init_play(struct audio_softc *);
-int audiostartr(struct audio_softc *);
-int audiostartp(struct audio_softc *);
-void audio_rint(void *);
-void audio_pint(void *);
-int audio_check_params(struct audio_params *);
-void audio_emu_setup(int, struct audio_params *, struct audio_emu *);
-
-void audio_set_blksize(struct audio_softc *, int, int);
-void audio_calc_blksize(struct audio_softc *, int);
-void audio_fill_silence(struct audio_params *, u_char *, u_char *, int);
-int audio_silence_copyout(struct audio_softc *, int, struct uio *);
-
-void audio_init_ringbuffer(struct audio_ringbuffer *);
-int audio_initbufs(struct audio_softc *);
-void audio_calcwater(struct audio_softc *);
-static __inline int audio_sleep_timo(int *, char *, int);
-static __inline int audio_sleep(int *, char *);
-static __inline void audio_wake(int *);
-void audio_selwakeup(struct audio_softc *sc, int play);
-int audio_drain(struct audio_softc *);
-void audio_clear(struct audio_softc *);
-static __inline void audio_pint_silence(struct audio_softc *, struct audio_ringbuffer *, u_char *, int);
-
-int audio_quiesce(struct audio_softc *);
-void audio_wakeup(struct audio_softc *);
-
-int audio_alloc_ring(struct audio_softc *, struct audio_ringbuffer *, int, int);
-void audio_free_ring(struct audio_softc *, struct audio_ringbuffer *);
-
-int audioprint(void *, const char *);
-
-int audioprobe(struct device *, void *, void *);
-void audioattach(struct device *, struct device *, void *);
-int audiodetach(struct device *, int);
-int audioactivate(struct device *, int);
-
-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 }
-};
-struct gainpref {
- char *class, *device;
-};
-static struct gainpref ipreftab[] = {
- { AudioCinputs, AudioNvolume },
- { AudioCinputs, AudioNinput },
- { AudioCinputs, AudioNrecord },
- { AudioCrecord, AudioNvolume },
- { AudioCrecord, AudioNrecord },
- { NULL, NULL}
-};
-static struct gainpref opreftab[] = {
- { AudioCoutputs, AudioNoutput },
- { AudioCoutputs, AudioNdac },
- { AudioCinputs, AudioNdac },
- { AudioCoutputs, AudioNmaster },
- { NULL, NULL}
-};
-static struct gainpref mpreftab[] = {
- { AudioCoutputs, AudioNmonitor },
- { AudioCmonitor, AudioNmonitor },
- { NULL, NULL}
-};
+int audio_match(struct device *, void *, void *);
+void audio_attach(struct device *, struct device *, void *);
+int audio_activate(struct device *, int);
+int audio_detach(struct device *, int);
+#if NWSKBD > 0
+void wskbd_mixer_init(struct audio_softc *);
+#endif
-void au_gain_match(struct audio_softc *, struct gainpref *,
- mixer_devinfo_t *, mixer_devinfo_t *, int *, int *);
-void au_check_ports(struct audio_softc *, struct au_mixer_ports *,
- mixer_devinfo_t *, mixer_devinfo_t *,
- char *, char *, struct portname *);
-int au_set_gain(struct audio_softc *, struct au_mixer_ports *,
- int, int);
-void au_get_gain(struct audio_softc *, struct au_mixer_ports *,
- u_int *, u_char *);
-int au_set_port(struct audio_softc *, struct au_mixer_ports *,
- u_int);
-int au_get_port(struct audio_softc *, struct au_mixer_ports *);
-int au_set_mute(struct audio_softc *, struct au_mixer_ports *, u_char);
-int au_get_mute(struct audio_softc *, struct au_mixer_ports *, u_char *);
-int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *,
- int *, int *r);
-int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *,
- int, int);
-int au_portof(struct audio_softc *, char *);
-
-
-/* The default audio mode: 8 kHz mono ulaw */
-struct audio_params audio_default =
- {8000, AUDIO_ENCODING_ULAW, 8, 1, 1, 1};
-
-struct cfattach audio_ca = {
- sizeof(struct audio_softc), audioprobe, audioattach,
- audiodetach, audioactivate
+const struct cfattach audio_ca = {
+ sizeof(struct audio_softc), audio_match, audio_attach,
+ audio_detach, audio_activate
};
struct cfdriver audio_cd = {
NULL, "audio", DV_DULL
};
-void filt_audiowdetach(struct knote *);
-int filt_audiowrite(struct knote *, long);
-
-struct filterops audiowrite_filtops =
- { 1, NULL, filt_audiowdetach, filt_audiowrite};
-
-void filt_audiordetach(struct knote *);
-int filt_audioread(struct knote *, long);
-
-struct filterops audioread_filtops =
- { 1, NULL, filt_audiordetach, filt_audioread};
-
-#if NWSKBD > 0
-/* Mixer manipulation using keyboard */
-int wskbd_set_mixervolume(long, long);
-void wskbd_set_mixervolume_callback(void *);
-#endif
-
/*
* This mutex protects data structures (including registers on the
* sound-card) that are manipulated by both the interrupt handler and
@@ -359,3212 +148,1788 @@ void wskbd_set_mixervolume_callback(void *);
*/
struct mutex audio_lock = MUTEX_INITIALIZER(IPL_AUDIO);
-int
-audioprobe(struct device *parent, void *match, 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;
-}
-
-void
-audioattach(struct device *parent, struct device *self, void *aux)
-{
- 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, cl;
- int ipref, opref, mpref;
-
- printf("\n");
-
-#ifdef DIAGNOSTIC
- if (hwp == 0 ||
- hwp->open == 0 ||
- hwp->close == 0 ||
- hwp->query_encoding == 0 ||
- hwp->set_params == 0 ||
- (hwp->start_output == 0 && hwp->trigger_output == 0) ||
- (hwp->start_input == 0 && hwp->trigger_input == 0) ||
- hwp->halt_output == 0 ||
- hwp->halt_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;
- }
+#ifdef AUDIO_DEBUG
+/*
+ * 0 - nothing, as if AUDIO_DEBUG isn't defined
+ * 1 - initialisations & setup
+ * 2 - blocks & interrupts
+ */
+int audio_debug = 1;
#endif
- sc->hw_if = hwp;
- sc->hw_hdl = hdlp;
- sc->sc_dev = parent;
- sc->sc_async_mixer = NULL;
-
- error = audio_alloc_ring(sc, &sc->sc_pr, AUMODE_PLAY, AU_RING_SIZE);
- if (error) {
- sc->hw_if = 0;
- printf("audio: could not allocate play buffer\n");
- return;
- }
- error = audio_alloc_ring(sc, &sc->sc_rr, AUMODE_RECORD, AU_RING_SIZE);
- if (error) {
- audio_free_ring(sc, &sc->sc_pr);
- sc->hw_if = 0;
- printf("audio: could not allocate record buffer\n");
- return;
- }
-
- /*
- * Set default softc params
- */
- if (hwp->get_default_params) {
- hwp->get_default_params(hdlp, AUMODE_PLAY, &sc->sc_pparams);
- hwp->get_default_params(hdlp, AUMODE_RECORD, &sc->sc_rparams);
- } else {
- sc->sc_pparams = audio_default;
- sc->sc_rparams = audio_default;
- }
- sc->sc_pemu.encoding = sc->sc_pparams.encoding;
- sc->sc_pemu.sw_code = NULL;
- sc->sc_remu.encoding = sc->sc_rparams.encoding;
- sc->sc_remu.sw_code = NULL;
-
- /* Set up some default values */
- sc->sc_rr.blkset = sc->sc_pr.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);
-
- ipref = opref = mpref = -1;
- sc->sc_inports.index = -1;
- sc->sc_inports.nports = 0;
- sc->sc_inports.isenum = 0;
- sc->sc_inports.allports = 0;
- sc->sc_inports.master = -1;
- sc->sc_outports.index = -1;
- sc->sc_outports.nports = 0;
- sc->sc_outports.isenum = 0;
- sc->sc_outports.allports = 0;
- sc->sc_outports.master = -1;
- 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)
- continue;
- cl.index = mi.mixer_class;
- if (hwp->query_devinfo(hdlp, &cl) != 0)
- continue;
-
- au_gain_match(sc, ipreftab, &cl, &mi, &sc->sc_inports.master, &ipref);
- au_gain_match(sc, opreftab, &cl, &mi, &sc->sc_outports.master, &opref);
- au_gain_match(sc, mpreftab, &cl, &mi, &sc->sc_monitor_port, &mpref);
-
- au_check_ports(sc, &sc->sc_inports, &cl, &mi,
- AudioCrecord, AudioNsource, itable);
- au_check_ports(sc, &sc->sc_outports, &cl, &mi,
- AudioCoutputs, AudioNselect, otable);
- }
- DPRINTF(("audio_attach: inputs ports=0x%x, output ports=0x%x\n",
- sc->sc_inports.allports, sc->sc_outports.allports));
-}
-
-int
-audioactivate(struct device *self, int act)
+unsigned int
+audio_gcd(unsigned int a, unsigned int b)
{
- struct audio_softc *sc = (struct audio_softc *)self;
+ unsigned int r;
- switch (act) {
- case DVACT_DEACTIVATE:
- sc->sc_dying = 1;
- break;
- case DVACT_QUIESCE:
- audio_quiesce(sc);
- break;
- case DVACT_WAKEUP:
- audio_wakeup(sc);
- break;
+ while (b > 0) {
+ r = a % b;
+ a = b;
+ b = r;
}
- return (0);
+ return a;
}
int
-audiodetach(struct device *self, int flags)
+audio_buf_init(struct audio_softc *sc, struct audio_buf *buf, int dir)
{
- struct audio_softc *sc = (struct audio_softc *)self;
- int maj, mn;
-
- DPRINTF(("audio_detach: sc=%p flags=%d\n", sc, flags));
-
- sc->sc_dying = 1;
-
- wakeup(&sc->sc_quiesce);
- wakeup(&sc->sc_wchan);
- wakeup(&sc->sc_rchan);
- mtx_enter(&audio_lock);
- if (--sc->sc_refcnt >= 0) {
- if (msleep(&sc->sc_refcnt, &audio_lock, PZERO, "auddet", hz * 120))
- printf("audiodetach: %s didn't detach\n",
- sc->dev.dv_xname);
- }
- mtx_leave(&audio_lock);
-
- /* free resources */
- audio_free_ring(sc, &sc->sc_pr);
- audio_free_ring(sc, &sc->sc_rr);
-
- /* locate the major number */
- for (maj = 0; maj < nchrdev; maj++)
- if (cdevsw[maj].d_open == audioopen)
- break;
-
- /* Nuke the vnodes for any open instances (calls close). */
- mn = self->dv_unit;
- vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);
- vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR);
-
- return (0);
+ if (sc->ops->round_buffersize) {
+ buf->datalen = sc->ops->round_buffersize(sc->arg,
+ dir, AUDIO_BUFSZ);
+ } else
+ buf->datalen = AUDIO_BUFSZ;
+ if (sc->ops->allocm) {
+ buf->data = sc->ops->allocm(sc->arg, dir, buf->datalen,
+ M_DEVBUF, M_WAITOK);
+ } else
+ buf->data = malloc(buf->datalen, M_DEVBUF, M_WAITOK);
+ if (buf->data == NULL)
+ return ENOMEM;
+ return 0;
}
-int
-au_portof(struct audio_softc *sc, char *name)
+void
+audio_buf_done(struct audio_softc *sc, struct audio_buf *buf)
{
- 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;
+ if (sc->ops->freem)
+ sc->ops->freem(sc->arg, buf->data, M_DEVBUF);
+ else
+ free(buf->data, M_DEVBUF, buf->datalen);
}
-void
-au_check_ports(struct audio_softc *sc, struct au_mixer_ports *ports,
- mixer_devinfo_t *cl, mixer_devinfo_t *mi, char *cname, char *mname,
- struct portname *tbl)
+/*
+ * return the reader pointer and the number of bytes available
+ */
+unsigned char *
+audio_buf_rgetblk(struct audio_buf *buf, size_t *rsize)
{
- int i, j;
+ size_t count;
- if (strcmp(cl->label.name, cname) != 0 ||
- strcmp(mi->label.name, mname) != 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;
- }
- }
- }
- }
+ count = buf->len - buf->start;
+ if (count > buf->used)
+ count = buf->used;
+ *rsize = count;
+ return buf->data + buf->start;
}
/*
- * check if the given (class, device) is better
- * than the current setting (*index), if so, set the
- * current setting.
+ * discard "count" bytes at the start postion.
*/
void
-au_gain_match(struct audio_softc *sc, struct gainpref *tbl,
- mixer_devinfo_t *cls, mixer_devinfo_t *dev, int *index, int *pref)
+audio_buf_rdiscard(struct audio_buf *buf, size_t count)
{
- int i;
-
- for (i = *pref + 1; tbl[i].class != NULL; i++) {
- if (strcmp(tbl[i].class, cls->label.name) == 0 &&
- strcmp(tbl[i].device, dev->label.name) == 0) {
- if (*pref < i) {
- DPRINTF(("au_gain_match: found %s.%s\n",
- cls->label.name, dev->label.name));
- *index = dev->index;
- *pref = i;
- }
- break;
- }
+#ifdef AUDIO_DEBUG
+ if (count > buf->used) {
+ panic("audio_buf_rdiscard: bad count = %zu\n", count);
}
+#endif
+ buf->used -= count;
+ buf->start += count;
+ if (buf->start >= buf->len)
+ buf->start -= buf->len;
}
/*
- * Called from hardware driver. This is where the MI audio driver gets
- * probed/attached to the hardware driver.
+ * advance the writer pointer by "count" bytes
*/
-struct device *
-audio_attach_mi(struct audio_hw_if *ahwp, void *hdlp, struct device *dev)
+void
+audio_buf_wcommit(struct audio_buf *buf, size_t count)
{
- struct audio_attach_args arg;
-
-#ifdef DIAGNOSTIC
- if (ahwp == NULL) {
- printf ("audio_attach_mi: NULL\n");
- return 0;
+#ifdef AUDIO_DEBUG
+ if (count > (buf->len - buf->used)) {
+ panic("audio_buf_wcommit: bad count = %zu\n", count);
}
#endif
-
- arg.type = AUDIODEV_TYPE_AUDIO;
- arg.hwif = ahwp;
- arg.hdl = hdlp;
- return config_found(dev, &arg, audioprint);
+ buf->used += count;
}
-int
-audioprint(void *aux, const char *pnp)
+/*
+ * get writer pointer and the number of bytes writable
+ */
+unsigned char *
+audio_buf_wgetblk(struct audio_buf *buf, size_t *rsize)
{
- struct audio_attach_args *arg = aux;
- const char *type;
+ size_t end, avail, count;
- if (pnp != NULL) {
- switch (arg->type) {
- case AUDIODEV_TYPE_AUDIO:
- type = "audio";
- break;
- case AUDIODEV_TYPE_OPL:
- type = "opl";
- break;
- case AUDIODEV_TYPE_MPU:
- type = "mpu";
- break;
- default:
- panic("audioprint: unknown type %d", arg->type);
- }
- printf("%s at %s", type, pnp);
- }
- return (UNCONF);
+ end = buf->start + buf->used;
+ if (end >= buf->len)
+ end -= buf->len;
+ avail = buf->len - buf->used;
+ count = buf->len - end;
+ if (count > avail)
+ count = avail;
+ *rsize = count;
+ return buf->data + end;
}
-#ifdef AUDIO_DEBUG
-void audio_printsc(struct audio_softc *);
-void audio_print_params(char *, struct audio_params *);
-
void
-audio_printsc(struct audio_softc *sc)
+audio_calc_sil(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("pblksz %d, rblksz %d", sc->sc_pr.blksize, sc->sc_rr.blksize);
- printf("hiwat %d lowat %d\n", sc->sc_pr.usedhigh, sc->sc_pr.usedlow);
+ unsigned char *q;
+ unsigned int s, i;
+ int d, e;
+
+ e = sc->sw_enc;
+#ifdef AUDIO_DEBUG
+ switch (e) {
+ case AUDIO_ENCODING_SLINEAR_LE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_BE:
+ break;
+ default:
+ printf("%s: unhandled play encoding %d\n", DEVNAME(sc), e);
+ memset(sc->silence, 0, sc->bps);
+ return;
+ }
+#endif
+ if (e == AUDIO_ENCODING_SLINEAR_BE || e == AUDIO_ENCODING_ULINEAR_BE) {
+ d = -1;
+ q = sc->silence + sc->bps - 1;
+ } else {
+ d = 1;
+ q = sc->silence;
+ }
+ if (e == AUDIO_ENCODING_SLINEAR_LE || e == AUDIO_ENCODING_SLINEAR_BE) {
+ s = 0;
+ } else {
+ s = 0x80000000;
+ if (sc->msb)
+ s >>= 32 - 8 * sc->bps;
+ else
+ s >>= 32 - sc->bits;
+ }
+ for (i = 0; i < sc->bps; i++) {
+ *q = s;
+ q += d;
+ s >>= 8;
+ }
+ if (sc->conv_enc)
+ sc->conv_enc(sc->silence, sc->bps);
}
void
-audio_print_params(char *s, struct audio_params *p)
+audio_fill_sil(struct audio_softc *sc, unsigned char *ptr, size_t count)
{
- printf("audio: %s sr=%ld, enc=%d, chan=%d, prec=%d bps=%d\n", s,
- p->sample_rate, p->encoding, p->channels, p->precision, p->bps);
-}
-#endif
+ unsigned char *q, *p;
+ size_t i, j;
-int
-audio_alloc_ring(struct audio_softc *sc, struct audio_ringbuffer *r,
- int direction, int bufsize)
-{
- struct audio_hw_if *hw = sc->hw_if;
- void *hdl = sc->hw_hdl;
- /*
- * Alloc DMA play and record buffers
- */
- if (bufsize < AUMINBUF)
- bufsize = AUMINBUF;
- ROUNDSIZE(bufsize);
- if (hw->round_buffersize)
- bufsize = hw->round_buffersize(hdl, direction, bufsize);
- r->bufsize = bufsize;
- if (hw->allocm)
- r->start = hw->allocm(hdl, direction, r->bufsize, M_DEVBUF,
- M_WAITOK);
- else
- r->start = malloc(bufsize, M_DEVBUF, M_WAITOK);
- if (r->start == 0)
- return ENOMEM;
- return 0;
+ q = ptr;
+ for (j = count / sc->bps; j > 0; j--) {
+ p = sc->silence;
+ for (i = sc->bps; i > 0; i--)
+ *q++ = *p++;
+ }
}
void
-audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r)
+audio_clear(struct audio_softc *sc)
{
- if (sc->hw_if->freem) {
- sc->hw_if->freem(sc->hw_hdl, r->start, M_DEVBUF);
- } else {
- free(r->start, M_DEVBUF, 0);
+ if (sc->mode & AUMODE_PLAY) {
+ sc->play.used = sc->play.start = 0;
+ sc->play.pos = sc->play.xrun = 0;
+ audio_fill_sil(sc, sc->play.data, sc->play.len);
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ sc->rec.used = sc->rec.start = 0;
+ sc->rec.pos = sc->rec.xrun = 0;
+ audio_fill_sil(sc, sc->rec.data, sc->rec.len);
}
}
-int
-audioopen(dev_t dev, int flags, int ifmt, struct proc *p)
+/*
+ * called whenever a block is consumed by the driver
+ */
+void
+audio_pintr(void *addr)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
+ struct audio_softc *sc = addr;
+ unsigned char *ptr;
+ size_t count;
int error;
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return ENXIO;
-
- if (sc->sc_dying)
- return (EIO);
-
- if (!sc->hw_if)
- return (ENXIO);
-
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- case AUDIOCTL_DEVICE:
- error = audio_open(dev, sc, flags, ifmt, p);
- break;
- case MIXER_DEVICE:
- error = mixer_open(dev, sc, flags, ifmt, p);
- break;
- default:
- error = ENXIO;
- break;
+ MUTEX_ASSERT_LOCKED(&audio_lock);
+ if (!(sc->mode & AUMODE_PLAY) || !sc->active) {
+ printf("%s: play interrupt but not playing\n", DEVNAME(sc));
+ return;
+ }
+ if (sc->quiesce) {
+ DPRINTF("%s: quesced, skipping play intr\n", DEVNAME(sc));
+ return;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ sc->play.pos += sc->play.blksz;
+ audio_fill_sil(sc, sc->play.data + sc->play.start, sc->play.blksz);
+ audio_buf_rdiscard(&sc->play, sc->play.blksz);
+ if (sc->play.used < sc->play.blksz) {
+ DPRINTFN(1, "%s: play underrun\n", DEVNAME(sc));
+ sc->play.xrun += sc->play.blksz;
+ audio_buf_wcommit(&sc->play, sc->play.blksz);
+ }
- return (error);
-}
+ DPRINTFN(1, "%s: play intr, used -> %zu, start -> %zu\n",
+ DEVNAME(sc), sc->play.used, sc->play.start);
-int
-audioclose(dev_t dev, int flags, int ifmt, struct proc *p)
-{
+ if (!sc->ops->trigger_output) {
+ ptr = audio_buf_rgetblk(&sc->play, &count);
+ error = sc->ops->start_output(sc->arg,
+ ptr, sc->play.blksz, audio_pintr, (void *)sc);
+ if (error) {
+ printf("%s: play restart failed: %d\n",
+ DEVNAME(sc), error);
+ }
+ }
- 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);
+ if (sc->play.used < sc->play.len) {
+ DPRINTFN(1, "%s: play wakeup, chan = %d\n",
+ DEVNAME(sc), sc->play.blocking);
+ if (sc->play.blocking) {
+ wakeup(&sc->play.blocking);
+ sc->play.blocking = 0;
+ }
+ selwakeup(&sc->play.sel);
}
}
-int
-audioread(dev_t dev, struct uio *uio, int ioflag)
+/*
+ * called whenever a block is produced by the driver
+ */
+void
+audio_rintr(void *addr)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
+ struct audio_softc *sc = addr;
+ unsigned char *ptr;
+ size_t count;
int error;
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return ENXIO;
+ MUTEX_ASSERT_LOCKED(&audio_lock);
+ if (!(sc->mode & AUMODE_RECORD) || !sc->active) {
+ printf("%s: rec interrupt but not recording\n", DEVNAME(sc));
+ return;
+ }
+ if (sc->quiesce) {
+ DPRINTF("%s: quesced, skipping rec intr\n", DEVNAME(sc));
+ return;
+ }
- if (sc->sc_dying)
- return (EIO);
+ sc->rec.pos += sc->rec.blksz;
+ audio_buf_wcommit(&sc->rec, sc->rec.blksz);
+ if (sc->rec.used == sc->rec.len) {
+ DPRINTFN(1, "%s: rec overrun\n", DEVNAME(sc));
+ sc->rec.xrun += sc->rec.blksz;
+ audio_buf_rdiscard(&sc->rec, sc->rec.blksz);
+ }
+ DPRINTFN(1, "%s: rec intr, used -> %zu\n", DEVNAME(sc), sc->rec.used);
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- error = audio_read(dev, uio, ioflag);
- break;
- case AUDIOCTL_DEVICE:
- case MIXER_DEVICE:
- error = ENODEV;
- break;
- default:
- error = ENXIO;
- break;
+ if (!sc->ops->trigger_input) {
+ ptr = audio_buf_wgetblk(&sc->rec, &count);
+ error = sc->ops->start_input(sc->arg,
+ ptr, sc->rec.blksz, audio_rintr, (void *)sc);
+ if (error) {
+ printf("%s: rec restart failed: %d\n",
+ DEVNAME(sc), error);
+ }
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
- return (error);
+ if (sc->rec.used > 0) {
+ DPRINTFN(1, "%s: rec wakeup, chan = %d\n",
+ DEVNAME(sc), sc->rec.blocking);
+ if (sc->rec.blocking) {
+ wakeup(&sc->rec.blocking);
+ sc->rec.blocking = 0;
+ }
+ selwakeup(&sc->rec.sel);
+ }
}
int
-audiowrite(dev_t dev, struct uio *uio, int ioflag)
+audio_start_do(struct audio_softc *sc)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
int error;
+ struct audio_params p;
+ unsigned char *ptr;
+ size_t count;
+
+ DPRINTFN(1, "%s: start play: "
+ "start = %zu, used = %zu, "
+ "len = %zu, blksz = %zu\n",
+ DEVNAME(sc), sc->play.start, sc->play.used,
+ sc->play.len, sc->play.blksz);
+ DPRINTFN(1, "%s: start rec: "
+ "start = %zu, used = %zu, "
+ "len = %zu, blksz = %zu\n",
+ DEVNAME(sc), sc->rec.start, sc->rec.used,
+ sc->rec.len, sc->rec.blksz);
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return ENXIO;
-
- if (sc->sc_dying)
- return (EIO);
-
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- error = audio_write(dev, uio, ioflag);
- break;
- case AUDIOCTL_DEVICE:
- case MIXER_DEVICE:
- error = ENODEV;
- break;
- default:
- error = ENXIO;
- break;
+ error = 0;
+ if (sc->mode & AUMODE_PLAY) {
+ if (sc->ops->trigger_output) {
+ p.encoding = sc->hw_enc;
+ p.precision = sc->bits;
+ p.bps = sc->bps;
+ p.msb = sc->msb;
+ p.sample_rate = sc->rate;
+ p.channels = sc->pchan;
+ error = sc->ops->trigger_output(sc->arg,
+ sc->play.data,
+ sc->play.data + sc->play.len,
+ sc->play.blksz,
+ audio_pintr, (void *)sc, &p);
+ } else {
+ mtx_enter(&audio_lock);
+ ptr = audio_buf_rgetblk(&sc->play, &count);
+ error = sc->ops->start_output(sc->arg,
+ ptr, sc->play.blksz, audio_pintr, (void *)sc);
+ mtx_leave(&audio_lock);
+ }
+ if (error)
+ printf("%s: failed to start playback\n", DEVNAME(sc));
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ if (sc->ops->trigger_input) {
+ p.encoding = sc->hw_enc;
+ p.precision = sc->bits;
+ p.bps = sc->bps;
+ p.msb = sc->msb;
+ p.sample_rate = sc->rate;
+ p.channels = sc->rchan;
+ error = sc->ops->trigger_input(sc->arg,
+ sc->rec.data,
+ sc->rec.data + sc->rec.len,
+ sc->rec.blksz,
+ audio_rintr, (void *)sc, &p);
+ } else {
+ mtx_enter(&audio_lock);
+ ptr = audio_buf_wgetblk(&sc->rec, &count);
+ error = sc->ops->start_input(sc->arg,
+ ptr, sc->rec.blksz, audio_rintr, (void *)sc);
+ mtx_leave(&audio_lock);
+ }
+ if (error)
+ printf("%s: failed to start recording\n", DEVNAME(sc));
}
-
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
- return (error);
+ return error;
}
int
-audioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+audio_stop_do(struct audio_softc *sc)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
- int error;
-
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return ENXIO;
-
- if (sc->sc_dying)
- return (EIO);
-
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- case AUDIOCTL_DEVICE:
- error = audio_ioctl(dev, cmd, addr, flag, p);
- break;
- case MIXER_DEVICE:
- error = mixer_ioctl(dev, cmd, addr, flag, p);
- break;
- default:
- error = ENXIO;
- break;
- }
+ if (sc->mode & AUMODE_PLAY)
+ sc->ops->halt_output(sc->arg);
+ if (sc->mode & AUMODE_RECORD)
+ sc->ops->halt_input(sc->arg);
+ return 0;
+}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
- return (error);
+int
+audio_start(struct audio_softc *sc)
+{
+ sc->active = 1;
+ sc->play.xrun = sc->play.pos = sc->rec.xrun = sc->rec.pos = 0;
+ return audio_start_do(sc);
}
int
-audiopoll(dev_t dev, int events, struct proc *p)
+audio_stop(struct audio_softc *sc)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
int error;
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return POLLERR;
-
- if (sc->sc_dying)
- return POLLERR;
-
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- error = audio_poll(dev, events, p);
- break;
- case AUDIOCTL_DEVICE:
- case MIXER_DEVICE:
- error = 0;
- break;
- default:
- error = 0;
- break;
- }
-
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
- return (error);
+ error = audio_stop_do(sc);
+ if (error)
+ return error;
+ audio_clear(sc);
+ sc->active = 0;
+ return 0;
}
-paddr_t
-audiommap(dev_t dev, off_t off, int prot)
+int
+audio_setpar(struct audio_softc *sc)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc;
- int ret;
+ struct audio_params p, r;
+ unsigned int nr, np, max, min, mult;
+ int error;
- if (unit >= audio_cd.cd_ndevs ||
- (sc = audio_cd.cd_devs[unit]) == NULL)
- return (-1);
+ DPRINTF("%s: setpar: req enc=%d bits=%d, bps=%d, msb=%d "
+ "rate=%d, pchan=%d, rchan=%d, round=%u, nblks=%d\n",
+ DEVNAME(sc), sc->sw_enc, sc->bits, sc->bps, sc->msb,
+ sc->rate, sc->pchan, sc->rchan, sc->round, sc->nblks);
- if (sc->sc_dying)
- return (-1);
+ /*
+ * AUDIO_ENCODING_SLINEAR and AUDIO_ENCODING_ULINEAR are not
+ * used anymore, promote them to the _LE and _BE equivalents
+ */
+ if (sc->sw_enc == AUDIO_ENCODING_SLINEAR) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
+#else
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR_BE;
+#endif
+ }
+ if (sc->sw_enc == AUDIO_ENCODING_ULINEAR) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ sc->sw_enc = AUDIO_ENCODING_ULINEAR_LE;
+#else
+ sc->sw_enc = AUDIO_ENCODING_ULINEAR_BE;
+#endif
+ }
- sc->sc_refcnt ++;
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- ret = audio_mmap(dev, off, prot);
- break;
- case AUDIOCTL_DEVICE:
- case MIXER_DEVICE:
- ret = -1;
+ /*
+ * check if requested parameters are in the allowed ranges
+ */
+ if (sc->mode & AUMODE_PLAY) {
+ if (sc->pchan < 1)
+ sc->pchan = 1;
+ if (sc->pchan > 64)
+ sc->pchan = 64;
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ if (sc->rchan < 1)
+ sc->rchan = 1;
+ if (sc->rchan > 64)
+ sc->rchan = 64;
+ }
+ switch (sc->sw_enc) {
+ case AUDIO_ENCODING_ULAW:
+ case AUDIO_ENCODING_ALAW:
+ case AUDIO_ENCODING_SLINEAR_LE:
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ case AUDIO_ENCODING_ULINEAR_BE:
break;
default:
- ret = -1;
- break;
- }
-
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
- return (ret);
-}
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
+ }
+ if (sc->bits < 8)
+ sc->bits = 8;
+ if (sc->bits > 32)
+ sc->bits = 32;
+ if (sc->bps < 1)
+ sc->bps = 1;
+ if (sc->bps > 4)
+ sc->bps = 4;
+ if (sc->rate < 4000)
+ sc->rate = 4000;
+ if (sc->rate > 192000)
+ sc->rate = 192000;
-/*
- * Audio driver
- */
-void
-audio_init_ringbuffer(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->stamp_last = 0;
- rp->drops = 0;
- rp->pdrops = 0;
- rp->mmapped = 0;
-}
-
-int
-audio_initbufs(struct audio_softc *sc)
-{
- struct audio_hw_if *hw = sc->hw_if;
- int error;
+ /*
+ * copy into struct audio_params, required by drivers
+ */
+ p.encoding = r.encoding = sc->sw_enc;
+ p.precision = r.precision = sc->bits;
+ p.bps = r.bps = sc->bps;
+ p.msb = r.msb = sc->msb;
+ p.sample_rate = r.sample_rate = sc->rate;
+ p.channels = sc->pchan;
+ r.channels = sc->rchan;
- 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;
+ /*
+ * set parameters
+ */
+ error = sc->ops->set_params(sc->arg, sc->mode, sc->mode, &p, &r);
+ if (error)
+ return error;
+ if (sc->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
+ if (p.encoding != r.encoding ||
+ p.precision != r.precision ||
+ p.bps != r.bps ||
+ p.msb != r.msb ||
+ p.sample_rate != r.sample_rate) {
+ printf("%s: different play and record parameters"
+ "returned by hardware\n", DEVNAME(sc));
+ return ENODEV;
+ }
}
-
- 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 (sc->mode & AUMODE_PLAY) {
+ sc->hw_enc = p.encoding;
+ sc->bits = p.precision;
+ sc->bps = p.bps;
+ sc->msb = p.msb;
+ sc->rate = p.sample_rate;
+ sc->pchan = p.channels;
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ sc->hw_enc = r.encoding;
+ sc->bits = r.precision;
+ sc->bps = r.bps;
+ sc->msb = r.msb;
+ sc->rate = r.sample_rate;
+ sc->rchan = r.channels;
+ }
+ if (sc->rate == 0 || sc->bps == 0 || sc->bits == 0) {
+ printf("%s: invalid parameters returned by hardware\n",
+ DEVNAME(sc));
+ return ENODEV;
+ }
+ if (sc->ops->commit_settings) {
+ error = sc->ops->commit_settings(sc->arg);
if (error)
return error;
}
-#ifdef AUDIO_INTR_TIME
- sc->sc_pnintr = 0;
- sc->sc_pblktime = (u_long)(
- (u_long)sc->sc_pr.blksize * 100000 /
- (u_long)(sc->sc_pparams.bps *
- sc->sc_pparams.channels *
- sc->sc_pparams.sample_rate)) * 10;
- DPRINTF(("audio: play blktime = %lu for %d\n",
- sc->sc_pblktime, sc->sc_pr.blksize));
- sc->sc_rnintr = 0;
- sc->sc_rblktime = (u_long)(
- (u_long)sc->sc_rr.blksize * 100000 /
- (u_long)(sc->sc_rparams.bps *
- sc->sc_rparams.channels *
- sc->sc_rparams.sample_rate)) * 10;
- DPRINTF(("audio: record blktime = %lu for %d\n",
- sc->sc_rblktime, sc->sc_rr.blksize));
+ /*
+ * conversion from/to exotic/dead encoding, for drivers not supporting
+ * linear
+ */
+ switch (sc->hw_enc) {
+ case AUDIO_ENCODING_SLINEAR_LE:
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ case AUDIO_ENCODING_ULINEAR_BE:
+ sc->sw_enc = sc->hw_enc;
+ sc->conv_dec = sc->conv_enc = NULL;
+ break;
+ case AUDIO_ENCODING_ULAW:
+#if BYTE_ORDER == LITTLE_ENDIAN
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
+#else
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR_BE;
#endif
+ if (sc->bits == 8) {
+ sc->conv_enc = slinear8_to_mulaw;
+ sc->conv_dec = mulaw_to_slinear8;
+ break;
+ } else if (sc->bits == 24) {
+ sc->conv_enc = slinear24_to_mulaw24;
+ sc->conv_dec = mulaw24_to_slinear24;
+ break;
+ }
+ sc->sw_enc = sc->hw_enc;
+ sc->conv_dec = sc->conv_enc = NULL;
+ break;
+ default:
+ printf("%s: setpar: enc = %d, bits = %d: emulation skipped\n",
+ DEVNAME(sc), sc->hw_enc, sc->bits);
+ sc->sw_enc = sc->hw_enc;
+ sc->conv_dec = sc->conv_enc = NULL;
+ }
+ audio_calc_sil(sc);
- return 0;
-}
-
-void
-audio_calcwater(struct audio_softc *sc)
-{
- int hiwat, lowat;
-
- hiwat = (sc->sc_pr.end - sc->sc_pr.start) / sc->sc_pr.blksize;
- lowat = hiwat * 3 / 4;
- if (lowat == hiwat)
- lowat = hiwat - 1;
- sc->sc_pr.usedhigh = hiwat * sc->sc_pr.blksize;
- sc->sc_pr.usedlow = lowat * sc->sc_pr.blksize;
- sc->sc_rr.usedhigh = sc->sc_rr.end - sc->sc_rr.start;
- sc->sc_rr.usedlow = 0;
-}
-
-static __inline int
-audio_sleep_timo(int *chan, char *label, int timo)
-{
- int st;
-
- if (!label)
- label = "audio";
+ /*
+ * get least multiplier of the number of frames per block
+ */
+ if (sc->ops->round_blocksize) {
+ mult = sc->ops->round_blocksize(sc->arg, 1);
+ if (mult == 0) {
+ printf("%s: 0x%x: bad block size multiplier\n",
+ DEVNAME(sc), mult);
+ return ENODEV;
+ }
+ } else
+ mult = 1;
+ DPRINTF("%s: hw block size multiplier: %u\n", DEVNAME(sc), mult);
+ if (sc->mode & AUMODE_PLAY) {
+ np = mult / audio_gcd(sc->pchan * sc->bps, mult);
+ if (!(sc->mode & AUMODE_RECORD))
+ nr = np;
+ DPRINTF("%s: play number of frames multiplier: %u\n",
+ DEVNAME(sc), np);
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ nr = mult / audio_gcd(sc->rchan * sc->bps, mult);
+ if (!(sc->mode & AUMODE_PLAY))
+ np = nr;
+ DPRINTF("%s: record number of frames multiplier: %u\n",
+ DEVNAME(sc), nr);
+ }
+ mult = nr * np / audio_gcd(nr, np);
+ DPRINTF("%s: least common number of frames multiplier: %u\n",
+ DEVNAME(sc), mult);
- DPRINTFN(3, ("audio_sleep_timo: chan=%p, label=%s, timo=%d\n",
- chan, label, timo));
- *chan = 1;
- st = msleep(chan, &audio_lock, PWAIT | PCATCH, label, timo);
- *chan = 0;
-#ifdef AUDIO_DEBUG
- if (st != 0)
- printf("audio_sleep: woke up st=%d\n", st);
-#endif
- return (st);
-}
+ /*
+ * get minumum and maximum frames per block
+ */
+ if (sc->mode & AUMODE_PLAY) {
+ np = sc->play.datalen / (sc->pchan * sc->bps * 2);
+ if (!(sc->mode & AUMODE_RECORD))
+ nr = np;
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ nr = sc->rec.datalen / (sc->rchan * sc->bps * 2);
+ if (!(sc->mode & AUMODE_PLAY))
+ np = nr;
+ }
+ max = np < nr ? np : nr;
+ max -= max % mult;
+ min = sc->rate / 1000 + mult - 1;
+ min -= min % mult;
+ DPRINTF("%s: frame number range: %u..%u\n", DEVNAME(sc), min, max);
+ if (max < min) {
+ printf("%s: %u: bad max frame number\n", DEVNAME(sc), max);
+ return EIO;
+ }
-static __inline int
-audio_sleep(int *chan, char *label)
-{
- return audio_sleep_timo(chan, label, 0);
-}
+ /*
+ * adjust the frame per block to match our constraints
+ */
+ sc->round += mult / 2;
+ sc->round -= sc->round % mult;
+ if (sc->round > max)
+ sc->round = max;
+ if (sc->round < min)
+ sc->round = min;
+ sc->round = sc->round;
-/* call with audio_lock */
-static __inline void
-audio_wake(int *chan)
-{
- DPRINTFN(3, ("audio_wakeup: chan=%p, *chan=%d\n", chan, *chan));
- if (*chan) {
- wakeup(chan);
- *chan = 0;
+ /*
+ * set buffer size (number of blocks)
+ */
+ if (sc->mode & AUMODE_PLAY) {
+ sc->play.blksz = sc->round * sc->pchan * sc->bps;
+ max = sc->play.datalen / sc->play.blksz;
+ if (sc->nblks > max)
+ sc->nblks = max;
+ if (sc->nblks < 2)
+ sc->nblks = 2;
+ sc->play.len = sc->nblks * sc->play.blksz;
+ sc->nblks = sc->nblks;
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ /*
+ * for recording, buffer size is not the latency (it's
+ * exactly one block), so let's get the maximum buffer
+ * size of maximum reliability during xruns
+ */
+ sc->rec.blksz = sc->round * sc->rchan * sc->bps;
+ sc->rec.len = sc->rec.datalen;
+ sc->rec.len -= sc->rec.datalen % sc->rec.blksz;
}
+
+ DPRINTF("%s: setpar: new enc=%d bits=%d, bps=%d, msb=%d "
+ "rate=%d, pchan=%d, rchan=%d, round=%u, nblks=%d\n",
+ DEVNAME(sc), sc->sw_enc, sc->bits, sc->bps, sc->msb,
+ sc->rate, sc->pchan, sc->rchan, sc->round, sc->nblks);
+ return 0;
}
int
-audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
- struct proc *p)
+audio_setinfo(struct audio_softc *sc, struct audio_info *ai)
{
+ struct audio_prinfo *r = &ai->record, *p = &ai->play;
int error;
- int mode;
- struct audio_info ai;
-
- 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 = sc->hw_if->open(sc->hw_hdl, flags);
- if (error)
- return (error);
-
- sc->sc_async_audio = 0;
- sc->sc_rchan = 0;
- sc->sc_wchan = 0;
- 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) &&
- (sc->hw_if->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;
- }
+ int set;
/*
- * Multiplex device: /dev/audio (default) and /dev/sound (last)
- * The /dev/audio is always (re)set to the default parameters.
- * For the other devices, you get what they were last set to.
+ * stop the device if requested to stop
*/
- if (ISDEVAUDIO(dev)) {
- /* /dev/audio */
- if (sc->hw_if->get_default_params) {
- sc->hw_if->get_default_params(sc->hw_hdl, AUMODE_PLAY,
- &sc->sc_pparams);
- sc->hw_if->get_default_params(sc->hw_hdl, AUMODE_RECORD,
- &sc->sc_rparams);
- } else {
- sc->sc_rparams = audio_default;
- sc->sc_pparams = audio_default;
+ if (sc->mode != 0) {
+ if (sc->mode & AUMODE_PLAY) {
+ if (p->pause != (unsigned char)~0)
+ sc->pause = p->pause;
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ if (r->pause != (unsigned char)~0)
+ sc->pause = r->pause;
+ }
+ if (sc->pause) {
+ if (sc->active)
+ audio_stop(sc);
}
}
-#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.
+ * copy parameters into the softc structure
*/
- if (sc->sc_rparams.precision == 0 || sc->sc_pparams.precision == 0) {
- printf("audio_open: 0 precision\n");
- error = EINVAL;
- goto bad;
+ set = 0;
+ if (ai->play.encoding != ~0) {
+ sc->sw_enc = ai->play.encoding;
+ set = 1;
+ }
+ if (ai->play.precision != ~0) {
+ sc->bits = ai->play.precision;
+ set = 1;
+ }
+ if (ai->play.bps != ~0) {
+ sc->bps = ai->play.bps;
+ set = 1;
+ }
+ if (ai->play.msb != ~0) {
+ sc->msb = ai->play.msb;
+ set = 1;
+ }
+ if (ai->play.sample_rate != ~0) {
+ sc->rate = ai->play.sample_rate;
+ set = 1;
+ }
+ if (ai->play.channels != ~0) {
+ sc->pchan = ai->play.channels;
+ set = 1;
+ }
+ if (ai->play.block_size != ~0) {
+ sc->round = ai->play.block_size /
+ (sc->bps * sc->pchan);
+ set = 1;
+ }
+ if (ai->hiwat != ~0) {
+ sc->nblks = ai->hiwat;
+ set = 1;
+ }
+ if (ai->record.encoding != ~0) {
+ sc->sw_enc = ai->record.encoding;
+ set = 1;
+ }
+ if (ai->record.precision != ~0) {
+ sc->bits = ai->record.precision;
+ set = 1;
+ }
+ if (ai->record.bps != ~0) {
+ sc->bps = ai->record.bps;
+ set = 1;
+ }
+ if (ai->record.msb != ~0) {
+ sc->msb = ai->record.msb;
+ set = 1;
+ }
+ if (ai->record.sample_rate != ~0) {
+ sc->rate = ai->record.sample_rate;
+ set = 1;
+ }
+ if (ai->record.channels != ~0) {
+ sc->rchan = ai->record.channels;
+ set = 1;
+ }
+ if (ai->record.block_size != ~0) {
+ sc->round = ai->record.block_size /
+ (sc->bps * sc->rchan);
+ set = 1;
}
-#endif
- AUDIO_INITINFO(&ai);
- ai.record.sample_rate = sc->sc_rparams.sample_rate;
- ai.record.encoding = sc->sc_remu.encoding;
- ai.record.channels = sc->sc_rparams.channels;
- ai.record.precision = sc->sc_rparams.precision;
- ai.record.bps = sc->sc_rparams.bps;
- ai.record.msb = sc->sc_rparams.msb;
- ai.record.pause = 0;
- ai.play.sample_rate = sc->sc_pparams.sample_rate;
- ai.play.encoding = sc->sc_pemu.encoding;
- ai.play.channels = sc->sc_pparams.channels;
- ai.play.precision = sc->sc_pparams.precision;
- ai.play.bps = sc->sc_pparams.bps;
- ai.play.msb = sc->sc_pparams.msb;
- ai.play.pause = 0;
- ai.mode = mode;
- sc->sc_rr.blkset = sc->sc_pr.blkset = 0; /* Block sizes not set yet */
- 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:
- sc->hw_if->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(struct audio_softc *sc)
-{
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- 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);
-}
-
-/*
- * Must be called from task context.
- */
-void
-audio_init_play(struct audio_softc *sc)
-{
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- sc->sc_wstamp = sc->sc_pr.stamp;
- if (sc->hw_if->speaker_ctl)
- sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON);
-}
-int
-audio_drain(struct audio_softc *sc)
-{
- int error, drops;
- struct audio_ringbuffer *cb = &sc->sc_pr;
+ DPRINTF("%s: setinfo: set = %d, mode = %d, pause = %d\n",
+ DEVNAME(sc), set, sc->mode, sc->pause);
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- DPRINTF(("audio_drain: enter busy=%d used=%d\n",
- sc->sc_pbus, sc->sc_pr.used));
- if (sc->sc_pr.mmapped || sc->sc_pr.used <= 0)
+ /*
+ * if the device not opened, we're done, don't touch the hardware
+ */
+ if (sc->mode == 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;
- if (sc->sc_pemu.sw_code) {
- audio_fill_silence(&sc->sc_pparams, cb->start, inp, cc);
- sc->sc_pemu.sw_code(sc->hw_hdl, inp, cc);
- } else
- audio_fill_silence(&sc->sc_pparams, cb->start, inp, cc);
- inp += cc;
- if (inp >= cb->end)
- inp = cb->start;
- cb->used += cc;
- cb->inp = inp;
- error = audiostartp(sc);
+
+ /*
+ * change parameters and recalculate buffer sizes
+ */
+ if (set) {
+ if (sc->active) {
+ DPRINTF("%s: can't change params during dma\n",
+ DEVNAME(sc));
+ return EBUSY;
+ }
+ error = audio_setpar(sc);
if (error)
return error;
+ audio_clear(sc);
+ if ((sc->mode & AUMODE_PLAY) && sc->ops->init_output) {
+ error = sc->ops->init_output(sc->arg,
+ sc->play.data, sc->play.len);
+ if (error)
+ return error;
+ }
+ if ((sc->mode & AUMODE_RECORD) && sc->ops->init_input) {
+ error = sc->ops->init_input(sc->arg,
+ sc->rec.data, sc->rec.len);
+ 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.
+ * if unpaused, start
*/
- mtx_enter(&audio_lock);
- drops = cb->drops;
- error = 0;
- 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);
- if (sc->sc_dying)
- error = EIO;
+ if (!sc->pause && !sc->active) {
+ error = audio_start(sc);
+ if (error)
+ return error;
}
- mtx_leave(&audio_lock);
- return error;
+ return 0;
}
int
-audio_quiesce(struct audio_softc *sc)
+audio_getinfo(struct audio_softc *sc, struct audio_info *ai)
{
- sc->sc_quiesce = AUDIO_QUIESCE_START;
+ ai->play.sample_rate = ai->record.sample_rate = sc->rate;
+ ai->play.encoding = ai->record.encoding = sc->sw_enc;
+ ai->play.precision = ai->record.precision = sc->bits;
+ ai->play.bps = ai->record.bps = sc->bps;
+ ai->play.msb = ai->record.msb = sc->msb;
+ ai->play.channels = sc->pchan;
+ ai->record.channels = sc->rchan;
+ /*
+ * XXX: this is used only to display counters through audioctl
+ * and the pos counters are more useful
+ */
mtx_enter(&audio_lock);
- while (sc->sc_pbus && !sc->sc_pqui)
- audio_sleep(&sc->sc_wchan, "audpqui");
- while (sc->sc_rbus && !sc->sc_rqui)
- audio_sleep(&sc->sc_rchan, "audrqui");
+ ai->play.samples = sc->play.pos - sc->play.xrun;
+ ai->record.samples = sc->rec.pos - sc->rec.xrun;
mtx_leave(&audio_lock);
- sc->sc_quiesce = AUDIO_QUIESCE_SILENT;
+ ai->play.pause = ai->record.pause = sc->pause;
+ ai->play.active = ai->record.active = sc->active;
- au_get_mute(sc, &sc->sc_outports, &sc->sc_mute);
- au_set_mute(sc, &sc->sc_outports, 1);
+ ai->play.buffer_size = sc->play.datalen;
+ ai->record.buffer_size = sc->rec.datalen;
- if (sc->sc_pbus)
- sc->hw_if->halt_output(sc->hw_hdl);
- if (sc->sc_rbus)
- sc->hw_if->halt_input(sc->hw_hdl);
+ ai->play.block_size = sc->round * sc->bps * sc->pchan;
+ ai->record.block_size = sc->round * sc->bps * sc->rchan;
+ ai->hiwat = sc->nblks;
+ ai->lowat = sc->nblks;
+ ai->mode = sc->mode;
return 0;
}
-void
-audio_wakeup(struct audio_softc *sc)
+int
+audio_match(struct device *parent, void *match, void *aux)
{
- int setmode = 0;
+ struct audio_attach_args *sa = aux;
- sc->sc_pqui = sc->sc_rqui = 0;
+ return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0;
+}
- au_set_mute(sc, &sc->sc_outports, sc->sc_mute);
+void
+audio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct audio_softc *sc = (void *)self;
+ struct audio_attach_args *sa = aux;
+ struct audio_hw_if *ops = sa->hwif;
+ void *arg = sa->hdl;
+ int error;
- if (sc->sc_pbus)
- setmode |= AUMODE_PLAY;
- if (sc->sc_rbus)
- setmode |= AUMODE_RECORD;
+ printf("\n");
- if (setmode) {
- sc->hw_if->set_params(sc->hw_hdl, setmode,
- sc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD),
- &sc->sc_pparams, &sc->sc_rparams);
+#ifdef DIAGNOSTIC
+ if (ops == 0 ||
+ ops->open == 0 ||
+ ops->close == 0 ||
+ ops->query_encoding == 0 ||
+ ops->set_params == 0 ||
+ (ops->start_output == 0 && ops->trigger_output == 0) ||
+ (ops->start_input == 0 && ops->trigger_input == 0) ||
+ ops->halt_output == 0 ||
+ ops->halt_input == 0 ||
+ ops->getdev == 0 ||
+ ops->set_port == 0 ||
+ ops->get_port == 0 ||
+ ops->query_devinfo == 0 ||
+ ops->get_props == 0) {
+ printf("%s: missing method\n", DEVNAME(sc));
+ sc->ops = 0;
+ return;
}
+#endif
+ sc->ops = ops;
+ sc->arg = arg;
- if (sc->sc_pbus) {
- if (sc->hw_if->trigger_output)
- sc->hw_if->trigger_output(sc->hw_hdl, sc->sc_pr.start,
- sc->sc_pr.end, sc->sc_pr.blksize,
- audio_pint, (void *)sc, &sc->sc_pparams);
- else
- sc->hw_if->start_output(sc->hw_hdl, sc->sc_pr.outp,
- sc->sc_pr.blksize, audio_pint, (void *)sc);
- }
- if (sc->sc_rbus) {
- if (sc->hw_if->trigger_input)
- sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.start,
- sc->sc_rr.end, sc->sc_rr.blksize,
- audio_rint, (void *)sc, &sc->sc_rparams);
- else
- sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.inp,
- sc->sc_rr.blksize, audio_rint, (void *)sc);
+#if NWSKBD > 0
+ wskbd_mixer_init(sc);
+#endif /* NWSKBD > 0 */
+
+ error = audio_buf_init(sc, &sc->play, AUMODE_PLAY);
+ if (error) {
+ sc->ops = 0;
+ printf("%s: could not allocate play buffer\n", DEVNAME(sc));
+ return;
+ }
+ error = audio_buf_init(sc, &sc->rec, AUMODE_RECORD);
+ if (error) {
+ audio_buf_done(sc, &sc->play);
+ sc->ops = 0;
+ printf("%s: could not allocate record buffer\n", DEVNAME(sc));
+ return;
}
- sc->sc_quiesce = 0;
- wakeup(&sc->sc_quiesce);
+ /* set defaults */
+ sc->sw_enc = AUDIO_ENCODING_SLINEAR;
+ sc->bits = 16;
+ sc->bps = 2;
+ sc->msb = 1;
+ sc->rate = 48000;
+ sc->pchan = 2;
+ sc->rchan = 2;
+ sc->round = 960;
+ sc->nblks = 2;
+ sc->play.pos = sc->play.xrun = sc->rec.pos = sc->rec.xrun = 0;
}
-/*
- * Close an audio chip.
- */
-/* ARGSUSED */
int
-audio_close(dev_t dev, int flags, int ifmt, struct proc *p)
+audio_activate(struct device *self, int act)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct audio_hw_if *hw = sc->hw_if;
+ struct audio_softc *sc = (struct audio_softc *)self;
- DPRINTF(("audio_close: unit=%d flags=0x%x\n", unit, flags));
+ switch (act) {
+ case DVACT_QUIESCE:
+ /*
+ * good drivers run play and rec handlers in a single
+ * interrupt. Grab the lock to ensure we expose the same
+ * sc->quiesce value to both play and rec handlers
+ */
+ mtx_enter(&audio_lock);
+ sc->quiesce = 1;
+ mtx_leave(&audio_lock);
-
- /* Stop recording. */
- if ((flags & FREAD) && 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.
+ * once sc->quiesce is set, interrupts may occur, but
+ * counters are not advanced and consequently processes
+ * keep sleeping.
+ *
+ * XXX: ensure read/write/ioctl don't start/stop
+ * DMA at the same time, this needs a "ready" condvar
*/
- 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;
- }
+ if (sc->mode != 0 && sc->active)
+ audio_stop_do(sc);
+ DPRINTF("%s: quesce: active = %d\n", DEVNAME(sc), sc->active);
+ break;
+ case DVACT_WAKEUP:
+ DPRINTF("%s: wakeup: active = %d\n", DEVNAME(sc), sc->active);
- /*
- * If there is pending output, let it drain (unless
- * the output is paused).
- */
- if ((flags & FWRITE) && sc->sc_pbus) {
/*
- * Block until output drains, but allow ^C interrupt.
- * XXX: drain is never used, remove it!
+ * keep buffer usage the same, but set start pointer to
+ * the beginning of the buffer.
+ *
+ * No need to grab the audio_lock as DMA is stopped and
+ * this is the only thread running (caller ensures this)
*/
- mtx_enter(&audio_lock);
- /* avoid excessive wakeups */
- sc->sc_pr.usedlow = sc->sc_pr.blksize;
- mtx_leave(&audio_lock);
- if (!sc->sc_pr.pause) {
- if (!audio_drain(sc) && hw->drain)
- (void)hw->drain(sc->hw_hdl);
+ sc->quiesce = 0;
+ wakeup(&sc->quiesce);
+
+ if(sc->mode != 0) {
+ if (audio_setpar(sc) != 0)
+ break;
+ if (sc->mode & AUMODE_PLAY) {
+ sc->play.start = 0;
+ audio_fill_sil(sc, sc->play.data, sc->play.len);
+ }
+ if (sc->mode & AUMODE_RECORD) {
+ sc->rec.start = sc->rec.len - sc->rec.used;
+ audio_fill_sil(sc, sc->rec.data, sc->rec.len);
+ }
+ if (sc->active)
+ audio_start_do(sc);
}
- sc->hw_if->halt_output(sc->hw_hdl);
- sc->sc_pbus = 0;
+ break;
}
+ return 0;
+}
- hw->close(sc->hw_hdl);
+int
+audio_detach(struct device *self, int flags)
+{
+ struct audio_softc *sc = (struct audio_softc *)self;
+ int maj, mn;
+
+ DPRINTF("%s: audio_detach: flags = %d\n", DEVNAME(sc), flags);
+ wakeup(&sc->quiesce);
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == audioopen)
+ break;
/*
- * If flags has neither read nor write then reset both
- * directions. Encountered when someone runs revoke(2).
+ * Nuke the vnodes for any open instances, calls close but as
+ * close uses device_lookup, it returns EXIO and does nothing
*/
+ mn = self->dv_unit;
+ vdevgone(maj, mn | AUDIO_DEV_SOUND, mn | AUDIO_DEV_SOUND, VCHR);
+ vdevgone(maj, mn | AUDIO_DEV_AUDIO, mn | AUDIO_DEV_AUDIO, VCHR);
+ vdevgone(maj, mn | AUDIO_DEV_AUDIOCTL, mn | AUDIO_DEV_AUDIOCTL, VCHR);
+ vdevgone(maj, mn | AUDIO_DEV_MIXER, mn | AUDIO_DEV_MIXER, VCHR);
- if ((flags & FREAD) || ((flags & (FREAD|FWRITE)) == 0)) {
- sc->sc_open &= ~AUOPEN_READ;
- sc->sc_mode &= ~AUMODE_RECORD;
- }
- if ((flags & FWRITE) || ((flags & (FREAD|FWRITE)) == 0)) {
- sc->sc_open &= ~AUOPEN_WRITE;
- sc->sc_mode &= ~(AUMODE_PLAY|AUMODE_PLAY_ALL);
+ /*
+ * The close() method did nothing, quickly halt DMA (normally
+ * parent is already gone, and code below is no-op), and wake-up
+ * user-land blocked in read/write/ioctl, which return EIO.
+ */
+ if (sc->mode != 0) {
+ if (sc->active) {
+ wakeup(&sc->play.blocking);
+ selwakeup(&sc->play.sel);
+ wakeup(&sc->rec.blocking);
+ selwakeup(&sc->rec.sel);
+ audio_stop(sc);
+ }
+ sc->ops->close(sc->arg);
+ sc->mode = 0;
}
- sc->sc_async_audio = 0;
- sc->sc_full_duplex = 0;
- DPRINTF(("audio_close: done\n"));
- return (0);
+ /* free resources */
+ audio_buf_done(sc, &sc->play);
+ audio_buf_done(sc, &sc->rec);
+ return 0;
}
-int
-audio_read(dev_t dev, struct uio *uio, int ioflag)
+struct device *
+audio_attach_mi(struct audio_hw_if *ops, void *arg, struct device *dev)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct audio_ringbuffer *cb = &sc->sc_rr;
- u_char *outp;
- int error, cc, n, resid;
-
- if (cb->mmapped)
- return EINVAL;
+ struct audio_attach_args aa;
- DPRINTFN(1,("audio_read: cc=%ld mode=%d\n",
- uio->uio_resid, sc->sc_mode));
+ aa.type = AUDIODEV_TYPE_AUDIO;
+ aa.hwif = ops;
+ aa.hdl = arg;
/*
- * Block if fully quiesced. Don't block when quiesce
- * has started, as the buffer position may still need
- * to advance.
+ * attach this driver to the caller (hardware driver), this
+ * checks the kernel config and possibly calls audio_attach()
*/
- while (sc->sc_quiesce == AUDIO_QUIESCE_SILENT)
- tsleep(&sc->sc_quiesce, 0, "aud_qrd", 0);
+ return config_found(dev, &aa, audioprint);
+}
- 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) {
- mtx_enter(&audio_lock);
- 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) {
- mtx_leave(&audio_lock);
- return EWOULDBLOCK;
- }
- error = audio_sleep(&sc->sc_rchan, "aud_hr");
- if (sc->sc_dying)
- error = EIO;
- if (error) {
- mtx_leave(&audio_lock);
- return error;
- }
- }
- mtx_leave(&audio_lock);
+int
+audioprint(void *aux, const char *pnp)
+{
+ struct audio_attach_args *arg = aux;
+ const char *type;
- if (uio->uio_resid < cc)
- cc = uio->uio_resid;
- DPRINTFN(1, ("audio_read: reading in write mode, cc=%d\n", cc));
- error = audio_silence_copyout(sc, cc, uio);
- sc->sc_wstamp += cc;
- }
- return (error);
- }
- while (uio->uio_resid > 0) {
- mtx_enter(&audio_lock);
- while (cb->used <= 0) {
- if (!sc->sc_rbus && !sc->sc_rr.pause) {
- mtx_leave(&audio_lock);
- error = audiostartr(sc);
- if (error)
- return error;
- mtx_enter(&audio_lock);
- continue;
- }
- if (ioflag & IO_NDELAY) {
- mtx_leave(&audio_lock);
- return (EWOULDBLOCK);
- }
- DPRINTFN(2, ("audio_read: sleep used=%d\n", cb->used));
- error = audio_sleep(&sc->sc_rchan, "aud_rd");
- if (sc->sc_dying)
- error = EIO;
- if (error) {
- mtx_leave(&audio_lock);
- return error;
- }
+ if (pnp != NULL) {
+ switch (arg->type) {
+ case AUDIODEV_TYPE_AUDIO:
+ type = "audio";
+ break;
+ case AUDIODEV_TYPE_OPL:
+ type = "opl";
+ break;
+ case AUDIODEV_TYPE_MPU:
+ type = "mpu";
+ break;
+ default:
+ panic("audioprint: unknown type %d", arg->type);
}
- resid = uio->uio_resid;
- outp = cb->outp;
- cc = cb->used - cb->usedlow; /* maximum to read */
- n = cb->end - outp;
- if (cc > n)
- cc = n; /* don't read beyond end of buffer */
-
- if (cc > resid)
- cc = resid; /* and no more than we want */
- cb->used -= cc;
- cb->outp += cc;
- if (cb->outp >= cb->end)
- cb->outp = cb->start;
- mtx_leave(&audio_lock);
- DPRINTFN(1,("audio_read: outp=%p, cc=%d\n", outp, cc));
- if (sc->sc_remu.sw_code)
- sc->sc_remu.sw_code(sc->hw_hdl, outp, cc);
- error = uiomove(outp, cc, uio);
- if (error)
- return error;
+ printf("%s at %s", type, pnp);
}
- return 0;
+ return UNCONF;
}
-void
-audio_clear(struct audio_softc *sc)
+int
+audio_open(struct audio_softc *sc, int flags)
{
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- if (sc->sc_rbus) {
- audio_wake(&sc->sc_rchan);
- sc->hw_if->halt_input(sc->hw_hdl);
- sc->sc_rbus = 0;
- }
- if (sc->sc_pbus) {
- audio_wake(&sc->sc_wchan);
- sc->hw_if->halt_output(sc->hw_hdl);
- sc->sc_pbus = 0;
- }
-}
+ int error;
+ int props;
-void
-audio_set_blksize(struct audio_softc *sc, int mode, int fpb) {
- struct audio_hw_if *hw = sc->hw_if;
- struct audio_params *parm;
- struct audio_ringbuffer *rb;
- int bs, fs, maxbs;
-
- if (mode == AUMODE_PLAY) {
- parm = &sc->sc_pparams;
- rb = &sc->sc_pr;
- } else {
- parm = &sc->sc_rparams;
- rb = &sc->sc_rr;
+ if (sc->mode)
+ return EBUSY;
+ error = sc->ops->open(sc->arg, flags);
+ if (error)
+ return error;
+ sc->active = 0;
+ sc->pause = 1;
+ sc->rec.blocking = 0;
+ sc->play.blocking = 0;
+ sc->mode = 0;
+ if (flags & FWRITE)
+ sc->mode |= AUMODE_PLAY;
+ if (flags & FREAD)
+ sc->mode |= AUMODE_RECORD;
+ props = sc->ops->get_props(sc->arg);
+ if (sc->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
+ if (!(props & AUDIO_PROP_FULLDUPLEX)) {
+ error = ENOTTY;
+ goto bad;
+ }
+ if (sc->ops->setfd) {
+ error = sc->ops->setfd(sc->arg, 1);
+ if (error)
+ goto bad;
+ }
}
- fs = parm->channels * parm->bps;
- bs = fpb * fs;
- maxbs = rb->bufsize / 2;
- if (bs > maxbs)
- bs = (maxbs / fs) * fs;
+ if (sc->ops->speaker_ctl) {
+ /*
+ * XXX: what is this used for?
+ */
+ sc->ops->speaker_ctl(sc->arg,
+ (sc->mode & AUMODE_PLAY) ? SPKR_ON : SPKR_OFF);
+ }
- ROUNDSIZE(bs);
- if (hw->round_blocksize)
- bs = hw->round_blocksize(sc->hw_hdl, bs);
- rb->blksize = bs;
+ error = audio_setpar(sc);
+ if (error)
+ goto bad;
+ audio_clear(sc);
- DPRINTF(("audio_set_blksize: %s blksize=%d\n",
- mode == AUMODE_PLAY ? "play" : "record", bs));
+ /*
+ * allow read(2)/write(2) to automatically start DMA, without
+ * the need for ioctl(), to make /dev/audio usable in scripts
+ */
+ sc->pause = 0;
+ return 0;
+bad:
+ sc->ops->close(sc->arg);
+ sc->mode = 0;
+ return error;
}
-void
-audio_calc_blksize(struct audio_softc *sc, int mode)
+int
+audio_drain(struct audio_softc *sc)
{
- struct audio_params *param;
+ int error, xrun;
+ unsigned char *ptr;
+ size_t count, bpf;
- if (mode == AUMODE_PLAY) {
- if (sc->sc_pr.blkset)
- return;
- param = &sc->sc_pparams;
- } else {
- if (sc->sc_rr.blkset)
- return;
- param = &sc->sc_rparams;
+ DPRINTF("%s: drain: mode = %d, pause = %d, active = %d, used = %zu\n",
+ DEVNAME(sc), sc->mode, sc->pause, sc->active, sc->play.used);
+ if (!(sc->mode & AUMODE_PLAY) || sc->pause)
+ return 0;
+
+ /* discard partial samples, required by audio_fill_sil() */
+ mtx_enter(&audio_lock);
+ bpf = sc->pchan * sc->bps;
+ sc->play.used -= sc->play.used % bpf;
+ if (sc->play.used == 0) {
+ mtx_leave(&audio_lock);
+ return 0;
}
- audio_set_blksize(sc, mode, param->sample_rate * audio_blk_ms / 1000);
-}
-void
-audio_fill_silence(struct audio_params *params, u_char *start, u_char *p, int n)
-{
- size_t rounderr;
- int i, nsamples;
- u_char auzero[4] = {0, 0, 0, 0};
+ if (!sc->active) {
+ /*
+ * dma not started yet because buffer was not full
+ * enough to start automatically. Pad it and start now.
+ */
+ for (;;) {
+ ptr = audio_buf_wgetblk(&sc->play, &count);
+ if (count == 0)
+ break;
+ audio_fill_sil(sc, ptr, count);
+ audio_buf_wcommit(&sc->play, count);
+ }
+ mtx_leave(&audio_lock);
+ error = audio_start(sc);
+ if (error)
+ return error;
+ mtx_enter(&audio_lock);
+ }
- /*
- * p may point the middle of a sample; round it to the
- * beginning of the sample, so we overwrite partially written
- * ones.
- */
- rounderr = (p - start) % params->bps;
- p -= rounderr;
- n += rounderr;
- nsamples = n / params->bps;
+ xrun = sc->play.xrun;
+ while (sc->play.xrun == xrun) {
+ DPRINTF("%s: drain: used = %zu, xrun = %ld\n",
+ DEVNAME(sc), sc->play.used, sc->play.xrun);
- switch (params->encoding) {
- case AUDIO_ENCODING_SLINEAR_LE:
- case AUDIO_ENCODING_SLINEAR_BE:
- break;
- case AUDIO_ENCODING_ULAW:
- auzero[0] = 0x7f;
- break;
- case AUDIO_ENCODING_ALAW:
- auzero[0] = 0x55;
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- if (params->msb == 1)
- auzero[params->bps - 1] = 0x80;
- else
- auzero[params->bps - 1] = 1 << ((params->precision + 7) % NBBY);
- break;
- case AUDIO_ENCODING_ULINEAR_BE:
- if (params->msb == 1)
- auzero[0] = 0x80;
- else
- auzero[0] = 1 << ((params->precision + 7) % NBBY);
- 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 */
- break;
- default:
- DPRINTF(("audio: bad encoding %d\n", params->encoding));
- break;
- }
- while (--nsamples >= 0) {
- for (i = 0; i < params->bps; i++)
- *p++ = auzero[i];
+ /*
+ * set a 5 second timeout, in case interrupts don't
+ * work, useful only for debugging drivers
+ */
+ sc->play.blocking = 1;
+ error = msleep(&sc->play.blocking, &audio_lock,
+ PWAIT | PCATCH, "au_dr", 5 * hz);
+ if (!(sc->dev.dv_flags & DVF_ACTIVE))
+ error = EIO;
+ if (error) {
+ DPRINTF("%s: drain, err = %d\n", DEVNAME(sc), error);
+ break;
+ }
}
+ mtx_leave(&audio_lock);
+ return error;
}
int
-audio_silence_copyout(struct audio_softc *sc, int n, struct uio *uio)
+audio_close(struct audio_softc *sc)
+{
+ audio_drain(sc);
+ if (sc->active)
+ audio_stop(sc);
+ sc->ops->close(sc->arg);
+ sc->mode = 0;
+ DPRINTF("%s: close: done\n", DEVNAME(sc));
+ return 0;
+}
+
+int
+audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
{
+ unsigned char *ptr;
+ size_t count;
int error;
- int k;
- u_char zerobuf[128];
- audio_fill_silence(&sc->sc_rparams, zerobuf, zerobuf, sizeof zerobuf);
+ DPRINTFN(1, "%s: read: resid = %zd\n", DEVNAME(sc), uio->uio_resid);
- error = 0;
- while (n > 0 && uio->uio_resid > 0 && !error) {
- k = min(n, min(uio->uio_resid, sizeof zerobuf));
- error = uiomovei(zerobuf, k, uio);
- n -= k;
+ /* block if quiesced */
+ while (sc->quiesce)
+ tsleep(&sc->quiesce, 0, "au_qrd", 0);
+
+ /* start automatically if setinfo() was never called */
+ mtx_enter(&audio_lock);
+ if (!sc->active && !sc->pause && sc->rec.used == 0) {
+ mtx_leave(&audio_lock);
+ error = audio_start(sc);
+ if (error)
+ return error;
+ mtx_enter(&audio_lock);
+ }
+
+ /* if there is no data then sleep */
+ while (sc->rec.used == 0) {
+ if (ioflag & IO_NDELAY) {
+ mtx_leave(&audio_lock);
+ return EWOULDBLOCK;
+ }
+ DPRINTFN(1, "%s: read sleep\n", DEVNAME(sc));
+ sc->rec.blocking = 1;
+ error = msleep(&sc->rec.blocking,
+ &audio_lock, PWAIT | PCATCH, "au_rd", 0);
+ if (!(sc->dev.dv_flags & DVF_ACTIVE))
+ error = EIO;
+#ifdef AUDIO_DEBUG
+ if (error) {
+ DPRINTF("%s: read woke up error = %d\n",
+ DEVNAME(sc), error);
+ }
+#endif
+ if (error) {
+ mtx_leave(&audio_lock);
+ return error;
+ }
}
- return (error);
+
+ /* at this stage, there is data to transfer */
+ while (uio->uio_resid > 0 && sc->rec.used > 0) {
+ ptr = audio_buf_rgetblk(&sc->rec, &count);
+ if (count > uio->uio_resid)
+ count = uio->uio_resid;
+ mtx_leave(&audio_lock);
+ DPRINTFN(1, "%s: read: start = %zu, count = %zu\n",
+ DEVNAME(sc), ptr - sc->rec.data, count);
+ if (sc->conv_dec)
+ sc->conv_dec(ptr, count);
+ error = uiomove(ptr, count, uio);
+ if (error)
+ return error;
+ mtx_enter(&audio_lock);
+ audio_buf_rdiscard(&sc->rec, count);
+ }
+ mtx_leave(&audio_lock);
+ return 0;
}
int
-audio_write(dev_t dev, struct uio *uio, int ioflag)
+audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct audio_ringbuffer *cb = &sc->sc_pr;
- u_char *inp;
- int error, n, cc, resid, avail;
+ unsigned char *ptr;
+ size_t count;
+ int error;
- DPRINTFN(2, ("audio_write: sc=%p(unit=%d) count=%zd used=%d(hi=%d)\n", sc, unit,
- uio->uio_resid, sc->sc_pr.used, sc->sc_pr.usedhigh));
+ DPRINTFN(1, "%s: write: resid = %zd\n", DEVNAME(sc), uio->uio_resid);
- if (cb->mmapped)
- return EINVAL;
+ /* block if quiesced */
+ while (sc->quiesce)
+ tsleep(&sc->quiesce, 0, "au_qwr", 0);
/*
- * Block if fully quiesced. Don't block when quiesce
- * has started, as the buffer position may still need
- * to advance.
+ * if IO_NDELAY flag is set then check if there is enough room
+ * in the buffer to store at least one byte. If not then dont
+ * start the write process.
*/
- while (sc->sc_quiesce == AUDIO_QUIESCE_SILENT)
- tsleep(&sc->sc_quiesce, 0, "aud_qwr", 0);
-
- 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;
+ mtx_enter(&audio_lock);
+ if (uio->uio_resid > 0 && (ioflag & IO_NDELAY)) {
+ if (sc->play.used == sc->play.len ) {
+ mtx_leave(&audio_lock);
+ return EWOULDBLOCK;
+ }
}
- DPRINTFN(1, ("audio_write: sr=%ld, enc=%d, prec=%d, chan=%d\n",
- sc->sc_pparams.sample_rate, sc->sc_pparams.encoding,
- sc->sc_pparams.precision, sc->sc_pparams.channels));
-
while (uio->uio_resid > 0) {
- mtx_enter(&audio_lock);
- while (cb->used >= cb->usedhigh) {
- DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d hiwat=%d\n",
- cb->used, cb->usedlow, cb->usedhigh));
+ while (1) {
+ ptr = audio_buf_wgetblk(&sc->play, &count);
+ if (count > 0)
+ break;
if (ioflag & IO_NDELAY) {
+ /*
+ * At this stage at least one byte is already
+ * moved so we do not return EWOULDBLOCK
+ */
mtx_leave(&audio_lock);
- return (EWOULDBLOCK);
+ return 0;
}
- error = audio_sleep(&sc->sc_wchan, "aud_wr");
- if (sc->sc_dying)
+ DPRINTFN(1, "%s: write sleep\n", DEVNAME(sc));
+ sc->play.blocking = 1;
+ error = msleep(&sc->play.blocking,
+ &audio_lock, PWAIT | PCATCH, "au_wr", 0);
+ if (!(sc->dev.dv_flags & DVF_ACTIVE))
error = EIO;
+#ifdef AUDIO_DEBUG
+ if (error) {
+ DPRINTF("%s: write woke up error = %d\n",
+ DEVNAME(sc), error);
+ }
+#endif
if (error) {
mtx_leave(&audio_lock);
return error;
}
}
- resid = uio->uio_resid;
- avail = cb->end - cb->inp;
- inp = cb->inp;
- cc = cb->usedhigh - cb->used;
- if (cc > resid)
- cc = resid;
- if (cc > avail)
- cc = avail;
- cb->inp += cc;
- if (cb->inp >= cb->end)
- cb->inp = cb->start;
- cb->used += cc;
- /*
- * This is a very suboptimal way of keeping track of
- * silence in the buffer, but it is simple.
- */
- sc->sc_sil_count = 0;
- if (!sc->sc_pbus && !cb->pause && cb->used >= cb->blksize) {
+ if (count > uio->uio_resid)
+ count = uio->uio_resid;
+ mtx_leave(&audio_lock);
+ error = uiomove(ptr, count, uio);
+ if (error)
+ return 0;
+ if (sc->conv_enc) {
+ sc->conv_enc(ptr, count);
+ DPRINTFN(1, "audio_write: converted count = %zu\n",
+ count);
+ }
+ mtx_enter(&audio_lock);
+ audio_buf_wcommit(&sc->play, count);
+
+ /* start automatically if setinfo() was never called */
+ if (!sc->active && !sc->pause &&
+ sc->play.used == sc->play.len) {
mtx_leave(&audio_lock);
- error = audiostartp(sc);
+ error = audio_start(sc);
if (error)
return error;
- } else
- mtx_leave(&audio_lock);
- DPRINTFN(1, ("audio_write: uiomove cc=%d inp=%p, left=%zd\n",
- cc, inp, uio->uio_resid));
- error = uiomovei(inp, cc, uio);
- if (error)
- return 0;
- if (sc->sc_pemu.sw_code) {
- sc->sc_pemu.sw_code(sc->hw_hdl, inp, cc);
- DPRINTFN(1, ("audio_write: expanded cc=%d\n", cc));
+ mtx_enter(&audio_lock);
}
}
+ mtx_leave(&audio_lock);
return 0;
}
int
-audio_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+audio_ioctl(struct audio_softc *sc, unsigned long cmd, void *addr)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct audio_hw_if *hw = sc->hw_if;
struct audio_offset *ao;
- struct audio_info ai;
- int error = 0, offs, fd;
- int rbus, pbus;
+ int error = 0, fd;
- /*
- * Block if fully quiesced. Don't block when quiesce
- * has started, as the buffer position may still need
- * to advance. An ioctl may be used to determine how
- * much to read or write.
- */
- while (sc->sc_quiesce == AUDIO_QUIESCE_SILENT)
- tsleep(&sc->sc_quiesce, 0, "aud_qio", 0);
+ /* block if quiesced */
+ while (sc->quiesce)
+ tsleep(&sc->quiesce, 0, "au_qio", 0);
- DPRINTF(("audio_ioctl(%ld,'%c',%ld)\n",
- IOCPARM_LEN(cmd), (int)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"));
- rbus = sc->sc_rbus;
- pbus = sc->sc_pbus;
- audio_clear(sc);
- error = audio_initbufs(sc);
- if (error) {
- return error;
- }
- sc->sc_rr.pause = 0;
- sc->sc_pr.pause = 0;
- 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);
- break;
-
- /*
- * Number of read (write) samples dropped. We don't know where or
- * when they were dropped.
- *
- * The audio_ringbuffer->drops count is the number of buffer
- * sample size bytes. Convert it to userland sample size bytes,
- * then convert to samples. There is no easy way to get the
- * buffer sample size, but the userland sample size can be
- * calculated with userland channels and userland precision.
- *
- * original formula:
- * sc->sc_rr.drops /
- * (sc->sc_rparams.channels * sc->sc_rparams.bps)
- */
- case AUDIO_RERROR:
- *(int *)addr = sc->sc_rr.drops /
- (sc->sc_rparams.channels * sc->sc_rparams.bps);
- break;
-
case AUDIO_PERROR:
- *(int *)addr = sc->sc_pr.drops /
- (sc->sc_pparams.channels * sc->sc_pparams.bps);
+ mtx_enter(&audio_lock);
+ *(int *)addr = sc->play.xrun / (sc->pchan * sc->bps);
+ mtx_leave(&audio_lock);
break;
-
- /*
- * Offsets into buffer.
- */
- case AUDIO_GETIOFFS:
+ case AUDIO_RERROR:
mtx_enter(&audio_lock);
- /* 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;
+ *(int *)addr = sc->rec.xrun / (sc->rchan * sc->bps);
mtx_leave(&audio_lock);
break;
-
case AUDIO_GETOOFFS:
mtx_enter(&audio_lock);
- /* 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;
+ ao->samples = sc->play.pos;
mtx_leave(&audio_lock);
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_pr.used;
+ case AUDIO_GETIOFFS:
+ mtx_enter(&audio_lock);
+ ao = (struct audio_offset *)addr;
+ ao->samples = sc->rec.pos;
+ mtx_leave(&audio_lock);
break;
-
case AUDIO_SETINFO:
- DPRINTF(("AUDIO_SETINFO mode=0x%x\n", sc->sc_mode));
- error = audiosetinfo(sc, (struct audio_info *)addr);
+ error = audio_setinfo(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);
+ error = audio_getinfo(sc, (struct audio_info *)addr);
break;
-
case AUDIO_GETDEV:
- DPRINTF(("AUDIO_GETDEV\n"));
- error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr);
+ error = sc->ops->getdev(sc->arg, (audio_device_t *)addr);
break;
-
case AUDIO_GETENC:
- DPRINTF(("AUDIO_GETENC\n"));
- /* Pass read/write info down to query_encoding */
- ((struct audio_encoding *)addr)->flags = sc->sc_open;
- error = hw->query_encoding(sc->hw_hdl, (struct audio_encoding *)addr);
+ error = sc->ops->query_encoding(sc->arg,
+ (struct audio_encoding *)addr);
break;
-
case AUDIO_GETFD:
- DPRINTF(("AUDIO_GETFD\n"));
- *(int *)addr = sc->sc_full_duplex;
+ *(int *)addr = (sc->mode & (AUMODE_PLAY | AUMODE_RECORD)) ==
+ (AUMODE_PLAY | AUMODE_RECORD);
break;
-
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;
- if (fd) {
- AUDIO_INITINFO(&ai);
- ai.mode = sc->sc_mode |
- (AUMODE_PLAY | AUMODE_RECORD);
- error = audiosetinfo(sc, &ai);
- }
- }
- } else {
- if (fd)
- error = ENOTTY;
- else
- error = 0;
- }
+ if ((sc->mode & (AUMODE_PLAY | AUMODE_RECORD)) !=
+ (AUMODE_PLAY | AUMODE_RECORD) || !fd)
+ return EINVAL;
break;
-
case AUDIO_GETPROPS:
- DPRINTF(("AUDIO_GETPROPS\n"));
- *(int *)addr = hw->get_props(sc->hw_hdl);
- break;
-
- case AUDIO_GETPRINFO:
- DPRINTF(("AUDIO_GETPRINFO\n"));
- error = audiogetbufinfo(sc, (struct audio_bufinfo *)addr,
- AUMODE_PLAY);
+ *(int *)addr = sc->ops->get_props(sc->arg);
break;
-
- case AUDIO_GETRRINFO:
- DPRINTF(("AUDIO_GETRRINFO\n"));
- error = audiogetbufinfo(sc, (struct audio_bufinfo *)addr,
- AUMODE_RECORD);
- break;
-
default:
- DPRINTF(("audio_ioctl: unknown ioctl\n"));
+ DPRINTF("%s: unknown ioctl 0x%lx\n", DEVNAME(sc), cmd);
error = ENOTTY;
break;
}
- DPRINTF(("audio_ioctl(%ld,'%c',%ld) result %d\n",
- IOCPARM_LEN(cmd), (int)IOCGROUP(cmd), cmd&0xff, error));
- return (error);
+ return error;
}
-void
-audio_selwakeup(struct audio_softc *sc, int play)
+int
+audio_ioctl_mixer(struct audio_softc *sc, unsigned long cmd, void *addr)
{
- struct selinfo *si;
+ int error;
- si = play? &sc->sc_wsel : &sc->sc_rsel;
+ /* block if quiesced */
+ while (sc->quiesce)
+ tsleep(&sc->quiesce, 0, "mix_qio", 0);
- audio_wake(play? &sc->sc_wchan : &sc->sc_rchan);
- selwakeup(si);
- if (sc->sc_async_audio)
- psignal(sc->sc_async_audio, SIGIO);
+ switch (cmd) {
+ case FIONBIO:
+ /* All handled in the upper FS layer. */
+ break;
+ case AUDIO_MIXER_DEVINFO:
+ ((mixer_devinfo_t *)addr)->un.v.delta = 0;
+ return sc->ops->query_devinfo(sc->arg, (mixer_devinfo_t *)addr);
+ case AUDIO_MIXER_READ:
+ return sc->ops->get_port(sc->arg, (mixer_ctrl_t *)addr);
+ case AUDIO_MIXER_WRITE:
+ error = sc->ops->set_port(sc->arg, (mixer_ctrl_t *)addr);
+ if (error)
+ return error;
+ if (sc->ops->commit_settings)
+ return sc->ops->commit_settings(sc->arg);
+ break;
+ default:
+ return ENOTTY;
+ }
+ return 0;
}
-#define AUDIO_FILTREAD(sc) ( \
- (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY)) ? \
- sc->sc_pr.stamp > sc->sc_wstamp : sc->sc_rr.used > sc->sc_rr.usedlow)
-
-#define AUDIO_FILTWRITE(sc) ( \
- (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_RECORD)) || \
- (!(sc->sc_mode & AUMODE_PLAY_ALL) && sc->sc_playdrop > 0) || \
- (sc->sc_pr.used < (sc->sc_pr.usedlow + sc->sc_pr.blksize)))
-
int
-audio_poll(dev_t dev, int events, struct proc *p)
+audio_poll(struct audio_softc *sc, int events, struct proc *p)
{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
int revents = 0;
mtx_enter(&audio_lock);
-
- DPRINTF(("audio_poll: events=0x%x mode=%d\n", events, sc->sc_mode));
-
- if (events & (POLLIN | POLLRDNORM)) {
- if (AUDIO_FILTREAD(sc))
- revents |= events & (POLLIN | POLLRDNORM);
- }
- if (events & (POLLOUT | POLLWRNORM)) {
- if (AUDIO_FILTWRITE(sc))
- revents |= events & (POLLOUT | POLLWRNORM);
- }
+ if ((sc->mode & AUMODE_RECORD) && sc->rec.used > 0)
+ revents |= events & (POLLIN | POLLRDNORM);
+ if ((sc->mode & AUMODE_PLAY) && sc->play.used < sc->play.len)
+ revents |= events & (POLLOUT | POLLWRNORM);
if (revents == 0) {
if (events & (POLLIN | POLLRDNORM))
- selrecord(p, &sc->sc_rsel);
+ selrecord(p, &sc->rec.sel);
if (events & (POLLOUT | POLLWRNORM))
- selrecord(p, &sc->sc_wsel);
+ selrecord(p, &sc->play.sel);
}
mtx_leave(&audio_lock);
- return (revents);
-}
-
-paddr_t
-audio_mmap(dev_t dev, off_t off, int prot)
-{
- 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=%lld, 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 PROT_WRITE you SIGSEGV
- * when writing to it, so PROT_READ|PROT_WRITE
- * has to be used for mmapping the play buffer.
- * 2) Even if calling mmap() with PROT_READ|PROT_WRITE
- * audio_mmap will get called at some point with PROT_READ
- * only.
- * So, alas, we always map the play buffer for now.
- */
- if (prot == (PROT_READ | PROT_WRITE) ||
- prot == PROT_WRITE)
- cb = &sc->sc_pr;
- else if (prot == PROT_READ)
- cb = &sc->sc_rr;
- else
- return -1;
-#else
- cb = &sc->sc_pr;
-#endif
-
- if ((u_int)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->start, cb->bufsize);
- if (!sc->sc_pbus && !sc->sc_pr.pause)
- (void)audiostartp(sc);
- } else {
- if (!sc->sc_rbus && !sc->sc_rr.pause)
- (void)audiostartr(sc);
- }
- }
-
- return hw->mappage(sc->hw_hdl, cb->start, off, prot);
-}
-
-int
-audiostartr(struct audio_softc *sc)
-{
- int error;
-
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- 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));
-
- if (sc->hw_if->trigger_input)
- error = sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.start,
- sc->sc_rr.end, sc->sc_rr.blksize,
- audio_rint, (void *)sc, &sc->sc_rparams);
- else
- 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;
+ return revents;
}
int
-audiostartp(struct audio_softc *sc)
-{
- int error;
-
- MUTEX_ASSERT_UNLOCKED(&audio_lock);
- 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.mmapped && sc->sc_pr.used < sc->sc_pr.blksize)
- return 0;
-
- if (sc->hw_if->trigger_output)
- error = sc->hw_if->trigger_output(sc->hw_hdl, sc->sc_pr.start,
- sc->sc_pr.end, sc->sc_pr.blksize,
- audio_pint, (void *)sc, &sc->sc_pparams);
- else
- 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 approximate way: it starts at sc_sil_start
- * and extends sc_sil_count bytes. If there is already silence in
- * the requested area nothing is done; so when the whole buffer is
- * silent nothing happens. When the writer starts again sc_sil_count
- * is set to 0.
- */
-/* XXX
- * Putting silence into the output buffer should not really be done
- * with audio_lock, but there is no softaudio level to do it at yet.
- */
-static __inline void
-audio_pint_silence(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);
- DPRINTFN(5, ("audio_pint_silence: fill cc=%d inp=%p, count=%d size=%d\n",
- cc, inp, sc->sc_sil_count, (int)(cb->end - cb->start)));
-
- if (sc->sc_pemu.sw_code) {
- audio_fill_silence(&sc->sc_pparams, cb->start, inp, cc);
- sc->sc_pemu.sw_code(sc->hw_hdl, inp, cc);
- } else
- audio_fill_silence(&sc->sc_pparams, cb->start, inp, cc);
-
- } else {
- DPRINTFN(5, ("audio_pint_silence: already silent cc=%d inp=%p\n", cc, inp));
-
- }
- } else {
- sc->sc_sil_start = inp;
- sc->sc_sil_count = cc;
- DPRINTFN(5, ("audio_pint_silence: start fill %p %d\n",
- inp, cc));
-
- if (sc->sc_pemu.sw_code) {
- audio_fill_silence(&sc->sc_pparams, cb->start, inp, cc);
- sc->sc_pemu.sw_code(sc->hw_hdl, inp, cc);
- } else
- audio_fill_silence(&sc->sc_pparams, cb->start, 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(void *v)
+audioopen(dev_t dev, int flags, int mode, struct proc *p)
{
- 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;
- int blksize;
+ struct audio_softc *sc;
int error;
- MUTEX_ASSERT_LOCKED(&audio_lock);
- if (!sc->sc_open)
- return; /* ignore interrupt if not open */
-
- if (sc->sc_pqui)
- return;
-
- blksize = cb->blksize;
-
- add_audio_randomness((long)cb);
-
- cb->outp += blksize;
- if (cb->outp >= cb->end)
- cb->outp = cb->start;
- cb->stamp += blksize;
- if (cb->mmapped) {
- DPRINTFN(5, ("audio_pint: mmapped outp=%p cc=%d inp=%p\n",
- cb->outp, blksize, cb->inp));
- if (!hw->trigger_output)
- (void)hw->start_output(sc->hw_hdl, cb->outp,
- 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 / 3) {
- 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) {
- printf("audio: play interrupt(%d) off absolute by %ld us (%lu) (LOST)\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 -= blksize;
- if (cb->used < blksize) {
- /* we don't have a full block to use */
- inp = cb->inp;
- cc = blksize - (inp - cb->start) % blksize;
- if (cb->pause)
- cb->pdrops += cc;
- else {
- cb->drops += cc;
- sc->sc_playdrop += cc;
- }
- 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, blksize);
- }
-
- DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->outp, blksize));
- if (!hw->trigger_output) {
- error = hw->start_output(sc->hw_hdl, cb->outp, blksize,
- audio_pint, (void *)sc);
- if (error) {
- /* XXX does this really help? */
- DPRINTF(("audio_pint restart failed: %d\n", error));
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ if (sc->ops == NULL)
+ error = ENXIO;
+ else {
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ error = audio_open(sc, flags);
+ break;
+ case AUDIO_DEV_AUDIOCTL:
+ case AUDIO_DEV_MIXER:
+ error = 0;
+ break;
+ default:
+ error = ENXIO;
}
}
-
- DPRINTFN(2, ("audio_pint: mode=%d pause=%d used=%d lowat=%d\n",
- sc->sc_mode, cb->pause, cb->used, cb->usedlow));
- if ((sc->sc_mode & AUMODE_PLAY) && !cb->pause &&
- cb->used <= cb->usedlow)
- audio_selwakeup(sc, 1);
-
- /* Possible to return one or more "phantom blocks" now. */
- if (!sc->sc_full_duplex && sc->sc_rchan)
- audio_selwakeup(sc, 0);
-
- /*
- * If quiesce requested, halt output when the ring buffer position
- * is at the beginning, because when the hardware is resumed, it's
- * buffer position is reset to the beginning. This will put
- * hardware and software positions in sync across a suspend cycle.
- */
- if (sc->sc_quiesce == AUDIO_QUIESCE_START && cb->outp == cb->start) {
- sc->sc_pqui = 1;
- audio_wake(&sc->sc_wchan);
- }
+ device_unref(&sc->dev);
+ return error;
}
-/*
- * 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(void *v)
+int
+audioclose(dev_t dev, int flags, int ifmt, struct proc *p)
{
- struct audio_softc *sc = v;
- struct audio_hw_if *hw = sc->hw_if;
- struct audio_ringbuffer *cb = &sc->sc_rr;
- int blksize;
+ struct audio_softc *sc;
int error;
- MUTEX_ASSERT_LOCKED(&audio_lock);
- if (!sc->sc_open)
- return; /* ignore interrupt if not open */
-
- if (sc->sc_rqui)
- return;
-
- add_audio_randomness((long)cb);
-
- blksize = cb->blksize;
-
- cb->inp += blksize;
- if (cb->inp >= cb->end)
- cb->inp = cb->start;
- cb->stamp += blksize;
- if (cb->mmapped) {
- DPRINTFN(2, ("audio_rint: mmapped inp=%p cc=%d\n",
- cb->inp, blksize));
- if (!hw->trigger_input)
- (void)hw->start_input(sc->hw_hdl, cb->inp, 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 += blksize;
- if (cb->pause) {
- DPRINTFN(1, ("audio_rint: pdrops %lu\n", cb->pdrops));
- cb->pdrops += blksize;
- cb->outp += blksize;
- if (cb->outp >= cb->end)
- cb->outp = cb->start;
- cb->used -= blksize;
- } else if (cb->used >= cb->usedhigh) {
- DPRINTFN(1, ("audio_rint: drops %lu\n", cb->drops));
- cb->drops += blksize;
- cb->outp += blksize;
- if (cb->outp >= cb->end)
- cb->outp = cb->start;
- cb->used -= blksize;
- }
-
- DPRINTFN(2, ("audio_rint: inp=%p cc=%d used=%d\n",
- cb->inp, blksize, cb->used));
- if (!hw->trigger_input) {
- error = hw->start_input(sc->hw_hdl, cb->inp, blksize,
- audio_rint, (void *)sc);
- if (error) {
- /* XXX does this really help? */
- DPRINTF(("audio_rint: restart failed: %d\n", error));
- }
- }
-
- audio_selwakeup(sc, 0);
-
- /*
- * If quiesce requested, halt input when the ring buffer position
- * is at the beginning, because when the hardware is resumed, it's
- * buffer position is reset to the beginning. This will put
- * hardware and software positions in sync across a suspend cycle.
- */
- if (sc->sc_quiesce == AUDIO_QUIESCE_START && cb->inp == cb->start) {
- sc->sc_rqui = 1;
- audio_wake(&sc->sc_rchan);
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ error = audio_close(sc);
+ break;
+ case AUDIO_DEV_MIXER:
+ case AUDIO_DEV_AUDIOCTL:
+ error = 0;
+ default:
+ error = ENXIO;
}
+ device_unref(&sc->dev);
+ return error;
}
int
-audio_check_params(struct audio_params *p)
+audioread(dev_t dev, struct uio *uio, int ioflag)
{
- if (p->channels < 1 || p->channels > 12)
- return (EINVAL);
-
- if (p->precision < 8 || p->precision > 32)
- return (EINVAL);
-
- 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;
- }
-
- 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
+ struct audio_softc *sc;
+ int error;
- switch (p->encoding) {
- case AUDIO_ENCODING_ADPCM:
- if (p->precision != 8)
- p->precision = 8;
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ error = audio_read(sc, uio, ioflag);
break;
- case AUDIO_ENCODING_ULAW:
- case AUDIO_ENCODING_ALAW:
- case AUDIO_ENCODING_SLINEAR_LE:
- case AUDIO_ENCODING_SLINEAR_BE:
- case AUDIO_ENCODING_ULINEAR_LE:
- case AUDIO_ENCODING_ULINEAR_BE:
- 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_DEV_AUDIOCTL:
+ case AUDIO_DEV_MIXER:
+ error = ENODEV;
break;
default:
- return (EINVAL);
- }
-
- return (0);
-}
-
-void
-audio_emu_setup(int mode, struct audio_params *p, struct audio_emu *e)
-{
- if (p->encoding == e->encoding) {
- e->sw_code = NULL;
- return;
- }
- switch (p->encoding) {
- case AUDIO_ENCODING_ULAW:
-#if BYTE_ORDER == LITTLE_ENDIAN
- e->encoding = AUDIO_ENCODING_SLINEAR_LE;
-#else
- e->encoding = AUDIO_ENCODING_SLINEAR_BE;
-#endif
- if (p->precision == 8) {
- e->sw_code = (mode == AUMODE_PLAY) ?
- slinear8_to_mulaw : mulaw_to_slinear8;
- break;
- } else if (p->precision == 24) {
- e->sw_code = (mode == AUMODE_PLAY) ?
- slinear24_to_mulaw24 : mulaw24_to_slinear24;
- break;
- }
- /* FALLTHROUGH */
- default:
- e->encoding = p->encoding;
- e->sw_code = NULL;
+ error = ENXIO;
}
-}
-
-int
-au_set_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int l, int 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_get_mute(struct audio_softc *sc, struct au_mixer_ports *ports, u_char *mute)
-{
- mixer_devinfo_t mi;
- mixer_ctrl_t ct;
- int error;
-
- *mute = 0;
-
- /* if no master, silently ignore request */
- if (ports->master == -1)
- return 0;
-
- mi.index = ports->master;
- error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
- if (error != 0)
- return error;
-
- /* master mute control should be the next device, if it exists */
- if (mi.next < 0)
- return 0;
-
- ct.dev = mi.next;
- ct.type = AUDIO_MIXER_ENUM;
- error = sc->hw_if->get_port(sc->hw_hdl, &ct);
- if (error != 0)
- return error;
-
- *mute = ct.un.ord;
-
+ device_unref(&sc->dev);
return error;
}
int
-au_set_mute(struct audio_softc *sc, struct au_mixer_ports *ports, u_char mute)
+audiowrite(dev_t dev, struct uio *uio, int ioflag)
{
- mixer_devinfo_t mi;
- mixer_ctrl_t ct;
+ struct audio_softc *sc;
int error;
- /* if no master, silently ignore request */
- if (ports->master == -1)
- return 0;
-
- mi.index = ports->master;
- error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
- if (error != 0)
- return error;
-
- /* master mute control should be the next device, if it exists */
- if (mi.next < 0)
- return 0;
-
- ct.dev = mi.next;
- ct.type = AUDIO_MIXER_ENUM;
- error = sc->hw_if->get_port(sc->hw_hdl, &ct);
- if (error != 0)
- return error;
-
- DPRINTF(("au_set_mute: mute (old): %d, mute (new): %d\n",
- ct.un.ord, mute));
-
- ct.un.ord = (mute != 0 ? 1 : 0);
- error = sc->hw_if->set_port(sc->hw_hdl, &ct);
-
- if (!error)
- mixer_signal(sc);
- return error;
-}
-
-int
-au_set_gain(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;
-
- /* XXX silently adjust to within limits or return EINVAL ? */
- if (gain > AUDIO_MAX_GAIN)
- gain = AUDIO_MAX_GAIN;
- else if (gain < AUDIO_MIN_GAIN)
- gain = AUDIO_MIN_GAIN;
-
- 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;
- }
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ error = audio_write(sc, uio, ioflag);
+ break;
+ case AUDIO_DEV_AUDIOCTL:
+ case AUDIO_DEV_MIXER:
+ error = ENODEV;
+ break;
+ default:
+ error = ENXIO;
}
- if (!error)
- mixer_signal(sc);
+ device_unref(&sc->dev);
return error;
}
int
-au_get_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int *l, int *r)
+audioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
+ struct audio_softc *sc;
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(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;
- }
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ error = audio_ioctl(sc, cmd, addr);
+ break;
+ case AUDIO_DEV_AUDIOCTL:
+ if (cmd == AUDIO_SETINFO && sc->mode != 0) {
+ error = EBUSY;
+ break;
}
+ error = audio_ioctl(sc, cmd, addr);
+ break;
+ case AUDIO_DEV_MIXER:
+ error = audio_ioctl_mixer(sc, cmd, addr);
+ break;
+ default:
+ error = ENXIO;
}
-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;
- }
+ device_unref(&sc->dev);
+ return error;
}
int
-au_set_port(struct audio_softc *sc, struct au_mixer_ports *ports, u_int port)
+audiopoll(dev_t dev, int events, struct proc *p)
{
- mixer_ctrl_t ct;
- int i, error;
-
- if (port == 0) /* allow this special case */
- return 0;
+ struct audio_softc *sc;
+ int revents;
- 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);
+ sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
+ if (sc == NULL)
+ return POLLERR;
+ switch (AUDIO_DEV(dev)) {
+ case AUDIO_DEV_SOUND:
+ case AUDIO_DEV_AUDIO:
+ revents = audio_poll(sc, events, p);
+ break;
+ case AUDIO_DEV_AUDIOCTL:
+ case AUDIO_DEV_MIXER:
+ revents = 0;
+ break;
+ default:
+ revents = 0;
}
- if (!error)
- mixer_signal(sc);
- return error;
+ device_unref(&sc->dev);
+ return revents;
}
+#if NWSKBD > 0
int
-au_get_port(struct audio_softc *sc, struct au_mixer_ports *ports)
+wskbd_initmute(struct audio_softc *sc, struct mixer_devinfo *vol)
{
- mixer_ctrl_t ct;
- int i, aumask;
+ struct mixer_devinfo mi;
- 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];
+ mi.index = vol->next;
+ for (mi.index = vol->next; mi.index != -1; mi.index = mi.next) {
+ if (sc->ops->query_devinfo(sc->arg, &mi) != 0)
+ break;
+ if (strcmp(mi.label.name, AudioNmute) == 0)
+ return mi.index;
}
- return aumask;
+ return -1;
}
int
-audiosetinfo(struct audio_softc *sc, struct audio_info *ai)
+wskbd_initvol(struct audio_softc *sc, struct wskbd_vol *vol, char *cn, char *dn)
{
- struct audio_prinfo *r = &ai->record, *p = &ai->play;
- int cleared;
- int setmode, modechange = 0;
- int error;
- struct audio_hw_if *hw = sc->hw_if;
- struct audio_params pp, rp;
- int np, nr;
- unsigned int blks;
- int oldpblksize, oldrblksize;
- int rbus, pbus;
- int fpb;
- int fs;
- u_int gain;
- u_char balance;
-
- 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->bps != ~0) {
- pp.bps = p->bps;
- np++;
- }
- if (r->bps != ~0) {
- rp.bps = r->bps;
- nr++;
- }
- if (p->msb != ~0) {
- pp.msb = p->msb;
- np++;
- }
- if (r->msb != ~0) {
- rp.msb = r->msb;
- 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);
- modechange = cleared = 1;
- setmode |= AUMODE_RECORD;
- }
- if (np) {
- if (!cleared)
- audio_clear(sc);
- modechange = cleared = 1;
- setmode |= AUMODE_PLAY;
- }
-
- if (ai->mode != ~0) {
- if (!cleared)
- audio_clear(sc);
- modechange = 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 (modechange) {
- int indep = hw->get_props(sc->hw_hdl) & AUDIO_PROP_INDEPENDENT;
- if (!indep) {
- if (setmode == AUMODE_RECORD)
- pp = rp;
- else
- rp = pp;
- }
- sc->sc_pemu.encoding = pp.encoding;
- sc->sc_remu.encoding = rp.encoding;
- error = hw->set_params(sc->hw_hdl, setmode,
- sc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD), &pp, &rp);
- if (error)
- return (error);
- if (sc->sc_mode & AUMODE_PLAY)
- audio_emu_setup(AUMODE_PLAY, &pp, &sc->sc_pemu);
- if (sc->sc_mode & AUMODE_RECORD)
- audio_emu_setup(AUMODE_RECORD, &rp, &sc->sc_remu);
- if (!indep) {
- if (setmode == AUMODE_RECORD) {
- pp.sample_rate = rp.sample_rate;
- pp.encoding = rp.encoding;
- pp.channels = rp.channels;
- pp.precision = rp.precision;
- pp.bps = rp.bps;
- pp.msb = rp.msb;
- } else if (setmode == AUMODE_PLAY) {
- rp.sample_rate = pp.sample_rate;
- rp.encoding = pp.encoding;
- rp.channels = pp.channels;
- rp.precision = pp.precision;
- rp.bps = pp.bps;
- rp.msb = pp.msb;
- }
- }
- sc->sc_rparams = rp;
- sc->sc_pparams = pp;
- }
-
- oldpblksize = sc->sc_pr.blksize;
- oldrblksize = sc->sc_rr.blksize;
-
- /*
- * allow old-style blocksize changes, for compatibility;
- * individual play/record block sizes have precedence
- */
- if (ai->blocksize != ~0) {
- if (r->block_size == ~0)
- r->block_size = ai->blocksize;
- if (p->block_size == ~0)
- p->block_size = ai->blocksize;
- }
- if (r->block_size != ~0) {
- sc->sc_rr.blkset = 0;
- if (!cleared)
- audio_clear(sc);
- cleared = 1;
- nr++;
- }
- if (p->block_size != ~0) {
- sc->sc_pr.blkset = 0;
- if (!cleared)
- audio_clear(sc);
- cleared = 1;
- np++;
- }
- if (nr) {
- if (r->block_size == ~0 || r->block_size == 0) {
- fpb = rp.sample_rate * audio_blk_ms / 1000;
- } else {
- fs = rp.channels * rp.bps;
- fpb = r->block_size / fs;
- }
- if (sc->sc_rr.blkset == 0)
- audio_set_blksize(sc, AUMODE_RECORD, fpb);
- }
- if (np) {
- if (p->block_size == ~0 || p->block_size == 0) {
- fpb = pp.sample_rate * audio_blk_ms / 1000;
- } else {
- fs = pp.channels * pp.bps;
- fpb = p->block_size / fs;
- }
- if (sc->sc_pr.blkset == 0)
- audio_set_blksize(sc, AUMODE_PLAY, fpb);
- }
- if (r->block_size != ~0 && r->block_size != 0)
- sc->sc_rr.blkset = 1;
- if (p->block_size != ~0 && p->block_size != 0)
- sc->sc_pr.blkset = 1;
-
-#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 = au_set_port(sc, &sc->sc_outports, p->port);
- if (error)
- return(error);
- }
- if (r->port != ~0) {
- if (!cleared)
- audio_clear(sc);
- cleared = 1;
+ struct mixer_devinfo dev, cls;
- error = au_set_port(sc, &sc->sc_inports, r->port);
- if (error)
- return(error);
- }
- if (p->gain != ~0) {
- 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) && (r->port != 0)) {
- 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) && (r->port != 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->output_muted != (u_char)~0) {
- error = au_set_mute(sc, &sc->sc_outports, ai->output_muted);
- 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] = ai->monitor_gain;
- error = sc->hw_if->set_port(sc->hw_hdl, &ct);
- if (error)
- return(error);
- }
-
- 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 (cleared) {
- 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 && !sc->sc_pr.pause)
- error = audiostartp(sc);
- if (!error &&
- (sc->sc_mode & AUMODE_RECORD) &&
- rbus && !sc->sc_rbus && !sc->sc_rr.pause)
- error = audiostartr(sc);
- err:
- 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;
- }
-
- if (p->pause != (u_char)~0) {
- sc->sc_pr.pause = p->pause;
- if (!p->pause && !sc->sc_pbus && (sc->sc_mode & AUMODE_PLAY)) {
- error = audiostartp(sc);
- if (error)
- return error;
- }
- }
- if (r->pause != (u_char)~0) {
- sc->sc_rr.pause = r->pause;
- if (!r->pause && !sc->sc_rbus && (sc->sc_mode & AUMODE_RECORD)) {
- error = audiostartr(sc);
- if (error)
- return error;
+ for (dev.index = 0; ; dev.index++) {
+ if (sc->ops->query_devinfo(sc->arg, &dev) != 0)
+ break;
+ cls.index = dev.mixer_class;
+ if (sc->ops->query_devinfo(sc->arg, &cls) != 0)
+ continue;
+ if (strcmp(cls.label.name, cn) == 0 &&
+ strcmp(dev.label.name, dn) == 0) {
+ vol->val = dev.index;
+ vol->nch = dev.un.v.num_channels;
+ vol->step = dev.un.v.delta > 8 ? dev.un.v.delta : 8;
+ vol->mute = wskbd_initmute(sc, &dev);
+ vol->val_pending = vol->mute_pending = 0;
+ DPRINTF("%s: wskbd using %s.%s, %s\n",
+ DEVNAME(sc), cn, dn, vol->mute >= -1 ? "mute control" : "");
+ return 1;
}
}
-
- return (0);
+ vol->val = vol->mute = -1;
+ return 0;
}
-int
-audiogetinfo(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;
-
- 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->bps = sc->sc_pparams.bps;
- r->bps = sc->sc_rparams.bps;
- p->msb = sc->sc_pparams.msb;
- r->msb = sc->sc_rparams.msb;
- p->encoding = sc->sc_pemu.encoding;
- r->encoding = sc->sc_remu.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;
-
- au_get_mute(sc, &sc->sc_outports, &ai->output_muted);
-
- 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;
-
- p->buffer_size = sc->sc_pr.bufsize;
- r->buffer_size = sc->sc_rr.bufsize;
+void
+wskbd_mixer_init(struct audio_softc *sc)
+{
+ static struct {
+ char *cn, *dn;
+ } spkr_names[] = {
+ {AudioCoutputs, AudioNmaster},
+ {AudioCinputs, AudioNdac},
+ {AudioCoutputs, AudioNdac},
+ {AudioCoutputs, AudioNoutput}
+ }, mic_names[] = {
+ {AudioCrecord, AudioNrecord},
+ {AudioCrecord, AudioNvolume},
+ {AudioCinputs, AudioNrecord},
+ {AudioCinputs, AudioNvolume},
+ {AudioCinputs, AudioNinput}
+ };
+ int i;
- r->block_size = sc->sc_rr.blksize;
- p->block_size = sc->sc_pr.blksize;
- if (p->block_size != 0) {
- ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize;
- ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize;
- } else {
- ai->hiwat = ai->lowat = 0;
+ if (sc->dev.dv_unit != 0) {
+ DPRINTF("%s: not configuring wskbd keys\n", DEVNAME(sc));
+ return;
}
- ai->blocksize = p->block_size; /* for compatibility, remove this */
- ai->mode = sc->sc_mode;
-
- return (0);
-}
-
-int
-audiogetbufinfo(struct audio_softc *sc, struct audio_bufinfo *info, int mode)
-{
- struct audio_ringbuffer *buf;
-
- if (mode == AUMODE_PLAY) {
- buf = &sc->sc_pr;
- } else {
- buf = &sc->sc_rr;
+ for (i = 0; i < sizeof(spkr_names) / sizeof(spkr_names[0]); i++) {
+ if (wskbd_initvol(sc, &sc->spkr,
+ spkr_names[i].cn, spkr_names[i].dn))
+ break;
}
-
- info->seek = buf->used;
- info->blksize = buf->blksize;
- if (buf->blksize != 0) {
- info->hiwat = buf->usedhigh / buf->blksize;
- info->lowat = buf->usedlow / buf->blksize;
- } else {
- info->hiwat = 0;
- info->lowat = 0;
+ for (i = 0; i < sizeof(mic_names) / sizeof(mic_names[0]); i++) {
+ if (wskbd_initvol(sc, &sc->mic,
+ mic_names[i].cn, mic_names[i].dn))
+ break;
}
-
- return (0);
}
-
-/*
- * Mixer driver
- */
-int
-mixer_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
- struct proc *p)
+void
+wskbd_mixer_update(struct audio_softc *sc, struct wskbd_vol *vol)
{
- DPRINTF(("mixer_open: dev=0x%x flags=0x%x sc=%p\n", dev, flags, sc));
-
- return (0);
-}
+ struct mixer_ctrl ctrl;
+ int val_pending, mute_pending, i, gain, error, s;
-/*
- * Remove a process from those to be signalled on mixer activity.
- */
-static void
-mixer_remove(struct audio_softc *sc, struct proc *p)
-{
- struct mixer_asyncs **pm, *m;
+ s = spltty();
+ val_pending = vol->val_pending;
+ vol->val_pending = 0;
+ mute_pending = vol->mute_pending;
+ vol->mute_pending = 0;
+ splx(s);
- for(pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) {
- if ((*pm)->proc == p) {
- m = *pm;
- *pm = m->next;
- free(m, M_DEVBUF, 0);
+ if (sc->ops == NULL)
+ return;
+ if (vol->mute >= 0 && mute_pending) {
+ ctrl.dev = vol->mute;
+ ctrl.type = AUDIO_MIXER_ENUM;
+ error = sc->ops->get_port(sc->arg, &ctrl);
+ if (error) {
+ DPRINTF("%s: get mute err = %d\n", DEVNAME(sc), error);
return;
}
- }
-}
-
-/*
- * Signal all processes waiting for the mixer.
- */
-static void
-mixer_signal(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_t dev, int flags, int 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);
-}
-
-int
-mixer_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
-{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct audio_hw_if *hw = sc->hw_if;
- int error = EINVAL;
-
- DPRINTF(("mixer_ioctl(%ld,'%c',%ld)\n",
- IOCPARM_LEN(cmd), (int)IOCGROUP(cmd), cmd & 0xff));
-
- /* Block when fully quiesced. No need to block earlier. */
- while (sc->sc_quiesce == AUDIO_QUIESCE_SILENT)
- tsleep(&sc->sc_quiesce, 0, "aud_qmi", 0);
-
- 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;
+ ctrl.un.ord = ctrl.un.ord ^ mute_pending;
+ DPRINTFN(1, "%s: wskbd mute setting to %d\n",
+ DEVNAME(sc), ctrl.un.ord);
+ error = sc->ops->set_port(sc->arg, &ctrl);
+ if (error) {
+ DPRINTF("%s: set mute err = %d\n", DEVNAME(sc), error);
+ return;
}
- 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"));
- ((mixer_devinfo_t *)addr)->un.v.delta = 0; /* default */
- 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:
- if (!(flag & FWRITE))
- return (EACCES);
- 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 = ENOTTY;
- break;
}
- DPRINTF(("mixer_ioctl(%ld,'%c',%ld) result %d\n",
- IOCPARM_LEN(cmd), (int)IOCGROUP(cmd), cmd & 0xff, error));
- return (error);
-}
-
-int
-audiokqfilter(dev_t dev, struct knote *kn)
-{
- int unit = AUDIOUNIT(dev);
- struct audio_softc *sc = audio_cd.cd_devs[unit];
- struct klist *klist;
-
- switch (kn->kn_filter) {
- case EVFILT_READ:
- klist = &sc->sc_rsel.si_note;
- kn->kn_fop = &audioread_filtops;
- break;
- case EVFILT_WRITE:
- klist = &sc->sc_wsel.si_note;
- kn->kn_fop = &audiowrite_filtops;
- break;
- default:
- return (EINVAL);
+ if (vol->val >= 0 && val_pending) {
+ ctrl.dev = vol->val;
+ ctrl.type = AUDIO_MIXER_VALUE;
+ ctrl.un.value.num_channels = vol->nch;
+ error = sc->ops->get_port(sc->arg, &ctrl);
+ if (error) {
+ DPRINTF("%s: get mute err = %d\n", DEVNAME(sc), error);
+ return;
+ }
+ for (i = 0; i < vol->nch; i++) {
+ gain = ctrl.un.value.level[i] + vol->step * val_pending;
+ if (gain > AUDIO_MAX_GAIN)
+ gain = AUDIO_MAX_GAIN;
+ if (gain < AUDIO_MIN_GAIN)
+ gain = AUDIO_MIN_GAIN;
+ ctrl.un.value.level[i] = gain;
+ DPRINTFN(1, "%s: wskbd level %d set to %d\n",
+ DEVNAME(sc), i, gain);
+ }
+ error = sc->ops->set_port(sc->arg, &ctrl);
+ if (error) {
+ DPRINTF("%s: set vol err = %d\n", DEVNAME(sc), error);
+ return;
+ }
}
- kn->kn_hook = (void *)sc;
-
- mtx_enter(&audio_lock);
- SLIST_INSERT_HEAD(klist, kn, kn_selnext);
- mtx_leave(&audio_lock);
-
- return (0);
}
void
-filt_audiordetach(struct knote *kn)
+wskbd_mixer_cb(void *addr)
{
- struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
+ struct audio_softc *sc = addr;
+ int s;
- mtx_enter(&audio_lock);
- SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext);
- mtx_leave(&audio_lock);
-}
-
-int
-filt_audioread(struct knote *kn, long hint)
-{
- struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
-
- return AUDIO_FILTREAD(sc);
-}
-
-void
-filt_audiowdetach(struct knote *kn)
-{
- struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
-
- mtx_enter(&audio_lock);
- SLIST_REMOVE(&sc->sc_wsel.si_note, kn, knote, kn_selnext);
- mtx_leave(&audio_lock);
-}
-
-int
-filt_audiowrite(struct knote *kn, long hint)
-{
- struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
-
- return AUDIO_FILTWRITE(sc);
+ wskbd_mixer_update(sc, &sc->spkr);
+ wskbd_mixer_update(sc, &sc->mic);
+ s = spltty();
+ sc->wskbd_taskset = 0;
+ splx(s);
+ device_unref(&sc->dev);
}
-#if NWSKBD > 0
-struct wskbd_vol_change {
- struct task t;
- long dir;
- long out;
-};
-
int
wskbd_set_mixervolume(long dir, long out)
{
struct audio_softc *sc;
- struct wskbd_vol_change *ch;
-
- if (audio_cd.cd_ndevs == 0 || (sc = audio_cd.cd_devs[0]) == NULL) {
- DPRINTF(("wskbd_set_mixervolume: audio_cd\n"));
- return (ENXIO);
- }
-
- ch = malloc(sizeof(*ch), M_TEMP, M_NOWAIT);
- if (ch == NULL)
- return (ENOMEM);
-
- task_set(&ch->t, wskbd_set_mixervolume_callback, ch);
- ch->dir = dir;
- ch->out = out;
- task_add(systq, &ch->t);
-
- return (0);
-}
-
-void
-wskbd_set_mixervolume_callback(void *xch)
-{
- struct wskbd_vol_change *ch = xch;
- struct audio_softc *sc;
- struct au_mixer_ports *ports;
- mixer_devinfo_t mi;
- u_char balance, mute;
- long dir, out;
- u_int gain;
- int error;
-
- dir = ch->dir;
- out = ch->out;
- free(ch, M_TEMP, sizeof(*ch));
+ struct wskbd_vol *vol;
sc = (struct audio_softc *)device_lookup(&audio_cd, 0);
if (sc == NULL)
- return;
-
- ports = out ? &sc->sc_outports : &sc->sc_inports;
-
- if (ports->master == -1) {
- DPRINTF(("%s: master == -1\n", __func__));
- goto done;
- }
-
- if (dir == 0) {
- /* Mute */
-
- error = au_get_mute(sc, ports, &mute);
- if (error != 0) {
- DPRINTF(("%s: au_get_mute: %d\n", __func__, error));
- goto done;
- }
-
- mute = !mute;
-
- error = au_set_mute(sc, ports, mute);
- if (error != 0) {
- DPRINTF(("%s: au_set_mute: %d\n", __func__, error));
- goto done;
- }
- } else {
- /* Raise or lower volume */
-
- mi.index = ports->master;
- error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
- if (error != 0) {
- DPRINTF(("%s: query_devinfo: %d\n", __func__, error));
- goto done;
- }
-
- au_get_gain(sc, ports, &gain, &balance);
-
- if (dir > 0)
- gain += mi.un.v.delta;
- else
- gain -= mi.un.v.delta;
-
- error = au_set_gain(sc, ports, gain, balance);
- if (error != 0) {
- DPRINTF(("%s: au_set_gain: %d\n", __func__, error));
- goto done;
- }
-
- /*
- * Unmute whenever we raise or lower the volume. This
- * mimicks the behaviour of the hardware volume
- * buttons on Thinkpads making sure that our software
- * mute state follows the hardware mute state.
- */
- error = au_set_mute(sc, ports, 0);
- if (error != 0) {
- DPRINTF(("%s: au_set_mute: %d\n", __func__, error));
- goto done;
- }
+ return ENODEV;
+ vol = out ? &sc->spkr : &sc->mic;
+ if (dir == 0)
+ vol->mute_pending ^= 1;
+ else
+ vol->val_pending += dir;
+ if (!sc->wskbd_taskset) {
+ task_set(&sc->wskbd_task, wskbd_mixer_cb, sc);
+ task_add(systq, &sc->wskbd_task);
+ sc->wskbd_taskset = 1;
}
-
-done:
- device_unref(&sc->dev);
+ return 0;
}
#endif /* NWSKBD > 0 */
diff --git a/sys/dev/audio_if.h b/sys/dev/audio_if.h
index 7c2500ce9d5..788ef0b5eba 100644
--- a/sys/dev/audio_if.h
+++ b/sys/dev/audio_if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: audio_if.h,v 1.29 2015/05/11 06:46:21 ratchov Exp $ */
+/* $OpenBSD: audio_if.h,v 1.30 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: audio_if.h,v 1.24 1998/01/10 14:07:25 tv Exp $ */
/*
@@ -46,7 +46,6 @@
* Generic interface to hardware driver.
*/
-struct audio_softc;
struct audio_device;
struct audio_encoding;
struct mixer_devinfo;
@@ -61,9 +60,6 @@ struct audio_params {
u_int channels; /* mono(1), stereo(2) */
};
-/* The default audio mode: 8 kHz mono mu-law */
-extern struct audio_params audio_default;
-
struct audio_hw_if {
int (*open)(void *, int); /* open hardware */
void (*close)(void *); /* close hardware */
@@ -148,27 +144,6 @@ struct audio_attach_args {
struct device *audio_attach_mi(struct audio_hw_if *, void *, struct device *);
int audioprint(void *, const char *);
-/* 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((x)) == SOUND_DEVICE)
-#define ISDEVAUDIO(x) (AUDIODEV((x)) == AUDIO_DEVICE)
-#define ISDEVAUDIOCTL(x) (AUDIODEV((x)) == AUDIOCTL_DEVICE)
-#define ISDEVMIXER(x) (AUDIODEV((x)) == MIXER_DEVICE)
-
-/*
- * USB Audio specification defines 12 channels:
- * L R C LFE Ls Rs Lc Rc S Sl Sr T
- */
-#define AUDIO_MAX_CHANNELS 12
-
extern struct mutex audio_lock;
#endif /* _SYS_DEV_AUDIO_IF_H_ */
-
diff --git a/sys/dev/isa/ad1848.c b/sys/dev/isa/ad1848.c
index ad7fdc01ab7..a1e985c205c 100644
--- a/sys/dev/isa/ad1848.c
+++ b/sys/dev/isa/ad1848.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ad1848.c,v 1.43 2015/05/11 06:52:35 ratchov Exp $ */
+/* $OpenBSD: ad1848.c,v 1.44 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: ad1848.c,v 1.45 1998/01/30 02:02:38 augustss Exp $ */
/*
@@ -140,6 +140,9 @@ static int ad1848_init_values[] = {
0 /* lower record count */
};
+static struct audio_params ad1848_audio_default =
+ {48000, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};
+
void ad1848_reset(struct ad1848_softc *);
int ad1848_set_speed(struct ad1848_softc *, u_long *);
void ad1848_mute_monitor(void *, int);
@@ -542,8 +545,8 @@ ad1848_attach(struct ad1848_softc *sc)
}
ad1848_reset(sc);
- pparams = audio_default;
- rparams = audio_default;
+ pparams = ad1848_audio_default;
+ rparams = ad1848_audio_default;
(void) ad1848_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0,
&pparams, &rparams);
diff --git a/sys/dev/isa/ess.c b/sys/dev/isa/ess.c
index 22b322e907c..1e42e6bc9b3 100644
--- a/sys/dev/isa/ess.c
+++ b/sys/dev/isa/ess.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ess.c,v 1.21 2015/05/11 06:46:21 ratchov Exp $ */
+/* $OpenBSD: ess.c,v 1.22 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: ess.c,v 1.44.4.1 1999/06/21 01:18:00 thorpej Exp $ */
/*
@@ -110,6 +110,9 @@ struct cfdriver ess_cd = {
NULL, "ess", DV_DULL
};
+struct audio_params ess_audio_default =
+ {44100, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};
+
int ess_setup_sc(struct ess_softc *, int);
int ess_open(void *, int);
@@ -929,8 +932,8 @@ essattach(struct ess_softc *sc)
* Set record and play parameters to default values defined in
* generic audio driver.
*/
- pparams = audio_default;
- rparams = audio_default;
+ pparams = ess_audio_default;
+ rparams = ess_audio_default;
ess_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
/* Do a hardware reset on the mixer. */
diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c
index 9d4ef0a393e..8b5146816d4 100644
--- a/sys/dev/isa/sbdsp.c
+++ b/sys/dev/isa/sbdsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sbdsp.c,v 1.35 2015/05/11 06:46:21 ratchov Exp $ */
+/* $OpenBSD: sbdsp.c,v 1.36 2015/06/25 06:43:46 ratchov Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -170,6 +170,9 @@ static struct sbmode sbrmodes[] = {
{ -1 }
};
+static struct audio_params sbdsp_audio_default =
+ {44100, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};
+
void sbversion(struct sbdsp_softc *);
void sbdsp_jazz16_probe(struct sbdsp_softc *);
void sbdsp_set_mixer_gain(struct sbdsp_softc *sc, int port);
@@ -348,8 +351,8 @@ sbdsp_attach(sc)
}
}
- pparams = audio_default;
- rparams = audio_default;
+ pparams = sbdsp_audio_default;
+ rparams = sbdsp_audio_default;
sbdsp_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
sbdsp_set_in_ports(sc, 1 << SB_MIC_VOL);
diff --git a/sys/dev/mulaw.c b/sys/dev/mulaw.c
index e34d0028f08..9a86fccf85e 100644
--- a/sys/dev/mulaw.c
+++ b/sys/dev/mulaw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mulaw.c,v 1.17 2015/06/04 06:03:11 jsg Exp $ */
+/* $OpenBSD: mulaw.c,v 1.18 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: mulaw.c,v 1.15 2001/01/18 20:28:20 jdolecek Exp $ */
/*
@@ -146,7 +146,7 @@ static const u_char lintomulaw[256] = {
};
void
-mulaw_to_slinear8(void *v, u_char *p, int cc)
+mulaw_to_slinear8(u_char *p, int cc)
{
/* Use the 16 bit table for 8 bits too. */
while (--cc >= 0) {
@@ -156,7 +156,7 @@ mulaw_to_slinear8(void *v, u_char *p, int cc)
}
void
-slinear8_to_mulaw(void *v, u_char *p, int cc)
+slinear8_to_mulaw(u_char *p, int cc)
{
while (--cc >= 0) {
*p = lintomulaw[*p ^ 0x80];
@@ -165,7 +165,7 @@ slinear8_to_mulaw(void *v, u_char *p, int cc)
}
void
-mulaw24_to_slinear24(void *v, u_char *p, int cc)
+mulaw24_to_slinear24(u_char *p, int cc)
{
int s, *q = (int *)p;
@@ -178,7 +178,7 @@ mulaw24_to_slinear24(void *v, u_char *p, int cc)
}
void
-slinear24_to_mulaw24(void *v, u_char *p, int cc)
+slinear24_to_mulaw24(u_char *p, int cc)
{
u_int *q = (u_int *)p;
diff --git a/sys/dev/mulaw.h b/sys/dev/mulaw.h
index 3626e6a451f..8723f7a1b4c 100644
--- a/sys/dev/mulaw.h
+++ b/sys/dev/mulaw.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mulaw.h,v 1.15 2015/05/11 06:46:21 ratchov Exp $ */
+/* $OpenBSD: mulaw.h,v 1.16 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: mulaw.h,v 1.11 1999/11/01 18:12:19 augustss Exp $ */
/*-
@@ -30,11 +30,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/* *_mts versions convert mono to stereo, in addition */
-
/* Convert 8-bit mu-law to/from 8 bit signed linear. */
-extern void mulaw_to_slinear8(void *, u_char *, int);
-extern void slinear8_to_mulaw(void *, u_char *, int);
+void mulaw_to_slinear8(u_char *, int);
+void slinear8_to_mulaw(u_char *, int);
/* Convert 24-bit mu-law to/from 24 bit signed linear. */
-void mulaw24_to_slinear24(void *, u_char *, int);
-void slinear24_to_mulaw24(void *, u_char *, int);
+void mulaw24_to_slinear24(u_char *, int);
+void slinear24_to_mulaw24(u_char *, int);
diff --git a/sys/dev/pci/envy.c b/sys/dev/pci/envy.c
index acf77cea608..a71b7c3f5ee 100644
--- a/sys/dev/pci/envy.c
+++ b/sys/dev/pci/envy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: envy.c,v 1.59 2015/03/14 03:38:48 jsg Exp $ */
+/* $OpenBSD: envy.c,v 1.60 2015/06/25 06:43:46 ratchov Exp $ */
/*
* Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
*
@@ -1881,27 +1881,7 @@ envy_set_params(void *self, int setmode, int usemode,
int
envy_round_blocksize(void *self, int blksz)
{
- struct envy_softc *sc = (struct envy_softc *)self;
- int mul, pmult, rmult;
-
- /*
- * XXX: audio(4) layer doesn't round to the sample size
- * until it's fixed, roll our own rounding
- */
-
- pmult = (sc->isht ? sc->card->noch : ENVY_PCHANS);
- if (pmult == 0)
- pmult = 1;
- rmult = (sc->isht ? sc->card->nich : ENVY_RCHANS);
- if (rmult == 0)
- rmult = 1;
- mul = pmult * rmult;
- while ((mul & 0x1f) != 0)
- mul <<= 1;
- blksz -= blksz % mul;
- if (blksz == 0)
- blksz = mul;
- return blksz;
+ return (blksz + 0x1f) & ~0x1f;
}
size_t
diff --git a/sys/sys/audioio.h b/sys/sys/audioio.h
index 1e72c131317..afbdd7a7a19 100644
--- a/sys/sys/audioio.h
+++ b/sys/sys/audioio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: audioio.h,v 1.21 2010/07/15 03:43:12 jakemsr Exp $ */
+/* $OpenBSD: audioio.h,v 1.22 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: audioio.h,v 1.24 1998/08/13 06:28:41 mrg Exp $ */
/*
@@ -48,21 +48,14 @@ struct audio_prinfo {
u_int bps; /* number of bytes/sample */
u_int msb; /* data alignment */
u_int encoding; /* data encoding (AUDIO_ENCODING_* below) */
- u_int gain; /* volume level */
- u_int port; /* selected I/O port */
- u_int seek; /* BSD extension */
- u_int avail_ports; /* available I/O ports */
+ u_int ispare2[4];
u_int buffer_size; /* total size audio buffer */
u_int block_size; /* size a block */
/* Current state of device: */
u_int samples; /* number of samples */
- u_int eof; /* End Of File (zero-size writes) counter */
+ u_int ispare[1];
u_char pause; /* non-zero if paused, zero to resume */
- u_char error; /* non-zero if underflow/overflow occurred */
- u_char waiting; /* non-zero if another process hangs in open */
- u_char balance; /* stereo channel balance */
- u_char cspare[2];
- u_char open; /* non-zero if currently open */
+ u_char cspare2[6];
u_char active; /* non-zero if I/O is currently active */
};
typedef struct audio_prinfo audio_prinfo_t;
@@ -70,32 +63,19 @@ 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 monitor_gain; /* input to output mix */
- /* BSD extensions */
- u_int blocksize; /* H/W read/write block size */
+ u_int ispare[2]; /* H/W read/write block size */
u_int hiwat; /* output high water mark */
u_int lowat; /* output low water mark */
- u_char output_muted; /* toggle play mute */
- u_char cspare[3];
+ u_char cspare[4];
u_int mode; /* current device mode */
#define AUMODE_PLAY 0x01
#define AUMODE_RECORD 0x02
-#define AUMODE_PLAY_ALL 0x04 /* don't do real-time correction */
};
typedef struct audio_info audio_info_t;
#define AUDIO_INITINFO(p) \
(void)memset((void *)(p), 0xff, sizeof(struct audio_info))
-struct audio_bufinfo {
- u_int blksize; /* block size */
- u_int hiwat; /* high water mark */
- u_int lowat; /* low water mark */
- u_int seek; /* current position */
-};
-typedef struct audio_bufinfo audio_bufinfo_t;
-
/*
* Parameter for the AUDIO_GETDEV ioctl to determine current
* audio devices.
@@ -109,8 +89,7 @@ typedef struct audio_device {
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 */
+ u_int unused[2];
} audio_offset_t;
/*
@@ -120,10 +99,6 @@ typedef struct audio_offset {
#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
@@ -131,15 +106,6 @@ typedef struct audio_offset {
#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
-#define AUDIO_ENCODING_MPEG_L3_STREAM 18
-#define AUDIO_ENCODING_MPEG_L3_PACKETS 19
-#define AUDIO_ENCODING_MPEG_L3_SYSTEM 20
typedef struct audio_encoding {
int index;
@@ -161,28 +127,11 @@ typedef struct audio_encoding {
#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)
#define AUDIO_SETINFO _IOWR('A', 22, struct audio_info)
#define AUDIO_DRAIN _IO('A', 23)
-#define AUDIO_FLUSH _IO('A', 24)
-#define AUDIO_WSEEK _IOR('A', 25, u_long)
#define AUDIO_RERROR _IOR('A', 26, int)
#define AUDIO_GETDEV _IOR('A', 27, struct audio_device)
#define AUDIO_GETENC _IOWR('A', 28, struct audio_encoding)
@@ -195,8 +144,6 @@ typedef struct audio_encoding {
#define AUDIO_PROP_FULLDUPLEX 0x01
#define AUDIO_PROP_MMAP 0x02
#define AUDIO_PROP_INDEPENDENT 0x04
-#define AUDIO_GETPRINFO _IOR('A', 35, struct audio_bufinfo)
-#define AUDIO_GETRRINFO _IOR('A', 36, struct audio_bufinfo)
/*
* Mixer device
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 2fd92e20979..fddc4bbd1d2 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.132 2015/05/17 16:55:51 deraadt Exp $ */
+/* $OpenBSD: conf.h,v 1.133 2015/06/25 06:43:46 ratchov Exp $ */
/* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */
/*-
@@ -324,7 +324,7 @@ extern struct cdevsw cdevsw[];
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,poll), \
- dev_init(c,n,mmap), 0, 0, dev_init(c,n,kqfilter) }
+ (dev_type_mmap((*))) enodev }
/* open, close, read, write, ioctl, poll, kqfilter */
#define cdev_midi_init(c,n) { \