aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-05-07 16:20:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:54 -0400
commit9198769363d4dc1d63d49ecb2e2b189aceb42d94 (patch)
tree9d031c4c97e652100438f59732db79e16d6dc2bc
parent988199fe34411b413d5a388fc751c91eb4686f36 (diff)
[PATCH] USB: pxa2xx_udc updates
This has several small updates to the px2xx UDC driver: * small fixes from Eugeny S. Mints <emints@ru.mvista.com> - 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 <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c43
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h10
2 files changed, 32 insertions, 21 deletions
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b8b4524ed746..6a0b957af335 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * linux/drivers/usb/gadget/pxa2xx_udc.c 2 * linux/drivers/usb/gadget/pxa2xx_udc.c
3 * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers 3 * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
4 * 4 *
5 * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) 5 * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
6 * Copyright (C) 2003 Robert Schwebel, Pengutronix 6 * Copyright (C) 2003 Robert Schwebel, Pengutronix
@@ -63,7 +63,7 @@
63 63
64 64
65/* 65/*
66 * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx 66 * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
67 * series processors. The UDC for the IXP 4xx series is very similar. 67 * series processors. The UDC for the IXP 4xx series is very similar.
68 * There are fifteen endpoints, in addition to ep0. 68 * There are fifteen endpoints, in addition to ep0.
69 * 69 *
@@ -79,8 +79,8 @@
79 * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. 79 * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
80 */ 80 */
81 81
82#define DRIVER_VERSION "14-Dec-2003" 82#define DRIVER_VERSION "4-May-2005"
83#define DRIVER_DESC "PXA 2xx USB Device Controller driver" 83#define DRIVER_DESC "PXA 25x USB Device Controller driver"
84 84
85 85
86static const char driver_name [] = "pxa2xx_udc"; 86static const char driver_name [] = "pxa2xx_udc";
@@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
290static int pxa2xx_ep_disable (struct usb_ep *_ep) 290static int pxa2xx_ep_disable (struct usb_ep *_ep)
291{ 291{
292 struct pxa2xx_ep *ep; 292 struct pxa2xx_ep *ep;
293 unsigned long flags;
293 294
294 ep = container_of (_ep, struct pxa2xx_ep, ep); 295 ep = container_of (_ep, struct pxa2xx_ep, ep);
295 if (!_ep || !ep->desc) { 296 if (!_ep || !ep->desc) {
@@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
297 _ep ? ep->ep.name : NULL); 298 _ep ? ep->ep.name : NULL);
298 return -EINVAL; 299 return -EINVAL;
299 } 300 }
301 local_irq_save(flags);
302
300 nuke (ep, -ESHUTDOWN); 303 nuke (ep, -ESHUTDOWN);
301 304
302#ifdef USE_DMA 305#ifdef USE_DMA
@@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
313 ep->desc = NULL; 316 ep->desc = NULL;
314 ep->stopped = 1; 317 ep->stopped = 1;
315 318
319 local_irq_restore(flags);
316 DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); 320 DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
317 return 0; 321 return 0;
318} 322}
@@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
971 kick_dma(ep, req); 975 kick_dma(ep, req);
972#endif 976#endif
973 /* can the FIFO can satisfy the request immediately? */ 977 /* can the FIFO can satisfy the request immediately? */
974 } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 978 } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
975 && (*ep->reg_udccs & UDCCS_BI_TFS) != 0 979 if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
976 && write_fifo(ep, req)) { 980 && write_fifo(ep, req))
977 req = NULL; 981 req = NULL;
978 } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 982 } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
979 && read_fifo(ep, req)) { 983 && read_fifo(ep, req)) {
980 req = NULL; 984 req = NULL;
@@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
1290 "%s version: %s\nGadget driver: %s\nHost %s\n\n", 1294 "%s version: %s\nGadget driver: %s\nHost %s\n\n",
1291 driver_name, DRIVER_VERSION SIZE_STR DMASTR, 1295 driver_name, DRIVER_VERSION SIZE_STR DMASTR,
1292 dev->driver ? dev->driver->driver.name : "(none)", 1296 dev->driver ? dev->driver->driver.name : "(none)",
1293 is_usb_connected() ? "full speed" : "disconnected"); 1297 is_vbus_present() ? "full speed" : "disconnected");
1294 size -= t; 1298 size -= t;
1295 next += t; 1299 next += t;
1296 1300
@@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
1339 next += t; 1343 next += t;
1340 } 1344 }
1341 1345
1342 if (!is_usb_connected() || !dev->driver) 1346 if (!is_vbus_present() || !dev->driver)
1343 goto done; 1347 goto done;
1344 1348
1345 t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", 1349 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)
1454 UFNRH = UFNRH_SIM; 1458 UFNRH = UFNRH_SIM;
1455 1459
1456 /* if hardware supports it, disconnect from usb */ 1460 /* if hardware supports it, disconnect from usb */
1457 make_usb_disappear(); 1461 pullup_off();
1458 1462
1459 udc_clear_mask_UDCCR(UDCCR_UDE); 1463 udc_clear_mask_UDCCR(UDCCR_UDE);
1460 1464
@@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
1567 UICR0 &= ~UICR0_IM0; 1571 UICR0 &= ~UICR0_IM0;
1568 1572
1569 /* if hardware supports it, pullup D+ and wait for reset */ 1573 /* if hardware supports it, pullup D+ and wait for reset */
1570 let_usb_appear(); 1574 pullup_on();
1571} 1575}
1572 1576
1573 1577
@@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
2052 if (unlikely(udccr & UDCCR_SUSIR)) { 2056 if (unlikely(udccr & UDCCR_SUSIR)) {
2053 udc_ack_int_UDCCR(UDCCR_SUSIR); 2057 udc_ack_int_UDCCR(UDCCR_SUSIR);
2054 handled = 1; 2058 handled = 1;
2055 DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected() 2059 DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
2056 ? "" : "+disconnect"); 2060 ? "" : "+disconnect");
2057 2061
2058 if (!is_usb_connected()) 2062 if (!is_vbus_present())
2059 stop_activity(dev, dev->driver); 2063 stop_activity(dev, dev->driver);
2060 else if (dev->gadget.speed != USB_SPEED_UNKNOWN 2064 else if (dev->gadget.speed != USB_SPEED_UNKNOWN
2061 && dev->driver 2065 && dev->driver
@@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
2073 if (dev->gadget.speed != USB_SPEED_UNKNOWN 2077 if (dev->gadget.speed != USB_SPEED_UNKNOWN
2074 && dev->driver 2078 && dev->driver
2075 && dev->driver->resume 2079 && dev->driver->resume
2076 && is_usb_connected()) 2080 && is_vbus_present())
2077 dev->driver->resume(&dev->gadget); 2081 dev->driver->resume(&dev->gadget);
2078 } 2082 }
2079 2083
@@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
2509 udc_disable(dev); 2513 udc_disable(dev);
2510 udc_reinit(dev); 2514 udc_reinit(dev);
2511 2515
2512 dev->vbus = is_usb_connected(); 2516 dev->vbus = is_vbus_present();
2513 2517
2514 /* irq setup after old hardware state is cleaned up */ 2518 /* irq setup after old hardware state is cleaned up */
2515 retval = request_irq(IRQ_USB, pxa2xx_udc_irq, 2519 retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
@@ -2555,6 +2559,12 @@ lubbock_fail0:
2555 2559
2556 return 0; 2560 return 0;
2557} 2561}
2562
2563static void pxa2xx_udc_shutdown(struct device *_dev)
2564{
2565 pullup_off();
2566}
2567
2558static int __exit pxa2xx_udc_remove(struct device *_dev) 2568static int __exit pxa2xx_udc_remove(struct device *_dev)
2559{ 2569{
2560 struct pxa2xx_udc *dev = dev_get_drvdata(_dev); 2570 struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
@@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = {
2624 .name = "pxa2xx-udc", 2634 .name = "pxa2xx-udc",
2625 .bus = &platform_bus_type, 2635 .bus = &platform_bus_type,
2626 .probe = pxa2xx_udc_probe, 2636 .probe = pxa2xx_udc_probe,
2637 .shutdown = pxa2xx_udc_shutdown,
2627 .remove = __exit_p(pxa2xx_udc_remove), 2638 .remove = __exit_p(pxa2xx_udc_remove),
2628 .suspend = pxa2xx_udc_suspend, 2639 .suspend = pxa2xx_udc_suspend,
2629 .resume = pxa2xx_udc_resume, 2640 .resume = pxa2xx_udc_resume,
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 1f3a7d999da7..d0bc396a85d5 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,23 +177,23 @@ struct pxa2xx_udc {
177 177
178static struct pxa2xx_udc *the_controller; 178static struct pxa2xx_udc *the_controller;
179 179
180/* one GPIO should be used to detect host disconnect */ 180/* one GPIO should be used to detect VBUS from the host */
181static inline int is_usb_connected(void) 181static inline int is_vbus_present(void)
182{ 182{
183 if (!the_controller->mach->udc_is_connected) 183 if (!the_controller->mach->udc_is_connected)
184 return 1; 184 return 1;
185 return the_controller->mach->udc_is_connected(); 185 return the_controller->mach->udc_is_connected();
186} 186}
187 187
188/* one GPIO should force the host to see this device (or not) */ 188/* one GPIO should control a D+ pullup, so host sees this device (or not) */
189static inline void make_usb_disappear(void) 189static inline void pullup_off(void)
190{ 190{
191 if (!the_controller->mach->udc_command) 191 if (!the_controller->mach->udc_command)
192 return; 192 return;
193 the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); 193 the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
194} 194}
195 195
196static inline void let_usb_appear(void) 196static inline void pullup_on(void)
197{ 197{
198 if (!the_controller->mach->udc_command) 198 if (!the_controller->mach->udc_command)
199 return; 199 return;