summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/ci_udc.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2014-05-29 14:53:00 -0600
committerMarek Vasut <marex@denx.de>2014-06-01 19:22:39 +0200
commit7484d84cbb58e01ff1d2d458d899ea1fba012724 (patch)
tree7938f628fa83b51bff0fea23654cc5d0e622ae4b /drivers/usb/gadget/ci_udc.c
parent77b83e6d099cb2149e5b2c33a700003227d99297 (diff)
usb: ci_udc: detect queued requests on ep0
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. Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'drivers/usb/gadget/ci_udc.c')
-rw-r--r--drivers/usb/gadget/ci_udc.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 9cd003636a4..a68a85f84e7 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;