diff options
Diffstat (limited to 'drivers/usb/dwc2/gadget.c')
-rw-r--r-- | drivers/usb/dwc2/gadget.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4c5e3005e1dc..26cf09d0fe3c 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,17 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) | |||
2969 | return 0; | 2974 | return 0; |
2970 | } | 2975 | } |
2971 | 2976 | ||
2977 | if (hs_ep->isochronous) { | ||
2978 | dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); | ||
2979 | return -EINVAL; | ||
2980 | } | ||
2981 | |||
2982 | if (!now && value && !list_empty(&hs_ep->queue)) { | ||
2983 | dev_dbg(hs->dev, "%s request is pending, cannot halt\n", | ||
2984 | ep->name); | ||
2985 | return -EAGAIN; | ||
2986 | } | ||
2987 | |||
2972 | if (hs_ep->dir_in) { | 2988 | if (hs_ep->dir_in) { |
2973 | epreg = DIEPCTL(index); | 2989 | epreg = DIEPCTL(index); |
2974 | epctl = dwc2_readl(hs->regs + epreg); | 2990 | epctl = dwc2_readl(hs->regs + epreg); |
@@ -3020,7 +3036,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) | |||
3020 | int ret = 0; | 3036 | int ret = 0; |
3021 | 3037 | ||
3022 | spin_lock_irqsave(&hs->lock, flags); | 3038 | spin_lock_irqsave(&hs->lock, flags); |
3023 | ret = dwc2_hsotg_ep_sethalt(ep, value); | 3039 | ret = dwc2_hsotg_ep_sethalt(ep, value, false); |
3024 | spin_unlock_irqrestore(&hs->lock, flags); | 3040 | spin_unlock_irqrestore(&hs->lock, flags); |
3025 | 3041 | ||
3026 | return ret; | 3042 | return ret; |