aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc2
diff options
context:
space:
mode:
authorVahram Aharonyan <vahrama@synopsys.com>2016-05-24 01:41:57 -0400
committerFelipe Balbi <felipe.balbi@linux.intel.com>2016-05-31 04:12:56 -0400
commit51da43b555ba19e0230ff5a5acc58eb0fffb6026 (patch)
tree7a9f167f9561b925998ee98f348f5b7eb219f84b /drivers/usb/dwc2
parentd246dcb2331c5783743720e6510892eb1d2801d9 (diff)
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>
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r--drivers/usb/dwc2/gadget.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 4c5e3005e1dc..e4e2a9031dee 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
1018 return 1; 1018 return 1;
1019} 1019}
1020 1020
1021static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value); 1021static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now);
1022 1022
1023/** 1023/**
1024 * get_ep_head - return the first request on the endpoint 1024 * 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 case USB_ENDPOINT_HALT: 1094 case USB_ENDPOINT_HALT:
1095 halted = ep->halted; 1095 halted = ep->halted;
1096 1096
1097 dwc2_hsotg_ep_sethalt(&ep->ep, set); 1097 dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
1098 1098
1099 ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 1099 ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
1100 if (ret) { 1100 if (ret) {
@@ -2948,8 +2948,13 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
2948 * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 2948 * dwc2_hsotg_ep_sethalt - set halt on a given endpoint
2949 * @ep: The endpoint to set halt. 2949 * @ep: The endpoint to set halt.
2950 * @value: Set or unset the halt. 2950 * @value: Set or unset the halt.
2951 * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if
2952 * the endpoint is busy processing requests.
2953 *
2954 * We need to stall the endpoint immediately if request comes from set_feature
2955 * protocol command handler.
2951 */ 2956 */
2952static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) 2957static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
2953{ 2958{
2954 struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 2959 struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
2955 struct dwc2_hsotg *hs = hs_ep->parent; 2960 struct dwc2_hsotg *hs = hs_ep->parent;
@@ -2969,6 +2974,12 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value)
2969 return 0; 2974 return 0;
2970 } 2975 }
2971 2976
2977 if (!now && value && !list_empty(&hs_ep->queue)) {
2978 dev_dbg(hs->dev, "%s request is pending, cannot halt\n",
2979 ep->name);
2980 return -EAGAIN;
2981 }
2982
2972 if (hs_ep->dir_in) { 2983 if (hs_ep->dir_in) {
2973 epreg = DIEPCTL(index); 2984 epreg = DIEPCTL(index);
2974 epctl = dwc2_readl(hs->regs + epreg); 2985 epctl = dwc2_readl(hs->regs + epreg);
@@ -3020,7 +3031,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
3020 int ret = 0; 3031 int ret = 0;
3021 3032
3022 spin_lock_irqsave(&hs->lock, flags); 3033 spin_lock_irqsave(&hs->lock, flags);
3023 ret = dwc2_hsotg_ep_sethalt(ep, value); 3034 ret = dwc2_hsotg_ep_sethalt(ep, value, false);
3024 spin_unlock_irqrestore(&hs->lock, flags); 3035 spin_unlock_irqrestore(&hs->lock, flags);
3025 3036
3026 return ret; 3037 return ret;