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 #include #include /* SLIST */ +#include #include #include @@ -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;