From 9198769363d4dc1d63d49ecb2e2b189aceb42d94 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 7 May 2005 13:20:19 -0700 Subject: [PATCH] USB: pxa2xx_udc updates This has several small updates to the px2xx UDC driver: * small fixes from Eugeny S. Mints - local_irq_save() around potential endpoint disable race - fix handling of enqueue to OUT endpoints (potential oops) * add shutdown() method to disable any D+ pullup * rename methods accessing raw signals, referencing the signals * describes itself as for "pxa25x", since pxa27x is different Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pxa2xx_udc.c | 43 ++++++++++++++++++++++++++--------------- drivers/usb/gadget/pxa2xx_udc.h | 10 +++++----- 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b8b4524ed74..6a0b957af33 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -1,6 +1,6 @@ /* * linux/drivers/usb/gadget/pxa2xx_udc.c - * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers + * Intel PXA25x and IXP4xx on-chip full speed USB device controllers * * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) * Copyright (C) 2003 Robert Schwebel, Pengutronix @@ -63,7 +63,7 @@ /* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx + * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x * series processors. The UDC for the IXP 4xx series is very similar. * There are fifteen endpoints, in addition to ep0. * @@ -79,8 +79,8 @@ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. */ -#define DRIVER_VERSION "14-Dec-2003" -#define DRIVER_DESC "PXA 2xx USB Device Controller driver" +#define DRIVER_VERSION "4-May-2005" +#define DRIVER_DESC "PXA 25x USB Device Controller driver" static const char driver_name [] = "pxa2xx_udc"; @@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep, static int pxa2xx_ep_disable (struct usb_ep *_ep) { struct pxa2xx_ep *ep; + unsigned long flags; ep = container_of (_ep, struct pxa2xx_ep, ep); if (!_ep || !ep->desc) { @@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) _ep ? ep->ep.name : NULL); return -EINVAL; } + local_irq_save(flags); + nuke (ep, -ESHUTDOWN); #ifdef USE_DMA @@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) ep->desc = NULL; ep->stopped = 1; + local_irq_restore(flags); DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0; } @@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) kick_dma(ep, req); #endif /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (*ep->reg_udccs & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) { - req = NULL; + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 + && write_fifo(ep, req)) + req = NULL; } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 && read_fifo(ep, req)) { req = NULL; @@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR DMASTR, dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected() ? "full speed" : "disconnected"); + is_vbus_present() ? "full speed" : "disconnected"); size -= t; next += t; @@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count, next += t; } - if (!is_usb_connected() || !dev->driver) + if (!is_vbus_present() || !dev->driver) goto done; t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", @@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev) UFNRH = UFNRH_SIM; /* if hardware supports it, disconnect from usb */ - make_usb_disappear(); + pullup_off(); udc_clear_mask_UDCCR(UDCCR_UDE); @@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev) UICR0 &= ~UICR0_IM0; /* if hardware supports it, pullup D+ and wait for reset */ - let_usb_appear(); + pullup_on(); } @@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (unlikely(udccr & UDCCR_SUSIR)) { udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; - DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected() + DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present() ? "" : "+disconnect"); - if (!is_usb_connected()) + if (!is_vbus_present()) stop_activity(dev, dev->driver); else if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver @@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r) if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume - && is_usb_connected()) + && is_vbus_present()) dev->driver->resume(&dev->gadget); } @@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev) udc_disable(dev); udc_reinit(dev); - dev->vbus = is_usb_connected(); + dev->vbus = is_vbus_present(); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USB, pxa2xx_udc_irq, @@ -2555,6 +2559,12 @@ lubbock_fail0: return 0; } + +static void pxa2xx_udc_shutdown(struct device *_dev) +{ + pullup_off(); +} + static int __exit pxa2xx_udc_remove(struct device *_dev) { struct pxa2xx_udc *dev = dev_get_drvdata(_dev); @@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = { .name = "pxa2xx-udc", .bus = &platform_bus_type, .probe = pxa2xx_udc_probe, + .shutdown = pxa2xx_udc_shutdown, .remove = __exit_p(pxa2xx_udc_remove), .suspend = pxa2xx_udc_suspend, .resume = pxa2xx_udc_resume, diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index 1f3a7d999da..d0bc396a85d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -177,23 +177,23 @@ struct pxa2xx_udc { static struct pxa2xx_udc *the_controller; -/* one GPIO should be used to detect host disconnect */ -static inline int is_usb_connected(void) +/* one GPIO should be used to detect VBUS from the host */ +static inline int is_vbus_present(void) { if (!the_controller->mach->udc_is_connected) return 1; return the_controller->mach->udc_is_connected(); } -/* one GPIO should force the host to see this device (or not) */ -static inline void make_usb_disappear(void) +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static inline void pullup_off(void) { if (!the_controller->mach->udc_command) return; the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); } -static inline void let_usb_appear(void) +static inline void pullup_on(void) { if (!the_controller->mach->udc_command) return; -- cgit v1.2.3-70-g09d2