Module Name: src Committed By: sborrill Date: Tue Sep 29 15:58:54 UTC 2009
Modified Files: src/share/man/man4: audio.4 src/sys/dev: audio.c audio_if.h src/sys/dev/pci/hdaudio: hdaudio_afg.c src/sys/sys: audioio.h Log Message: Add support for playback- or capture-only devices. Fixes PR 42050 To generate a diff of this commit: cvs rdiff -u -r1.69 -r1.70 src/share/man/man4/audio.4 cvs rdiff -u -r1.247 -r1.248 src/sys/dev/audio.c cvs rdiff -u -r1.65 -r1.66 src/sys/dev/audio_if.h cvs rdiff -u -r1.15 -r1.16 src/sys/dev/pci/hdaudio/hdaudio_afg.c cvs rdiff -u -r1.32 -r1.33 src/sys/sys/audioio.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man4/audio.4 diff -u src/share/man/man4/audio.4:1.69 src/share/man/man4/audio.4:1.70 --- src/share/man/man4/audio.4:1.69 Sat Jan 3 17:44:20 2009 +++ src/share/man/man4/audio.4 Tue Sep 29 15:58:54 2009 @@ -1,4 +1,4 @@ -.\" $NetBSD: audio.4,v 1.69 2009/01/03 17:44:20 christos Exp $ +.\" $NetBSD: audio.4,v 1.70 2009/09/29 15:58:54 sborrill Exp $ .\" .\" Copyright (c) 1996 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 3, 2009 +.Dd September 29, 2009 .Dt AUDIO 4 .Os .Sh NAME @@ -243,6 +243,10 @@ .It Dv AUDIO_PROP_INDEPENDENT the device can set the playing and recording encoding parameters independently. +.It Dv AUDIO_PROP_PLAYBACK +the device is capable of audio playback. +.It Dv AUDIO_PROP_CAPTURE +the device is capable of audio capture. .El .It Dv AUDIO_GETIOFFS (audio_offset_t) .It Dv AUDIO_GETOOFFS (audio_offset_t) Index: src/sys/dev/audio.c diff -u src/sys/dev/audio.c:1.247 src/sys/dev/audio.c:1.248 --- src/sys/dev/audio.c:1.247 Thu Sep 24 16:03:11 2009 +++ src/sys/dev/audio.c Tue Sep 29 15:58:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: audio.c,v 1.247 2009/09/24 16:03:11 sborrill Exp $ */ +/* $NetBSD: audio.c,v 1.248 2009/09/29 15:58:54 sborrill Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.247 2009/09/24 16:03:11 sborrill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.248 2009/09/29 15:58:54 sborrill Exp $"); #include "audio.h" #if NAUDIO > 0 @@ -192,6 +192,10 @@ static void audio_mixer_capture(struct audio_softc *); static void audio_mixer_restore(struct audio_softc *); +static int audio_get_props(struct audio_softc *); +static bool audio_can_playback(struct audio_softc *); +static bool audio_can_capture(struct audio_softc *); + static void audio_softintr_rd(void *); static void audio_softintr_wr(void *); @@ -315,41 +319,51 @@ } #endif - props = hwp->get_props(hdlp); + sc->hw_if = hwp; + sc->hw_hdl = hdlp; + sc->sc_dev = parent; + sc->sc_opencnt = 0; + sc->sc_writing = sc->sc_waitcomp = 0; + sc->sc_lastinfovalid = false; - aprint_naive("\n"); + props = audio_get_props(sc); if (props & AUDIO_PROP_FULLDUPLEX) aprint_normal(": full duplex"); else aprint_normal(": half duplex"); + if (props & AUDIO_PROP_PLAYBACK) + aprint_normal(", playback"); + if (props & AUDIO_PROP_CAPTURE) + aprint_normal(", capture"); if (props & AUDIO_PROP_MMAP) aprint_normal(", mmap"); if (props & AUDIO_PROP_INDEPENDENT) aprint_normal(", independent"); + aprint_naive("\n"); aprint_normal("\n"); - sc->hw_if = hwp; - sc->hw_hdl = hdlp; - sc->sc_dev = parent; - sc->sc_opencnt = 0; - sc->sc_writing = sc->sc_waitcomp = 0; - sc->sc_lastinfovalid = false; - - error = audio_alloc_ring(sc, &sc->sc_pr, AUMODE_PLAY, AU_RING_SIZE); - if (error) { - sc->hw_if = NULL; - aprint_error("audio: could not allocate play buffer\n"); - return; + if (audio_can_playback(sc)) { + error = audio_alloc_ring(sc, &sc->sc_pr, + AUMODE_PLAY, AU_RING_SIZE); + if (error) { + sc->hw_if = NULL; + aprint_error("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 = NULL; - aprint_error("audio: could not allocate record buffer\n"); - return; + if (audio_can_capture(sc)) { + error = audio_alloc_ring(sc, &sc->sc_rr, + AUMODE_RECORD, AU_RING_SIZE); + if (error) { + if (sc->sc_pr.s.start != 0) + audio_free_ring(sc, &sc->sc_pr); + sc->hw_if = NULL; + aprint_error("audio: could not allocate record buffer\n"); + return; + } } sc->sc_lastgain = 128; @@ -742,6 +756,8 @@ void audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r) { + if (r->s.start == 0) + return; if (sc->hw_if->freem) sc->hw_if->freem(sc->hw_hdl, r->s.start, M_DEVBUF); @@ -1301,41 +1317,49 @@ DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode)); hw = sc->hw_if; - audio_init_ringbuffer(sc, &sc->sc_rr, AUMODE_RECORD); - if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { - error = hw->init_input(sc->hw_hdl, sc->sc_rr.s.start, + if (audio_can_capture(sc)) { + audio_init_ringbuffer(sc, &sc->sc_rr, AUMODE_RECORD); + if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) { + error = hw->init_input(sc->hw_hdl, sc->sc_rr.s.start, sc->sc_rr.s.end - sc->sc_rr.s.start); - if (error) - return error; + if (error) + return error; + } } - audio_init_ringbuffer(sc, &sc->sc_pr, AUMODE_PLAY); - sc->sc_sil_count = 0; - if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { - error = hw->init_output(sc->hw_hdl, sc->sc_pr.s.start, + if (audio_can_playback(sc)) { + audio_init_ringbuffer(sc, &sc->sc_pr, AUMODE_PLAY); + sc->sc_sil_count = 0; + if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) { + error = hw->init_output(sc->hw_hdl, sc->sc_pr.s.start, sc->sc_pr.s.end - sc->sc_pr.s.start); - if (error) - return error; + if (error) + return error; + } } #ifdef AUDIO_INTR_TIME #define double u_long - sc->sc_pnintr = 0; - sc->sc_pblktime = (u_long)( - (double)sc->sc_pr.blksize * 100000 / - (double)(sc->sc_pparams.precision / NBBY * - 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)( - (double)sc->sc_rr.blksize * 100000 / - (double)(sc->sc_rparams.precision / NBBY * - 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)); + if (audio_can_playback(sc)) { + sc->sc_pnintr = 0; + sc->sc_pblktime = (u_long)( + (double)sc->sc_pr.blksize * 100000 / + (double)(sc->sc_pparams.precision / NBBY * + 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)); + } + if (audio_can_capture(sc)) { + sc->sc_rnintr = 0; + sc->sc_rblktime = (u_long)( + (double)sc->sc_rr.blksize * 100000 / + (double)(sc->sc_rparams.precision / NBBY * + 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)); + } #undef double #endif @@ -1347,18 +1371,24 @@ { /* set high at 100% */ - sc->sc_pr.usedhigh = sc->sc_pustream->end - sc->sc_pustream->start; - /* set low at 75% of usedhigh */ - sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; - if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) - sc->sc_pr.usedlow -= sc->sc_pr.blksize; - - sc->sc_rr.usedhigh = sc->sc_rustream->end - sc->sc_rustream->start - - sc->sc_rr.blksize; - sc->sc_rr.usedlow = 0; - DPRINTF(("%s: plow=%d phigh=%d rlow=%d rhigh=%d\n", __func__, - sc->sc_pr.usedlow, sc->sc_pr.usedhigh, - sc->sc_rr.usedlow, sc->sc_rr.usedhigh)); + if (audio_can_playback(sc)) { + sc->sc_pr.usedhigh = + sc->sc_pustream->end - sc->sc_pustream->start; + /* set low at 75% of usedhigh */ + sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; + if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) + sc->sc_pr.usedlow -= sc->sc_pr.blksize; + } + + if (audio_can_capture(sc)) { + sc->sc_rr.usedhigh = + sc->sc_rustream->end - sc->sc_rustream->start - + sc->sc_rr.blksize; + sc->sc_rr.usedlow = 0; + DPRINTF(("%s: plow=%d phigh=%d rlow=%d rhigh=%d\n", __func__, + sc->sc_pr.usedlow, sc->sc_pr.usedhigh, + sc->sc_rr.usedlow, sc->sc_rr.usedhigh)); + } } static inline int @@ -1436,7 +1466,7 @@ sc->sc_full_duplex = (flags & (FWRITE|FREAD)) == (FWRITE|FREAD) && - (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX); + (audio_get_props(sc) & AUDIO_PROP_FULLDUPLEX); mode = 0; if (flags & FREAD) { @@ -2251,7 +2281,7 @@ case AUDIO_SETFD: DPRINTF(("AUDIO_SETFD\n")); fd = *(int *)addr; - if (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX) { + if (audio_get_props(sc) & AUDIO_PROP_FULLDUPLEX) { if (hw->setfd) error = hw->setfd(sc->hw_hdl, fd); else @@ -2268,7 +2298,7 @@ case AUDIO_GETPROPS: DPRINTF(("AUDIO_GETPROPS\n")); - *(int *)addr = hw->get_props(sc->hw_hdl); + *(int *)addr = audio_get_props(sc); break; default: @@ -2439,7 +2469,7 @@ DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot)); hw = sc->hw_if; - if (!(hw->get_props(sc->hw_hdl) & AUDIO_PROP_MMAP) || !hw->mappage) + if (!(audio_get_props(sc) & AUDIO_PROP_MMAP) || !hw->mappage) return -1; #if 0 /* XXX @@ -2498,6 +2528,9 @@ sc->sc_rr.s.start, audio_stream_get_used(&sc->sc_rr.s), sc->sc_rr.usedhigh, sc->sc_rr.mmapped)); + if (!audio_can_capture(sc)) + return EINVAL; + if (sc->hw_if->trigger_input) error = sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.s.start, sc->sc_rr.s.end, sc->sc_rr.blksize, @@ -2524,6 +2557,9 @@ sc->sc_pr.s.start, used, sc->sc_pr.usedhigh, sc->sc_pr.blksize, sc->sc_pr.mmapped)); + if (!audio_can_playback(sc)) + return EINVAL; + if (!sc->sc_pr.mmapped && used < sc->sc_pr.blksize) { wakeup(&sc->sc_wchan); DPRINTF(("%s: wakeup and return\n", __func__)); @@ -3331,6 +3367,12 @@ rp.channels = r->channels; nr++; } + + if (!audio_can_capture(sc)) + nr = 0; + if (!audio_can_playback(sc)) + np = 0; + #ifdef AUDIO_DEBUG if (audiodebug && nr > 0) audio_print_params("audiosetinfo() Setting record params:", &rp); @@ -3382,7 +3424,7 @@ if (modechange) { int indep; - indep = hw->get_props(sc->hw_hdl) & AUDIO_PROP_INDEPENDENT; + indep = audio_get_props(sc) & AUDIO_PROP_INDEPENDENT; if (!indep) { if (setmode == AUMODE_RECORD) pp = rp; @@ -3716,12 +3758,15 @@ p->active = sc->sc_pbus; r->active = sc->sc_rbus; - p->buffer_size = sc->sc_pustream->bufsize; - r->buffer_size = sc->sc_rustream->bufsize; + p->buffer_size = sc->sc_pustream ? sc->sc_pustream->bufsize : 0; + r->buffer_size = sc->sc_rustream ? sc->sc_rustream->bufsize : 0; ai->blocksize = sc->sc_pr.blksize; - ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize; - ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize; + if (sc->sc_pr.blksize > 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; ai->mode = sc->sc_mode; return 0; @@ -4137,4 +4182,35 @@ splx(s); } +static int +audio_get_props(struct audio_softc *sc) +{ + const struct audio_hw_if *hw; + int props; + + hw = sc->hw_if; + props = hw->get_props(sc->hw_hdl); + + /* + * if neither playback nor capture properties are reported, + * assume both are supported by the device driver + */ + if ((props & (AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE)) == 0) + props |= (AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE); + + return props; +} + +static bool +audio_can_playback(struct audio_softc *sc) +{ + return audio_get_props(sc) & AUDIO_PROP_PLAYBACK ? true : false; +} + +static bool +audio_can_capture(struct audio_softc *sc) +{ + return audio_get_props(sc) & AUDIO_PROP_CAPTURE ? true : false; +} + #endif /* NAUDIO > 0 */ Index: src/sys/dev/audio_if.h diff -u src/sys/dev/audio_if.h:1.65 src/sys/dev/audio_if.h:1.66 --- src/sys/dev/audio_if.h:1.65 Tue Mar 4 18:23:44 2008 +++ src/sys/dev/audio_if.h Tue Sep 29 15:58:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: audio_if.h,v 1.65 2008/03/04 18:23:44 cube Exp $ */ +/* $NetBSD: audio_if.h,v 1.66 2009/09/29 15:58:54 sborrill Exp $ */ /* * Copyright (c) 1994 Havard Eidnes. @@ -86,13 +86,15 @@ static __inline int audio_stream_get_space(const audio_stream_t *s) { - return (s->end - s->start) - s->used; + if (s) + return (s->end - s->start) - s->used; + return 0; } static __inline int audio_stream_get_used(const audio_stream_t *s) { - return s->used; + return s ? s->used : 0; } static __inline uint8_t * Index: src/sys/dev/pci/hdaudio/hdaudio_afg.c diff -u src/sys/dev/pci/hdaudio/hdaudio_afg.c:1.15 src/sys/dev/pci/hdaudio/hdaudio_afg.c:1.16 --- src/sys/dev/pci/hdaudio/hdaudio_afg.c:1.15 Sun Sep 27 02:36:38 2009 +++ src/sys/dev/pci/hdaudio/hdaudio_afg.c Tue Sep 29 15:58:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: hdaudio_afg.c,v 1.15 2009/09/27 02:36:38 jmcneill Exp $ */ +/* $NetBSD: hdaudio_afg.c,v 1.16 2009/09/29 15:58:54 sborrill Exp $ */ /* * Copyright (c) 2009 Precedence Technologies Ltd <supp...@precedence.co.uk> @@ -60,7 +60,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hdaudio_afg.c,v 1.15 2009/09/27 02:36:38 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hdaudio_afg.c,v 1.16 2009/09/29 15:58:54 sborrill Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -3323,13 +3323,11 @@ int bufsize; st = (mode == AUMODE_PLAY) ? ad->ad_playback : ad->ad_capture; -#ifdef DIAGNOSTIC if (st == NULL) { - hda_error(ad->ad_sc, + hda_trace(ad->ad_sc, "round_blocksize called for invalid stream\n"); - return 256; + return 128; } -#endif /* Multiple of 128 */ blksize &= ~128; @@ -3583,8 +3581,21 @@ static int hdaudio_afg_get_props(void *opaque) { + struct hdaudio_audiodev *ad = opaque; + int props = 0; + + if (ad->ad_playback) + props |= AUDIO_PROP_PLAYBACK; + if (ad->ad_capture) + props |= AUDIO_PROP_CAPTURE; + if (ad->ad_playback && ad->ad_capture) { + props |= AUDIO_PROP_FULLDUPLEX; + props |= AUDIO_PROP_INDEPENDENT; + } + /* TODO: AUDIO_PROP_MMAP */ - return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; + + return props; } static int Index: src/sys/sys/audioio.h diff -u src/sys/sys/audioio.h:1.32 src/sys/sys/audioio.h:1.33 --- src/sys/sys/audioio.h:1.32 Mon Jun 11 13:05:47 2007 +++ src/sys/sys/audioio.h Tue Sep 29 15:58:54 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: audioio.h,v 1.32 2007/06/11 13:05:47 joerg Exp $ */ +/* $NetBSD: audioio.h,v 1.33 2009/09/29 15:58:54 sborrill Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -185,6 +185,8 @@ #define AUDIO_PROP_FULLDUPLEX 0x01 #define AUDIO_PROP_MMAP 0x02 #define AUDIO_PROP_INDEPENDENT 0x04 +#define AUDIO_PROP_PLAYBACK 0x10 +#define AUDIO_PROP_CAPTURE 0x20 #define AUDIO_GETBUFINFO _IOR('A', 35, struct audio_info) /*