Date: Thu, 12 May 2011 07:44:41 +0000 (UTC) From: Andriy Gapon <avg@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r221803 - head/sys/dev/sound/pcm Message-ID: <201105120744.p4C7ifiM025825@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105120744.p4C7ifiM025825>