diff options
author | Vahram Aharonyan <vahrama@synopsys.com> | 2016-05-24 01:41:57 -0400 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2016-05-31 04:12:56 -0400 |
commit | 51da43b555ba19e0230ff5a5acc58eb0fffb6026 (patch) | |
tree | 7a9f167f9561b925998ee98f348f5b7eb219f84b /drivers/usb/dwc2 | |
parent | d246dcb2331c5783743720e6510892eb1d2801d9 (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.c | 19 |
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 | ||
1021 | static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value); | 1021 | static 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 | */ |
2952 | static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) | 2957 | static 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; |