diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 9cd003636a4499ba57637f37f9e8fdeed709340f..a68a85f84e703f18b4b097ea27033b3680fcfe86 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -397,6 +397,21 @@ static int ci_ep_queue(struct usb_ep *ep, num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; + if (!num && ci_ep->req_primed) { + /* + * The flipping of ep0 between IN and OUT relies on + * ci_ep_queue consuming the current IN/OUT setting + * immediately. If this is deferred to a later point when the + * req is pulled out of ci_req->queue, then the IN/OUT setting + * may have been changed since the req was queued, and state + * will get out of sync. This condition doesn't occur today, + * but could if bugs were introduced later, and this error + * check will save a lot of debugging time. + */ + printf("%s: ep0 transaction already in progress\n", __func__); + return -EPROTO; + } + ret = ci_bounce(ci_req, in); if (ret) return ret;