4/4: I don't believe V4L2_BUF_FLAG_QUEUED and V4L2_BUF_FLAG_DONE
     flags are handled correctly in our uvideo driver.

According to linuxtv.org Buffers Chap 3. Input/Output Table 3.4
Buffer Flags:

https://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html#buffer-flags

V4L2_BUF_FLAG_QUEUED
        [The buffer] automatically moves to the outgoing queue
        after the buffer has been filled or displayed. Drivers
        set or clear this flag when the _QUERYBUF ioctl is
        called.
        After (successful) calling the _QBUF ioctl it is always
        set and after _DQBUF alwyas cleared

V4L2_BUF_FLAG_DONE
        When this flag is set, the buffer is currently on the
        outgoing queue, ready to be dequeued from the driver.
        Drivers set or clear this flag when the _QUERYBUF ioctl
        is called.
        After calling the _QBUF or _DQBUF it is always cleared.
        Of course a buffer cannot be on both queues at the same
        time, the _QUEUED and _DONE flag are mutually exclusive.
        They can be both cleared however, then the buffer is in
        "dequeued" state, in the application domain so to say.

This patch I'm a bit lukewarm on.

It gets rid of sc_mmap_cur used mainly in uvideo_mmap_queue()
looking to find a buffer which can be "queued".

Since the _QUEUE flag is never cleared in this driver, is it
potentially reusing a buffer which the client/consumer may not
yet be done with?

Also, I couldn't convince myself that the while()-loop searching
for this buffer, once the _QUEUE flag clearing is fixed, would
not end up in a situation where it would equal to sc_mmap_count
and never get past returning ENOMEM.

I think (but am not sure) the intent of sc_mmap_cur is to give
each buffer a fair chance at getting used. Where, w/o it, and
a fast client/consumer, it is possible that only the first few
buffers would get all the attention.

Or maybe I'm reading all this incorrectly.

Thoughts?


Index: uvideo.c
===================================================================
RCS file: /cvs/obsd/src/sys/dev/usb/uvideo.c,v
retrieving revision 1.185
diff -u -p -u -p -r1.185 uvideo.c
--- uvideo.c    17 May 2016 08:27:17 -0000      1.185
+++ uvideo.c    17 May 2016 23:08:32 -0000
@@ -78,7 +78,6 @@ struct uvideo_softc {
        size_t                                   sc_mmap_buffer_size;
        q_mmap                                   sc_mmap_q;
        int                                      sc_mmap_count;
-       int                                      sc_mmap_cur;
        int                                      sc_mmap_flag;
 
        struct vnode                            *sc_vp;
@@ -590,7 +589,6 @@ uvideo_attach_hook(struct device *self)
 
        /* init mmap queue */
        SIMPLEQ_INIT(&sc->sc_mmap_q);
-       sc->sc_mmap_cur = -1;
        sc->sc_mmap_count = 0;
 
        DPRINTF(1, "uvideo_attach: doing video_attach_mi\n");
@@ -1695,7 +1693,6 @@ uvideo_vs_free_frame(struct uvideo_softc
        while (!SIMPLEQ_EMPTY(&sc->sc_mmap_q))
                SIMPLEQ_REMOVE_HEAD(&sc->sc_mmap_q, q_frames);
 
-       sc->sc_mmap_cur = -1;
        sc->sc_mmap_count = 0;
 }
 
@@ -2208,44 +2205,45 @@ uvideo_vs_decode_stream_header_isight(st
 }
 
 int
+uvideo_find_queued(struct uvideo_softc *sc)
+{
+       int     i;
+       for (i = 0; i < sc->sc_mmap_count; ++i) {
+               if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
+                       continue;
+               if (sc->sc_mmap[i].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)
+                       break;
+       }
+       return (i == sc->sc_mmap_count) ? -1 : i;
+}
+
+int
 uvideo_mmap_queue(struct uvideo_softc *sc, uint8_t *buf, int len)
 {
-       if (sc->sc_mmap_cur < 0 || sc->sc_mmap_count == 0 ||
-           sc->sc_mmap_buffer == NULL)
+       int     i;
+
+       if (sc->sc_mmap_count == 0 || sc->sc_mmap_buffer == NULL)
                panic("%s: mmap buffers not allocated", __func__);
 
        /* 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) {
-               DPRINTF(1, "%s: %s: mmap queue is full!",
-                   DEVNAME(sc), __func__);
+       if (-1 == (i = uvideo_find_queued(sc)))
                return ENOMEM;
-       }
 
        /* copy frame to mmap buffer and report length */
-       bcopy(buf, sc->sc_mmap[sc->sc_mmap_cur].buf, len);
-       sc->sc_mmap[sc->sc_mmap_cur].v4l2_buf.bytesused = len;
+       bcopy(buf, sc->sc_mmap[i].buf, len);
+       sc->sc_mmap[i].v4l2_buf.bytesused = len;
 
        /* timestamp it */
-       getmicrotime(&sc->sc_mmap[sc->sc_mmap_cur].v4l2_buf.timestamp);
+       getmicrotime(&sc->sc_mmap[i].v4l2_buf.timestamp);
+
+       /* appropriately set/clear flags */
+       sc->sc_mmap[i].v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+       sc->sc_mmap[i].v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
 
        /* queue it */
-       SIMPLEQ_INSERT_TAIL(&sc->sc_mmap_q, &sc->sc_mmap[sc->sc_mmap_cur],
-           q_frames);
+       SIMPLEQ_INSERT_TAIL(&sc->sc_mmap_q, &sc->sc_mmap[i], q_frames);
        DPRINTF(2, "%s: %s: frame queued on index %d\n",
-           DEVNAME(sc), __func__, sc->sc_mmap_cur);
-
-       /* point to next mmap buffer */
-       sc->sc_mmap_cur++;
-       if (sc->sc_mmap_cur == sc->sc_mmap_count)
-               /* we reached the end of the mmap buffer, start over */
-               sc->sc_mmap_cur = 0;
+           DEVNAME(sc), __func__, i);
 
        wakeup(sc);
 
@@ -3214,9 +3212,6 @@ uvideo_reqbufs(void *v, struct v4l2_requ
        /* tell how many buffers we have really allocated */
        rb->count = sc->sc_mmap_count;
 
-       /* start with the first buffer */
-       sc->sc_mmap_cur = 0;
-
        return (0);
 }
 
@@ -3286,7 +3281,8 @@ uvideo_dqbuf(void *v, struct v4l2_buffer
 
        bcopy(&mmap->v4l2_buf, dqb, sizeof(struct v4l2_buffer));
 
-       mmap->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+       mmap->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_DONE|V4L2_BUF_FLAG_QUEUED);
+       mmap->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED;
 
        DPRINTF(2, "%s: %s: frame dequeued from index %d\n",
            DEVNAME(sc), __func__, mmap->v4l2_buf.index);

Reply via email to