diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/udc/pch_udc.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index e9c2f67a8b10..1090b846df38 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2329,6 +2329,21 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) pch_udc_set_dma(dev, DMA_DIR_RX); } +static int pch_udc_gadget_setup(struct pch_udc_dev *dev) + __must_hold(&dev->lock) +{ + int rc; + + /* In some cases we can get an interrupt before driver gets setup */ + if (!dev->driver) + return -ESHUTDOWN; + + spin_unlock(&dev->lock); + rc = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_lock(&dev->lock); + return rc; +} + /** * pch_udc_svc_control_in() - Handle Control IN endpoint interrupts * @dev: Reference to the device structure @@ -2400,15 +2415,12 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; else /* OUT */ dev->gadget.ep0 = &ep->ep; - spin_lock(&dev->lock); /* If Mass storage Reset */ if ((dev->setup_data.bRequestType == 0x21) && (dev->setup_data.bRequest == 0xFF)) dev->prot_stall = 0; /* call gadget with setup data received */ - setup_supported = dev->driver->setup(&dev->gadget, - &dev->setup_data); - spin_unlock(&dev->lock); + setup_supported = pch_udc_gadget_setup(dev); if (dev->setup_data.bRequestType & USB_DIR_IN) { ep->td_data->status = (ep->td_data->status & @@ -2656,9 +2668,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) dev->ep[i].halted = 0; } dev->stall = 0; - spin_unlock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + pch_udc_gadget_setup(dev); } /** @@ -2693,9 +2703,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) dev->stall = 0; /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + pch_udc_gadget_setup(dev); } /** |