Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91987693 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman
Browse files

[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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 988199fe
Loading
Loading
Loading
Loading
+27 −16
Original line number Diff line number Diff line
/*
 * 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,9 +975,9 @@ 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)) {
		} 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)) {
@@ -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 @@ static int __init pxa2xx_udc_probe(struct device *_dev)

	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,
+5 −5
Original line number Diff line number Diff line
@@ -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;