Commit 51da43b5 authored by Vahram Aharonyan's avatar Vahram Aharonyan Committed by Felipe Balbi

usb: dwc2: gadget: Do not halt endpoint if active

The gadget API function usb_ep_set_halt() expects the gadget to return
-EAGAIN if the ep is active. Add support for this behavior.

Otherwise this may break mass storage protocol if a STALL is attempted
on the endpoint.
Signed-off-by: default avatarVahram Aharonyan <vahrama@synopsys.com>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent d246dcb2
...@@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, ...@@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
return 1; return 1;
} }
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value); static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now);
/** /**
* get_ep_head - return the first request on the endpoint * get_ep_head - return the first request on the endpoint
...@@ -1094,7 +1094,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, ...@@ -1094,7 +1094,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
case USB_ENDPOINT_HALT: case USB_ENDPOINT_HALT:
halted = ep->halted; halted = ep->halted;
dwc2_hsotg_ep_sethalt(&ep->ep, set); dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
if (ret) { if (ret) {
...@@ -2948,8 +2948,13 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) ...@@ -2948,8 +2948,13 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
* dwc2_hsotg_ep_sethalt - set halt on a given endpoint * dwc2_hsotg_ep_sethalt - set halt on a given endpoint
* @ep: The endpoint to set halt. * @ep: The endpoint to set halt.
* @value: Set or unset the halt. * @value: Set or unset the halt.
* @now: If true, stall the endpoint now. Otherwise return -EAGAIN if
* the endpoint is busy processing requests.
*
* We need to stall the endpoint immediately if request comes from set_feature
* protocol command handler.
*/ */
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
{ {
struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent; struct dwc2_hsotg *hs = hs_ep->parent;
...@@ -2969,6 +2974,12 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) ...@@ -2969,6 +2974,12 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value)
return 0; return 0;
} }
if (!now && value && !list_empty(&hs_ep->queue)) {
dev_dbg(hs->dev, "%s request is pending, cannot halt\n",
ep->name);
return -EAGAIN;
}
if (hs_ep->dir_in) { if (hs_ep->dir_in) {
epreg = DIEPCTL(index); epreg = DIEPCTL(index);
epctl = dwc2_readl(hs->regs + epreg); epctl = dwc2_readl(hs->regs + epreg);
...@@ -3020,7 +3031,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) ...@@ -3020,7 +3031,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
int ret = 0; int ret = 0;
spin_lock_irqsave(&hs->lock, flags); spin_lock_irqsave(&hs->lock, flags);
ret = dwc2_hsotg_ep_sethalt(ep, value); ret = dwc2_hsotg_ep_sethalt(ep, value, false);
spin_unlock_irqrestore(&hs->lock, flags); spin_unlock_irqrestore(&hs->lock, flags);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment