USB - Add support for xfer-restart-before-callback
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 8 Jun 2009 18:49:05 +0000 (11:49 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 8 Jun 2009 18:49:05 +0000 (11:49 -0700)
Interrupt pipes restart their xfers.  When used for a USB
keyboard the xfer must be restarted before the callback,
even though there may be state data races, otherwise
the CTL-ALT-ESC sequence into the debugger will leave
the xfer unqueued and the keyboard will stop working.

sys/bus/usb/usbdi.c
sys/bus/usb/usbdi.h
sys/dev/usbmisc/ukbd/ukbd.c

index 0dfb020..21d4237 100644 (file)
@@ -829,8 +829,13 @@ usb_transfer_complete(usbd_xfer_handle xfer)
         * will not go away and the "done" method may modify it. Otherwise
         * reverse the order in case the callback wants to free or reuse
         * the xfer.
+        *
+        * USBD_CALLBACK_LAST is set by the keyboard driver to ensure
+        * that the xfer is restarted prior to doing the callback.
+        * Otherwise a CTL-ALT-ESC into the debugger will leave the
+        * xfer inactive and the keyboard will stop working.
         */
-       if (repeat) {
+       if (repeat && (xfer->flags & USBD_CALLBACK_LAST) == 0) {
                if (xfer->callback)
                        xfer->callback(xfer, xfer->priv, xfer->status);
                pipe->methods->done(xfer);
index 8a2ff5d..7c83843 100644 (file)
@@ -88,6 +88,7 @@ typedef void (*usbd_callback)(usbd_xfer_handle, usbd_private_handle,
 #define USBD_SYNCHRONOUS       0x02    /* wait for completion */
 /* in usb.h #define USBD_SHORT_XFER_OK 0x04*/  /* allow short reads */
 #define USBD_FORCE_SHORT_XFER  0x08    /* force last short packet on write */
+#define USBD_CALLBACK_LAST     0x10    /* restart xfer BEFORE making callback */
 
 #define USBD_NO_TIMEOUT 0
 #define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */
index b9731e7..6459cc5 100644 (file)
@@ -647,7 +647,7 @@ ukbd_enable_intr(keyboard_t *kbd, int on, usbd_intr_t *func)
 
                state->ks_ifstate |= INTRENABLED;
                err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr,
-                                       USBD_SHORT_XFER_OK,
+                                       USBD_SHORT_XFER_OK | USBD_CALLBACK_LAST,
                                        &state->ks_intrpipe, kbd,
                                        &state->ks_ndata,
                                        sizeof(state->ks_ndata), func,