diff options
author | Felipe Balbi <balbi@ti.com> | 2014-09-24 15:19:52 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-10-20 16:58:48 -0400 |
commit | 7a60855972f0d3c014093046cb6f013a1ee5bb19 (patch) | |
tree | 8c25e151ddaab4d8840bcd82ba31c0c5eff99a94 /drivers/usb | |
parent | 95aa4e8d658778f787e2ce205d3018443d027477 (diff) |
usb: dwc3: gadget: fix set_halt() bug with pending transfers
According to our Gadget Framework API documentation,
->set_halt() *must* return -EAGAIN if we have pending
transfers (on either direction) or FIFO isn't empty (on
TX endpoints).
Fix this bug so that the mass storage gadget can be used
without stall=0 parameter.
This patch should be backported to all kernels since v3.2.
Cc: <stable@vger.kernel.org> # v3.2+
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 4 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 16 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.h | 2 |
3 files changed, 15 insertions, 7 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 36f61582b5b5..ae6b5753fe67 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c | |||
@@ -256,7 +256,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) | |||
256 | 256 | ||
257 | /* stall is always issued on EP0 */ | 257 | /* stall is always issued on EP0 */ |
258 | dep = dwc->eps[0]; | 258 | dep = dwc->eps[0]; |
259 | __dwc3_gadget_ep_set_halt(dep, 1); | 259 | __dwc3_gadget_ep_set_halt(dep, 1, false); |
260 | dep->flags = DWC3_EP_ENABLED; | 260 | dep->flags = DWC3_EP_ENABLED; |
261 | dwc->delayed_status = false; | 261 | dwc->delayed_status = false; |
262 | 262 | ||
@@ -480,7 +480,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, | |||
480 | return -EINVAL; | 480 | return -EINVAL; |
481 | if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) | 481 | if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) |
482 | break; | 482 | break; |
483 | ret = __dwc3_gadget_ep_set_halt(dep, set); | 483 | ret = __dwc3_gadget_ep_set_halt(dep, set, true); |
484 | if (ret) | 484 | if (ret) |
485 | return -EINVAL; | 485 | return -EINVAL; |
486 | break; | 486 | break; |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b98295efd912..f6d1dbafa298 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -581,7 +581,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) | |||
581 | 581 | ||
582 | /* make sure HW endpoint isn't stalled */ | 582 | /* make sure HW endpoint isn't stalled */ |
583 | if (dep->flags & DWC3_EP_STALL) | 583 | if (dep->flags & DWC3_EP_STALL) |
584 | __dwc3_gadget_ep_set_halt(dep, 0); | 584 | __dwc3_gadget_ep_set_halt(dep, 0, false); |
585 | 585 | ||
586 | reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); | 586 | reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); |
587 | reg &= ~DWC3_DALEPENA_EP(dep->number); | 587 | reg &= ~DWC3_DALEPENA_EP(dep->number); |
@@ -1202,7 +1202,7 @@ out0: | |||
1202 | return ret; | 1202 | return ret; |
1203 | } | 1203 | } |
1204 | 1204 | ||
1205 | int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) | 1205 | int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) |
1206 | { | 1206 | { |
1207 | struct dwc3_gadget_ep_cmd_params params; | 1207 | struct dwc3_gadget_ep_cmd_params params; |
1208 | struct dwc3 *dwc = dep->dwc; | 1208 | struct dwc3 *dwc = dep->dwc; |
@@ -1216,6 +1216,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) | |||
1216 | memset(¶ms, 0x00, sizeof(params)); | 1216 | memset(¶ms, 0x00, sizeof(params)); |
1217 | 1217 | ||
1218 | if (value) { | 1218 | if (value) { |
1219 | if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || | ||
1220 | (!list_empty(&dep->req_queued) || | ||
1221 | !list_empty(&dep->request_list)))) { | ||
1222 | dev_dbg(dwc->dev, "%s: pending request, cannot halt\n", | ||
1223 | dep->name); | ||
1224 | return -EAGAIN; | ||
1225 | } | ||
1226 | |||
1219 | ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, | 1227 | ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, |
1220 | DWC3_DEPCMD_SETSTALL, ¶ms); | 1228 | DWC3_DEPCMD_SETSTALL, ¶ms); |
1221 | if (ret) | 1229 | if (ret) |
@@ -1246,7 +1254,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) | |||
1246 | int ret; | 1254 | int ret; |
1247 | 1255 | ||
1248 | spin_lock_irqsave(&dwc->lock, flags); | 1256 | spin_lock_irqsave(&dwc->lock, flags); |
1249 | ret = __dwc3_gadget_ep_set_halt(dep, value); | 1257 | ret = __dwc3_gadget_ep_set_halt(dep, value, false); |
1250 | spin_unlock_irqrestore(&dwc->lock, flags); | 1258 | spin_unlock_irqrestore(&dwc->lock, flags); |
1251 | 1259 | ||
1252 | return ret; | 1260 | return ret; |
@@ -1265,7 +1273,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) | |||
1265 | if (dep->number == 0 || dep->number == 1) | 1273 | if (dep->number == 0 || dep->number == 1) |
1266 | ret = __dwc3_gadget_ep0_set_halt(ep, 1); | 1274 | ret = __dwc3_gadget_ep0_set_halt(ep, 1); |
1267 | else | 1275 | else |
1268 | ret = __dwc3_gadget_ep_set_halt(dep, 1); | 1276 | ret = __dwc3_gadget_ep_set_halt(dep, 1, false); |
1269 | spin_unlock_irqrestore(&dwc->lock, flags); | 1277 | spin_unlock_irqrestore(&dwc->lock, flags); |
1270 | 1278 | ||
1271 | return ret; | 1279 | return ret; |
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index f889008faa63..18ae3eaa8b6f 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h | |||
@@ -86,7 +86,7 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); | |||
86 | int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); | 86 | int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); |
87 | int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, | 87 | int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, |
88 | gfp_t gfp_flags); | 88 | gfp_t gfp_flags); |
89 | int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); | 89 | int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); |
90 | 90 | ||
91 | /** | 91 | /** |
92 | * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW | 92 | * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW |