summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2010-07-14 21:24:34 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2010-07-14 21:24:34 +0000
commit81c8999e12495a51ea0759ead04090728988f96f (patch)
tree0b99fe64cc7c5765b7f231ee209b6627db76f3b6
parent8e83a9f87b54a93ba4328c58978fe4e21d3d3697 (diff)
implement poll() for video(4)
ok mglocker
-rw-r--r--sys/dev/usb/uvideo.c3
-rw-r--r--sys/dev/video.c102
-rw-r--r--sys/dev/videovar.h10
-rw-r--r--sys/sys/conf.h4
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 */