Add support for Siemens SX1 mobile phone;
add support for USB-based console
(enable with "setenv stdout usbtty; setenv stdin usbtty")
diff --git a/drivers/Makefile b/drivers/Makefile
index b333aed..32a6a06 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,5 +1,5 @@
 #
-# (C) Copyright 2000
+# (C) Copyright 2000-2004
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 #
 # See file CREDITS for list of people who contributed to this
@@ -12,7 +12,7 @@
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
@@ -29,7 +29,7 @@
 
 OBJS	= 3c589.o 5701rls.o ali512x.o \
 	  bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \
-	  cs8900.o ct69000.o dataflash.o dc2114x.o          \
+	  cs8900.o ct69000.o dataflash.o dc2114x.o	    \
 	  e1000.o eepro100.o \
 	  i8042.o i82365.o inca-ip_sw.o \
 	  lan91c96.o natsemi.o netarm_eth.o \
@@ -40,11 +40,12 @@
 	  rtl8019.o rtl8139.o \
 	  s3c24x0_i2c.o sed13806.o serial.o serial_max3100.o \
 	  smc91111.o smiLynxEM.o status_led.o sym53c8xx.o \
-	  ti_pci1410a.o tigon3.o w83c553f.o
+	  ti_pci1410a.o tigon3.o w83c553f.o omap1510_i2c.o \
+	  usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o
 
 all:	$(LIB)
 
-$(LIB):	$(OBJS)
+$(LIB): $(OBJS)
 	$(AR) crv $@ $(OBJS)
 
 #########################################################################
