summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHu hui <b29976@freescale.com>2010-10-18 10:43:19 +0800
committerHu Hui <b29976@freescale.com>2010-10-18 10:44:35 +0800
commit86c82e487066b04ff934453242e78ea901d16cc0 (patch)
tree8eeab596ccd25db68460f218340f9b60449254f2
parenta3f165de7ec64aa95166d5349170172c5fe8a496 (diff)
ENGR00132608 I.MX USB:crashed with cable unpluged during data transfer
During data transfer between pc and imx board, if unplug the cable, the udc will enter low power mode and the gadget class driver is disconnected from the udc driver with the ep->desc cleared, this is done in udc irq handler which may interrupte the current udc queue operation, so when queue operation can continue it's work, the ep->desc may be NULL which will cause the NULL pointer exception in kernel. Signed-off-by: Hu Hui <b29976@freescale.com>
-rw-r--r--drivers/usb/gadget/arcotg_udc.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index b86d293eb150..595ad380054f 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -1072,26 +1072,33 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
unsigned long flags;
int is_iso = 0;
- if (!_ep || (!ep->desc && ep_index(ep))) {
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!_ep || !ep->desc) {
VDBG("%s, bad ep\n", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
return -EINVAL;
}
/* catch various bogus parameters */
if (!_req || !req->req.buf || (ep_index(ep)
&& !list_empty(&req->queue))) {
VDBG("%s, bad params\n", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
return -EINVAL;
}
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- if (req->req.length > ep->ep.maxpacket)
+ if (req->req.length > ep->ep.maxpacket) {
+ spin_unlock_irqrestore(&udc->lock, flags);
return -EMSGSIZE;
+ }
is_iso = 1;
}
udc = ep->udc;
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ spin_unlock_irqrestore(&udc->lock, flags);
return -ESHUTDOWN;
-
+ }
req->ep = ep;
/* map virtual address to hardware */
@@ -1119,8 +1126,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->buffer_offset = 0;
}
- spin_lock_irqsave(&udc->lock, flags);
-
/* build dtds and push them to device queue */
if (!fsl_req_to_dtd(req)) {
fsl_queue_td(ep, req);