summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/uvideo.c110
-rw-r--r--sys/dev/usb/uvideo.h14
2 files changed, 111 insertions, 13 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index b45a7ef7710..8e5892d37f7 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.24 2008/06/06 19:14:45 mglocker Exp $ */
+/* $OpenBSD: uvideo.c,v 1.25 2008/06/07 22:14:57 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -99,6 +99,7 @@ void uvideo_vs_cb(usbd_xfer_handle, usbd_private_handle,
usbd_status);
int uvideo_vs_decode_stream_header(struct uvideo_softc *,
uint8_t *, int);
+int uvideo_mmap_queue(struct uvideo_softc *, uint8_t *, int);
#ifdef UVIDEO_DEBUG
void uvideo_dump_desc_all(struct uvideo_softc *);
void uvideo_dump_desc_vc_header(struct uvideo_softc *,
@@ -139,6 +140,9 @@ int uvideo_enum_input(void *, struct v4l2_input *);
int uvideo_s_input(void *, int);
int uvideo_reqbufs(void *, struct v4l2_requestbuffers *);
int uvideo_querybuf(void *, struct v4l2_buffer *);
+int uvideo_qbuf(void *, struct v4l2_buffer *);
+int uvideo_dqbuf(void *, struct v4l2_buffer *);
+int uvideo_streamon(void *, int);
int uvideo_try_fmt(void *, struct v4l2_format *);
caddr_t uvideo_mappage(void *, off_t, int);
@@ -173,7 +177,9 @@ struct video_hw_if uvideo_hw_if = {
uvideo_s_input, /* VIDIOC_S_INPUT */
uvideo_reqbufs, /* VIDIOC_REQBUFS */
uvideo_querybuf, /* VIDIOC_QUERYBUF */
- NULL, /* VIDIOC_DQBUF */
+ uvideo_qbuf, /* VIDIOC_QBUF */
+ uvideo_dqbuf, /* VIDIOC_DQBUF */
+ uvideo_streamon, /* VIDIOC_STREAMON */
uvideo_try_fmt, /* VIDIOC_TRY_FMT */
uvideo_mappage /* mmap */
};
@@ -248,7 +254,7 @@ uvideo_open(void *addr, int flags, int *size, uint8_t *buffer,
return(EIO);
usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_sample, sc);
#endif
- uvideo_vs_start(sc);
+ //uvideo_vs_start(sc);
return (0);
}
@@ -329,6 +335,11 @@ uvideo_attach(struct device * parent, struct device * self, void *aux)
if (error != USBD_NORMAL_COMPLETION)
return;
+ /* init mmap queue */
+ SIMPLEQ_INIT(&sc->sc_mmap_q);
+ sc->sc_mmap_cur = 0;
+ sc->sc_mmap_count = 0;
+
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, &sc->sc_dev);
DPRINTF(1, "uvideo_attach: doing video_attach_mi\n");
@@ -1194,6 +1205,7 @@ uvideo_vs_decode_stream_header(struct uvideo_softc *sc, uint8_t *frame,
usb_rem_task(sc->sc_udev, &sc->sc_task_write);
usb_add_task(sc->sc_udev, &sc->sc_task_write);
#endif
+#if 0
/*
* Copy video frame to upper layer buffer and call
* upper layer interrupt.
@@ -1201,6 +1213,8 @@ uvideo_vs_decode_stream_header(struct uvideo_softc *sc, uint8_t *frame,
*sc->sc_uplayer_fsize = fb->offset;
bcopy(fb->buf, sc->sc_uplayer_fbuffer, fb->offset);
sc->sc_uplayer_intr(sc->sc_uplayer_arg);
+#endif
+ uvideo_mmap_queue(sc, fb->buf, fb->offset);
} else {
DPRINTF(1, "%s: %s: sample too large, skipped!\n",
DEVNAME(sc), __func__);
@@ -1214,6 +1228,35 @@ uvideo_vs_decode_stream_header(struct uvideo_softc *sc, uint8_t *frame,
return (0);
}
+int
+uvideo_mmap_queue(struct uvideo_softc *sc, uint8_t *buf, int len)
+{
+ /* find a buffer which is ready for queueing */
+ while (sc->sc_mmap_cur < sc->sc_mmap_count) {
+ if (sc->sc_mmap[sc->sc_mmap_cur].v4l2_buf.flags &
+ V4L2_BUF_FLAG_QUEUED)
+ break;
+ /* not ready for queueing, try next */
+ sc->sc_mmap_cur++;
+ }
+ if (sc->sc_mmap_cur == sc->sc_mmap_count)
+ panic("uvideo_mmap_queue: mmap queue is full!");
+
+ /* copy frame to mmap buffer */
+ bcopy(buf, sc->sc_mmap[sc->sc_mmap_cur].buf, len);
+
+ /* queue it */
+ SIMPLEQ_INSERT_TAIL(&sc->sc_mmap_q, &sc->sc_mmap[sc->sc_mmap_cur],
+ q_frames);
+
+ /* point to next mmap buffer */
+ sc->sc_mmap_cur++;
+
+ wakeup(sc);
+
+ return (0);
+}
+
#ifdef UVIDEO_DEBUG
void
uvideo_dump_desc_all(struct uvideo_softc *sc)
@@ -1741,19 +1784,19 @@ int
uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb)
{
struct uvideo_softc *sc = v;
- int i, buf_count, buf_size, buf_size_total;
+ int i, buf_size, buf_size_total;
DPRINTF(1, "%s: count=%d\n", __func__, rb->count);
/* limit the buffers */
if (rb->count > UVIDEO_MAX_BUFFERS)
- buf_count = UVIDEO_MAX_BUFFERS;
+ sc->sc_mmap_count = UVIDEO_MAX_BUFFERS;
else
- buf_count = rb->count;
+ sc->sc_mmap_count = rb->count;
/* allocate the total mmap buffer */
buf_size = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize);
- buf_size_total = buf_count * buf_size;
+ buf_size_total = sc->sc_mmap_count * buf_size;
buf_size_total = round_page(buf_size_total); /* page align buffer */
sc->sc_mmap_buffer = malloc(buf_size_total, M_DEVBUF, M_NOWAIT);
if (sc->sc_mmap_buffer == NULL) {
@@ -1764,7 +1807,7 @@ uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb)
DEVNAME(sc), buf_size_total);
/* fill the v4l2_buffer structure */
- for (i = 0; i < buf_count; i++) {
+ for (i = 0; i < sc->sc_mmap_count; i++) {
sc->sc_mmap[i].buf = sc->sc_mmap_buffer + (i * buf_size);
sc->sc_mmap[i].v4l2_buf.index = i;
@@ -1784,7 +1827,7 @@ uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb)
}
/* tell how many buffers we have really allocated */
- rb->count = buf_count;
+ rb->count = sc->sc_mmap_count;
return (0);
}
@@ -1811,6 +1854,55 @@ uvideo_querybuf(void *v, struct v4l2_buffer *qb)
}
int
+uvideo_qbuf(void *v, struct v4l2_buffer *qb)
+{
+ struct uvideo_softc *sc = v;
+
+ sc->sc_mmap[qb->index].v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+ sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
+ sc->sc_mmap[qb->index].v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED;
+
+ return (0);
+}
+
+int
+uvideo_dqbuf(void *v, struct v4l2_buffer *dqb)
+{
+ struct uvideo_softc *sc = v;
+ struct uvideo_mmap *mmap;
+ int error;
+
+ if (SIMPLEQ_EMPTY(&sc->sc_mmap_q)) {
+ /* mmap queue is empty, block until first frame is queued */
+ error = tsleep(sc, PWAIT | PCATCH, "vid_mmap", 0);
+ if (error)
+ return (EINVAL);
+ }
+
+ mmap = SIMPLEQ_FIRST(&sc->sc_mmap_q);
+ if (mmap == NULL)
+ panic("uvideo_dqbuf: NULL pointer!");
+
+ bcopy(&mmap->v4l2_buf, dqb, sizeof(struct v4l2_buffer));
+
+ mmap->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
+
+ return (0);
+}
+
+int
+uvideo_streamon(void *v, int type)
+{
+ struct uvideo_softc *sc = v;
+
+ uvideo_vs_start(sc);
+
+ return (0);
+}
+
+int
uvideo_try_fmt(void *v, struct v4l2_format *fmt)
{
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h
index 33b1865bc13..1081b69e729 100644
--- a/sys/dev/usb/uvideo.h
+++ b/sys/dev/usb/uvideo.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.h,v 1.11 2008/06/06 19:14:45 mglocker Exp $ */
+/* $OpenBSD: uvideo.h,v 1.12 2008/06/07 22:14:58 mglocker Exp $ */
/*
* Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
@@ -17,6 +17,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <sys/queue.h>
#include <sys/videoio.h>
/*
@@ -353,15 +354,16 @@ struct uvideo_sample_buffer {
#define UVIDEO_MAX_BUFFERS 256
struct uvideo_mmap {
+ SIMPLEQ_ENTRY(uvideo_mmap) q_frames;
/*
* TODO
* Complete buffer so we can queue/dequeue video frames.
* Maybe we should use some queue macros for this?
*/
- uint8_t *buf;
-
- struct v4l2_buffer v4l2_buf;
+ uint8_t *buf;
+ struct v4l2_buffer v4l2_buf;
};
+typedef SIMPLEQ_HEAD(, uvideo_mmap) q_mmap;
struct uvideo_softc {
struct device sc_dev;
@@ -392,8 +394,12 @@ struct uvideo_softc {
u_int32_t quirks;
struct uvideo_sample_buffer sc_sample_buffer;
+
struct uvideo_mmap sc_mmap[UVIDEO_MAX_BUFFERS];
uint8_t *sc_mmap_buffer;
+ q_mmap sc_mmap_q;
+ int sc_mmap_count;
+ int sc_mmap_cur;
struct vnode *sc_vp;
struct usb_task sc_task_write;