Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Audio mmap now works with all devices as hw->mappage is no l...
details: https://anonhg.NetBSD.org/src/rev/6b5e15b850e6
branches: trunk
changeset: 823747:6b5e15b850e6
user: nat <nat%NetBSD.org@localhost>
date: Sun May 07 08:19:39 2017 +0000
description:
Audio mmap now works with all devices as hw->mappage is no longer used.
Audio ring buffers are now uvm objects.
This was made possibile with help from christos@ and much help and mmap
functions written by riastradh@.
diffstat:
share/man/man4/audio.4 | 6 +-
sys/dev/audio.c | 175 ++++++++++++++++++++++++++++++------------------
sys/dev/audiovar.h | 3 +-
3 files changed, 112 insertions(+), 72 deletions(-)
diffs (truncated from 429 to 300 lines):
diff -r 8be806e0ecb8 -r 6b5e15b850e6 share/man/man4/audio.4
--- a/share/man/man4/audio.4 Sun May 07 08:14:06 2017 +0000
+++ b/share/man/man4/audio.4 Sun May 07 08:19:39 2017 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: audio.4,v 1.78 2017/04/17 22:40:06 nat Exp $
+.\" $NetBSD: audio.4,v 1.79 2017/05/07 08:19:39 nat Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -190,7 +190,6 @@
.Xr write 2
calls, but it can also be mapped into user memory with
.Xr mmap 2
-(when supported by the device).
Once the device has been mapped it can no longer be accessed
by read or write; all access is by reading and writing to
the mapped memory.
@@ -776,6 +775,3 @@
.Sh HISTORY
Support for virtual channels and mixing first appeared in
.Nx 8.0 .
-.Sh BUGS
-.Xr mmap 2
-currently does not work and should be avoided.
diff -r 8be806e0ecb8 -r 6b5e15b850e6 sys/dev/audio.c
--- a/sys/dev/audio.c Sun May 07 08:14:06 2017 +0000
+++ b/sys/dev/audio.c Sun May 07 08:19:39 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.335 2017/05/06 00:13:25 nat Exp $ */
+/* $NetBSD: audio.c,v 1.336 2017/05/07 08:19:39 nat Exp $ */
/*-
* Copyright (c) 2016 Nathanial Sloss <nathanialsloss%yahoo.com.au@localhost>
@@ -148,7 +148,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.335 2017/05/06 00:13:25 nat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.336 2017/05/07 08:19:39 nat Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -179,6 +179,7 @@
#include <sys/intr.h>
#include <sys/kthread.h>
#include <sys/cpu.h>
+#include <sys/mman.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
@@ -231,8 +232,8 @@
int audio_poll(struct audio_softc *, int, struct lwp *,
struct virtual_channel *);
int audio_kqfilter(struct audio_chan *, struct knote *);
-paddr_t audiommap(dev_t, off_t, int, struct virtual_channel *);
-paddr_t audio_mmap(struct audio_softc *, off_t, int, struct virtual_channel *);
+int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *,
+ struct uvm_object **, int *, struct virtual_channel *);
static int audio_fop_mmap(struct file *, off_t *, size_t, int, int *, int *,
struct uvm_object **, int *);
@@ -1175,6 +1176,9 @@
const struct audio_hw_if *hw;
struct audio_chan *chan;
void *hdl;
+ vaddr_t vstart;
+ vsize_t vsize;
+ int error;
chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
hw = sc->hw_if;
@@ -1188,12 +1192,35 @@
if (hw->round_buffersize) {
bufsize = hw->round_buffersize(hdl, direction, bufsize);
}
- if (hw->allocm && (r == &chan->vc->sc_mpr || r == &chan->vc->sc_mrr))
+
+ if (hw->allocm && (r == &chan->vc->sc_mpr || r == &chan->vc->sc_mrr)) {
+ /* Hardware ringbuffer. No dedicated uvm object.*/
+ r->uobj = NULL;
r->s.start = hw->allocm(hdl, direction, bufsize);
- else
- r->s.start = kmem_zalloc(bufsize, KM_SLEEP);
- if (r->s.start == NULL)
- return ENOMEM;
+ if (r->s.start == NULL)
+ return ENOMEM;
+ } else {
+ /* Software ringbuffer. */
+ vstart = 0;
+
+ /* Get a nonzero multiple of PAGE_SIZE. */
+ vsize = roundup2(MAX(bufsize, PAGE_SIZE), PAGE_SIZE);
+
+ /* Create a uvm anonymous object. */
+ r->uobj = uao_create(vsize, 0);
+
+ /* Map it into the kernel virtual address space. */
+ error = uvm_map(kernel_map, &vstart, vsize, r->uobj, 0, 0,
+ UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE,
+ UVM_ADV_NORMAL, 0));
+ if (error) {
+ uao_detach(r->uobj); /* release reference */
+ r->uobj = NULL; /* paranoia */
+ return error;
+ }
+ r->s.start = (void *)vstart;
+ }
+
r->s.bufsize = bufsize;
return 0;
@@ -1203,6 +1230,8 @@
audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r)
{
struct audio_chan *chan;
+ vaddr_t vstart;
+ vsize_t vsize;
if (r->s.start == NULL)
return;
@@ -1210,10 +1239,25 @@
chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
if (sc->hw_if->freem && (r == &chan->vc->sc_mpr ||
- r == &chan->vc->sc_mrr))
+ r == &chan->vc->sc_mrr)) {
+ /* Hardware ringbuffer. */
+ KASSERT(r->uobj == NULL);
sc->hw_if->freem(sc->hw_hdl, r->s.start, r->s.bufsize);
- else
- kmem_free(r->s.start, r->s.bufsize);
+ } else {
+ /* Software ringbuffer. */
+ vstart = (vaddr_t)r->s.start;
+ vsize = roundup2(MAX(r->s.bufsize, PAGE_SIZE), PAGE_SIZE);
+
+ /*
+ * Unmap the kernel mapping. uvm_unmap releases the
+ * reference to the uvm object, and this should be the
+ * last virtual mapping of the uvm object, so no need
+ * to explicitly release (`detach') the object.
+ */
+ uvm_unmap(kernel_map, vstart, vsize);
+ r->uobj = NULL; /* paranoia */
+ }
+
r->s.start = NULL;
}
@@ -1646,17 +1690,18 @@
static int
audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
- int ioflag)
+ int flags)
{
struct audio_softc *sc;
struct virtual_channel *vc;
- int error;
+ int error, ioflag;
dev_t dev;
if (fp->f_audioctx == NULL)
return EIO;
dev = fp->f_audioctx->dev;
+ ioflag = 0;
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return error;
@@ -1685,17 +1730,18 @@
static int
audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
- int ioflag)
+ int flags)
{
struct audio_softc *sc;
struct virtual_channel *vc;
- int error;
+ int error, ioflag;
dev_t dev;
if (fp->f_audioctx == NULL)
return EIO;
dev = fp->f_audioctx->dev;
+ ioflag = 0;
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return error;
@@ -1874,41 +1920,21 @@
return rv;
}
-/* XXX:NS mmap is disabled. */
static int
audio_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
int *advicep, struct uvm_object **uobjp, int *maxprotp)
{
+ struct audio_softc *sc;
struct audio_chan *chan;
struct virtual_channel *vc;
dev_t dev;
-
- return -1;
+ int error;
chan = fp->f_audioctx;
dev = chan->dev;
vc = chan->vc;
-
- *offp = audiommap(dev, *offp, prot, vc);
- *maxprotp = prot;
- *advicep = UVM_ADV_RANDOM;
- return -1;
-}
-
-paddr_t
-audiommap(dev_t dev, off_t off, int prot, struct virtual_channel *vc)
-{
- struct audio_softc *sc;
- paddr_t error;
-
- return -1;
-
- /*
- * Acquire a reader lock. audio_mmap() will drop sc_lock
- * in order to allow the device's mmap routine to sleep.
- * Although not yet possible, we want to prevent memory
- * from being allocated or freed out from under us.
- */
+ error = 0;
+
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return 1;
device_active(sc->dev, DVA_SYSTEM); /* XXXJDM */
@@ -1916,17 +1942,17 @@
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- error = audio_mmap(sc, off, prot, vc);
+ error = audio_mmap(sc, offp, len, prot, flagsp, advicep,
+ uobjp, maxprotp, vc);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
- error = -1;
- break;
default:
- error = -1;
+ error = ENOTSUP;
break;
}
audio_exit(sc);
+
return error;
}
@@ -2446,7 +2472,8 @@
vc->sc_pbus = false;
}
if (sc->sc_opens == 1) {
- audio_drain(sc, SIMPLEQ_FIRST(&sc->sc_audiochan));
+ if (vc->sc_mpr.mmapped == false)
+ audio_drain(sc, SIMPLEQ_FIRST(&sc->sc_audiochan));
if (hw->drain)
(void)hw->drain(sc->hw_hdl);
hw->halt_output(sc->hw_hdl);
@@ -3364,13 +3391,12 @@
return 0;
}
-/* XXX:NS mmap to be fixed. */
-paddr_t
-audio_mmap(struct audio_softc *sc, off_t off, int prot,
- struct virtual_channel *vc)
+int
+audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot,
+ int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp,
+ struct virtual_channel *vc)
{
struct audio_ringbuffer *cb;
- paddr_t rv;
KASSERT(mutex_owned(sc->sc_lock));
@@ -3379,7 +3405,14 @@
DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot));
if (!(audio_get_props(sc) & AUDIO_PROP_MMAP))
- return -1;
+ return ENOTSUP;
+
+ if (*offp < 0)
+ return EINVAL;
+ if ((off_t)(*offp + len) < *offp) {
+ /* no offset wrapping */
+ return EOVERFLOW;
Home |
Main Index |
Thread Index |
Old Index