From 8069d0dbe3969ba410e2a7148cb59e4670241e30 Mon Sep 17 00:00:00 2001 From: Marcus Glocker Date: Thu, 5 Jun 2008 20:50:29 +0000 Subject: Add some first mmap bits. Help by miod@ --- sys/dev/usb/uvideo.c | 102 +++++++++++++++++++++++++++++++++++++++++++++------ sys/dev/usb/uvideo.h | 15 +++++++- sys/dev/video.c | 47 +++++++++++++++++------- sys/dev/video_if.h | 7 ++-- 4 files changed, 143 insertions(+), 28 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c index 0fa8ef73151..d82bf4eb2f5 100644 --- a/sys/dev/usb/uvideo.c +++ b/sys/dev/usb/uvideo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.c,v 1.22 2008/05/30 06:37:38 mglocker Exp $ */ +/* $OpenBSD: uvideo.c,v 1.23 2008/06/05 20:50:28 mglocker Exp $ */ /* * Copyright (c) 2008 Robert Nagy @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -134,10 +135,12 @@ int uvideo_querycap(void *, struct v4l2_capability *); int uvideo_enum_fmt(void *, struct v4l2_fmtdesc *); int uvideo_s_fmt(void *, struct v4l2_format *); int uvideo_g_fmt(void *, struct v4l2_format *); -int uvideo_reqbufs(void *, struct v4l2_requestbuffers *); 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_try_fmt(void *, struct v4l2_format *); +caddr_t uvideo_mappage(void *, off_t, int); #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) @@ -166,12 +169,13 @@ struct video_hw_if uvideo_hw_if = { uvideo_enum_fmt, /* VIDIOC_ENUM_FMT */ uvideo_s_fmt, /* VIDIOC_S_FMT */ uvideo_g_fmt, /* VIDIOC_G_FMT */ - uvideo_reqbufs, /* VIDIOC_REQBUFS */ uvideo_enum_input, /* VIDIOC_ENUMINPUT */ uvideo_s_input, /* VIDIOC_S_INPUT */ - NULL, /* VIDIOC_QBUF */ + uvideo_reqbufs, /* VIDIOC_REQBUFS */ + uvideo_querybuf, /* VIDIOC_QUERYBUF */ NULL, /* VIDIOC_DQBUF */ - uvideo_try_fmt /* VIDIOC_TRY_FMT */ + uvideo_try_fmt, /* VIDIOC_TRY_FMT */ + uvideo_mappage /* mmap */ }; int @@ -1710,12 +1714,6 @@ uvideo_g_fmt(void *v, struct v4l2_format *fmt) return (0); } -int -uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb) -{ - return (0); -} - int uvideo_enum_input(void *v, struct v4l2_input *input) { @@ -1739,6 +1737,77 @@ uvideo_s_input(void *v, int input) return (0); } +int +uvideo_reqbufs(void *v, struct v4l2_requestbuffers *rb) +{ + struct uvideo_softc *sc = v; + int i, buf_count, 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; + else + buf_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 = round_page(buf_size_total); /* page align buffer */ + sc->sc_mmap_buffer.buf = malloc(buf_size_total, M_DEVBUF, M_NOWAIT); + if (sc->sc_mmap_buffer.buf == NULL) { + printf("%s: can't allocate mmap buffer!\n", DEVNAME(sc)); + return (EINVAL); + } + DPRINTF(1, "%s: allocated %d bytes mmap buffer\n", + DEVNAME(sc), buf_size_total); + + /* fill the v4l2_buffer structure */ + for (i = 0; i < buf_count; i++) { + sc->sc_mmap_buffer.v4l2_buf[i].index = i; + sc->sc_mmap_buffer.v4l2_buf[i].m.offset = i * buf_size; + sc->sc_mmap_buffer.v4l2_buf[i].length = buf_size; + sc->sc_mmap_buffer.v4l2_buf[i].type = + V4L2_BUF_TYPE_VIDEO_CAPTURE; + sc->sc_mmap_buffer.v4l2_buf[i].sequence = 0; + sc->sc_mmap_buffer.v4l2_buf[i].field = V4L2_FIELD_NONE; + sc->sc_mmap_buffer.v4l2_buf[i].memory = V4L2_MEMORY_MMAP; + sc->sc_mmap_buffer.v4l2_buf[i].flags = V4L2_MEMORY_MMAP; + DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n", + DEVNAME(sc), __func__, + sc->sc_mmap_buffer.v4l2_buf[i].index, + sc->sc_mmap_buffer.v4l2_buf[i].m.offset, + sc->sc_mmap_buffer.v4l2_buf[i].length); + } + + /* tell how many buffers we have really allocated */ + rb->count = buf_count; + + return (0); +} + +int +uvideo_querybuf(void *v, struct v4l2_buffer *qb) +{ + struct uvideo_softc *sc = v; + + if (qb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + qb->memory != V4L2_MEMORY_MMAP) + return (EINVAL); + + bcopy(&sc->sc_mmap_buffer.v4l2_buf[qb->index], qb, + sizeof(struct v4l2_buffer)); + + DPRINTF(1, "%s: %s: index=%d, offset=%d, length=%d\n", + DEVNAME(sc), __func__, + qb->index, + qb->m.offset, + qb->length); + + return (0); +} + int uvideo_try_fmt(void *v, struct v4l2_format *fmt) { @@ -1747,3 +1816,14 @@ uvideo_try_fmt(void *v, struct v4l2_format *fmt) return (0); } + +caddr_t +uvideo_mappage(void *v, off_t off, int prot) +{ + struct uvideo_softc *sc = v; + caddr_t p; + + p = sc->sc_mmap_buffer.buf + off; + + return (p); +} diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h index efb996ea0f2..593ea01138c 100644 --- a/sys/dev/usb/uvideo.h +++ b/sys/dev/usb/uvideo.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.h,v 1.9 2008/05/27 17:47:28 mglocker Exp $ */ +/* $OpenBSD: uvideo.h,v 1.10 2008/06/05 20:50:28 mglocker Exp $ */ /* * Copyright (c) 2007 Robert Nagy @@ -351,6 +351,18 @@ struct uvideo_sample_buffer { uint8_t *buf; }; +#define UVIDEO_MAX_BUFFERS 256 +struct uvideo_mmap_buffer { + /* + * 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[UVIDEO_MAX_BUFFERS]; +}; + struct uvideo_softc { struct device sc_dev; usbd_device_handle sc_udev; @@ -380,6 +392,7 @@ struct uvideo_softc { u_int32_t quirks; struct uvideo_sample_buffer sc_sample_buffer; + struct uvideo_mmap_buffer sc_mmap_buffer; struct vnode *sc_vp; struct usb_task sc_task_write; diff --git a/sys/dev/video.c b/sys/dev/video.c index 4131a767f7d..e72ca70778d 100644 --- a/sys/dev/video.c +++ b/sys/dev/video.c @@ -1,4 +1,4 @@ -/* $OpenBSD: video.c,v 1.5 2008/05/30 06:37:38 mglocker Exp $ */ +/* $OpenBSD: video.c,v 1.6 2008/06/05 20:50:28 mglocker Exp $ */ /* * Copyright (c) 2008 Robert Nagy * @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -179,11 +181,6 @@ videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) error = (sc->hw_if->g_fmt)(sc->hw_hdl, (struct v4l2_format *)data); break; - case VIDIOC_REQBUFS: - if (sc->hw_if->reqbufs) - error = (sc->hw_if->reqbufs)(sc->hw_hdl, - (struct v4l2_requestbuffers *)data); - break; case VIDIOC_ENUMINPUT: if (sc->hw_if->enum_input) error = (sc->hw_if->enum_input)(sc->hw_hdl, @@ -194,9 +191,17 @@ videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) error = (sc->hw_if->s_input)(sc->hw_hdl, (int)*data); break; + case VIDIOC_REQBUFS: + if (sc->hw_if->reqbufs) + error = (sc->hw_if->reqbufs)(sc->hw_hdl, + (struct v4l2_requestbuffers *)data); + break; case VIDIOC_QUERYBUF: + if (sc->hw_if->querybuf) + error = (sc->hw_if->querybuf)(sc->hw_hdl, + (struct v4l2_buffer *)data); break; - case VIDIOC_QBUF: + case VIDIOC_DQBUF: break; case VIDIOC_TRY_FMT: if (sc->hw_if->try_fmt) @@ -215,18 +220,34 @@ videommap(dev_t dev, off_t off, int prot) { struct video_softc *sc; int unit; + caddr_t p; + paddr_t pa; + + DPRINTF(("%s: off=%d, prot=%d\n", __func__, off, prot)); unit = VIDEOUNIT(dev); if (unit >= video_cd.cd_ndevs || (sc = video_cd.cd_devs[unit]) == NULL) - return (ENXIO); + return (-1); if (sc->sc_dying) - return (EIO); - - /* TODO */ - - return (0); + return (-1); + + if (sc->hw_if->mappage == NULL) + return (-1); + + p = sc->hw_if->mappage(sc->hw_hdl, off, prot); + if (p == NULL) + return (-1); + if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) + panic("videommap: invalid page"); + pmap_update(pmap_kernel()); + +#if defined(__powerpc__) || defined(__sparc64__) + return (pa); +#else + return (atop(pa)); +#endif } /* diff --git a/sys/dev/video_if.h b/sys/dev/video_if.h index eb672e75302..492ae2d96e9 100644 --- a/sys/dev/video_if.h +++ b/sys/dev/video_if.h @@ -1,4 +1,4 @@ -/* $OpenBSD: video_if.h,v 1.5 2008/05/30 06:37:38 mglocker Exp $ */ +/* $OpenBSD: video_if.h,v 1.6 2008/06/05 20:50:28 mglocker Exp $ */ /* * Copyright (c) 2008 Robert Nagy * @@ -38,12 +38,13 @@ struct video_hw_if { int (*enum_fmt)(void *, struct v4l2_fmtdesc *); int (*s_fmt)(void *, struct v4l2_format *); int (*g_fmt)(void *, struct v4l2_format *); - int (*reqbufs)(void *, struct v4l2_requestbuffers *); int (*enum_input)(void *, struct v4l2_input *); int (*s_input)(void *, int); - int (*qbuf)(void *, struct v4l2_buffer *); + int (*reqbufs)(void *, struct v4l2_requestbuffers *); + int (*querybuf)(void *, struct v4l2_buffer *); int (*dqbuf)(void *, struct v4l2_buffer *); int (*try_fmt)(void *, struct v4l2_format *); + caddr_t (*mappage)(void *, off_t, int); }; struct video_attach_args { -- cgit v1.2.3