diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-07-14 21:24:34 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-07-14 21:24:34 +0000 |
commit | 81c8999e12495a51ea0759ead04090728988f96f (patch) | |
tree | 0b99fe64cc7c5765b7f231ee209b6627db76f3b6 | |
parent | 8e83a9f87b54a93ba4328c58978fe4e21d3d3697 (diff) |
implement poll() for video(4)
ok mglocker
-rw-r--r-- | sys/dev/usb/uvideo.c | 3 | ||||
-rw-r--r-- | sys/dev/video.c | 102 | ||||
-rw-r--r-- | sys/dev/videovar.h | 10 | ||||
-rw-r--r-- | sys/sys/conf.h | 4 |
4 files changed, 96 insertions, 23 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c index 513da57cd15..ba5bd60acbd 100644 --- a/sys/dev/usb/uvideo.c +++ b/sys/dev/usb/uvideo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.c,v 1.131 2010/04/27 03:38:34 marco Exp $ */ +/* $OpenBSD: uvideo.c,v 1.132 2010/07/14 21:24:33 jakemsr Exp $ */ /* * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> @@ -2094,6 +2094,7 @@ uvideo_mmap_queue(struct uvideo_softc *sc, uint8_t *buf, int len) sc->sc_mmap_cur = 0; wakeup(sc); + sc->sc_uplayer_intr(sc->sc_uplayer_arg); } void diff --git a/sys/dev/video.c b/sys/dev/video.c index 38be4417898..3502438e58b 100644 --- a/sys/dev/video.c +++ b/sys/dev/video.c @@ -1,4 +1,4 @@ -/* $OpenBSD: video.c,v 1.24 2009/10/13 19:33:16 pirofti Exp $ */ +/* $OpenBSD: video.c,v 1.25 2010/07/14 21:24:33 jakemsr Exp $ */ /* * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org> @@ -22,6 +22,7 @@ #include <sys/errno.h> #include <sys/ioctl.h> #include <sys/fcntl.h> +#include <sys/poll.h> #include <sys/device.h> #include <sys/vnode.h> #include <sys/kernel.h> @@ -105,7 +106,8 @@ videoopen(dev_t dev, int flags, int fmt, struct proc *p) return (EBUSY); sc->sc_open |= VIDEO_OPEN; - sc->sc_start_read = 0; + sc->sc_vidmode = VIDMODE_NONE; + sc->sc_frames_ready = 0; if (sc->hw_if->open != NULL) return (sc->hw_if->open(sc->hw_hdl, flags, &sc->sc_fsize, @@ -144,27 +146,35 @@ videoread(dev_t dev, struct uio *uio, int ioflag) if (sc->sc_dying) return (EIO); - /* start the stream */ - if (sc->hw_if->start_read && !sc->sc_start_read) { - error = sc->hw_if->start_read(sc->hw_hdl); - if (error) - return (error); - sc->sc_start_read = 1; - } + if (sc->sc_vidmode == VIDMODE_MMAP) + return (EBUSY); + /* start the stream if not already started */ + if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { + error = sc->hw_if->start_read(sc->hw_hdl); + if (error) + return (error); + sc->sc_vidmode = VIDMODE_READ; + } + DPRINTF(("resid=%d\n", uio->uio_resid)); - /* block userland read until a frame is ready */ - error = tsleep(sc, PWAIT | PCATCH, "vid_rd", 0); - if (error) - return (error); + if (sc->sc_frames_ready < 1) { + /* block userland read until a frame is ready */ + error = tsleep(sc, PWAIT | PCATCH, "vid_rd", 0); + if (sc->sc_dying) + error = EIO; + if (error) + return (error); + } - /* move the frame to userland */ + /* move no more than 1 frame to userland, as per specification */ if (sc->sc_fsize < uio->uio_resid) size = sc->sc_fsize; else size = uio->uio_resid; error = uiomove(sc->sc_fbuffer, size, uio); + sc->sc_frames_ready--; if (error) return (error); @@ -247,9 +257,16 @@ videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) (struct v4l2_buffer *)data); break; case VIDIOC_DQBUF: - if (sc->hw_if->dqbuf) - error = (sc->hw_if->dqbuf)(sc->hw_hdl, - (struct v4l2_buffer *)data); + if (!sc->hw_if->dqbuf) + break; + /* should have called mmap() before now */ + if (sc->sc_vidmode != VIDMODE_MMAP) { + error = EINVAL; + break; + } + error = (sc->hw_if->dqbuf)(sc->hw_hdl, + (struct v4l2_buffer *)data); + sc->sc_frames_ready--; break; case VIDIOC_STREAMON: if (sc->hw_if->streamon) @@ -288,6 +305,48 @@ videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) return (error); } +int +videopoll(dev_t dev, int events, struct proc *p) +{ + int unit = VIDEOUNIT(dev); + struct video_softc *sc; + int error, revents = 0; + + if (unit >= video_cd.cd_ndevs || + (sc = video_cd.cd_devs[unit]) == NULL) + return (POLLERR); + + if (sc->sc_dying) + return (POLLERR); + + DPRINTF(("%s: events=0x%x\n", __func__, events)); + + if (events & (POLLIN | POLLRDNORM)) { + if (sc->sc_frames_ready > 0) + revents |= events & (POLLIN | POLLRDNORM); + } + if (revents == 0) { + if (events & (POLLIN | POLLRDNORM)) + /* + * Start the stream in read() mode if not already + * started. If the user wanted mmap() mode, + * he should have called mmap() before now. + */ + if (sc->sc_vidmode == VIDMODE_NONE && + sc->hw_if->start_read) { + error = sc->hw_if->start_read(sc->hw_hdl); + if (error) + return (POLLERR); + sc->sc_vidmode = VIDMODE_READ; + } + selrecord(p, &sc->sc_rsel); + } + + DPRINTF(("%s: revents=0x%x\n", __func__, revents)); + + return (revents); +} + paddr_t videommap(dev_t dev, off_t off, int prot) { @@ -314,6 +373,7 @@ videommap(dev_t dev, off_t off, int prot) return (-1); if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) panic("videommap: invalid page"); + sc->sc_vidmode = VIDMODE_MMAP; #if defined(__powerpc__) || defined(__sparc64__) return (pa); @@ -342,7 +402,13 @@ video_intr(void *addr) struct video_softc *sc = (struct video_softc *)addr; DPRINTF(("video_intr sc=%p\n", sc)); - wakeup(sc); + if (sc->sc_vidmode != VIDMODE_NONE) + sc->sc_frames_ready++; + else + printf("%s: interrupt but no streams!\n", __func__); + if (sc->sc_vidmode == VIDMODE_READ) + wakeup(sc); + selwakeup(&sc->sc_rsel); } int diff --git a/sys/dev/videovar.h b/sys/dev/videovar.h index 678a6da1e35..8426dfd81fd 100644 --- a/sys/dev/videovar.h +++ b/sys/dev/videovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: videovar.h,v 1.6 2008/07/23 22:10:21 mglocker Exp $ */ +/* $OpenBSD: videovar.h,v 1.7 2010/07/14 21:24:33 jakemsr Exp $ */ /* * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org> @@ -30,7 +30,13 @@ struct video_softc { int sc_fsize; uint8_t *sc_fbuffer; - int sc_start_read; + int sc_vidmode; /* access mode */ +#define VIDMODE_NONE 0 +#define VIDMODE_MMAP 1 +#define VIDMODE_READ 2 + int sc_frames_ready; + + struct selinfo sc_rsel; /* read selector */ }; #endif /* _SYS_DEV_VIDEOVAR_H */ diff --git a/sys/sys/conf.h b/sys/sys/conf.h index c8e6b770d3f..67e387f7463 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.99 2010/07/08 20:15:01 deraadt Exp $ */ +/* $OpenBSD: conf.h,v 1.100 2010/07/14 21:24:33 jakemsr Exp $ */ /* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */ /*- @@ -441,7 +441,7 @@ void randomattach(void); #define cdev_video_init(c,n) { \ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ - (dev_type_stop((*))) enodev, 0, selfalse, \ + (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ dev_init(c,n,mmap) } /* open, close, write, ioctl */ |