svn commit: r221803 - head/sys/dev/sound/pcm
Andriy Gapon
avg at FreeBSD.org
Thu May 12 07:44:41 UTC 2011
Author: avg
Date: Thu May 12 07:44:41 2011
New Revision: 221803
URL: http://svn.freebsd.org/changeset/base/221803
Log:
dsp/pcm: allow to mmap both read and write buffers using the same fd
This brings our implementation in line with OSS specification for
systems that support mmap. The change should also improve compatibility
with OSS software not specifically written for FreeBSD, e.g. PulseAudio
OSS plugin.
Reviewed by: kib, jhb
MFC after: 1 week
Modified:
head/sys/dev/sound/pcm/dsp.c
Modified: head/sys/dev/sound/pcm/dsp.c
==============================================================================
--- head/sys/dev/sound/pcm/dsp.c Thu May 12 03:37:03 2011 (r221802)
+++ head/sys/dev/sound/pcm/dsp.c Thu May 12 07:44:41 2011 (r221803)
@@ -34,6 +34,11 @@
#include <sys/ctype.h>
#include <sys/sysent.h>
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
SND_DECLARE_FILE("$FreeBSD$");
static int dsp_mmap_allow_prot_exec = 0;
@@ -67,6 +72,7 @@ static d_write_t dsp_write;
static d_ioctl_t dsp_ioctl;
static d_poll_t dsp_poll;
static d_mmap_t dsp_mmap;
+static d_mmap_single_t dsp_mmap_single;
struct cdevsw dsp_cdevsw = {
.d_version = D_VERSION,
@@ -77,6 +83,7 @@ struct cdevsw dsp_cdevsw = {
.d_ioctl = dsp_ioctl,
.d_poll = dsp_poll,
.d_mmap = dsp_mmap,
+ .d_mmap_single = dsp_mmap_single,
.d_name = "dsp",
};
@@ -2187,6 +2194,16 @@ static int
dsp_mmap(struct cdev *i_dev, vm_ooffset_t offset, vm_paddr_t *paddr,
int nprot, vm_memattr_t *memattr)
{
+
+ /* XXX memattr is not honored */
+ *paddr = vtophys(offset);
+ return (0);
+}
+
+static int
+dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
+ vm_size_t size, struct vm_object **object, int nprot)
+{
struct snddev_info *d;
struct pcm_channel *wrch, *rdch, *c;
@@ -2205,51 +2222,48 @@ dsp_mmap(struct cdev *i_dev, vm_ooffset_
#else
if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1)
#endif
- return (-1);
+ return (EINVAL);
+
+ /*
+ * PROT_READ (alone) selects the input buffer.
+ * PROT_WRITE (alone) selects the output buffer.
+ * PROT_WRITE|PROT_READ together select the output buffer.
+ */
+ if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
+ return (EINVAL);
d = dsp_get_info(i_dev);
if (!DSP_REGISTERED(d, i_dev))
- return (-1);
+ return (EINVAL);
PCM_GIANT_ENTER(d);
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
- /*
- * XXX The linux api uses the nprot to select read/write buffer
- * our vm system doesn't allow this, so force write buffer.
- *
- * This is just a quack to fool full-duplex mmap, so that at
- * least playback _or_ recording works. If you really got the
- * urge to make _both_ work at the same time, avoid O_RDWR.
- * Just open each direction separately and mmap() it.
- *
- * Failure is not an option due to INVARIANTS check within
- * device_pager.c, which means, we have to give up one over
- * another.
- */
- c = (wrch != NULL) ? wrch : rdch;
-
+ c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
- offset >= sndbuf_getsize(c->bufsoft) ||
+ (*offset + size) > sndbuf_getsize(c->bufsoft) ||
(wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
(rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
PCM_GIANT_EXIT(d);
- return (-1);
+ return (EINVAL);
}
- /* XXX full-duplex quack. */
if (wrch != NULL)
wrch->flags |= CHN_F_MMAP;
if (rdch != NULL)
rdch->flags |= CHN_F_MMAP;
- *paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
+ *offset = (vm_ooffset_t)sndbuf_getbufofs(c->bufsoft, *offset);
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ *object = vm_pager_allocate(OBJT_DEVICE, i_dev,
+ size, nprot, *offset, curthread->td_ucred);
PCM_GIANT_LEAVE(d);
+ if (*object == NULL)
+ return (EINVAL);
return (0);
}
More information about the svn-src-head
mailing list