Skip to content

Commit

Permalink
usb: gadget: ci13xxx: move endpoint (de-)initialization to probe/remove
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alexander Shishkin authored and Greg Kroah-Hartman committed May 9, 2012
1 parent 0f08909 commit 790c2d5
Showing 1 changed file with 80 additions and 81 deletions.
161 changes: 80 additions & 81 deletions drivers/usb/gadget/ci13xxx_udc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -2984,6 +2969,10 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
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;
Expand All @@ -2998,12 +2987,22 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
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);
Expand Down

0 comments on commit 790c2d5

Please sign in to comment.