diff --git a/drivers/ns16550.c b/drivers/ns16550.c
index a7aa40f..05862ee 100644
--- a/drivers/ns16550.c
+++ b/drivers/ns16550.c
@@ -18,7 +18,7 @@
 {
 	com_port->ier = 0x00;
 #ifdef CONFIG_OMAP1510
-	com_port->mdr1 = 0x7;   /* mode select reset TL16C750*/
+	com_port->mdr1 = 0x7;	/* mode select reset TL16C750*/
 #endif
 	com_port->lcr = LCR_BKSE | LCRVAL;
 	com_port->dll = baud_divisor & 0xff;
@@ -50,7 +50,12 @@
 
 char NS16550_getc (NS16550_t com_port)
 {
-	while ((com_port->lsr & LSR_DR) == 0);
+	while ((com_port->lsr & LSR_DR) == 0) {
+#ifdef CONFIG_USB_TTY
+		extern void usbtty_poll(void);
+		usbtty_poll();
+#endif
+	}
 	return (com_port->rbr);
 }
 
diff --git a/drivers/omap1510_i2c.c b/drivers/omap1510_i2c.c
new file mode 100644
index 0000000..04400fb
--- /dev/null
+++ b/drivers/omap1510_i2c.c
@@ -0,0 +1,281 @@
+/*
+ * Basic I2C functions
+ *
+ * Copyright (c) 2003 Texas Instruments
+ *
+ * This package is free software;  you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Jian Zhang jzhang@ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
+ * Rewritten to fit into the current U-Boot framework
+ *
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_DRIVER_OMAP1510_I2C
+
+static void wait_for_bb (void);
+static u16 wait_for_pin (void);
+
+void i2c_init (int speed, int slaveadd)
+{
+	u16 scl;
+
+	if (inw (I2C_CON) & I2C_CON_EN) {
+		outw (0, I2C_CON);
+		udelay (5000);
+	}
+
+	/* 12Mhz I2C module clock */
+	outw (0, I2C_PSC);
+	outw (I2C_CON_EN, I2C_CON);
+	outw (0, I2C_SYSTEST);
+	/* have to enable intrrupts or OMAP i2c module doesn't work */
+	outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
+	      I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
+	scl = (12000000 / 2) / speed - 6;
+	outw (scl, I2C_SCLL);
+	outw (scl, I2C_SCLH);
+	/* own address */
+	outw (slaveadd, I2C_OA);
+	outw (0, I2C_CNT);
+	udelay (1000);
+}
+
+static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
+{
+	int i2c_error = 0;
+	u16 status;
+
+	/* wait until bus not busy */
+	wait_for_bb ();
+
+	/* one byte only */
+	outw (1, I2C_CNT);
+	/* set slave address */
+	outw (devaddr, I2C_SA);
+	/* no stop bit needed here */
+	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
+
+	status = wait_for_pin ();
+
+	if (status & I2C_STAT_XRDY) {
+		/* Important: have to use byte access */
+		*(volatile u8 *) (I2C_DATA) = regoffset;
+		udelay (20000);
+		if (inw (I2C_STAT) & I2C_STAT_NACK) {
+			i2c_error = 1;
+		}
+	} else {
+		i2c_error = 1;
+	}
+
+	if (!i2c_error) {
+		/* free bus, otherwise we can't use a combined transction */
+		outw (0, I2C_CON);
+		while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
+			udelay (10000);
+			/* Have to clear pending interrupt to clear I2C_STAT */
+			inw (I2C_IV);
+		}
+
+		wait_for_bb ();
+		/* set slave address */
+		outw (devaddr, I2C_SA);
+		/* read one byte from slave */
+		outw (1, I2C_CNT);
+		/* need stop bit here */
+		outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
+		      I2C_CON);
+
+		status = wait_for_pin ();
+		if (status & I2C_STAT_RRDY) {
+			*value = inw (I2C_DATA);
+			udelay (20000);
+		} else {
+			i2c_error = 1;
+		}
+
+		if (!i2c_error) {
+			outw (I2C_CON_EN, I2C_CON);
+			while (inw (I2C_STAT)
+			       || (inw (I2C_CON) & I2C_CON_MST)) {
+				udelay (10000);
+				inw (I2C_IV);
+			}
+		}
+	}
+
+	return i2c_error;
+}
+
+static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
+{
+	int i2c_error = 0;
+	u16 status;
+
+	/* wait until bus not busy */
+	wait_for_bb ();
+
+	/* two bytes */
+	outw (2, I2C_CNT);
+	/* set slave address */
+	outw (devaddr, I2C_SA);
+	/* stop bit needed here */
+	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+	      I2C_CON_STP, I2C_CON);
+
+	/* wait until state change */
+	status = wait_for_pin ();
+
+	if (status & I2C_STAT_XRDY) {
+		/* send out two bytes */
+		outw ((value << 8) + regoffset, I2C_DATA);
+		/* must have enough delay to allow BB bit to go low */
+		udelay (30000);
+		if (inw (I2C_STAT) & I2C_STAT_NACK) {
+			i2c_error = 1;
+		}
+	} else {
+		i2c_error = 1;
+	}
+
+	if (!i2c_error) {
+		outw (I2C_CON_EN, I2C_CON);
+		while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
+			udelay (1000);
+			/* have to read to clear intrrupt */
+			inw (I2C_IV);
+		}
+	}
+
+	return i2c_error;
+}
+
+int i2c_probe (uchar chip)
+{
+	int res = 1;
+
+	if (chip == inw (I2C_OA)) {
+		return res;
+	}
+
+	/* wait until bus not busy */
+	wait_for_bb ();
+
+	/* try to read one byte */
+	outw (1, I2C_CNT);
+	/* set slave address */
+	outw (chip, I2C_SA);
+	/* stop bit needed here */
+	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
+	/* enough delay for the NACK bit set */
+	udelay (2000);
+	if (!(inw (I2C_STAT) & I2C_STAT_NACK)) {
+		res = 0;
+	} else {
+		outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON);
+		udelay (20);
+		wait_for_bb ();
+	}
+
+	return res;
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+	int i;
+
+	if (alen > 1) {
+		printf ("I2C read: addr len %d not supported\n", alen);
+		return 1;
+	}
+
+	if (addr + len > 256) {
+		printf ("I2C read: address out of range\n");
+		return 1;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (i2c_read_byte (chip, addr + i, &buffer[i])) {
+			printf ("I2C read: I/O error\n");
+			i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
+{
+	int i;
+
+	if (alen > 1) {
+		printf ("I2C read: addr len %d not supported\n", alen);
+		return 1;
+	}
+
+	if (addr + len > 256) {
+		printf ("I2C read: address out of range\n");
+		return 1;
+	}
+
+	for (i = 0; i < len; i++) {
+		if (i2c_write_byte (chip, addr + i, buffer[i])) {
+			printf ("I2C read: I/O error\n");
+			i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void wait_for_bb (void)
+{
+	int timeout = 10;
+
+	while ((inw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
+		inw (I2C_IV);
+		udelay (1000);
+	}
+
+	if (timeout <= 0) {
+		printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
+			inw (I2C_STAT));
+	}
+}
+
+static u16 wait_for_pin (void)
+{
+	u16 status, iv;
+	int timeout = 10;
+
+	do {
+		udelay (1000);
+		status = inw (I2C_STAT);
+		iv = inw (I2C_IV);
+	} while (!iv &&
+		 !(status &
+		   (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
+		    I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
+		    I2C_STAT_AL)) && timeout--);
+
+	if (timeout <= 0) {
+		printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
+			inw (I2C_STAT));
+	}
+
+	return status;
+}
+
+#endif /* CONFIG_DRIVER_OMAP1510_I2C */
diff --git a/drivers/usbdcore.c b/drivers/usbdcore.c
new file mode 100644
index 0000000..308c7ce
--- /dev/null
+++ b/drivers/usbdcore.c
@@ -0,0 +1,684 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *	Stuart Lynne <sl@lineo.com>,
+ *	Tom Rushworth <tbr@lineo.com>,
+ *	Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <malloc.h>
+#include "usbdcore.h"
+
+#define MAX_INTERFACES 2
+
+
+int maxstrings = 20;
+
+/* Global variables ************************************************************************** */
+
+struct usb_string_descriptor **usb_strings;
+
+int usb_devices;
+
+extern struct usb_function_driver ep0_driver;
+
+int registered_functions;
+int registered_devices;
+
+char *usbd_device_events[] = {
+	"DEVICE_UNKNOWN",
+	"DEVICE_INIT",
+	"DEVICE_CREATE",
+	"DEVICE_HUB_CONFIGURED",
+	"DEVICE_RESET",
+	"DEVICE_ADDRESS_ASSIGNED",
+	"DEVICE_CONFIGURED",
+	"DEVICE_SET_INTERFACE",
+	"DEVICE_SET_FEATURE",
+	"DEVICE_CLEAR_FEATURE",
+	"DEVICE_DE_CONFIGURED",
+	"DEVICE_BUS_INACTIVE",
+	"DEVICE_BUS_ACTIVITY",
+	"DEVICE_POWER_INTERRUPTION",
+	"DEVICE_HUB_RESET",
+	"DEVICE_DESTROY",
+	"DEVICE_FUNCTION_PRIVATE",
+};
+
+char *usbd_device_states[] = {
+	"STATE_INIT",
+	"STATE_CREATED",
+	"STATE_ATTACHED",
+	"STATE_POWERED",
+	"STATE_DEFAULT",
+	"STATE_ADDRESSED",
+	"STATE_CONFIGURED",
+	"STATE_UNKNOWN",
+};
+
+char *usbd_device_requests[] = {
+	"GET STATUS",		/* 0 */
+	"CLEAR FEATURE",	/* 1 */
+	"RESERVED",		/* 2 */
+	"SET FEATURE",		/* 3 */
+	"RESERVED",		/* 4 */
+	"SET ADDRESS",		/* 5 */
+	"GET DESCRIPTOR",	/* 6 */
+	"SET DESCRIPTOR",	/* 7 */
+	"GET CONFIGURATION",	/* 8 */
+	"SET CONFIGURATION",	/* 9 */
+	"GET INTERFACE",	/* 10 */
+	"SET INTERFACE",	/* 11 */
+	"SYNC FRAME",		/* 12 */
+};
+
+char *usbd_device_descriptors[] = {
+	"UNKNOWN",		/* 0 */
+	"DEVICE",		/* 1 */
+	"CONFIG",		/* 2 */
+	"STRING",		/* 3 */
+	"INTERFACE",		/* 4 */
+	"ENDPOINT",		/* 5 */
+	"DEVICE QUALIFIER",	/* 6 */
+	"OTHER SPEED",		/* 7 */
+	"INTERFACE POWER",	/* 8 */
+};
+
+char *usbd_device_status[] = {
+	"USBD_OPENING",
+	"USBD_OK",
+	"USBD_SUSPENDED",
+	"USBD_CLOSING",
+};
+
+
+/* Descriptor support functions ************************************************************** */
+
+
+/**
+ * usbd_get_string - find and return a string descriptor
+ * @index: string index to return
+ *
+ * Find an indexed string and return a pointer to a it.
+ */
+struct usb_string_descriptor *usbd_get_string (__u8 index)
+{
+	if (index >= maxstrings) {
+		return NULL;
+	}
+	return usb_strings[index];
+}
+
+
+/* Access to device descriptor functions ***************************************************** */
+
+
+/* *
+ * usbd_device_configuration_instance - find a configuration instance for this device
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Get specifed device configuration. Index should be bConfigurationValue-1.
+ */
+static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
+		unsigned int port, unsigned int configuration)
+{
+	/* XXX */
+	configuration = configuration ? configuration - 1 : 0;
+
+	if (configuration >= device->configurations) {
+		return NULL;
+	}
+	return device->configuration_instance_array + configuration;
+}
+
+
+/* *
+ * usbd_device_interface_instance
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
+{
+	struct usb_configuration_instance *configuration_instance;
+
+	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
+		return NULL;
+	}
+	if (interface >= configuration_instance->interfaces) {
+		return NULL;
+	}
+	return configuration_instance->interface_instance_array + interface;
+}
+
+/* *
+ * usbd_device_alternate_descriptor_list
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified alternate descriptor for the specified device.
+ */
+struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
+{
+	struct usb_interface_instance *interface_instance;
+
+	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
+		return NULL;
+	}
+
+	if (alternate >= interface_instance->alternates) {
+		return NULL;
+	}
+
+	return interface_instance->alternates_instance_array + alternate;
+}
+
+
+/* *
+ * usbd_device_device_descriptor
+ * @device: which device
+ * @configuration: index to configuration, 0 - N-1
+ * @port: which port
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
+{
+	return (device->device_descriptor);
+}
+
+
+/**
+ * usbd_device_configuration_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
+									   usb_device_instance
+									   *device, int port, int configuration)
+{
+	struct usb_configuration_instance *configuration_instance;
+	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
+		return NULL;
+	}
+	return (configuration_instance->configuration_descriptor);
+}
+
+
+/**
+ * usbd_device_interface_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
+								   *device, int port, int configuration, int interface, int alternate)
+{
+	struct usb_interface_instance *interface_instance;
+	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
+		return NULL;
+	}
+	if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
+		return NULL;
+	}
+	return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
+}
+
+/**
+ * usbd_device_endpoint_descriptor_index
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: index setting
+ * @index: which index
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
+								       *device, int port, int configuration, int interface, int alternate, int index)
+{
+	struct usb_alternate_instance *alternate_instance;
+
+	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+		return NULL;
+	}
+	if (index >= alternate_instance->endpoints) {
+		return NULL;
+	}
+	return *(alternate_instance->endpoints_descriptor_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_transfersize
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @index: which index
+ *
+ * Return the specified endpoint transfer size;
+ */
+int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
+{
+	struct usb_alternate_instance *alternate_instance;
+
+	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+		return 0;
+	}
+	if (index >= alternate_instance->endpoints) {
+		return 0;
+	}
+	return *(alternate_instance->endpoint_transfersize_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ * @endpoint: which endpoint
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
+{
+	struct usb_endpoint_descriptor *endpoint_descriptor;
+	int i;
+
+	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
+		if (endpoint_descriptor->bEndpointAddress == endpoint) {
+			return endpoint_descriptor;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * usbd_endpoint_halted
+ * @device: point to struct usb_device_instance
+ * @endpoint: endpoint to check
+ *
+ * Return non-zero if endpoint is halted.
+ */
+int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
+{
+	return (device->status == USB_STATUS_HALT);
+}
+
+
+/**
+ * usbd_rcv_complete - complete a receive
+ * @endpoint:
+ * @len:
+ * @urb_bad:
+ *
+ * Called from rcv interrupt to complete.
+ */
+void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
+{
+	if (endpoint) {
+		struct urb *rcv_urb;
+
+		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
+
+		/* if we had an urb then update actual_length, dispatch if neccessary */
+		if ((rcv_urb = endpoint->rcv_urb)) {
+
+			/*usbdbg("actual: %d buffer: %d\n", */
+			/*rcv_urb->actual_length, rcv_urb->buffer_length); */
+
+			/* check the urb is ok, are we adding data less than the packetsize */
+			if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
+			  /*usbdbg("updating actual_length by %d\n",len); */
+
+				/* increment the received data size */
+				rcv_urb->actual_length += len;
+
+			} else {
+				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
+				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
+
+				rcv_urb->actual_length = 0;
+				rcv_urb->status = RECV_ERROR;
+			}
+		} else {
+			usberr("no rcv_urb!");
+		}
+	} else {
+		usberr("no endpoint!");
+	}
+
+}
+
+/**
+ * usbd_tx_complete - complete a transmit
+ * @endpoint:
+ * @resetart:
+ *
+ * Called from tx interrupt to complete.
+ */
+void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
+{
+	if (endpoint) {
+		struct urb *tx_urb;
+
+		/* if we have a tx_urb advance or reset, finish if complete */
+		if ((tx_urb = endpoint->tx_urb)) {
+			int sent = endpoint->last;
+			endpoint->sent += sent;
+			endpoint->last -= sent;
+
+			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
+				tx_urb->actual_length = 0;
+				endpoint->sent = 0;
+				endpoint->last = 0;
+
+				/* Remove from active, save for re-use */
+				urb_detach(tx_urb);
+				urb_append(&endpoint->done, tx_urb);
+				/*usbdbg("done->next %p, tx_urb %p, done %p", */
+				/*	 endpoint->done.next, tx_urb, &endpoint->done); */
+
+				endpoint->tx_urb = first_urb_detached(&endpoint->tx);
+				if( endpoint->tx_urb ) {
+					endpoint->tx_queue--;
+					usbdbg("got urb from tx list");
+				}
+				if( !endpoint->tx_urb ) {
+					/*usbdbg("taking urb from done list"); */
+					endpoint->tx_urb = first_urb_detached(&endpoint->done);
+				}
+				if( !endpoint->tx_urb ) {
+					usbdbg("allocating new urb for tx_urb");
+					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
+				}
+			}
+		}
+	}
+}
+
+/* URB linked list functions ***************************************************** */
+
+/*
+ * Initialize an urb_link to be a single element list.
+ * If the urb_link is being used as a distinguished list head
+ * the list is empty when the head is the only link in the list.
+ */
+void urb_link_init (urb_link * ul)
+{
+	if (ul) {
+		ul->prev = ul->next = ul;
+	}
+}
+
+/*
+ * Detach an urb_link from a list, and set it
+ * up as a single element list, so no dangling
+ * pointers can be followed, and so it can be
+ * joined to another list if so desired.
+ */
+void urb_detach (struct urb *urb)
+{
+	if (urb) {
+		urb_link *ul = &urb->link;
+		ul->next->prev = ul->prev;
+		ul->prev->next = ul->next;
+		urb_link_init (ul);
+	}
+}
+
+/*
+ * Return the first urb_link in a list with a distinguished
+ * head "hd", or NULL if the list is empty.  This will also
+ * work as a predicate, returning NULL if empty, and non-NULL
+ * otherwise.
+ */
+urb_link *first_urb_link (urb_link * hd)
+{
+	urb_link *nx;
+	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
+		/* There is at least one element in the list */
+		/* (besides the distinguished head). */
+		return (nx);
+	}
+	/* The list is empty */
+	return (NULL);
+}
+
+/*
+ * Return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ */
+struct urb *first_urb (urb_link * hd)
+{
+	urb_link *nx;
+	if (NULL == (nx = first_urb_link (hd))) {
+		/* The list is empty */
+		return (NULL);
+	}
+	return (p2surround (struct urb, link, nx));
+}
+
+/*
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ */
+struct urb *first_urb_detached (urb_link * hd)
+{
+	struct urb *urb;
+	if ((urb = first_urb (hd))) {
+		urb_detach (urb);
+	}
+	return urb;
+}
+
+
+/*
+ * Append an urb_link (or a whole list of
+ * urb_links) to the tail of another list
+ * of urb_links.
+ */
+void urb_append (urb_link * hd, struct urb *urb)
+{
+	if (hd && urb) {
+		urb_link *new = &urb->link;
+
+		/* This allows the new urb to be a list of urbs, */
+		/* with new pointing at the first, but the link */
+		/* must be initialized. */
+		/* Order is important here... */
+		urb_link *pul = hd->prev;
+		new->prev->next = hd;
+		hd->prev = new->prev;
+		new->prev = pul;
+		pul->next = new;
+	}
+}
+
+/* URB create/destroy functions ***************************************************** */
+
+/**
+ * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
+ * @device: device instance
+ * @endpoint: endpoint
+ *
+ * Allocate an urb structure. The usb device urb structure is used to
+ * contain all data associated with a transfer, including a setup packet for
+ * control transfers.
+ *
+ * NOTE: endpoint_address MUST contain a direction flag.
+ */
+struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint)
+{
+	struct urb *urb;
+
+	if( !(urb = (struct urb*)malloc(sizeof(struct urb))) ) {
+	  usberr(" F A T A L:  malloc(%u) FAILED!!!!", sizeof(struct urb));
+	  return NULL;
+	}
+
+	/* Fill in known fields */
+	memset(urb, 0, sizeof(struct urb));
+	urb->endpoint = endpoint;
+	urb->device = device;
+	urb->buffer = (u8*)urb->buffer_data;
+	urb->buffer_length = sizeof(urb->buffer_data);
+
+	urb_link_init (&urb->link);
+
+	return urb;
+}
+
+/**
+ * usbd_dealloc_urb - deallocate an URB and associated buffer
+ * @urb: pointer to an urb structure
+ *
+ * Deallocate an urb structure and associated data.
+ */
+void usbd_dealloc_urb (struct urb *urb)
+{
+	if (urb) {
+		free (urb);
+	}
+}
+
+/* Event signaling functions ***************************************************** */
+
+/**
+ * usbd_device_event - called to respond to various usb events
+ * @device: pointer to struct device
+ * @event: event to respond to
+ *
+ * Used by a Bus driver to indicate an event.
+ */
+void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
+{
+	usb_device_state_t state;
+
+	if (!device || !device->bus) {
+		usberr("(%p,%d) NULL device or device->bus", device, event);
+		return;
+	}
+
+	state = device->device_state;
+
+	usbinfo("%s", usbd_device_events[event]);
+
+	switch (event) {
+	case DEVICE_UNKNOWN:
+		break;
+	case DEVICE_INIT:
+		device->device_state = STATE_INIT;
+		break;
+
+	case DEVICE_CREATE:
+		device->device_state = STATE_ATTACHED;
+		break;
+
+	case DEVICE_HUB_CONFIGURED:
+		device->device_state = STATE_POWERED;
+		break;
+
+	case DEVICE_RESET:
+		device->device_state = STATE_DEFAULT;
+		device->address = 0;
+		break;
+
+	case DEVICE_ADDRESS_ASSIGNED:
+		device->device_state = STATE_ADDRESSED;
+		break;
+
+	case DEVICE_CONFIGURED:
+		device->device_state = STATE_CONFIGURED;
+		break;
+
+	case DEVICE_DE_CONFIGURED:
+		device->device_state = STATE_ADDRESSED;
+		break;
+
+	case DEVICE_BUS_INACTIVE:
+		if (device->status != USBD_CLOSING) {
+			device->status = USBD_SUSPENDED;
+		}
+		break;
+	case DEVICE_BUS_ACTIVITY:
+		if (device->status != USBD_CLOSING) {
+			device->status = USBD_OK;
+		}
+		break;
+
+	case DEVICE_SET_INTERFACE:
+		break;
+	case DEVICE_SET_FEATURE:
+		break;
+	case DEVICE_CLEAR_FEATURE:
+		break;
+
+	case DEVICE_POWER_INTERRUPTION:
+		device->device_state = STATE_POWERED;
+		break;
+	case DEVICE_HUB_RESET:
+		device->device_state = STATE_ATTACHED;
+		break;
+	case DEVICE_DESTROY:
+		device->device_state = STATE_UNKNOWN;
+		break;
+
+	case DEVICE_FUNCTION_PRIVATE:
+		break;
+
+	default:
+		usbdbg("event %d - not handled",event);
+		break;
+	}
+	/*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
+		device->name, event, state,
+		device->device_state, device->status, device->address); */
+
+	/* tell the bus interface driver */
+	if( device->event ) {
+		/* usbdbg("calling device->event"); */
+		device->event(device, event, data);
+	}
+}
diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c
new file mode 100644
index 0000000..260befe
--- /dev/null
+++ b/drivers/usbdcore_ep0.c
@@ -0,0 +1,686 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/ep0.c
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ *	Stuart Lynne <sl@lineo.com>,
+ *	Tom Rushworth <tbr@lineo.com>,
+ *	Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * This is the builtin ep0 control function. It implements all required functionality
+ * for responding to control requests (SETUP packets).
+ *
+ * XXX
+ *
+ * Currently we do not pass any SETUP packets (or other) to the configured
+ * function driver. This may need to change.
+ *
+ * XXX
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+#include "usbdcore.h"
+
+#if 0
+#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define dbg_ep0(lvl,fmt,args...)
+#endif
+
+/* EP0 Configuration Set ********************************************************************* */
+
+
+/**
+ * ep0_get_status - fill in URB data with appropriate status
+ * @device:
+ * @urb:
+ * @index:
+ * @requesttype:
+ *
+ */
+static int ep0_get_status (struct usb_device_instance *device,
+			   struct urb *urb, int index, int requesttype)
+{
+	char *cp;
+
+	urb->actual_length = 2;
+	cp = urb->buffer;
+	cp[0] = cp[1] = 0;
+
+	switch (requesttype) {
+	case USB_REQ_RECIPIENT_DEVICE:
+		cp[0] = USB_STATUS_SELFPOWERED;
+		break;
+	case USB_REQ_RECIPIENT_INTERFACE:
+		break;
+	case USB_REQ_RECIPIENT_ENDPOINT:
+		cp[0] = usbd_endpoint_halted (device, index);
+		break;
+	case USB_REQ_RECIPIENT_OTHER:
+		urb->actual_length = 0;
+	default:
+		break;
+	}
+	dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
+	return 0;
+}
+
+/**
+ * ep0_get_one
+ * @device:
+ * @urb:
+ * @result:
+ *
+ * Set a single byte value in the urb send buffer. Return non-zero to signal
+ * a request error.
+ */
+static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
+			__u8 result)
+{
+	urb->actual_length = 1;	/* XXX 2? */
+	((char *) urb->buffer)[0] = result;
+	return 0;
+}
+
+/**
+ * copy_config
+ * @urb: pointer to urb
+ * @data: pointer to configuration data
+ * @length: length of data
+ *
+ * Copy configuration data to urb transfer buffer if there is room for it.
+ */
+static void copy_config (struct urb *urb, void *data, int max_length,
+			 int max_buf)
+{
+	int available;
+	int length;
+
+	/*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
+
+	if (!data) {
+		dbg_ep0 (1, "data is NULL");
+		return;
+	}
+	if (!(length = *(unsigned char *) data)) {
+		dbg_ep0 (1, "length is zero");
+		return;
+	}
+
+	if (length > max_length) {
+		dbg_ep0 (1, "length: %d >= max_length: %d", length,
+			 max_length);
+		return;
+	}
+	/*dbg_ep0(1, "   actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
+
+	if ((available =
+	     /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
+		return;
+	}
+	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+	if (length > available) {
+		length = available;
+	}
+	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+	memcpy (urb->buffer + urb->actual_length, data, length);
+	urb->actual_length += length;
+
+	dbg_ep0 (3,
+		 "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
+		 urb->actual_length, urb->buffer_length, max_buf, max_length,
+		 available);
+}
+
+/**
+ * ep0_get_descriptor
+ * @device:
+ * @urb:
+ * @max:
+ * @descriptor_type:
+ * @index:
+ *
+ * Called by ep0_rx_process for a get descriptor device command. Determine what
+ * descriptor is being requested, copy to send buffer. Return zero if ok to send,
+ * return non-zero to signal a request error.
+ */
+static int ep0_get_descriptor (struct usb_device_instance *device,
+			       struct urb *urb, int max, int descriptor_type,
+			       int index)
+{
+	int port = 0;		/* XXX compound device */
+	char *cp;
+
+	/*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
+
+	if (!urb || !urb->buffer || !urb->buffer_length
+	    || (urb->buffer_length < 255)) {
+		dbg_ep0 (2, "invalid urb %p", urb);
+		return -1L;
+	}
+
+	/* setup tx urb */
+	urb->actual_length = 0;
+	cp = urb->buffer;
+
+	dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
+
+	switch (descriptor_type) {
+	case USB_DESCRIPTOR_TYPE_DEVICE:
+		{
+			struct usb_device_descriptor *device_descriptor;
+
+			if (!
+			    (device_descriptor =
+			     usbd_device_device_descriptor (device, port))) {
+				return -1;
+			}
+			/* copy descriptor for this device */
+			copy_config (urb, device_descriptor,
+				     sizeof (struct usb_device_descriptor),
+				     max);
+
+			/* correct the correct control endpoint 0 max packet size into the descriptor */
+			device_descriptor =
+				(struct usb_device_descriptor *) urb->buffer;
+			device_descriptor->bMaxPacketSize0 =
+				urb->device->bus->maxpacketsize;
+
+		}
+		/*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
+		break;
+
+	case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+		{
+			int bNumInterface;
+			struct usb_configuration_descriptor
+				*configuration_descriptor;
+			struct usb_device_descriptor *device_descriptor;
+
+			if (!
+			    (device_descriptor =
+			     usbd_device_device_descriptor (device, port))) {
+				return -1;
+			}
+			/*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
+			if (index > device_descriptor->bNumConfigurations) {
+				dbg_ep0 (0, "index too large: %d > %d", index,
+					 device_descriptor->
+					 bNumConfigurations);
+				return -1;
+			}
+
+			if (!
+			    (configuration_descriptor =
+			     usbd_device_configuration_descriptor (device,
+								   port,
+								   index))) {
+				dbg_ep0 (0,
+					 "usbd_device_configuration_descriptor failed: %d",
+					 index);
+				return -1;
+			}
+			copy_config (urb, configuration_descriptor,
+				     sizeof (struct
+					     usb_configuration_descriptor),
+				     max);
+
+
+			/* iterate across interfaces for specified configuration */
+			dbg_ep0 (0, "bNumInterfaces: %d",
+				 configuration_descriptor->bNumInterfaces);
+			for (bNumInterface = 0;
+			     bNumInterface <
+			     configuration_descriptor->bNumInterfaces;
+			     bNumInterface++) {
+
+				int bAlternateSetting;
+				struct usb_interface_instance
+					*interface_instance;
+
+				dbg_ep0 (3, "[%d] bNumInterfaces: %d",
+					 bNumInterface,
+					 configuration_descriptor->bNumInterfaces);
+
+				if (! (interface_instance = usbd_device_interface_instance (device,
+								     port, index, bNumInterface)))
+				{
+					dbg_ep0 (3, "[%d] interface_instance NULL",
+						 bNumInterface);
+					return -1;
+				}
+				/* iterate across interface alternates */
+				for (bAlternateSetting = 0;
+				     bAlternateSetting < interface_instance->alternates;
+				     bAlternateSetting++) {
+					/*int class; */
+					int bNumEndpoint;
+					struct usb_interface_descriptor *interface_descriptor;
+
+					struct usb_alternate_instance *alternate_instance;
+
+					dbg_ep0 (3, "[%d:%d] alternates: %d",
+						 bNumInterface,
+						 bAlternateSetting,
+						 interface_instance->alternates);
+
+					if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) {
+						dbg_ep0 (3, "[%d] alternate_instance NULL",
+							 bNumInterface);
+						return -1;
+					}
+					/* copy descriptor for this interface */
+					copy_config (urb, alternate_instance->interface_descriptor,
+						     sizeof (struct usb_interface_descriptor),
+						     max);
+
+					/*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */
+					/*        alternate_instance->classes, alternate_instance->endpoints); */
+
+					/* iterate across classes for this alternate interface */
+#if 0
+					for (class = 0;
+					     class < alternate_instance->classes;
+					     class++) {
+						struct usb_class_descriptor *class_descriptor;
+						/*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */
+						/*        class, alternate_instance->classes); */
+						if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) {
+							dbg_ep0 (3, "[%d] class NULL",
+								 class);
+							return -1;
+						}
+						/* copy descriptor for this class */
+						copy_config (urb, class_descriptor,
+							sizeof (struct usb_class_descriptor),
+							max);
+					}
+#endif
+
+					/* iterate across endpoints for this alternate interface */
+					interface_descriptor = alternate_instance->interface_descriptor;
+					for (bNumEndpoint = 0;
+					     bNumEndpoint < alternate_instance->endpoints;
+					     bNumEndpoint++) {
+						struct usb_endpoint_descriptor *endpoint_descriptor;
+						dbg_ep0 (3, "[%d:%d:%d] endpoint: %d",
+							 bNumInterface,
+							 bAlternateSetting,
+							 bNumEndpoint,
+							 interface_descriptor->
+							 bNumEndpoints);
+						if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) {
+							dbg_ep0 (3, "[%d] endpoint NULL",
+								 bNumEndpoint);
+							return -1;
+						}
+						/* copy descriptor for this endpoint */
+						copy_config (urb, endpoint_descriptor,
+							     sizeof (struct usb_endpoint_descriptor),
+							     max);
+					}
+				}
+			}
+			dbg_ep0 (3, "lengths: %d %d",
+				 le16_to_cpu (configuration_descriptor->wTotalLength),
+				 urb->actual_length);
+		}
+		break;
+
+	case USB_DESCRIPTOR_TYPE_STRING:
+		{
+			struct usb_string_descriptor *string_descriptor;
+
+			if (!(string_descriptor = usbd_get_string (index))) {
+				return -1;
+			}
+			/*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */
+			copy_config (urb, string_descriptor, string_descriptor->bLength, max);
+		}
+		break;
+	case USB_DESCRIPTOR_TYPE_INTERFACE:
+		return -1;
+	case USB_DESCRIPTOR_TYPE_ENDPOINT:
+		return -1;
+	case USB_DESCRIPTOR_TYPE_HID:
+		{
+			return -1;	/* unsupported at this time */
+#if 0
+			int bNumInterface =
+				le16_to_cpu (urb->device_request.wIndex);
+			int bAlternateSetting = 0;
+			int class = 0;
+			struct usb_class_descriptor *class_descriptor;
+
+			if (!(class_descriptor =
+			      usbd_device_class_descriptor_index (device,
+								  port, 0,
+								  bNumInterface,
+								  bAlternateSetting,
+								  class))
+			    || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
+				dbg_ep0 (3, "[%d] interface is not HID",
+					 bNumInterface);
+				return -1;
+			}
+			/* copy descriptor for this class */
+			copy_config (urb, class_descriptor,
+				     class_descriptor->descriptor.hid.bLength,
+				     max);
+#endif
+		}
+		break;
+	case USB_DESCRIPTOR_TYPE_REPORT:
+		{
+			return -1;	/* unsupported at this time */
+#if 0
+			int bNumInterface =
+				le16_to_cpu (urb->device_request.wIndex);
+			int bAlternateSetting = 0;
+			int class = 0;
+			struct usb_class_report_descriptor *report_descriptor;
+
+			if (!(report_descriptor =
+			      usbd_device_class_report_descriptor_index
+			      (device, port, 0, bNumInterface,
+			       bAlternateSetting, class))
+			    || report_descriptor->bDescriptorType !=
+			    USB_DT_REPORT) {
+				dbg_ep0 (3, "[%d] descriptor is not REPORT",
+					 bNumInterface);
+				return -1;
+			}
+			/* copy report descriptor for this class */
+			/*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
+			if (max - urb->actual_length > 0) {
+				int length =
+					MIN (report_descriptor->wLength,
+					     max - urb->actual_length);
+				memcpy (urb->buffer + urb->actual_length,
+					&report_descriptor->bData[0], length);
+				urb->actual_length += length;
+			}
+#endif
+		}
+		break;
+	default:
+		return -1;
+	}
+
+
+	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d",
+		 urb->buffer, urb->buffer_length, urb->actual_length,
+		 device->bus->endpoint_array[0].tx_packetSize);
+/*
+    if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
+	dbg_ep0(0, "adding null byte");
+	urb->buffer[urb->actual_length++] = 0;
+	dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
+		urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
+    }
+*/
+	return 0;
+
+}
+
+/**
+ * ep0_recv_setup - called to indicate URB has been received
+ * @urb: pointer to struct urb
+ *
+ * Check if this is a setup packet, process the device request, put results
+ * back into the urb and return zero or non-zero to indicate success (DATA)
+ * or failure (STALL).
+ *
+ */
+int ep0_recv_setup (struct urb *urb)
+{
+	/*struct usb_device_request *request = urb->buffer; */
+	/*struct usb_device_instance *device = urb->device; */
+
+	struct usb_device_request *request;
+	struct usb_device_instance *device;
+	int address;
+
+	dbg_ep0 (0, "entering ep0_recv_setup()");
+	if (!urb || !urb->device) {
+		dbg_ep0 (3, "invalid URB %p", urb);
+		return -1;
+	}
+
+	request = &urb->device_request;
+	device = urb->device;
+
+	dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
+
+
+	/*dbg_ep0(2, "-       -       -       -       -       -       -       -       -       -"); */
+
+	dbg_ep0 (2,
+		 "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
+		 request->bmRequestType, request->bRequest,
+		 le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
+		 le16_to_cpu (request->wLength),
+		 USBD_DEVICE_REQUESTS (request->bRequest));
+
+	/* handle USB Standard Request (c.f. USB Spec table 9-2) */
+	if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+		dbg_ep0 (1, "non standard request: %x",
+			 request->bmRequestType & USB_REQ_TYPE_MASK);
+		return -1;	/* Stall here */
+	}
+
+	switch (device->device_state) {
+	case STATE_CREATED:
+	case STATE_ATTACHED:
+	case STATE_POWERED:
+		/* It actually is important to allow requests in these states,
+		 * Windows will request descriptors before assigning an
+		 * address to the client.
+		 */
+
+		/*dbg_ep0 (1, "request %s not allowed in this state: %s", */
+		/*                USBD_DEVICE_REQUESTS(request->bRequest), */
+		/*                usbd_device_states[device->device_state]); */
+		/*return -1; */
+		break;
+
+	case STATE_INIT:
+	case STATE_DEFAULT:
+		switch (request->bRequest) {
+		case USB_REQ_GET_STATUS:
+		case USB_REQ_GET_INTERFACE:
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+		case USB_REQ_SET_DESCRIPTOR:
+			/* case USB_REQ_SET_CONFIGURATION: */
+		case USB_REQ_SET_INTERFACE:
+			dbg_ep0 (1,
+				 "request %s not allowed in DEFAULT state: %s",
+				 USBD_DEVICE_REQUESTS (request->bRequest),
+				 usbd_device_states[device->device_state]);
+			return -1;
+
+		case USB_REQ_SET_CONFIGURATION:
+		case USB_REQ_SET_ADDRESS:
+		case USB_REQ_GET_DESCRIPTOR:
+		case USB_REQ_GET_CONFIGURATION:
+			break;
+		}
+	case STATE_ADDRESSED:
+	case STATE_CONFIGURED:
+		break;
+	case STATE_UNKNOWN:
+		dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
+			 USBD_DEVICE_REQUESTS (request->bRequest),
+			 usbd_device_states[device->device_state]);
+		return -1;
+	}
+
+	/* handle all requests that return data (direction bit set on bm RequestType) */
+	if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
+
+		dbg_ep0 (3, "Device-to-Host");
+
+		switch (request->bRequest) {
+
+		case USB_REQ_GET_STATUS:
+			return ep0_get_status (device, urb, request->wIndex,
+					       request->bmRequestType &
+					       USB_REQ_RECIPIENT_MASK);
+
+		case USB_REQ_GET_DESCRIPTOR:
+			return ep0_get_descriptor (device, urb,
+						   le16_to_cpu (request->wLength),
+						   le16_to_cpu (request->wValue) >> 8,
+						   le16_to_cpu (request->wValue) & 0xff);
+
+		case USB_REQ_GET_CONFIGURATION:
+			return ep0_get_one (device, urb,
+					    device->configuration);
+
+		case USB_REQ_GET_INTERFACE:
+			return ep0_get_one (device, urb, device->alternate);
+
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+			return -1;
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+		case USB_REQ_SET_ADDRESS:
+		case USB_REQ_SET_DESCRIPTOR:
+		case USB_REQ_SET_CONFIGURATION:
+		case USB_REQ_SET_INTERFACE:
+			return -1;
+		}
+	}
+	/* handle the requests that do not return data */
+	else {
+
+
+		/*dbg_ep0(3, "Host-to-Device"); */
+		switch (request->bRequest) {
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+			dbg_ep0 (0, "Host-to-Device");
+			switch (request->
+				bmRequestType & USB_REQ_RECIPIENT_MASK) {
+			case USB_REQ_RECIPIENT_DEVICE:
+				/* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
+				/* XXX fall through for now as we do not support either */
+			case USB_REQ_RECIPIENT_INTERFACE:
+			case USB_REQ_RECIPIENT_OTHER:
+				dbg_ep0 (0, "request %s not",
+					 USBD_DEVICE_REQUESTS (request->bRequest));
+			default:
+				return -1;
+
+			case USB_REQ_RECIPIENT_ENDPOINT:
+				dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
+				if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
+					/*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
+					/*                    request->bRequest == USB_REQ_SET_FEATURE); */
+					/* NEED TO IMPLEMENT THIS!!! */
+					return -1;
+				} else {
+					dbg_ep0 (1, "request %s bad wValue: %04x",
+						 USBD_DEVICE_REQUESTS
+						 (request->bRequest),
+						 le16_to_cpu (request->wValue));
+					return -1;
+				}
+			}
+
+		case USB_REQ_SET_ADDRESS:
+			/* check if this is a re-address, reset first if it is (this shouldn't be possible) */
+			if (device->device_state != STATE_DEFAULT) {
+				dbg_ep0 (1, "set_address: %02x state: %s",
+					 le16_to_cpu (request->wValue),
+					 usbd_device_states[device->device_state]);
+				return -1;
+			}
+			address = le16_to_cpu (request->wValue);
+			if ((address & 0x7f) != address) {
+				dbg_ep0 (1, "invalid address %04x %04x",
+					 address, address & 0x7f);
+				return -1;
+			}
+			device->address = address;
+
+			/*dbg_ep0(2, "address: %d %d %d", */
+			/*        request->wValue, le16_to_cpu(request->wValue), device->address); */
+
+			serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
+			return 0;
+
+		case USB_REQ_SET_DESCRIPTOR:	/* XXX should we support this? */
+			dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
+			return -1;
+
+		case USB_REQ_SET_CONFIGURATION:
+			/* c.f. 9.4.7 - the top half of wValue is reserved */
+			/* */
+			if ((device->configuration =
+			     le16_to_cpu (request->wValue) & 0x7f) != 0) {
+				/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */
+				/* is the same is configuration zero */
+				device->configuration = 0;	/* TBR - ?????? */
+			}
+			/* reset interface and alternate settings */
+			device->interface = device->alternate = 0;
+
+			/*dbg_ep0(2, "set configuration: %d", device->configuration); */
+			/*serial_printf("DEVICE_CONFIGURED.. event?\n"); */
+			return 0;
+
+		case USB_REQ_SET_INTERFACE:
+			device->interface = le16_to_cpu (request->wIndex);
+			device->alternate = le16_to_cpu (request->wValue);
+			/*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
+			serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
+			return 0;
+
+		case USB_REQ_GET_STATUS:
+		case USB_REQ_GET_DESCRIPTOR:
+		case USB_REQ_GET_CONFIGURATION:
+		case USB_REQ_GET_INTERFACE:
+		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */
+			return -1;
+		}
+	}
+	return -1;
+}
+
+#endif
diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c
new file mode 100644
index 0000000..042f319
--- /dev/null
+++ b/drivers/usbdcore_omap1510.c
@@ -0,0 +1,1494 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usb/device/bi/omap.c
+ * TI OMAP1510 USB bus interface driver
+ *
+ * Author: MontaVista Software, Inc.
+ *	   source@mvista.com
+ *	   (C) Copyright 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ *
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "usbdcore.h"
+#include "usbdcore_omap1510.h"
+#include "usbdcore_ep0.h"
+
+
+#define UDC_MAX_ENDPOINTS	     31 /* Number of endpoints on this UDC */
+
+/* Some kind of debugging output... */
+#if 1
+#define UDCDBG(str)
+#define UDCDBGA(fmt,args...)
+#else  /* The bugs still exists... */
+#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)
+#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)
+#endif
+
+#if 1
+#define UDCREG(name)
+#define UDCREGL(name)
+#else  /* The bugs still exists... */
+#define UDCREG(name)	 serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name))	/* For 16-bit regs */
+#define UDCREGL(name)	 serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name))	/* For 32-bit regs */
+#endif
+
+
+static struct urb *ep0_urb = NULL;
+
+static struct usb_device_instance *udc_device;	/* Used in interrupt handler */
+static u16 udc_devstat = 0;	/* UDC status (DEVSTAT) */
+static u32 udc_interrupts = 0;
+
+static void udc_stall_ep (unsigned int ep_addr);
+
+
+static struct usb_endpoint_instance *omap1510_find_ep (int ep)
+{
+	int i;
+
+	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+		if (udc_device->bus->endpoint_array[i].endpoint_address == ep)
+			return &udc_device->bus->endpoint_array[i];
+	}
+	return NULL;
+}
+
+/* ************************************************************************** */
+/* IO
+ */
+
+/*
+ * omap1510_prepare_endpoint_for_rx
+ *
+ * This function implements TRM Figure 14-11.
+ *
+ * The endpoint to prepare for transfer is specified as a physical endpoint
+ * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint
+ * configuration register is checked to see if the endpoint is ISO or not.
+ * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.
+ * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
+ */
+static void omap1510_prepare_endpoint_for_rx (int ep_addr)
+{
+	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+	UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr);
+	if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) {
+		if ((inw (UDC_EP_RX (ep_num)) &
+		     (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) ==
+		    UDC_EPn_RX_Valid) {
+			/* rx endpoint is valid, non-ISO, so enable its FIFO */
+			outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+			outw (UDC_Set_FIFO_En, UDC_CTRL);
+			outw (0, UDC_EP_NUM);
+		}
+	}
+}
+
+/* omap1510_configure_endpoints
+ *
+ * This function implements TRM Figure 14-10.
+ */
+static void omap1510_configure_endpoints (struct usb_device_instance *device)
+{
+	int ep;
+	struct usb_bus_instance *bus;
+	struct usb_endpoint_instance *endpoint;
+	unsigned short ep_ptr;
+	unsigned short ep_size;
+	unsigned short ep_isoc;
+	unsigned short ep_doublebuffer;
+	int ep_addr;
+	int packet_size;
+	int buffer_size;
+	int attributes;
+
+	bus = device->bus;
+
+	/* There is a dedicated 2048 byte buffer for USB packets that may be
+	 * arbitrarily partitioned among the endpoints on 8-byte boundaries.
+	 * The first 8 bytes are reserved for receiving setup packets on
+	 * endpoint 0.
+	 */
+	ep_ptr = 8;		/* reserve the first 8 bytes for the setup fifo */
+
+	for (ep = 0; ep < bus->max_endpoints; ep++) {
+		endpoint = bus->endpoint_array + ep;
+		ep_addr = endpoint->endpoint_address;
+		if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			/* IN endpoint */
+			packet_size = endpoint->tx_packetSize;
+			attributes = endpoint->tx_attributes;
+		} else {
+			/* OUT endpoint */
+			packet_size = endpoint->rcv_packetSize;
+			attributes = endpoint->rcv_attributes;
+		}
+
+		switch (packet_size) {
+		case 0:
+			ep_size = 0;
+			break;
+		case 8:
+			ep_size = 0;
+			break;
+		case 16:
+			ep_size = 1;
+			break;
+		case 32:
+			ep_size = 2;
+			break;
+		case 64:
+			ep_size = 3;
+			break;
+		case 128:
+			ep_size = 4;
+			break;
+		case 256:
+			ep_size = 5;
+			break;
+		case 512:
+			ep_size = 6;
+			break;
+		default:
+			UDCDBGA ("ep 0x%02x has bad packet size %d",
+				 ep_addr, packet_size);
+			packet_size = 0;
+			ep_size = 0;
+			break;
+		}
+
+		switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
+		case USB_ENDPOINT_XFER_CONTROL:
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+		default:
+			/* A non-isochronous endpoint may optionally be
+			 * double-buffered. For now we disable
+			 * double-buffering.
+			 */
+			ep_doublebuffer = 0;
+			ep_isoc = 0;
+			if (packet_size > 64)
+				packet_size = 0;
+			if (!ep || !ep_doublebuffer)
+				buffer_size = packet_size;
+			else
+				buffer_size = packet_size * 2;
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			/* Isochronous endpoints are always double-
+			 * buffered, but the double-buffering bit
+			 * in the endpoint configuration register
+			 * becomes the msb of the endpoint size so we
+			 * set the double-buffering flag to zero.
+			 */
+			ep_doublebuffer = 0;
+			ep_isoc = 1;
+			buffer_size = packet_size * 2;
+			break;
+		}
+
+		/* check to see if our packet buffer RAM is exhausted */
+		if ((ep_ptr + buffer_size) > 2048) {
+			UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size);
+			buffer_size = packet_size = 0;
+		}
+
+		/* force a default configuration for endpoint 0 since it is
+		 * always enabled
+		 */
+		if (!ep && ((packet_size < 8) || (packet_size > 64))) {
+			buffer_size = packet_size = 64;
+			ep_size = 3;
+		}
+
+		if (!ep) {
+			/* configure endpoint 0 */
+			outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
+			/*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */
+			/*	ep_ptr, packet_size); */
+		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			/* IN endpoint */
+			if (packet_size) {
+				outw ((1 << 15) | (ep_doublebuffer << 14) |
+				      (ep_size << 12) | (ep_isoc << 11) |
+				      (ep_ptr >> 3),
+				      UDC_EP_TX (ep_addr &
+						 USB_ENDPOINT_NUMBER_MASK));
+				UDCDBGA ("IN ep %d buffer offset 0x%03x"
+					 " packet size 0x%03x",
+					 ep_addr & USB_ENDPOINT_NUMBER_MASK,
+					 ep_ptr, packet_size);
+			} else {
+				outw (0,
+				      UDC_EP_TX (ep_addr &
+						 USB_ENDPOINT_NUMBER_MASK));
+			}
+		} else {
+			/* OUT endpoint */
+			if (packet_size) {
+				outw ((1 << 15) | (ep_doublebuffer << 14) |
+				      (ep_size << 12) | (ep_isoc << 11) |
+				      (ep_ptr >> 3),
+				      UDC_EP_RX (ep_addr &
+						 USB_ENDPOINT_NUMBER_MASK));
+				UDCDBGA ("OUT ep %d buffer offset 0x%03x"
+					 " packet size 0x%03x",
+					 ep_addr & USB_ENDPOINT_NUMBER_MASK,
+					 ep_ptr, packet_size);
+			} else {
+				outw (0,
+				      UDC_EP_RX (ep_addr &
+						 USB_ENDPOINT_NUMBER_MASK));
+			}
+		}
+		ep_ptr += buffer_size;
+	}
+}
+
+/* omap1510_deconfigure_device
+ *
+ * This function balances omap1510_configure_device.
+ */
+static void omap1510_deconfigure_device (void)
+{
+	int epnum;
+
+	UDCDBG ("clear Cfg_Lock");
+	outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
+	UDCREG (UDC_SYSCON1);
+
+	/* deconfigure all endpoints */
+	for (epnum = 1; epnum <= 15; epnum++) {
+		outw (0, UDC_EP_RX (epnum));
+		outw (0, UDC_EP_TX (epnum));
+	}
+}
+
+/* omap1510_configure_device
+ *
+ * This function implements TRM Figure 14-9.
+ */
+static void omap1510_configure_device (struct usb_device_instance *device)
+{
+	omap1510_configure_endpoints (device);
+
+
+	/* Figure 14-9 indicates we should enable interrupts here, but we have
+	 * other routines (udc_all_interrupts, udc_suspended_interrupts) to
+	 * do that.
+	 */
+
+	UDCDBG ("set Cfg_Lock");
+	outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
+	UDCREG (UDC_SYSCON1);
+}
+
+/* omap1510_write_noniso_tx_fifo
+ *
+ * This function implements TRM Figure 14-30.
+ *
+ * If the endpoint has an active tx_urb, then the next packet of data from the
+ * URB is written to the tx FIFO.  The total amount of data in the urb is given
+ * by urb->actual_length.  The maximum amount of data that can be sent in any
+ * one packet is given by endpoint->tx_packetSize.  The number of data bytes
+ * from this URB that have already been transmitted is given by endpoint->sent.
+ * endpoint->last is updated by this routine with the number of data bytes
+ * transmitted in this packet.
+ *
+ * In accordance with Figure 14-30, the EP_NUM register must already have been
+ * written with the value to select the appropriate tx FIFO before this routine
+ * is called.
+ */
+static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance
+					   *endpoint)
+{
+	struct urb *urb = endpoint->tx_urb;
+
+	if (urb) {
+		unsigned int last, i;
+
+		UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d",
+			 urb->buffer, urb->buffer_length, urb->actual_length);
+		if ((last =
+		     MIN (urb->actual_length - endpoint->sent,
+			  endpoint->tx_packetSize))) {
+			u8 *cp = urb->buffer + endpoint->sent;
+
+			UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last);
+
+			if (((u32) cp & 1) == 0) {	/* word aligned? */
+				outsw (UDC_DATA, cp, last >> 1);
+			} else {	/* byte aligned. */
+				for (i = 0; i < (last >> 1); i++) {
+					u16 w = ((u16) cp[2 * i + 1] << 8) |
+						(u16) cp[2 * i];
+					outw (w, UDC_DATA);
+				}
+			}
+			if (last & 1) {
+				outb (*(cp + last - 1), UDC_DATA);
+			}
+		}
+		endpoint->last = last;
+	}
+}
+
+/* omap1510_read_noniso_rx_fifo
+ *
+ * This function implements TRM Figure 14-28.
+ *
+ * If the endpoint has an active rcv_urb, then the next packet of data is read
+ * from the rcv FIFO and written to rcv_urb->buffer at offset
+ * rcv_urb->actual_length to append the packet data to the data from any
+ * previous packets for this transfer.	We assume that there is sufficient room
+ * left in the buffer to hold an entire packet of data.
+ *
+ * The return value is the number of bytes read from the FIFO for this packet.
+ *
+ * In accordance with Figure 14-28, the EP_NUM register must already have been
+ * written with the value to select the appropriate rcv FIFO before this routine
+ * is called.
+ */
+static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance
+					 *endpoint)
+{
+	struct urb *urb = endpoint->rcv_urb;
+	int len = 0;
+
+	if (urb) {
+		len = inw (UDC_RXFSTAT);
+
+		if (len) {
+			unsigned char *cp = urb->buffer + urb->actual_length;
+
+			insw (UDC_DATA, cp, len >> 1);
+			if (len & 1)
+				*(cp + len - 1) = inb (UDC_DATA);
+		}
+	}
+	return len;
+}
+
+/* omap1510_prepare_for_control_write_status
+ *
+ * This function implements TRM Figure 14-17.
+ *
+ * We have to deal here with non-autodecoded control writes that haven't already
+ * been dealt with by ep0_recv_setup.  The non-autodecoded standard control
+ * write requests are:	set/clear endpoint feature, set configuration, set
+ * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for
+ * ENDPOINT_HALT by halting the endpoint for a set request and resetting the
+ * endpoint for a clear request.  ep0_recv_setup returns an error for
+ * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
+ * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by
+ * generating a DEVICE_SET_INTERFACE event.  This leaves only the
+ * SET_CONFIGURATION event for us to deal with here.
+ *
+ */
+static void omap1510_prepare_for_control_write_status (struct urb *urb)
+{
+	struct usb_device_request *request = &urb->device_request;;
+
+	/* check for a SET_CONFIGURATION request */
+	if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
+		int configuration = le16_to_cpu (request->wValue) & 0xff;
+		unsigned short devstat = inw (UDC_DEVSTAT);
+
+		if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
+			/* device is currently in ADDRESSED state */
+			if (configuration) {
+				/* Assume the specified non-zero configuration
+				 * value is valid and switch to the CONFIGURED
+				 * state.
+				 */
+				outw (UDC_Dev_Cfg, UDC_SYSCON2);
+			}
+		} else if ((devstat & UDC_CFG) == UDC_CFG) {
+			/* device is currently in CONFIGURED state */
+			if (!configuration) {
+				/* Switch to ADDRESSED state. */
+				outw (UDC_Clr_Cfg, UDC_SYSCON2);
+			}
+		}
+	}
+
+	/* select EP0 tx FIFO */
+	outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+	/* clear endpoint (no data bytes in status stage) */
+	outw (UDC_Clr_EP, UDC_CTRL);
+	/* enable the EP0 tx FIFO */
+	outw (UDC_Set_FIFO_En, UDC_CTRL);
+	/* deselect the endpoint */
+	outw (UDC_EP_Dir, UDC_EP_NUM);
+}
+
+/* udc_state_transition_up
+ * udc_state_transition_down
+ *
+ * Helper functions to implement device state changes.	The device states and
+ * the events that transition between them are:
+ *
+ *				STATE_ATTACHED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_POWERED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION
+ *				||	/\
+ *				\/	||
+ *				STATE_DEFAULT
+ *				||	/\
+ *				\/	||
+ *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_ADDRESSED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED
+ *				||	/\
+ *				\/	||
+ *				STATE_CONFIGURED
+ *
+ * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way.  If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition_down transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ * These functions must only be called with interrupts disabled.
+ */
+static void udc_state_transition_up (usb_device_state_t initial,
+				     usb_device_state_t final)
+{
+	if (initial < final) {
+		switch (initial) {
+		case STATE_ATTACHED:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_HUB_CONFIGURED, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_ADDRESS_ASSIGNED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
+					       0);
+		case STATE_CONFIGURED:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void udc_state_transition_down (usb_device_state_t initial,
+				       usb_device_state_t final)
+{
+	if (initial > final) {
+		switch (initial) {
+		case STATE_CONFIGURED:
+			usbd_device_event_irq (udc_device, DEVICE_DE_CONFIGURED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq (udc_device, DEVICE_POWER_INTERRUPTION, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, 0);
+		case STATE_ATTACHED:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/* Handle all device state changes.
+ * This function implements TRM Figure 14-21.
+ */
+static void omap1510_udc_state_changed (void)
+{
+	u16 bits;
+	u16 devstat = inw (UDC_DEVSTAT);
+
+	UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat);
+
+	bits = devstat ^ udc_devstat;
+	if (bits) {
+		if (bits & UDC_ATT) {
+			if (devstat & UDC_ATT) {
+				UDCDBG ("device attached and powered");
+				udc_state_transition_up (udc_device->device_state, STATE_POWERED);
+			} else {
+				UDCDBG ("device detached or unpowered");
+				udc_state_transition_down (udc_device->device_state, STATE_ATTACHED);
+			}
+		}
+		if (bits & UDC_USB_Reset) {
+			if (devstat & UDC_USB_Reset) {
+				UDCDBG ("device reset in progess");
+				udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+			} else {
+				UDCDBG ("device reset completed");
+			}
+		}
+		if (bits & UDC_DEF) {
+			if (devstat & UDC_DEF) {
+				UDCDBG ("device entering default state");
+				udc_state_transition_up (udc_device->device_state, STATE_DEFAULT);
+			} else {
+				UDCDBG ("device leaving default state");
+				udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+			}
+		}
+		if (bits & UDC_SUS) {
+			if (devstat & UDC_SUS) {
+				UDCDBG ("entering suspended state");
+				usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0);
+			} else {
+				UDCDBG ("leaving suspended state");
+				usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0);
+			}
+		}
+		if (bits & UDC_R_WK_OK) {
+			UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK)
+				 ? "enabled" : "disabled");
+		}
+		if (bits & UDC_ADD) {
+			if (devstat & UDC_ADD) {
+				UDCDBG ("default -> addressed");
+				udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED);
+			} else {
+				UDCDBG ("addressed -> default");
+				udc_state_transition_down (udc_device->device_state, STATE_DEFAULT);
+			}
+		}
+		if (bits & UDC_CFG) {
+			if (devstat & UDC_CFG) {
+				UDCDBG ("device configured");
+				/* The ep0_recv_setup function generates the
+				 * DEVICE_CONFIGURED event when a
+				 * USB_REQ_SET_CONFIGURATION setup packet is
+				 * received, so we should already be in the
+				 * state STATE_CONFIGURED.
+				 */
+				udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED);
+			} else {
+				UDCDBG ("device deconfigured");
+				udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED);
+			}
+		}
+	}
+
+	/* Clear interrupt source */
+	outw (UDC_DS_Chg, UDC_IRQ_SRC);
+
+	/* Save current DEVSTAT */
+	udc_devstat = devstat;
+}
+
+/* Handle SETUP USB interrupt.
+ * This function implements TRM Figure 14-14.
+ */
+static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
+{
+	UDCDBG ("-> Entering device setup");
+
+	do {
+		const int setup_pktsize = 8;
+		unsigned char *datap =
+			(unsigned char *) &ep0_urb->device_request;
+
+		/* Gain access to EP 0 setup FIFO */
+		outw (UDC_Setup_Sel, UDC_EP_NUM);
+
+		/* Read control request data */
+		insb (UDC_DATA, datap, setup_pktsize);
+
+		UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]",
+			 *(datap + 0), *(datap + 1), *(datap + 2),
+			 *(datap + 3), *(datap + 4), *(datap + 5),
+			 *(datap + 6), *(datap + 7));
+
+		/* Reset EP0 setup FIFO */
+		outw (0, UDC_EP_NUM);
+	} while (inw (UDC_IRQ_SRC) & UDC_Setup);
+
+	/* Try to process setup packet */
+	if (ep0_recv_setup (ep0_urb)) {
+		/* Not a setup packet, stall next EP0 transaction */
+		udc_stall_ep (0);
+		UDCDBG ("can't parse setup packet, still waiting for setup");
+		return;
+	}
+
+	/* Check direction */
+	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+	    == USB_REQ_HOST2DEVICE) {
+		UDCDBG ("control write on EP0");
+		if (le16_to_cpu (ep0_urb->device_request.wLength)) {
+			/* We don't support control write data stages.
+			 * The only standard control write request with a data
+			 * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
+			 * support that so we just stall those requests.  A
+			 * function driver might support a non-standard
+			 * write request with a data stage, but it isn't
+			 * obvious what we would do with the data if we read it
+			 * so we'll just stall it.  It seems like the API isn't
+			 * quite right here.
+			 */
+#if 0
+			/* Here is what we would do if we did support control
+			 * write data stages.
+			 */
+			ep0_urb->actual_length = 0;
+			outw (0, UDC_EP_NUM);
+			/* enable the EP0 rx FIFO */
+			outw (UDC_Set_FIFO_En, UDC_CTRL);
+#else
+			/* Stall this request */
+			UDCDBG ("Stalling unsupported EP0 control write data "
+				"stage.");
+			udc_stall_ep (0);
+#endif
+		} else {
+			omap1510_prepare_for_control_write_status (ep0_urb);
+		}
+	} else {
+		UDCDBG ("control read on EP0");
+		/* The ep0_recv_setup function has already placed our response
+		 * packet data in ep0_urb->buffer and the packet length in
+		 * ep0_urb->actual_length.
+		 */
+		endpoint->tx_urb = ep0_urb;
+		endpoint->sent = 0;
+		/* select the EP0 tx FIFO */
+		outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+		/* Write packet data to the FIFO.  omap1510_write_noniso_tx_fifo
+		 * will update endpoint->last with the number of bytes written
+		 * to the FIFO.
+		 */
+		omap1510_write_noniso_tx_fifo (endpoint);
+		/* enable the FIFO to start the packet transmission */
+		outw (UDC_Set_FIFO_En, UDC_CTRL);
+		/* deselect the EP0 tx FIFO */
+		outw (UDC_EP_Dir, UDC_EP_NUM);
+	}
+
+	UDCDBG ("<- Leaving device setup");
+}
+
+/* Handle endpoint 0 RX interrupt
+ * This routine implements TRM Figure 14-16.
+ */
+static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint)
+{
+	unsigned short status;
+
+	UDCDBG ("RX on EP0");
+	/* select EP0 rx FIFO */
+	outw (UDC_EP_Sel, UDC_EP_NUM);
+
+	status = inw (UDC_STAT_FLG);
+
+	if (status & UDC_ACK) {
+		/* Check direction */
+		if ((ep0_urb->device_request.bmRequestType
+		     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+			/* This rx interrupt must be for a control write data
+			 * stage packet.
+			 *
+			 * We don't support control write data stages.
+			 * We should never end up here.
+			 */
+
+			/* clear the EP0 rx FIFO */
+			outw (UDC_Clr_EP, UDC_CTRL);
+
+			/* deselect the EP0 rx FIFO */
+			outw (0, UDC_EP_NUM);
+
+			UDCDBG ("Stalling unexpected EP0 control write "
+				"data stage packet");
+			udc_stall_ep (0);
+		} else {
+			/* This rx interrupt must be for a control read status
+			 * stage packet.
+			 */
+			UDCDBG ("ACK on EP0 control read status stage packet");
+			/* deselect EP0 rx FIFO */
+			outw (0, UDC_EP_NUM);
+		}
+	} else if (status & UDC_STALL) {
+		UDCDBG ("EP0 stall during RX");
+		/* deselect EP0 rx FIFO */
+		outw (0, UDC_EP_NUM);
+	} else {
+		/* deselect EP0 rx FIFO */
+		outw (0, UDC_EP_NUM);
+	}
+}
+
+/* Handle endpoint 0 TX interrupt
+ * This routine implements TRM Figure 14-18.
+ */
+static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint)
+{
+	unsigned short status;
+	struct usb_device_request *request = &ep0_urb->device_request;
+
+	UDCDBG ("TX on EP0");
+	/* select EP0 TX FIFO */
+	outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+
+	status = inw (UDC_STAT_FLG);
+	if (status & UDC_ACK) {
+		/* Check direction */
+		if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
+		    USB_REQ_HOST2DEVICE) {
+			/* This tx interrupt must be for a control write status
+			 * stage packet.
+			 */
+			UDCDBG ("ACK on EP0 control write status stage packet");
+			/* deselect EP0 TX FIFO */
+			outw (UDC_EP_Dir, UDC_EP_NUM);
+		} else {
+			/* This tx interrupt must be for a control read data
+			 * stage packet.
+			 */
+			int wLength = le16_to_cpu (request->wLength);
+
+			/* Update our count of bytes sent so far in this
+			 * transfer.
+			 */
+			endpoint->sent += endpoint->last;
+
+			/* We are finished with this transfer if we have sent
+			 * all of the bytes in our tx urb (urb->actual_length)
+			 * unless we need a zero-length terminating packet.  We
+			 * need a zero-length terminating packet if we returned
+			 * fewer bytes than were requested (wLength) by the host,
+			 * and the number of bytes we returned is an exact
+			 * multiple of the packet size endpoint->tx_packetSize.
+			 */
+			if ((endpoint->sent == ep0_urb->actual_length)
+			    && ((ep0_urb->actual_length == wLength)
+				|| (endpoint->last !=
+				    endpoint->tx_packetSize))) {
+				/* Done with control read data stage. */
+				UDCDBG ("control read data stage complete");
+				/* deselect EP0 TX FIFO */
+				outw (UDC_EP_Dir, UDC_EP_NUM);
+				/* select EP0 RX FIFO to prepare for control
+				 * read status stage.
+				 */
+				outw (UDC_EP_Sel, UDC_EP_NUM);
+				/* clear the EP0 RX FIFO */
+				outw (UDC_Clr_EP, UDC_CTRL);
+				/* enable the EP0 RX FIFO */
+				outw (UDC_Set_FIFO_En, UDC_CTRL);
+				/* deselect the EP0 RX FIFO */
+				outw (0, UDC_EP_NUM);
+			} else {
+				/* We still have another packet of data to send
+				 * in this control read data stage or else we
+				 * need a zero-length terminating packet.
+				 */
+				UDCDBG ("ACK control read data stage packet");
+				omap1510_write_noniso_tx_fifo (endpoint);
+				/* enable the EP0 tx FIFO to start transmission */
+				outw (UDC_Set_FIFO_En, UDC_CTRL);
+				/* deselect EP0 TX FIFO */
+				outw (UDC_EP_Dir, UDC_EP_NUM);
+			}
+		}
+	} else if (status & UDC_STALL) {
+		UDCDBG ("EP0 stall during TX");
+		/* deselect EP0 TX FIFO */
+		outw (UDC_EP_Dir, UDC_EP_NUM);
+	} else {
+		/* deselect EP0 TX FIFO */
+		outw (UDC_EP_Dir, UDC_EP_NUM);
+	}
+}
+
+/* Handle RX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-27.
+ * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
+ * in the range 1 to 15.
+ */
+static void omap1510_udc_epn_rx (int ep)
+{
+	unsigned short status;
+
+	/* Check endpoint status */
+	status = inw (UDC_STAT_FLG);
+
+	if (status & UDC_ACK) {
+		int nbytes;
+		struct usb_endpoint_instance *endpoint =
+			omap1510_find_ep (ep);
+
+		nbytes = omap1510_read_noniso_rx_fifo (endpoint);
+		usbd_rcv_complete (endpoint, nbytes, 0);
+
+		/* enable rx FIFO to prepare for next packet */
+		outw (UDC_Set_FIFO_En, UDC_CTRL);
+	} else if (status & UDC_STALL) {
+		UDCDBGA ("STALL on RX endpoint %d", ep);
+	} else if (status & UDC_NAK) {
+		UDCDBGA ("NAK on RX ep %d", ep);
+	} else {
+		serial_printf ("omap-bi: RX on ep %d with status %x", ep,
+			       status);
+	}
+}
+
+/* Handle TX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-29.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void omap1510_udc_epn_tx (int ep)
+{
+	unsigned short status;
+
+	/*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */
+
+	/* Check endpoint status */
+	status = inw (UDC_STAT_FLG);
+
+	if (status & UDC_ACK) {
+		struct usb_endpoint_instance *endpoint =
+			omap1510_find_ep (ep);
+
+		/* We need to transmit a terminating zero-length packet now if
+		 * we have sent all of the data in this URB and the transfer
+		 * size was an exact multiple of the packet size.
+		 */
+		if (endpoint->tx_urb
+		    && (endpoint->last == endpoint->tx_packetSize)
+		    && (endpoint->tx_urb->actual_length - endpoint->sent -
+			endpoint->last == 0)) {
+			/* Prepare to transmit a zero-length packet. */
+			endpoint->sent += endpoint->last;
+			/* write 0 bytes of data to FIFO */
+			omap1510_write_noniso_tx_fifo (endpoint);
+			/* enable tx FIFO to start transmission */
+			outw (UDC_Set_FIFO_En, UDC_CTRL);
+		} else if (endpoint->tx_urb
+			   && endpoint->tx_urb->actual_length) {
+			/* retire the data that was just sent */
+			usbd_tx_complete (endpoint);
+			/* Check to see if we have more data ready to transmit
+			 * now.
+			 */
+			if (endpoint->tx_urb
+			    && endpoint->tx_urb->actual_length) {
+				/* write data to FIFO */
+				omap1510_write_noniso_tx_fifo (endpoint);
+				/* enable tx FIFO to start transmission */
+				outw (UDC_Set_FIFO_En, UDC_CTRL);
+			}
+		}
+	} else if (status & UDC_STALL) {
+		UDCDBGA ("STALL on TX endpoint %d", ep);
+	} else if (status & UDC_NAK) {
+		UDCDBGA ("NAK on TX endpoint %d", ep);
+	} else {
+		/*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */
+	}
+}
+
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+/* Handle general USB interrupts and dispatch according to type.
+ * This function implements TRM Figure 14-13.
+ */
+void omap1510_udc_irq (void)
+{
+	u16 irq_src = inw (UDC_IRQ_SRC);
+	int valid_irq = 0;
+
+	if (!(irq_src & ~UDC_SOF_Flg))	/* ignore SOF interrupts ) */
+		return;
+
+	UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src);
+	/*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */
+
+	if (irq_src & UDC_DS_Chg) {
+		/* Device status changed */
+		omap1510_udc_state_changed ();
+		valid_irq++;
+	}
+	if (irq_src & UDC_EP0_RX) {
+		/* Endpoint 0 receive */
+		outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */
+		omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0);
+		valid_irq++;
+	}
+	if (irq_src & UDC_EP0_TX) {
+		/* Endpoint 0 transmit */
+		outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */
+		omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0);
+		valid_irq++;
+	}
+	if (irq_src & UDC_Setup) {
+		/* Device setup */
+		omap1510_udc_setup (udc_device->bus->endpoint_array + 0);
+		valid_irq++;
+	}
+	/*if (!valid_irq) */
+	/*	serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */
+	UDCDBGA ("< IRQ #%d end >", udc_interrupts);
+	udc_interrupts++;
+}
+
+/* This function implements TRM Figure 14-26. */
+void omap1510_udc_noniso_irq (void)
+{
+	unsigned short epnum;
+	unsigned short irq_src = inw (UDC_IRQ_SRC);
+	int valid_irq = 0;
+
+	if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX)))
+		return;
+
+	UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC));
+
+	if (irq_src & UDC_EPn_RX) {	/* Endpoint N OUT transaction */
+		/* Determine the endpoint number for this interrupt */
+		epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8;
+		UDCDBGA ("RX on ep %x", epnum);
+
+		/* acknowledge interrupt */
+		outw (UDC_EPn_RX, UDC_IRQ_SRC);
+
+		if (epnum) {
+			/* select the endpoint FIFO */
+			outw (UDC_EP_Sel | epnum, UDC_EP_NUM);
+
+			omap1510_udc_epn_rx (epnum);
+
+			/* deselect the endpoint FIFO */
+			outw (epnum, UDC_EP_NUM);
+		}
+		valid_irq++;
+	}
+	if (irq_src & UDC_EPn_TX) {	/* Endpoint N IN transaction */
+		/* Determine the endpoint number for this interrupt */
+		epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN;
+		UDCDBGA ("TX on ep %x", epnum);
+
+		/* acknowledge interrupt */
+		outw (UDC_EPn_TX, UDC_IRQ_SRC);
+
+		if (epnum) {
+			/* select the endpoint FIFO */
+			outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+
+			omap1510_udc_epn_tx (epnum);
+
+			/* deselect the endpoint FIFO */
+			outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+		}
+		valid_irq++;
+	}
+	if (!valid_irq)
+		serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n",
+			       irq_src);
+}
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+
+/*
+ * Start of public functions.
+ */
+
+/* Called to start packet transmission. */
+void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
+{
+	unsigned short epnum =
+		endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+
+	UDCDBGA ("Starting transmit on ep %x", epnum);
+
+	if (endpoint->tx_urb) {
+		/* select the endpoint FIFO */
+		outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+		/* write data to FIFO */
+		omap1510_write_noniso_tx_fifo (endpoint);
+		/* enable tx FIFO to start transmission */
+		outw (UDC_Set_FIFO_En, UDC_CTRL);
+		/* deselect the endpoint FIFO */
+		outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+	}
+}
+
+/* Start to initialize h/w stuff */
+int udc_init (void)
+{
+	u16 udc_rev;
+	uchar wert;
+
+	udc_device = NULL;
+
+	UDCDBG ("starting");
+
+	/* Check peripheral reset. Must be 1 to make sure
+	   MPU TIPB peripheral reset is inactive */
+	UDCREG (ARM_RSTCT2);
+
+	/* Set and check clock control.
+	 * We might ought to be using the clock control API to do
+	 * this instead of fiddling with the clock registers directly
+	 * here.
+	 */
+	outw ((1 << 4) | (1 << 5), CLOCK_CTRL);
+	UDCREG (CLOCK_CTRL);
+	/* Set and check APLL */
+	outw (0x0008, APLL_CTRL);
+	UDCREG (APLL_CTRL);
+	/* Set and check DPLL */
+	outw (0x2210, DPLL_CTRL);
+	UDCREG (DPLL_CTRL);
+	/* Set and check SOFT */
+	outw ((1 << 4) | (1 << 3) | 1, SOFT_REQ);
+	/* Short delay to wait for DPLL */
+	udelay (1000);
+
+	/* Print banner with device revision */
+	udc_rev = inw (UDC_REV) & 0xff;
+	printf ("USB:   TI OMAP1510 USB function module rev %d.%d\n",
+		udc_rev >> 4, udc_rev & 0xf);
+
+	/* Configure some Sofia Unit registers
+	 */
+	i2c_read (0x32, 0x04, 1, &wert, 1);	/* SOF_Control_CONT */
+	wert |= 0x04;		/* SOF_ContCONT_dis_usb_det */
+	i2c_write (0x32, 0x04, 1, &wert, 1);
+
+	i2c_read (0x32, 0x03, 1, &wert, 1);	/* SOF_Control */
+	wert |= 0x01;		/* SOF_Cont_usb_en */
+	i2c_write (0x32, 0x03, 1, &wert, 1);
+
+	/* The VBUS_MODE bit selects whether VBUS detection is done via
+	 * software (1) or hardware (0).  When software detection is
+	 * selected, VBUS_CTRL selects whether USB is not connected (0)
+	 * or connected (1).
+	 */
+	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+	outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+	UDCREGL (FUNC_MUX_CTRL_0);
+
+	/*
+	 * At this point, device is ready for configuration...
+	 */
+
+	UDCDBG ("disable USB interrupts");
+	outw (0, UDC_IRQ_EN);
+	UDCREG (UDC_IRQ_EN);
+
+	UDCDBG ("disable USB DMA");
+	outw (0, UDC_DMA_IRQ_EN);
+	UDCREG (UDC_DMA_IRQ_EN);
+
+	UDCDBG ("initialize SYSCON1");
+	outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1);
+	UDCREG (UDC_SYSCON1);
+
+	return 0;
+}
+
+/* Stall endpoint */
+static void udc_stall_ep (unsigned int ep_addr)
+{
+	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+	UDCDBGA ("stall ep_addr %d", ep_addr);
+
+	/* REVISIT?
+	 * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
+	 * is empty before halting the endpoint.  The current implementation
+	 * doesn't check that the FIFO is empty.
+	 */
+
+	if (!ep_num) {
+		outw (UDC_Stall_Cmd, UDC_SYSCON2);
+	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+		if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+			/* we have a valid rx endpoint, so halt it */
+			outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+			outw (UDC_Set_Halt, UDC_CTRL);
+			outw (ep_num, UDC_EP_NUM);
+		}
+	} else {
+		if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+			/* we have a valid tx endpoint, so halt it */
+			outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM);
+			outw (UDC_Set_Halt, UDC_CTRL);
+			outw (ep_num, UDC_EP_NUM);
+		}
+	}
+}
+
+/* Reset endpoint */
+#if 0
+static void udc_reset_ep (unsigned int ep_addr)
+{
+	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+	UDCDBGA ("reset ep_addr %d", ep_addr);
+
+	if (!ep_num) {
+		/* control endpoint 0 can't be reset */
+	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+		UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num,
+			 inw (UDC_EP_RX (ep_num)));
+		if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+			/* we have a valid rx endpoint, so reset it */
+			outw (ep_num | UDC_EP_Sel, UDC_EP_NUM);
+			outw (UDC_Reset_EP, UDC_CTRL);
+			outw (ep_num, UDC_EP_NUM);
+			UDCDBGA ("OUT endpoint %d reset", ep_num);
+		}
+	} else {
+		UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num,
+			 inw (UDC_EP_TX (ep_num)));
+		/* Resetting of tx endpoints seems to be causing the USB function
+		 * module to fail, which causes problems when the driver is
+		 * uninstalled.	 We'll skip resetting tx endpoints for now until
+		 * we figure out what the problem is.
+		 */
+#if 0
+		if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+			/* we have a valid tx endpoint, so reset it */
+			outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+			outw (UDC_Reset_EP, UDC_CTRL);
+			outw (ep_num | UDC_EP_Dir, UDC_EP_NUM);
+			UDCDBGA ("IN endpoint %d reset", ep_num);
+		}
+#endif
+	}
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_check_ep - check logical endpoint
+  *
+ * Return physical endpoint number to use for this logical endpoint or zero if not valid.
+ */
+#if 0
+int udc_check_ep (int logical_endpoint, int packetsize)
+{
+	if ((logical_endpoint == 0x80) ||
+	    ((logical_endpoint & 0x8f) != logical_endpoint)) {
+		return 0;
+	}
+
+	switch (packetsize) {
+	case 8:
+	case 16:
+	case 32:
+	case 64:
+	case 128:
+	case 256:
+	case 512:
+		break;
+	default:
+		return 0;
+	}
+
+	return EP_ADDR_TO_PHYS_EP (logical_endpoint);
+}
+#endif
+
+/*
+ * udc_setup_ep - setup endpoint
+ *
+ * Associate a physical endpoint with endpoint_instance
+ */
+void udc_setup_ep (struct usb_device_instance *device,
+		   unsigned int ep, struct usb_endpoint_instance *endpoint)
+{
+	UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address);
+
+	/* This routine gets called by bi_modinit for endpoint 0 and from
+	 * bi_config for all of the other endpoints.  bi_config gets called
+	 * during the DEVICE_CREATE, DEVICE_CONFIGURED, and
+	 * DEVICE_SET_INTERFACE events.	 We need to reconfigure the OMAP packet
+	 * RAM after bi_config scans the selected device configuration and
+	 * initializes the endpoint structures, but before this routine enables
+	 * the OUT endpoint FIFOs.  Since bi_config calls this routine in a
+	 * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our
+	 * packet RAM here when ep==1.
+	 * I really hate to do this here, but it seems like the API exported
+	 * by the USB bus interface controller driver to the usbd-bi module
+	 * isn't quite right so there is no good place to do this.
+	 */
+	if (ep == 1) {
+		omap1510_deconfigure_device ();
+		omap1510_configure_device (device);
+	}
+
+	if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
+		int ep_addr = endpoint->endpoint_address;
+
+		if (!ep_addr) {
+			/* nothing to do for endpoint 0 */
+		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			/* nothing to do for IN (tx) endpoints */
+		} else {	/* OUT (rx) endpoint */
+			if (endpoint->rcv_packetSize) {
+				/*struct urb* urb = &(urb_out_array[ep&0xFF]); */
+				/*urb->endpoint = endpoint; */
+				/*urb->device = device; */
+				/*urb->buffer_length = sizeof(urb->buffer); */
+
+				/*endpoint->rcv_urb = urb; */
+				omap1510_prepare_endpoint_for_rx (ep_addr);
+			}
+		}
+	}
+}
+
+/**
+ * udc_disable_ep - disable endpoint
+ * @ep:
+ *
+ * Disable specified endpoint
+ */
+#if 0
+void udc_disable_ep (unsigned int ep_addr)
+{
+	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr);	/*udc_device->bus->endpoint_array + ep; */
+
+	UDCDBGA ("disable ep_addr %d", ep_addr);
+
+	if (!ep_num) {
+		/* nothing to do for endpoint 0 */ ;
+	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		if (endpoint->tx_packetSize) {
+			/* we have a valid tx endpoint */
+			/*usbd_flush_tx(endpoint); */
+			endpoint->tx_urb = NULL;
+		}
+	} else {
+		if (endpoint->rcv_packetSize) {
+			/* we have a valid rx endpoint */
+			/*usbd_flush_rcv(endpoint); */
+			endpoint->rcv_urb = NULL;
+		}
+	}
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_connected - is the USB cable connected
+ *
+ * Return non-zero if cable is connected.
+ */
+#if 0
+int udc_connected (void)
+{
+	return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
+}
+#endif
+
+/* Turn on the USB connection by enabling the pullup resistor */
+void udc_connect (void)
+{
+	UDCDBG ("connect, enable Pullup");
+	outl (0x00000018, FUNC_MUX_CTRL_D);
+}
+
+/* Turn off the USB connection by disabling the pullup resistor */
+void udc_disconnect (void)
+{
+	UDCDBG ("disconnect, disable Pullup");
+	outl (0x00000000, FUNC_MUX_CTRL_D);
+}
+
+/* ************************************************************************** */
+
+
+/*
+ * udc_disable_interrupts - disable interrupts
+ * switch off interrupts
+ */
+#if 0
+void udc_disable_interrupts (struct usb_device_instance *device)
+{
+	UDCDBG ("disabling all interrupts");
+	outw (0, UDC_IRQ_EN);
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_ep0_packetsize - return ep0 packetsize
+ */
+#if 0
+int udc_ep0_packetsize (void)
+{
+	return EP0_PACKETSIZE;
+}
+#endif
+
+/* Switch on the UDC */
+void udc_enable (struct usb_device_instance *device)
+{
+	UDCDBGA ("enable device %p, status %d", device, device->status);
+
+	/* initialize driver state variables */
+	udc_devstat = 0;
+
+	/* Save the device structure pointer */
+	udc_device = device;
+
+	/* Setup ep0 urb */
+	if (!ep0_urb) {
+		ep0_urb =
+			usbd_alloc_urb (udc_device,
+					udc_device->bus->endpoint_array);
+	} else {
+		serial_printf ("udc_enable: ep0_urb already allocated %p\n",
+			       ep0_urb);
+	}
+
+	UDCDBG ("Check clock status");
+	UDCREG (STATUS_REQ);
+
+	/* The VBUS_MODE bit selects whether VBUS detection is done via
+	 * software (1) or hardware (0).  When software detection is
+	 * selected, VBUS_CTRL selects whether USB is not connected (0)
+	 * or connected (1).
+	 */
+	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
+	      FUNC_MUX_CTRL_0);
+	UDCREGL (FUNC_MUX_CTRL_0);
+
+	omap1510_configure_device (device);
+}
+
+/* Switch off the UDC */
+void udc_disable (void)
+{
+	UDCDBG ("disable UDC");
+
+	omap1510_deconfigure_device ();
+
+	/* The VBUS_MODE bit selects whether VBUS detection is done via
+	 * software (1) or hardware (0).  When software detection is
+	 * selected, VBUS_CTRL selects whether USB is not connected (0)
+	 * or connected (1).
+	 */
+	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+	outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+	UDCREGL (FUNC_MUX_CTRL_0);
+
+	/* Free ep0 URB */
+	if (ep0_urb) {
+		/*usbd_dealloc_urb(ep0_urb); */
+		ep0_urb = NULL;
+	}
+
+	/* Reset device pointer.
+	 * We ought to do this here to balance the initialization of udc_device
+	 * in udc_enable, but some of our other exported functions get called
+	 * by the bus interface driver after udc_disable, so we have to hang on
+	 * to the device pointer to avoid a null pointer dereference. */
+	/* udc_device = NULL; */
+}
+
+/**
+ * udc_startup - allow udc code to do any additional startup
+ */
+void udc_startup_events (struct usb_device_instance *device)
+{
+	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+	usbd_device_event_irq (device, DEVICE_INIT, 0);
+
+	/* The DEVICE_CREATE event puts the USB device in the state
+	 * STATE_ATTACHED.
+	 */
+	usbd_device_event_irq (device, DEVICE_CREATE, 0);
+
+	/* Some USB controller driver implementations signal
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+	 * The OMAP USB client controller has the capability to detect when the
+	 * USB cable is connected to a powered USB bus via the ATT bit in the
+	 * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
+	 * DEVICE_RESET events until later.
+	 */
+
+	udc_enable (device);
+}
+
+#endif
diff --git a/drivers/usbtty.c b/drivers/usbtty.c
new file mode 100644
index 0000000..2f89e2b
--- /dev/null
+++ b/drivers/usbtty.c
@@ -0,0 +1,647 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ *
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_TTY
+
+#include <circbuf.h>
+#include <devices.h>
+#include "usbtty.h"
+
+#if 0
+#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define TTYDBG(fmt,args...) do{}while(0)
+#endif
+
+#if 0
+#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define TTYERR(fmt,args...) do{}while(0)
+#endif
+
+/*
+ * Buffers to hold input and output data
+ */
+#define USBTTY_BUFFER_SIZE 256
+static circbuf_t usbtty_input;
+static circbuf_t usbtty_output;
+
+
+/*
+ * Instance variables
+ */
+static device_t usbttydev;
+static struct usb_device_instance	 device_instance[1];
+static struct usb_bus_instance		 bus_instance[1];
+static struct usb_configuration_instance config_instance[NUM_CONFIGS];
+static struct usb_interface_instance	 interface_instance[NUM_INTERFACES];
+static struct usb_alternate_instance	 alternate_instance[NUM_INTERFACES];
+static struct usb_endpoint_instance	 endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */
+
+/*
+ * Static allocation of urbs
+ */
+#define RECV_ENDPOINT 1
+#define TX_ENDPOINT 2
+
+/*
+ * Global flag
+ */
+int usbtty_configured_flag = 0;
+
+
+/*
+ * Descriptors
+ */
+static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
+static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
+static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
+static u8 wstrSerial[2 + 2*(sizeof(CONFIG_USBD_SERIAL_NUMBER)-1)];
+static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
+static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
+
+static struct usb_string_descriptor *usbtty_string_table[] = {
+  (struct usb_string_descriptor*)wstrLang,
+  (struct usb_string_descriptor*)wstrManufacturer,
+  (struct usb_string_descriptor*)wstrProduct,
+  (struct usb_string_descriptor*)wstrSerial,
+  (struct usb_string_descriptor*)wstrConfiguration,
+  (struct usb_string_descriptor*)wstrInterface
+};
+extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */
+
+static struct usb_device_descriptor device_descriptor = {
+  bLength:	      sizeof(struct usb_device_descriptor),
+  bDescriptorType:    USB_DT_DEVICE,
+  bcdUSB:	      USB_BCD_VERSION,
+  bDeviceClass:	      USBTTY_DEVICE_CLASS,
+  bDeviceSubClass:    USBTTY_DEVICE_SUBCLASS,
+  bDeviceProtocol:    USBTTY_DEVICE_PROTOCOL,
+  bMaxPacketSize0:    EP0_MAX_PACKET_SIZE,
+  idVendor:	      CONFIG_USBD_VENDORID,
+  idProduct:	      CONFIG_USBD_PRODUCTID,
+  bcdDevice:	      USBTTY_BCD_DEVICE,
+  iManufacturer:      STR_MANUFACTURER,
+  iProduct:	      STR_PRODUCT,
+  iSerialNumber:      STR_SERIAL,
+  bNumConfigurations: NUM_CONFIGS
+  };
+static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = {
+  {
+    bLength:		 sizeof(struct usb_configuration_descriptor),
+    bDescriptorType:	 USB_DT_CONFIG,
+    wTotalLength:	 (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) +
+			 (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) +
+			 (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS),
+    bNumInterfaces:	 NUM_INTERFACES,
+    bConfigurationValue: 1,
+    iConfiguration:	 STR_CONFIG,
+    bmAttributes:	 BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
+    bMaxPower:		 USBTTY_MAXPOWER
+  },
+};
+static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = {
+  {
+    bLength:		 sizeof(struct usb_interface_descriptor),
+    bDescriptorType:	 USB_DT_INTERFACE,
+    bInterfaceNumber:	 0,
+    bAlternateSetting:	 0,
+    bNumEndpoints:	 NUM_ENDPOINTS,
+    bInterfaceClass:	 USBTTY_INTERFACE_CLASS,
+    bInterfaceSubClass:	 USBTTY_INTERFACE_SUBCLASS,
+    bInterfaceProtocol:	 USBTTY_INTERFACE_PROTOCOL,
+    iInterface:		 STR_INTERFACE
+  },
+};
+static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = {
+  {
+    bLength:		 sizeof(struct usb_endpoint_descriptor),
+    bDescriptorType:	 USB_DT_ENDPOINT,
+    bEndpointAddress:	 CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT,
+    bmAttributes:	 USB_ENDPOINT_XFER_BULK,
+    wMaxPacketSize:	 CONFIG_USBD_SERIAL_OUT_PKTSIZE,
+    bInterval:		 0
+  },
+  {
+    bLength:		 sizeof(struct usb_endpoint_descriptor),
+    bDescriptorType:	 USB_DT_ENDPOINT,
+    bEndpointAddress:	 CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN,
+    bmAttributes:	 USB_ENDPOINT_XFER_BULK,
+    wMaxPacketSize:	 CONFIG_USBD_SERIAL_IN_PKTSIZE,
+    bInterval:		 0
+  },
+  {
+    bLength:		 sizeof(struct usb_endpoint_descriptor),
+    bDescriptorType:	 USB_DT_ENDPOINT,
+    bEndpointAddress:	 CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN,
+    bmAttributes:	 USB_ENDPOINT_XFER_INT,
+    wMaxPacketSize:	 CONFIG_USBD_SERIAL_INT_PKTSIZE,
+    bInterval:		 0
+  },
+};
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = {
+  &(ep_descriptors[0]),
+  &(ep_descriptors[1]),
+  &(ep_descriptors[2]),
+};
+
+/* utility function for converting char* to wide string used by USB */
+static void str2wide (char *str, u16 * wide)
+{
+	int i;
+
+	for (i = 0; i < strlen (str) && str[i]; i++)
+		wide[i] = (u16) str[i];
+}
+
+/*
+ * Prototypes
+ */
+static void usbtty_init_strings (void);
+static void usbtty_init_instances (void);
+static void usbtty_init_endpoints (void);
+
+static void usbtty_event_handler (struct usb_device_instance *device,
+				  usb_device_event_t event, int data);
+static int usbtty_configured (void);
+
+static int write_buffer (circbuf_t * buf);
+static int fill_buffer (circbuf_t * buf);
+
+void usbtty_poll (void);
+static void pretend_interrupts (void);
+
+
+/*
+ * Test whether a character is in the RX buffer
+ */
+int usbtty_tstc (void)
+{
+	usbtty_poll ();
+	return (usbtty_input.size > 0);
+}
+
+/*
+ * Read a single byte from the usb client port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+int usbtty_getc (void)
+{
+	char c;
+
+	while (usbtty_input.size <= 0) {
+		usbtty_poll ();
+	}
+
+	buf_pop (&usbtty_input, &c, 1);
+	return c;
+}
+
+/*
+ * Output a single byte to the usb client port.
+ */
+void usbtty_putc (const char c)
+{
+	buf_push (&usbtty_output, &c, 1);
+	/* If \n, also do \r */
+	if (c == '\n')
+		buf_push (&usbtty_output, "\r", 1);
+
+	/* Poll at end to handle new data... */
+	if ((usbtty_output.size + 2) >= usbtty_output.totalsize) {
+		usbtty_poll ();
+	}
+}
+
+
+/* usbtty_puts() helper function for finding the next '\n' in a string */
+static int next_nl_pos (const char *s)
+{
+	int i;
+
+	for (i = 0; s[i] != '\0'; i++) {
+		if (s[i] == '\n')
+			return i;
+	}
+	return i;
+}
+
+/*
+ * Output a string to the usb client port.
+ */
+static void __usbtty_puts (const char *str, int len)
+{
+	int maxlen = usbtty_output.totalsize;
+	int space, n;
+
+	/* break str into chunks < buffer size, if needed */
+	while (len > 0) {
+		space = maxlen - usbtty_output.size;
+
+		/* Empty buffer here, if needed, to ensure space... */
+		if (space <= 0) {
+			write_buffer (&usbtty_output);
+			space = maxlen - usbtty_output.size;
+			if (space <= 0) {
+				space = len;	/* allow old data to be overwritten. */
+			}
+		}
+
+		n = MIN (space, MIN (len, maxlen));
+		buf_push (&usbtty_output, str, n);
+
+		str += n;
+		len -= n;
+	}
+}
+
+void usbtty_puts (const char *str)
+{
+	int n;
+	int len = strlen (str);
+
+	/* add '\r' for each '\n' */
+	while (len > 0) {
+		n = next_nl_pos (str);
+
+		if (str[n] == '\n') {
+			__usbtty_puts (str, n + 1);
+			__usbtty_puts ("\r", 1);
+			str += (n + 1);
+			len -= (n + 1);
+		} else {
+			/* No \n found.	 All done. */
+			__usbtty_puts (str, n);
+			break;
+		}
+	}
+
+	/* Poll at end to handle new data... */
+	usbtty_poll ();
+}
+
+/*
+ * Initialize the usb client port.
+ *
+ */
+int drv_usbtty_init (void)
+{
+	int rc;
+
+
+	/* prepare buffers... */
+	buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
+	buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
+
+	/* Now, set up USB controller and infrastructure */
+	udc_init ();		/* Basic USB initialization */
+
+	usbtty_init_strings ();
+	usbtty_init_instances ();
+
+	udc_startup_events (device_instance);	/* Enable our device, initialize udc pointers */
+	udc_connect ();		/* Enable pullup for host detection */
+
+	usbtty_init_endpoints ();
+
+	/* Device initialization */
+	memset (&usbttydev, 0, sizeof (usbttydev));
+
+	strcpy (usbttydev.name, "usbtty");
+	usbttydev.ext = 0;	/* No extensions */
+	usbttydev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT;
+	usbttydev.tstc = usbtty_tstc;	/* 'tstc' function */
+	usbttydev.getc = usbtty_getc;	/* 'getc' function */
+	usbttydev.putc = usbtty_putc;	/* 'putc' function */
+	usbttydev.puts = usbtty_puts;	/* 'puts' function */
+
+	rc = device_register (&usbttydev);
+
+	return (rc == 0) ? 1 : rc;
+}
+
+static void usbtty_init_strings (void)
+{
+	struct usb_string_descriptor *string;
+
+	string = (struct usb_string_descriptor *) wstrManufacturer;
+	string->bLength = sizeof (wstrManufacturer);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
+
+	string = (struct usb_string_descriptor *) wstrProduct;
+	string->bLength = sizeof (wstrProduct);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
+
+	string = (struct usb_string_descriptor *) wstrSerial;
+	string->bLength = sizeof (wstrSerial);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_SERIAL_NUMBER, string->wData);
+
+	string = (struct usb_string_descriptor *) wstrConfiguration;
+	string->bLength = sizeof (wstrConfiguration);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData);
+
+	string = (struct usb_string_descriptor *) wstrInterface;
+	string->bLength = sizeof (wstrInterface);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_INTERFACE_STR, string->wData);
+
+	/* Now, initialize the string table for ep0 handling */
+	usb_strings = usbtty_string_table;
+}
+
+static void usbtty_init_instances (void)
+{
+	int i;
+
+	/* initialize device instance */
+	memset (device_instance, 0, sizeof (struct usb_device_instance));
+	device_instance->device_state = STATE_INIT;
+	device_instance->device_descriptor = &device_descriptor;
+	device_instance->event = usbtty_event_handler;
+	device_instance->bus = bus_instance;
+	device_instance->configurations = NUM_CONFIGS;
+	device_instance->configuration_instance_array = config_instance;
+
+	/* initialize bus instance */
+	memset (bus_instance, 0, sizeof (struct usb_bus_instance));
+	bus_instance->device = device_instance;
+	bus_instance->endpoint_array = endpoint_instance;
+	bus_instance->max_endpoints = 1;
+	bus_instance->maxpacketsize = 64;
+	bus_instance->serial_number_str = CONFIG_USBD_SERIAL_NUMBER;
+
+	/* configuration instance */
+	memset (config_instance, 0,
+		sizeof (struct usb_configuration_instance));
+	config_instance->interfaces = NUM_INTERFACES;
+	config_instance->configuration_descriptor = config_descriptors;
+	config_instance->interface_instance_array = interface_instance;
+
+	/* interface instance */
+	memset (interface_instance, 0,
+		sizeof (struct usb_interface_instance));
+	interface_instance->alternates = 1;
+	interface_instance->alternates_instance_array = alternate_instance;
+
+	/* alternates instance */
+	memset (alternate_instance, 0,
+		sizeof (struct usb_alternate_instance));
+	alternate_instance->interface_descriptor = interface_descriptors;
+	alternate_instance->endpoints = NUM_ENDPOINTS;
+	alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs;
+
+	/* endpoint instances */
+	memset (&endpoint_instance[0], 0,
+		sizeof (struct usb_endpoint_instance));
+	endpoint_instance[0].endpoint_address = 0;
+	endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE;
+	endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL;
+	endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE;
+	endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL;
+	udc_setup_ep (device_instance, 0, &endpoint_instance[0]);
+
+	for (i = 1; i <= NUM_ENDPOINTS; i++) {
+		memset (&endpoint_instance[i], 0,
+			sizeof (struct usb_endpoint_instance));
+
+		endpoint_instance[i].endpoint_address =
+			ep_descriptors[i - 1].bEndpointAddress;
+
+		endpoint_instance[i].rcv_packetSize =
+			ep_descriptors[i - 1].wMaxPacketSize;
+		endpoint_instance[i].rcv_attributes =
+			ep_descriptors[i - 1].bmAttributes;
+
+		endpoint_instance[i].tx_packetSize =
+			ep_descriptors[i - 1].wMaxPacketSize;
+		endpoint_instance[i].tx_attributes =
+			ep_descriptors[i - 1].bmAttributes;
+
+		urb_link_init (&endpoint_instance[i].rcv);
+		urb_link_init (&endpoint_instance[i].rdy);
+		urb_link_init (&endpoint_instance[i].tx);
+		urb_link_init (&endpoint_instance[i].done);
+
+		if (endpoint_instance[i].endpoint_address & USB_DIR_IN)
+			endpoint_instance[i].tx_urb =
+				usbd_alloc_urb (device_instance,
+						&endpoint_instance[i]);
+		else
+			endpoint_instance[i].rcv_urb =
+				usbd_alloc_urb (device_instance,
+						&endpoint_instance[i]);
+	}
+}
+
+static void usbtty_init_endpoints (void)
+{
+	int i;
+
+	bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+	for (i = 0; i <= NUM_ENDPOINTS; i++) {
+		udc_setup_ep (device_instance, i, &endpoint_instance[i]);
+	}
+}
+
+
+/*********************************************************************************/
+
+static struct urb *next_urb (struct usb_device_instance *device,
+			     struct usb_endpoint_instance *endpoint)
+{
+	struct urb *current_urb = NULL;
+	int space;
+
+	/* If there's a queue, then we should add to the last urb */
+	if (!endpoint->tx_queue) {
+		current_urb = endpoint->tx_urb;
+	} else {
+		/* Last urb from tx chain */
+		current_urb =
+			p2surround (struct urb, link, endpoint->tx.prev);
+	}
+
+	/* Make sure this one has enough room */
+	space = current_urb->buffer_length - current_urb->actual_length;
+	if (space > 0) {
+		return current_urb;
+	} else {		/* No space here */
+		/* First look at done list */
+		current_urb = first_urb_detached (&endpoint->done);
+		if (!current_urb) {
+			current_urb = usbd_alloc_urb (device, endpoint);
+		}
+
+		urb_append (&endpoint->tx, current_urb);
+		endpoint->tx_queue++;
+	}
+	return current_urb;
+}
+
+static int write_buffer (circbuf_t * buf)
+{
+	if (!usbtty_configured ()) {
+		return 0;
+	}
+
+	if (buf->size) {
+
+		struct usb_endpoint_instance *endpoint =
+			&endpoint_instance[TX_ENDPOINT];
+		struct urb *current_urb = NULL;
+		char *dest;
+
+		int space_avail;
+		int popnum, popped;
+		int total = 0;
+
+		/* Break buffer into urb sized pieces, and link each to the endpoint */
+		while (buf->size > 0) {
+			current_urb = next_urb (device_instance, endpoint);
+			if (!current_urb) {
+				TTYERR ("current_urb is NULL, buf->size %d\n",
+					buf->size);
+				return total;
+			}
+
+			dest = current_urb->buffer +
+				current_urb->actual_length;
+
+			space_avail =
+				current_urb->buffer_length -
+				current_urb->actual_length;
+			popnum = MIN (space_avail, buf->size);
+			if (popnum == 0)
+				break;
+
+			popped = buf_pop (buf, dest, popnum);
+			if (popped == 0)
+				break;
+			current_urb->actual_length += popped;
+			total += popped;
+
+			/* If endpoint->last == 0, then transfers have not started on this endpoint */
+			if (endpoint->last == 0) {
+				udc_endpoint_write (endpoint);
+			}
+
+		}		/* end while */
+		return total;
+	}			/* end if tx_urb */
+
+	return 0;
+}
+
+static int fill_buffer (circbuf_t * buf)
+{
+	struct usb_endpoint_instance *endpoint =
+		&endpoint_instance[RECV_ENDPOINT];
+
+	if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
+		unsigned int nb = endpoint->rcv_urb->actual_length;
+		char *src = (char *) endpoint->rcv_urb->buffer;
+
+		buf_push (buf, src, nb);
+		endpoint->rcv_urb->actual_length = 0;
+
+		return nb;
+	}
+
+	return 0;
+}
+
+static int usbtty_configured (void)
+{
+	return usbtty_configured_flag;
+}
+
+/*********************************************************************************/
+
+static void usbtty_event_handler (struct usb_device_instance *device,
+				  usb_device_event_t event, int data)
+{
+	switch (event) {
+	case DEVICE_RESET:
+	case DEVICE_BUS_INACTIVE:
+		usbtty_configured_flag = 0;
+		break;
+	case DEVICE_CONFIGURED:
+		usbtty_configured_flag = 1;
+		break;
+
+	case DEVICE_ADDRESS_ASSIGNED:
+		usbtty_init_endpoints ();
+
+	default:
+		break;
+	}
+}
+
+/*********************************************************************************/
+
+
+/*
+ * Since interrupt handling has not yet been implemented, we use this function
+ * to handle polling.  This is called by the tstc,getc,putc,puts routines to
+ * update the USB state.
+ */
+void usbtty_poll (void)
+{
+	/* New interrupts? */
+	pretend_interrupts ();
+
+	/* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */
+	if (usbtty_configured ()) {
+		write_buffer (&usbtty_output);
+	}
+
+	/* New interrupts? */
+	pretend_interrupts ();
+
+	/* Check for new data from host.. (do this after checking interrupts to get latest data) */
+	if (usbtty_configured ()) {
+		fill_buffer (&usbtty_input);
+	}
+
+	/* New interrupts? */
+	pretend_interrupts ();
+}
+
+static void pretend_interrupts (void)
+{
+	/* Loop while we have interrupts.
+	 * If we don't do this, the input chain
+	 * polling delay is likely to miss
+	 * host requests.
+	 */
+	while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
+		/* Handle any new IRQs */
+		omap1510_udc_irq ();
+		omap1510_udc_noniso_irq ();
+	}
+}
+#endif
diff --git a/drivers/usbtty.h b/drivers/usbtty.h
new file mode 100644
index 0000000..79c2fe5
--- /dev/null
+++ b/drivers/usbtty.h
@@ -0,0 +1,64 @@
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ *
+ */
+
+#ifndef __USB_TTY_H__
+#define __USB_TTY_H__
+
+
+#include "usbdcore.h"
+#include "usbdcore_omap1510.h"
+
+
+#define NUM_CONFIGS    1
+#define NUM_INTERFACES 1
+#define NUM_ENDPOINTS  3
+
+#define EP0_MAX_PACKET_SIZE 64
+
+#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
+#define CONFIG_USBD_INTERFACE_STR     "Simple Serial Data Interface - Bulk Mode"
+
+
+#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2
+#define CONFIG_USBD_SERIAL_OUT_PKTSIZE	64
+#define CONFIG_USBD_SERIAL_IN_ENDPOINT	1
+#define CONFIG_USBD_SERIAL_IN_PKTSIZE	64
+#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5
+#define CONFIG_USBD_SERIAL_INT_PKTSIZE	16
+
+
+#define USBTTY_DEVICE_CLASS	COMMUNICATIONS_DEVICE_CLASS
+#define USBTTY_DEVICE_SUBCLASS	COMMUNICATIONS_NO_SUBCLASS
+#define USBTTY_DEVICE_PROTOCOL	COMMUNICATIONS_NO_PROTOCOL
+
+#define USBTTY_INTERFACE_CLASS	   0xFF /* Vendor Specific */
+#define USBTTY_INTERFACE_SUBCLASS  0x02
+#define USBTTY_INTERFACE_PROTOCOL  0x01
+
+#define USBTTY_BCD_DEVICE 0x0
+#define USBTTY_MAXPOWER	  0x0
+
+#define STR_MANUFACTURER 1
+#define STR_PRODUCT	 2
+#define STR_SERIAL	 3
+#define STR_CONFIG	 4
+#define STR_INTERFACE	 5
+
+#endif