Index: sys/dev/usb/uvideo.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uvideo.c,v
retrieving revision 1.14
diff -u -u -r1.14 uvideo.c
--- sys/dev/usb/uvideo.c        20 Sep 2008 15:55:38 -0000      1.14
+++ sys/dev/usb/uvideo.c        20 Sep 2008 17:19:16 -0000
@@ -64,6 +64,7 @@
#include <sys/vnode.h>
#include <sys/poll.h>
#include <sys/queue.h> /* SLIST */
+#include <sys/kthread.h>

#include <sys/videoio.h>
#include <dev/video_if.h>
@@ -80,6 +81,7 @@
#endif

#define UVIDEO_NXFERS  3
+#define PRI_UVIDEO     PRI_BIO

/* #define UVIDEO_DISABLE_MJPEG */

@@ -243,7 +245,11 @@
       char                    *sc_devname;

       device_ptr_t            sc_videodev;
+       char                    sc_running;

+       kcondvar_t              sc_cv;
+       kmutex_t                sc_mtx;
+
       int                     sc_dying;
       uvideo_state            sc_state;

@@ -684,6 +690,64 @@
       return rv;
}

+static void
+uvideo_transfer_thread(void *opaque)
+{
+       struct uvideo_stream *vs = opaque;
+       struct uvideo_softc *sc = vs->vs_parent;
+       struct uvideo_bulk_xfer *bx = &vs->vs_xfer.bulk;
+       const uvideo_payload_header_t *hdr;
+       int error, frameno;
+       struct video_payload payload;
+       uint32_t len = bx->bx_buflen;
+
+       frameno = -1;
+
+       printf("uvideo_stream_recv_bulk_start");
+       while (sc->sc_running) {
+               /*
+                * The payload can only be smaller than
+                * bx_buflen on the last payload. If this is the
+                * last one then we are done.
+                */
+               if (len < bx->bx_buflen)
+                       continue;
+
+               error = usbd_bulk_transfer(bx->bx_xfer, bx->bx_pipe,
+                           USBD_SHORT_XFER_OK|USBD_NO_COPY, 50000,
+                           bx->bx_buffer, &len, "uvideorb");
+               if (len >= sizeof(uvideo_payload_header_t) &&
+                   error == USBD_NORMAL_COMPLETION) {
+
+                       hdr = (const uvideo_payload_header_t *)&bx->bx_buffer;
+                       if (hdr->bHeaderLength == 0)
+                               continue;
+
+                       payload.data = bx->bx_buffer + hdr->bHeaderLength;
+                       payload.size = bx->bx_buflen - hdr->bHeaderLength;
+                       payload.frameno = hdr->bmHeaderInfo & UV_FRAME_ID;
+                       payload.end_of_frame =
+                           hdr->bmHeaderInfo & UV_END_OF_FRAME;
+
+                       if (frameno == -1)
+                               frameno = payload.frameno;
+
+                       video_submit_payload(sc->sc_videodev, &payload);
+
+                       if (frameno != payload.frameno ||
+                           payload.end_of_frame)
+                               break;
+               } else
+                       break;
+       }
+
+       mutex_enter(&sc->sc_mtx);
+       cv_broadcast(&sc->sc_cv);
+       mutex_exit(&sc->sc_mtx);
+
+       kthread_exit(0);
+}
+
/* Search the stream list for a stream matching the interface number.
 * This is an O(n) search, but most devices should have only one or at
 * most two streams. */
@@ -1110,7 +1174,13 @@
                                       bx->bx_endpt =
                                           GET(usb_endpoint_descriptor_t,
                                               desc, bEndpointAddress);
+                                       bx->bx_buflen =
+                                           UGETW(GET(usb_endpoint_descriptor_t,
+                                               desc, wMaxPacketSize));
+                                       printf("wMaxPacketSize = %d\n", bx->bx_buflen);
+
                               }
+
                       } else if (xfer_type == UE_ISOCHRONOUS) {
                               ix = &vs->vs_xfer.isoc;
                               for (i = 0; i < UVIDEO_NXFERS; i++) {
@@ -1428,14 +1498,49 @@
       uint32_t vframe_len;    /* rough bytes per video frame */
       uint32_t uframe_len;    /* bytes per usb frame (TODO: or microframe?) */
       uint32_t nframes;       /* number of usb frames (TODO: or microframs?) */
-       int i;
+       int i, ret;

       struct uvideo_alternate *alt, *alt_maybe;
       usbd_status err;

       switch (vs->vs_xfer_type) {
       case UE_BULK:
+               ret = 0;
               bx = &vs->vs_xfer.bulk;
+               err = usbd_open_pipe(vs->vs_iface, bx->bx_endpt,
+                                    USBD_EXCLUSIVE_USE, &bx->bx_pipe);
+               if (err != USBD_NORMAL_COMPLETION) {
+                       DPRINTF(("uvideo: error opening pipe: %s (%d)\n",
+                                usbd_errstr(err), err));
+                       return EIO;
+               }
+
+               bx->bx_xfer = usbd_alloc_xfer(sc->sc_udev);
+               if (bx->bx_xfer == NULL) {
+                       DPRINTF(("uvideo: failed to alloc xfer: %s"
+                        " (%d)\n",
+                        usbd_errstr(err), err));
+                       return ENOMEM;
+               }
+
+               bx->bx_buffer = usbd_alloc_buffer(bx->bx_xfer,
+                                   bx->bx_buflen);
+               if (bx->bx_xfer == NULL) {
+                       DPRINTF(("uvideo: failed to alloc buf: %s"
+                        " (%d)\n",
+                        usbd_errstr(err), err));
+                       return ENOMEM;
+               }
+
+               mutex_enter(&sc->sc_mtx);
+               if (sc->sc_running == 0) {
+                       sc->sc_running = 1;
+                       ret = kthread_create(PRI_UVIDEO, 0, NULL, uvideo_transfer_thread,
+                               vs, NULL, device_xname(sc->sc_dev));
+               } else
+                       aprint_error_dev(sc->sc_dev, "transfer already in progress\n");
+               mutex_exit(&sc->sc_mtx);
+
               return 0;
       case UE_ISOCHRONOUS:
               ix = &vs->vs_xfer.isoc;
@@ -1548,6 +1653,7 @@
static int
uvideo_stream_stop_xfer(struct uvideo_stream *vs)
{
+       struct uvideo_softc *sc = vs->vs_parent;
       struct uvideo_bulk_xfer *bx;
       struct uvideo_isoc_xfer *ix;
       usbd_status err;
@@ -1556,6 +1662,15 @@
       switch (vs->vs_xfer_type) {
       case UE_BULK:
               bx = &vs->vs_xfer.bulk;
+
+               mutex_enter(&sc->sc_mtx);
+               if (sc->sc_running) {
+                       sc->sc_running = 0;
+                       cv_wait_sig(&sc->sc_cv, &sc->sc_mtx);
+               }
+               mutex_exit(&sc->sc_mtx);
+
+               /* TODO: Free resources */
               return 0;
       case UE_ISOCHRONOUS:
               ix = &vs->vs_xfer.isoc;