From eb50702539f9be3765127d927d3e9ccfeb65f26e Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 24 Jan 2009 23:55:34 -0800 Subject: USB: pxa27x_udc: factor pullup code to prepare otg transceiver Prepare pxa27x_udc to handle usb D+ pullup properly : it should connect the pullup resistor and disconnect it only if no external transceiver is handling it. [ dbrownell@users.sourceforge.net: kerneldoc and gpio fixes ] Signed-off-by: Robert Jarzmik Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 140 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 990f40f..f814559 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1471,6 +1472,32 @@ static struct usb_ep_ops pxa_ep_ops = { .fifo_flush = pxa_ep_fifo_flush, }; +/** + * dplus_pullup - Connect or disconnect pullup resistor to D+ pin + * @udc: udc device + * @on: 0 if disconnect pullup resistor, 1 otherwise + * Context: any + * + * Handle D+ pullup resistor, make the device visible to the usb bus, and + * declare it as a full speed usb device + */ +static void dplus_pullup(struct pxa_udc *udc, int on) +{ + if (on) { + if (gpio_is_valid(udc->mach->gpio_pullup)) + gpio_set_value(udc->mach->gpio_pullup, + !udc->mach->gpio_pullup_inverted); + if (udc->mach->udc_command) + udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); + } else { + if (gpio_is_valid(udc->mach->gpio_pullup)) + gpio_set_value(udc->mach->gpio_pullup, + udc->mach->gpio_pullup_inverted); + if (udc->mach->udc_command) + udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); + } + udc->pullup_on = on; +} /** * pxa_udc_get_frame - Returns usb frame number @@ -1500,21 +1527,91 @@ static int pxa_udc_wakeup(struct usb_gadget *_gadget) return 0; } +static void udc_enable(struct pxa_udc *udc); +static void udc_disable(struct pxa_udc *udc); + +/** + * should_enable_udc - Tells if UDC should be enabled + * @udc: udc device + * Context: any + * + * The UDC should be enabled if : + * - the pullup resistor is connected + * - and a gadget driver is bound + * + * Returns 1 if UDC should be enabled, 0 otherwise + */ +static int should_enable_udc(struct pxa_udc *udc) +{ + int put_on; + + put_on = ((udc->pullup_on) && (udc->driver)); + return put_on; +} + +/** + * should_disable_udc - Tells if UDC should be disabled + * @udc: udc device + * Context: any + * + * The UDC should be disabled if : + * - the pullup resistor is not connected + * - or no gadget driver is bound + * + * Returns 1 if UDC should be disabled + */ +static int should_disable_udc(struct pxa_udc *udc) +{ + int put_off; + + put_off = ((!udc->pullup_on) || (!udc->driver)); + return put_off; +} + +/** + * pxa_udc_pullup - Offer manual D+ pullup control + * @_gadget: usb gadget using the control + * @is_active: 0 if disconnect, else connect D+ pullup resistor + * Context: !in_interrupt() + * + * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup + */ +static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) +{ + struct pxa_udc *udc = to_gadget_udc(_gadget); + + if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) + return -EOPNOTSUPP; + + dplus_pullup(udc, is_active); + + if (should_enable_udc(udc)) + udc_enable(udc); + if (should_disable_udc(udc)) + udc_disable(udc); + return 0; +} + static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, .wakeup = pxa_udc_wakeup, + .pullup = pxa_udc_pullup, /* current versions must always be self-powered */ }; /** * udc_disable - disable udc device controller * @udc: udc device + * Context: any * * Disables the udc device : disables clocks, udc interrupts, control endpoint * interrupts. */ static void udc_disable(struct pxa_udc *udc) { + if (!udc->enabled) + return; + udc_writel(udc, UDCICR0, 0); udc_writel(udc, UDCICR1, 0); @@ -1523,8 +1620,8 @@ static void udc_disable(struct pxa_udc *udc) ep0_idle(udc); udc->gadget.speed = USB_SPEED_UNKNOWN; - if (udc->mach->udc_command) - udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); + + udc->enabled = 0; } /** @@ -1570,6 +1667,9 @@ static __init void udc_init_data(struct pxa_udc *dev) */ static void udc_enable(struct pxa_udc *udc) { + if (udc->enabled) + return; + udc_writel(udc, UDCICR0, 0); udc_writel(udc, UDCICR1, 0); udc_clear_mask_UDCCR(udc, UDCCR_UDE); @@ -1598,9 +1698,7 @@ static void udc_enable(struct pxa_udc *udc) /* enable ep0 irqs */ pio_irq_enable(&udc->pxa_ep[0]); - dev_info(udc->dev, "UDC connecting\n"); - if (udc->mach->udc_command) - udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); + udc->enabled = 1; } /** @@ -1612,6 +1710,9 @@ static void udc_enable(struct pxa_udc *udc) * usb traffic follows until a disconnect is reported. Then a host may connect * again, or the driver might get unbound. * + * Note that the udc is not automatically enabled. Check function + * should_enable_udc(). + * * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise */ int usb_gadget_register_driver(struct usb_gadget_driver *driver) @@ -1630,6 +1731,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) /* first hook up the driver ... */ udc->driver = driver; udc->gadget.dev.driver = &driver->driver; + dplus_pullup(udc, 1); retval = device_add(&udc->gadget.dev); if (retval) { @@ -1645,7 +1747,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev_dbg(udc->dev, "registered gadget driver '%s'\n", driver->driver.name); - udc_enable(udc); + if (should_enable_udc(udc)) + udc_enable(udc); return 0; bind_fail: @@ -1699,6 +1802,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) stop_activity(udc, driver); udc_disable(udc); + dplus_pullup(udc, 0); driver->unbind(&udc->gadget); udc->driver = NULL; @@ -2212,7 +2316,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev) { struct resource *regs; struct pxa_udc *udc = &memory; - int retval; + int retval = 0, gpio; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) @@ -2224,6 +2328,19 @@ static int __init pxa_udc_probe(struct platform_device *pdev) udc->dev = &pdev->dev; udc->mach = pdev->dev.platform_data; + gpio = udc->mach->gpio_pullup; + if (gpio_is_valid(gpio)) { + retval = gpio_request(gpio, "USB D+ pullup"); + if (retval == 0) + gpio_direction_output(gpio, + udc->mach->gpio_pullup_inverted); + } + if (retval) { + dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n", + gpio, retval); + return retval; + } + udc->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(udc->clk)) { retval = PTR_ERR(udc->clk); @@ -2273,10 +2390,13 @@ err_clk: static int __exit pxa_udc_remove(struct platform_device *_dev) { struct pxa_udc *udc = platform_get_drvdata(_dev); + int gpio = udc->mach->gpio_pullup; usb_gadget_unregister_driver(udc->driver); free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); + if (gpio_is_valid(gpio)) + gpio_free(gpio); platform_set_drvdata(_dev, NULL); the_controller = NULL; @@ -2319,6 +2439,8 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) } udc_disable(udc); + udc->pullup_resume = udc->pullup_on; + dplus_pullup(udc, 0); return 0; } @@ -2346,7 +2468,9 @@ static int pxa_udc_resume(struct platform_device *_dev) ep->udccsr_value, ep->udccr_value); } - udc_enable(udc); + dplus_pullup(udc, udc->pullup_resume); + if (should_enable_udc(udc)) + udc_enable(udc); /* * We do not handle OTG yet. * -- cgit v1.1 From b799a7eb68082af620b7e37b6f41c98802e831f6 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 24 Jan 2009 23:56:42 -0800 Subject: USB: pxa27x_udc: add vbus session handling On vbus_session() call, optionally activate D+ pullup resistor and enable the udc, or deactivate D+ pullup resistor and disable the udc. It is intentional to not handle any VBus sense related irq. An external transceiver driver (like gpio_vbus) should catch VBus sense signal, and call usb_gadget_vbus_connect() or usb_gadget_vbus_disconnect(). Signed-off-by: Robert Jarzmik Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index f814559..0c93071 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1536,8 +1536,10 @@ static void udc_disable(struct pxa_udc *udc); * Context: any * * The UDC should be enabled if : + * - the pullup resistor is connected * - and a gadget driver is bound + * - and vbus is sensed (or no vbus sense is available) * * Returns 1 if UDC should be enabled, 0 otherwise */ @@ -1546,6 +1548,7 @@ static int should_enable_udc(struct pxa_udc *udc) int put_on; put_on = ((udc->pullup_on) && (udc->driver)); + put_on &= ((udc->vbus_sensed) || (!udc->transceiver)); return put_on; } @@ -1557,6 +1560,7 @@ static int should_enable_udc(struct pxa_udc *udc) * The UDC should be disabled if : * - the pullup resistor is not connected * - or no gadget driver is bound + * - or no vbus is sensed (when vbus sesing is available) * * Returns 1 if UDC should be disabled */ @@ -1565,6 +1569,7 @@ static int should_disable_udc(struct pxa_udc *udc) int put_off; put_off = ((!udc->pullup_on) || (!udc->driver)); + put_off |= ((!udc->vbus_sensed) && (udc->transceiver)); return put_off; } @@ -1592,10 +1597,37 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) return 0; } +static void udc_enable(struct pxa_udc *udc); +static void udc_disable(struct pxa_udc *udc); + +/** + * pxa_udc_vbus_session - Called by external transceiver to enable/disable udc + * @_gadget: usb gadget + * @is_active: 0 if should disable the udc, 1 if should enable + * + * Enables the udc, and optionnaly activates D+ pullup resistor. Or disables the + * udc, and deactivates D+ pullup resistor. + * + * Returns 0 + */ +static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct pxa_udc *udc = to_gadget_udc(_gadget); + + udc->vbus_sensed = is_active; + if (should_enable_udc(udc)) + udc_enable(udc); + if (should_disable_udc(udc)) + udc_disable(udc); + + return 0; +} + static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, .wakeup = pxa_udc_wakeup, .pullup = pxa_udc_pullup, + .vbus_session = pxa_udc_vbus_session, /* current versions must always be self-powered */ }; @@ -2357,6 +2389,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev) device_initialize(&udc->gadget.dev); udc->gadget.dev.parent = &pdev->dev; udc->gadget.dev.dma_mask = NULL; + udc->vbus_sensed = 0; the_controller = udc; platform_set_drvdata(pdev, udc); -- cgit v1.1 From 7fec3c25b773883bd50c4078bcccdd23d3dadeac Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 24 Jan 2009 23:57:30 -0800 Subject: USB: pxa27x_udc: add otg transceiver support When a transceiver driver is used, no automatic udc enable is done. The transceiver (OTG or not) should : - take care of VBus sensing - call usb_gadget_vbus_connect() - call usb_gadget_vbus_disconnect() The pullup should remain within this driver's management, either by gpio_pullup of udc_command() fields. Signed-off-by: Robert Jarzmik Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 0c93071..1151047 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1779,10 +1779,21 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev_dbg(udc->dev, "registered gadget driver '%s'\n", driver->driver.name); + if (udc->transceiver) { + retval = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (retval) { + dev_err(udc->dev, "can't bind to transceiver\n"); + goto transceiver_fail; + } + } + if (should_enable_udc(udc)) udc_enable(udc); return 0; +transceiver_fail: + if (driver->unbind) + driver->unbind(&udc->gadget); bind_fail: device_del(&udc->gadget.dev); add_fail: @@ -1840,9 +1851,11 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc->driver = NULL; device_del(&udc->gadget.dev); - dev_info(udc->dev, "unregistered gadget driver '%s'\n", driver->driver.name); + + if (udc->transceiver) + return otg_set_peripheral(udc->transceiver, NULL); return 0; } EXPORT_SYMBOL(usb_gadget_unregister_driver); @@ -2359,6 +2372,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev) udc->dev = &pdev->dev; udc->mach = pdev->dev.platform_data; + udc->transceiver = otg_get_transceiver(); gpio = udc->mach->gpio_pullup; if (gpio_is_valid(gpio)) { @@ -2431,6 +2445,9 @@ static int __exit pxa_udc_remove(struct platform_device *_dev) if (gpio_is_valid(gpio)) gpio_free(gpio); + otg_put_transceiver(udc->transceiver); + + udc->transceiver = NULL; platform_set_drvdata(_dev, NULL); the_controller = NULL; clk_put(udc->clk); -- cgit v1.1 From ee069fb1185895e725ad942c7a529f947e25166d Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 24 Jan 2009 23:59:38 -0800 Subject: USB: pxa27x_udc: add vbus_draw callback Add the vbus_draw() callback to inform the transceiver, if it exists, how much current may be drawn. The decision is taken on gadget driver side using the configuration chosen by the host and its bMaxPower field. Some systems can use the host's VBUS supply to augment or recharge a battery. (There's also a default of 100 mA for unconfigured devices, or 8 mA if they're OTG devices.) Signed-off-by: Robert Jarzmik Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 1151047..e50419d 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1623,12 +1623,34 @@ static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active) return 0; } +/** + * pxa_udc_vbus_draw - Called by gadget driver after SET_CONFIGURATION completed + * @_gadget: usb gadget + * @mA: current drawn + * + * Context: !in_interrupt() + * + * Called after a configuration was chosen by a USB host, to inform how much + * current can be drawn by the device from VBus line. + * + * Returns 0 or -EOPNOTSUPP if no transceiver is handling the udc + */ +static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) +{ + struct pxa_udc *udc; + + udc = to_gadget_udc(_gadget); + if (udc->transceiver) + return otg_set_power(udc->transceiver, mA); + return -EOPNOTSUPP; +} + static const struct usb_gadget_ops pxa_udc_ops = { .get_frame = pxa_udc_get_frame, .wakeup = pxa_udc_wakeup, .pullup = pxa_udc_pullup, .vbus_session = pxa_udc_vbus_session, - /* current versions must always be self-powered */ + .vbus_draw = pxa_udc_vbus_draw, }; /** -- cgit v1.1 From 00185a60c37549531b9eee562d3eba19020875d5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 21 Dec 2008 16:41:36 +0100 Subject: USB: Remove redundant test in pxa27x_udc and ftdi_sio priv is checked not to be NULL near the beginning of the function and not changed subsequently, making the test redundant. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; position p1,p2; @@ if (x@p1 == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( x@p2 == NULL | x@p2 != NULL ) // another path to the test that is not through p1? @s exists@ local idexpression r.x; position r.p1,r.p2; @@ ... when != x@p1 ( x@p2 == NULL | x@p2 != NULL ) @fix depends on !s@ position r.p1,r.p2; expression x,E; statement S1,S2; @@ ( - if ((x@p2 != NULL) || ...) S1 | - if ((x@p2 == NULL) && ...) S1 | - BUG_ON(x@p2 == NULL); ) // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index e50419d..91ba1e9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -279,7 +279,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc) goto err_queues; eps = debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops); - if (!queues) + if (!eps) goto err_eps; udc->debugfs_root = root; -- cgit v1.1 From 4c24b6d045a9d355c95ca4e6beb10ce2fd263390 Mon Sep 17 00:00:00 2001 From: Vernon Sauder Date: Fri, 20 Mar 2009 01:44:50 -0700 Subject: USB: pxa27x_udc: typo fixes and code cleanups This patch is a merge of patches : - fix function doc and debug - cleanup loop count - optimize code to remove local variable and extra check - init 'req' before use - add missing iounmap call [dbrownell@users.sourceforge.net: capitalize IN/OUT directions in doc] Signed-off-by: Vernon Sauder [folded by Robert Jarzmik Signed-off-by: Robert Jarzmik Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa27x_udc.c | 54 ++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 30 deletions(-) (limited to 'drivers/usb/gadget/pxa27x_udc.c') diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 91ba1e9..8cc676e 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -748,13 +748,13 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status) } /** - * ep_end_out_req - Ends control endpoint in request + * ep_end_out_req - Ends endpoint OUT request * @ep: physical endpoint * @req: pxa request * * Context: ep->lock held * - * Ends endpoint in request (completes usb request). + * Ends endpoint OUT request (completes usb request). */ static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) { @@ -763,13 +763,13 @@ static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) } /** - * ep0_end_out_req - Ends control endpoint in request (ends data stage) + * ep0_end_out_req - Ends control endpoint OUT request (ends data stage) * @ep: physical endpoint * @req: pxa request * * Context: ep->lock held * - * Ends control endpoint in request (completes usb request), and puts + * Ends control endpoint OUT request (completes usb request), and puts * control endpoint into idle state */ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) @@ -780,13 +780,13 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req) } /** - * ep_end_in_req - Ends endpoint out request + * ep_end_in_req - Ends endpoint IN request * @ep: physical endpoint * @req: pxa request * * Context: ep->lock held * - * Ends endpoint out request (completes usb request). + * Ends endpoint IN request (completes usb request). */ static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) { @@ -795,20 +795,18 @@ static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) } /** - * ep0_end_in_req - Ends control endpoint out request (ends data stage) + * ep0_end_in_req - Ends control endpoint IN request (ends data stage) * @ep: physical endpoint * @req: pxa request * * Context: ep->lock held * - * Ends control endpoint out request (completes usb request), and puts + * Ends control endpoint IN request (completes usb request), and puts * control endpoint into status state */ static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req) { - struct pxa_udc *udc = ep->dev; - - set_ep0state(udc, IN_STATUS_STAGE); + set_ep0state(ep->dev, IN_STATUS_STAGE); ep_end_in_req(ep, req); } @@ -1168,7 +1166,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, ep_end_in_req(ep, req); } else { ep_err(ep, "got a request of %d bytes while" - "in state WATI_ACK_SET_CONF_INTERF\n", + "in state WAIT_ACK_SET_CONF_INTERF\n", length); ep_del_request(ep, req); rc = -EL2HLT; @@ -1214,30 +1212,26 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) struct udc_usb_ep *udc_usb_ep; struct pxa27x_request *req; unsigned long flags; - int rc; + int rc = -EINVAL; if (!_ep) - return -EINVAL; + return rc; udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); ep = udc_usb_ep->pxa_ep; if (!ep || is_ep0(ep)) - return -EINVAL; + return rc; spin_lock_irqsave(&ep->lock, flags); /* make sure it's actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) + if (&req->req == _req) { + req_done(ep, req, -ECONNRESET); + rc = 0; break; + } } - rc = -EINVAL; - if (&req->req != _req) - goto out; - - rc = 0; - req_done(ep, req, -ECONNRESET); -out: spin_unlock_irqrestore(&ep->lock, flags); return rc; } @@ -1706,10 +1700,9 @@ static __init void udc_init_data(struct pxa_udc *dev) } /* USB endpoints init */ - for (i = 0; i < NR_USB_ENDPOINTS; i++) - if (i != 0) - list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, - &dev->gadget.ep_list); + for (i = 1; i < NR_USB_ENDPOINTS; i++) + list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, + &dev->gadget.ep_list); } /** @@ -1994,14 +1987,14 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) struct pxa27x_request *req = NULL; int completed = 0; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + udccsr0 = udc_ep_readl(ep, UDCCSR); ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n", EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR), (fifo_irq << 1 | opc_irq)); - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, struct pxa27x_request, queue); - if (udccsr0 & UDCCSR0_SST) { ep_dbg(ep, "clearing stall status\n"); nuke(ep, -EPIPE); @@ -2473,6 +2466,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev) platform_set_drvdata(_dev, NULL); the_controller = NULL; clk_put(udc->clk); + iounmap(udc->regs); return 0; } -- cgit v1.1