In order to function as a "newstyle" udc, move endpoint (de-)initialization from gadget's start/stop to platform driver's probe/remove. Since there is no need in the global _udc pointer, remove it. Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> --- drivers/usb/gadget/ci13xxx_udc.c | 248 ++++++++++++++++---------------------- 1 file changed, 104 insertions(+), 144 deletions(-) diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index bfc9bca..8a282f2 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -96,9 +96,6 @@ ctrl_endpt_in_desc = { .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), }; -/* UDC descriptor */ -static struct ci13xxx *_udc; - /* Interrupt statistics */ #define ISR_MASK 0x1F static struct { @@ -1679,7 +1676,8 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) usb_ep_fifo_flush(&udc->ep0out->ep); usb_ep_fifo_flush(&udc->ep0in->ep); - udc->driver->disconnect(gadget); + if (udc->driver) + udc->driver->disconnect(gadget); /* make sure to disable all endpoints */ gadget_for_each_ep(ep, gadget) { @@ -1789,7 +1787,7 @@ __acquires(mEp->lock) if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { /* Assume that device is bus powered for now. */ - *(u16 *)req->buf = _udc->remote_wakeup << 1; + *(u16 *)req->buf = udc->remote_wakeup << 1; retval = 0; } else if ((setup->bRequestType & USB_RECIP_MASK) \ == USB_RECIP_ENDPOINT) { @@ -1896,7 +1894,7 @@ __acquires(mEp->lock) spin_unlock(mEp->lock); if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && mReq->req.length) - mEpTemp = _udc->ep0in; + mEpTemp = mEp->udc->ep0in; mReq->req.complete(&mEpTemp->ep, &mReq->req); spin_lock(mEp->lock); } @@ -2277,6 +2275,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, { struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + struct ci13xxx *udc = mEp->udc; int retval = 0; unsigned long flags; @@ -2289,8 +2288,8 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { if (req->length) - mEp = (_udc->ep0_dir == RX) ? - _udc->ep0out : _udc->ep0in; + mEp = (udc->ep0_dir == RX) ? + udc->ep0out : udc->ep0in; if (!list_empty(&mEp->qh.queue)) { _ep_nuke(mEp); retval = -EOVERFLOW; @@ -2556,9 +2555,10 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -ENOTSUPP; } -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int ci13xxx_stop(struct usb_gadget_driver *driver); +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); /** * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) @@ -2568,62 +2568,15 @@ static const struct usb_gadget_ops usb_gadget_ops = { .vbus_session = ci13xxx_vbus_session, .wakeup = ci13xxx_wakeup, .vbus_draw = ci13xxx_vbus_draw, - .start = ci13xxx_start, - .stop = ci13xxx_stop, + .udc_start = ci13xxx_start, + .udc_stop = ci13xxx_stop, }; -/** - * ci13xxx_start: register a gadget driver - * @driver: the driver being registered - * @bind: the driver's bind callback - * - * Check ci13xxx_start() at <linux/usb/gadget.h> for details. - * Interrupts are enabled here. - */ -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int init_eps(struct ci13xxx *udc) { - struct ci13xxx *udc = _udc; - unsigned long flags; - int i, j; - int retval = -ENOMEM; - - trace(udc->dev, "%p", driver); - - if (driver == NULL || - bind == NULL || - driver->setup == NULL || - driver->disconnect == NULL) - return -EINVAL; - else if (udc == NULL) - return -ENODEV; - else if (udc->driver != NULL) - return -EBUSY; - - /* alloc resources */ - udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, - sizeof(struct ci13xxx_qh), - 64, CI13XXX_PAGE_SIZE); - if (udc->qh_pool == NULL) - return -ENOMEM; - - udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, - sizeof(struct ci13xxx_td), - 64, CI13XXX_PAGE_SIZE); - if (udc->td_pool == NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - return -ENOMEM; - } + int retval = 0, i, j; - spin_lock_irqsave(&udc->lock, flags); - - dev_info(udc->dev, "hw_ep_max = %d\n", udc->hw_ep_max); - - udc->gadget.dev.driver = NULL; - - retval = 0; - for (i = 0; i < udc->hw_ep_max/2; i++) { + for (i = 0; i < udc->hw_ep_max/2; i++) for (j = RX; j <= TX; j++) { int k = i + j * udc->hw_ep_max/2; struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; @@ -2641,10 +2594,8 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; INIT_LIST_HEAD(&mEp->qh.queue); - spin_unlock_irqrestore(&udc->lock, flags); mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, - &mEp->qh.dma); - spin_lock_irqsave(&udc->lock, flags); + &mEp->qh.dma); if (mEp->qh.ptr == NULL) retval = -ENOMEM; else @@ -2665,11 +2616,30 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); } - } - if (retval) - goto done; - spin_unlock_irqrestore(&udc->lock, flags); + return retval; +} + +/** + * ci13xxx_start: register a gadget driver + * @gadget: our gadget + * @driver: the driver being registered + * + * Interrupts are enabled here. + */ +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + int retval = -ENOMEM; + + trace(udc->dev, "%p", driver); + + if (driver->disconnect == NULL) + return -EINVAL; + + udc->ep0out->ep.desc = &ctrl_endpt_out_desc; retval = usb_ep_enable(&udc->ep0out->ep); if (retval) @@ -2681,20 +2651,6 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, return retval; spin_lock_irqsave(&udc->lock, flags); - udc->gadget.ep0 = &udc->ep0in->ep; - /* bind gadget */ - driver->driver.bus = NULL; - udc->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(&udc->lock, flags); - retval = bind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(&udc->lock, flags); - - if (retval) { - udc->gadget.dev.driver = NULL; - goto done; - } - udc->driver = driver; pm_runtime_get_sync(&udc->gadget.dev); if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { @@ -2718,23 +2674,15 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, /** * ci13xxx_stop: unregister a gadget driver - * - * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details */ -static int ci13xxx_stop(struct usb_gadget_driver *driver) +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct ci13xxx *udc = _udc; - unsigned long i, flags; + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; trace(udc->dev, "%p", driver); - if (driver == NULL || - driver->unbind == NULL || - driver->setup == NULL || - driver->disconnect == NULL || - driver != udc->driver) - return -EINVAL; - spin_lock_irqsave(&udc->lock, flags); if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || @@ -2743,44 +2691,15 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver) if (udc->udc_driver->notify_event) udc->udc_driver->notify_event(udc, CI13XXX_CONTROLLER_STOPPED_EVENT); + udc->driver = NULL; spin_unlock_irqrestore(&udc->lock, flags); _gadget_stop_activity(&udc->gadget); spin_lock_irqsave(&udc->lock, flags); pm_runtime_put(&udc->gadget.dev); } - /* unbind gadget */ - spin_unlock_irqrestore(&udc->lock, flags); - driver->unbind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(&udc->lock, flags); - - udc->gadget.dev.driver = NULL; - - /* free resources */ - for (i = 0; i < udc->hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - - if (mEp->num) - list_del_init(&mEp->ep.ep_list); - - if (mEp->qh.ptr != NULL) - dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); - } - - udc->gadget.ep0 = NULL; - udc->driver = NULL; - spin_unlock_irqrestore(&udc->lock, flags); - if (udc->td_pool != NULL) { - dma_pool_destroy(udc->td_pool); - udc->td_pool = NULL; - } - if (udc->qh_pool != NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - } - return 0; } @@ -2795,7 +2714,7 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver) */ static irqreturn_t udc_irq(int irq, void *data) { - struct ci13xxx *udc = _udc; + struct ci13xxx *udc = data; irqreturn_t retval; u32 intr; @@ -2885,7 +2804,7 @@ static void udc_release(struct device *dev) * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask */ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, - void __iomem *regs) + void __iomem *regs, struct ci13xxx **_udc) { struct ci13xxx *udc; int retval = 0; @@ -2911,7 +2830,6 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, udc->gadget.name = driver->name; INIT_LIST_HEAD(&udc->gadget.ep_list); - udc->gadget.ep0 = NULL; dev_set_name(&udc->gadget.dev, "gadget"); udc->gadget.dev.dma_mask = dev->dma_mask; @@ -2921,16 +2839,42 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, udc->dev = dev; - retval = hw_device_init(udc, regs, driver->capoffset); - if (retval < 0) + /* alloc resources */ + udc->qh_pool = dma_pool_create("ci13xxx_qh", dev, + sizeof(struct ci13xxx_qh), + 64, CI13XXX_PAGE_SIZE); + if (udc->qh_pool == NULL) { + retval = -ENOMEM; goto free_udc; + } + + udc->td_pool = dma_pool_create("ci13xxx_td", dev, + sizeof(struct ci13xxx_td), + 64, CI13XXX_PAGE_SIZE); + if (udc->td_pool == NULL) { + retval = -ENOMEM; + goto free_qh_pool; + } + + retval = hw_device_init(udc, regs, driver->capoffset); + if (retval < 0) { + trace(dev, "hw_device_init failed\n"); + goto free_pools; + } + trace(dev, "hw_device_init succeeded\n"); + + retval = init_eps(udc); + if (retval) + goto free_pools; + + udc->gadget.ep0 = &udc->ep0in->ep; udc->transceiver = usb_get_transceiver(); if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { if (udc->transceiver == NULL) { retval = -ENODEV; - goto free_udc; + goto free_pools; } } @@ -2966,7 +2910,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, pm_runtime_no_callbacks(&udc->gadget.dev); pm_runtime_enable(&udc->gadget.dev); - _udc = udc; + *_udc = udc; return retval; remove_trans: @@ -2985,9 +2929,13 @@ unreg_device: put_transceiver: if (udc->transceiver) usb_put_transceiver(udc->transceiver); +free_pools: + dma_pool_destroy(udc->td_pool); +free_qh_pool: + dma_pool_destroy(udc->qh_pool); free_udc: kfree(udc); - _udc = NULL; + *_udc = NULL; return retval; } @@ -2996,15 +2944,24 @@ free_udc: * * No interrupts active, the IRQ has been released */ -static void udc_remove(void) +static void udc_remove(struct ci13xxx *udc) { - struct ci13xxx *udc = _udc; + int i; if (udc == NULL) return; usb_del_gadget_udc(&udc->gadget); + for (i = 0; i < udc->hw_ep_max; i++) { + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + + dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); + } + + dma_pool_destroy(udc->td_pool); + dma_pool_destroy(udc->qh_pool); + if (udc->transceiver) { otg_set_peripheral(udc->transceiver->otg, &udc->gadget); usb_put_transceiver(udc->transceiver); @@ -3016,13 +2973,13 @@ static void udc_remove(void) kfree(udc->hw_bank.regmap); kfree(udc); - _udc = NULL; } static int __devinit ci_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ci13xxx_udc_driver *driver = dev->platform_data; + struct ci13xxx *udc; struct resource *res; void __iomem *base; int ret; @@ -3044,30 +3001,33 @@ static int __devinit ci_udc_probe(struct platform_device *pdev) return -ENOMEM; } - ret = udc_probe(driver, dev, base); + ret = udc_probe(driver, dev, base, &udc); if (ret) return ret; - _udc->irq = platform_get_irq(pdev, 0); - if (_udc->irq < 0) { + udc->irq = platform_get_irq(pdev, 0); + if (udc->irq < 0) { dev_err(dev, "missing IRQ\n"); ret = -ENODEV; goto out; } - ret = request_irq(_udc->irq, udc_irq, IRQF_SHARED, driver->name, _udc); + platform_set_drvdata(pdev, udc); + ret = request_irq(udc->irq, udc_irq, IRQF_SHARED, driver->name, udc); out: if (ret) - udc_remove(); + udc_remove(udc); return ret; } static int __devexit ci_udc_remove(struct platform_device *pdev) { - free_irq(_udc->irq, _udc); - udc_remove(); + struct ci13xxx *udc = platform_get_drvdata(pdev); + + free_irq(udc->irq, udc); + udc_remove(udc); return 0; } -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html