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;