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: Vahram Aharonyan <vahrama@synopsys.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
committed by
Felipe Balbi
parent
d246dcb233
commit
51da43b555
@@ -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,
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user