]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/gadget/fsl_qe_udc.c
USB: fsl_qe_udc: Fix recursive locking bug in ch9getstatus()
[linux-2.6-omap-h63xx.git] / drivers / usb / gadget / fsl_qe_udc.c
index d6c5bcd400641730a40e88cbf31961a88cd9309f..064582fb6a87fa378c2ceea4acd148c41986b644 100644 (file)
@@ -1681,14 +1681,11 @@ static void qe_free_request(struct usb_ep *_ep, struct usb_request *_req)
                kfree(req);
 }
 
-/* queues (submits) an I/O request to an endpoint */
-static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
-                               gfp_t gfp_flags)
+static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req)
 {
        struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
        struct qe_req *req = container_of(_req, struct qe_req, req);
        struct qe_udc *udc;
-       unsigned long flags;
        int reval;
 
        udc = ep->udc;
@@ -1732,7 +1729,7 @@ static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        list_add_tail(&req->queue, &ep->queue);
        dev_vdbg(udc->dev, "gadget have request in %s! %d\n",
                        ep->name, req->req.length);
-       spin_lock_irqsave(&udc->lock, flags);
+
        /* push the request to device */
        if (ep_is_in(ep))
                reval = ep_req_send(ep, req);
@@ -1748,11 +1745,24 @@ static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        if (ep->dir == USB_DIR_OUT)
                reval = ep_req_receive(ep, req);
 
-       spin_unlock_irqrestore(&udc->lock, flags);
-
        return 0;
 }
 
+/* queues (submits) an I/O request to an endpoint */
+static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+                      gfp_t gfp_flags)
+{
+       struct qe_ep *ep = container_of(_ep, struct qe_ep, ep);
+       struct qe_udc *udc = ep->udc;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       ret = __qe_ep_queue(_ep, _req);
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return ret;
+}
+
 /* dequeues (cancels, unlinks) an I/O request from an endpoint */
 static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
@@ -2008,7 +2018,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
        udc->ep0_dir = USB_DIR_IN;
 
        /* data phase */
-       status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
+       status = __qe_ep_queue(&ep->ep, &req->req);
 
        if (status == 0)
                return;
@@ -2604,6 +2614,10 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
                        (unsigned long)udc_controller);
        /* request irq and disable DR  */
        udc_controller->usb_irq = irq_of_parse_and_map(np, 0);
+       if (!udc_controller->usb_irq) {
+               ret = -EINVAL;
+               goto err_noirq;
+       }
 
        ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0,
                                driver_name, udc_controller);
@@ -2625,6 +2639,8 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
 err6:
        free_irq(udc_controller->usb_irq, udc_controller);
 err5:
+       irq_dispose_mapping(udc_controller->usb_irq);
+err_noirq:
        if (udc_controller->nullmap) {
                dma_unmap_single(udc_controller->gadget.dev.parent,
                        udc_controller->nullp, 256,
@@ -2648,7 +2664,7 @@ err2:
        iounmap(udc_controller->usb_regs);
 err1:
        kfree(udc_controller);
-
+       udc_controller = NULL;
        return ret;
 }
 
@@ -2710,6 +2726,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
        kfree(ep->txframe);
 
        free_irq(udc_controller->usb_irq, udc_controller);
+       irq_dispose_mapping(udc_controller->usb_irq);
 
        tasklet_kill(&udc_controller->rx_tasklet);