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