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.
* 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);
#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 */
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,