summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2012-05-08 23:29:03 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-09 15:00:26 -0700
commit790c2d52b24e2ecd00ca014821c1adc41be2ac94 (patch)
treeaec4892d6b5d57c6a2a0e35d4411feee0a18a118 /drivers/usb/gadget
parent0f089094cde53a2639c965cd3bd3fdef27006446 (diff)
usb: gadget: ci13xxx: move endpoint (de-)initialization to probe/remove
Currently, endpoints are initialized in gadget start/stop methods, however for the new style gadgets it is expected that bind() can be called before controller's start(), and we need endpoints already initialized at that point. So, move endpoint initialization to controller's probe before we switch to the "new style" gadget framework. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c161
1 files changed, 80 insertions, 81 deletions
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index ce50af97ab3f..c18068df73a1 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2571,58 +2571,11 @@ static const struct usb_gadget_ops usb_gadget_ops = {
.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;
+ int retval = 0, i, j;
- 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;
- }
-
- 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];
@@ -2640,10 +2593,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
@@ -2664,9 +2615,43 @@ static int ci13xxx_start(struct usb_gadget_driver *driver,
list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
}
- }
- if (retval)
- goto done;
+
+ return retval;
+}
+
+/**
+ * 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 *))
+{
+ 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;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ dev_info(udc->dev, "hw_ep_max = %d\n", udc->hw_ep_max);
+
+ udc->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&udc->lock, flags);
udc->ep0out->ep.desc = &ctrl_endpt_out_desc;
@@ -2680,7 +2665,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;
@@ -2754,32 +2738,10 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver)
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;
}
@@ -2920,16 +2882,39 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
udc->dev = dev;
+ /* 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)
- goto free_udc;
+ goto free_pools;
+
+ 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;
}
}
@@ -2984,6 +2969,10 @@ 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;
@@ -2998,12 +2987,22 @@ free_udc:
static void udc_remove(void)
{
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);