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 <[email protected]>
@@ -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)
/*